diff options
391 files changed, 11590 insertions, 7299 deletions
diff --git a/AndroidKernel.mk b/AndroidKernel.mk index 15877a69027..bc15d8a7783 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -1,25 +1,55 @@ #Android makefile to build kernel as a part of Android Build PERL = perl +TARGET_KERNEL_ARCH := $(strip $(TARGET_KERNEL_ARCH)) +ifeq ($(TARGET_KERNEL_ARCH),) +KERNEL_ARCH := arm +else +KERNEL_ARCH := $(TARGET_KERNEL_ARCH) +endif + +TARGET_KERNEL_HEADER_ARCH := $(strip $(TARGET_KERNEL_HEADER_ARCH)) +ifeq ($(TARGET_KERNEL_HEADER_ARCH),) +KERNEL_HEADER_ARCH := $(KERNEL_ARCH) +else +$(warning Forcing kernel header generation only for '$(TARGET_KERNEL_HEADER_ARCH)') +KERNEL_HEADER_ARCH := $(TARGET_KERNEL_HEADER_ARCH) +endif + +KERNEL_HEADER_DEFCONFIG := $(strip $(KERNEL_HEADER_DEFCONFIG)) +ifeq ($(KERNEL_HEADER_DEFCONFIG),) +KERNEL_HEADER_DEFCONFIG := $(KERNEL_DEFCONFIG) +endif + +TARGET_KERNEL_CROSS_COMPILE_PREFIX := $(strip $(TARGET_KERNEL_CROSS_COMPILE_PREFIX)) +ifeq ($(TARGET_KERNEL_CROSS_COMPILE_PREFIX),) +KERNEL_CROSS_COMPILE := arm-eabi- +else +KERNEL_CROSS_COMPILE := $(TARGET_KERNEL_CROSS_COMPILE_PREFIX) +endif + ifeq ($(TARGET_PREBUILT_KERNEL),) KERNEL_OUT := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ KERNEL_CONFIG := $(KERNEL_OUT)/.config -ifeq ($(TARGET_KERNEL_APPEND_DTB), true) -TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/arm/boot/zImage-dtb + +ifeq ($(TARGET_USES_UNCOMPRESSED_KERNEL),true) +$(info Using uncompressed kernel) +TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/Image else -TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/arm/boot/zImage +TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/zImage +endif + +ifeq ($(TARGET_KERNEL_APPEND_DTB), true) +$(info Using appended DTB) +TARGET_PREBUILT_INT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL)-dtb endif + KERNEL_HEADERS_INSTALL := $(KERNEL_OUT)/usr KERNEL_MODULES_INSTALL := system KERNEL_MODULES_OUT := $(TARGET_OUT)/lib/modules -ifeq ($(TARGET_USES_UNCOMPRESSED_KERNEL),true) -$(info Using uncompressed kernel) -TARGET_PREBUILT_KERNEL := $(KERNEL_OUT)/piggy -else TARGET_PREBUILT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL) -endif define mv-modules mdpath=`find $(KERNEL_MODULES_OUT) -type f -name modules.dep`;\ @@ -41,30 +71,31 @@ $(KERNEL_OUT): mkdir -p $(KERNEL_OUT) $(KERNEL_CONFIG): $(KERNEL_OUT) - $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- $(KERNEL_DEFCONFIG) - -$(KERNEL_OUT)/piggy : $(TARGET_PREBUILT_INT_KERNEL) - $(hide) gunzip -c $(KERNEL_OUT)/arch/arm/boot/compressed/piggy.gzip > $(KERNEL_OUT)/piggy + $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG) -$(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_CONFIG) $(KERNEL_HEADERS_INSTALL) - $(hide) rm -rf $(KERNEL_OUT)/arch/arm/boot/dts - $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- - $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- modules - $(MAKE) -C kernel O=../$(KERNEL_OUT) INSTALL_MOD_PATH=../../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 ARCH=arm CROSS_COMPILE=arm-eabi- modules_install +$(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL) + $(hide) rm -rf $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts + $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) + $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules + $(MAKE) -C kernel O=../$(KERNEL_OUT) INSTALL_MOD_PATH=../../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules_install $(mv-modules) $(clean-module-folder) -$(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) $(KERNEL_CONFIG) - $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- headers_install +$(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) + $(hide) rm -f ../$(KERNEL_CONFIG) + $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_HEADER_DEFCONFIG) + $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) headers_install + $(hide) rm -f ../$(KERNEL_CONFIG) + $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG) kerneltags: $(KERNEL_OUT) $(KERNEL_CONFIG) - $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- tags + $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) tags kernelconfig: $(KERNEL_OUT) $(KERNEL_CONFIG) env KCONFIG_NOTIMESTAMP=true \ - $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- menuconfig + $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) menuconfig env KCONFIG_NOTIMESTAMP=true \ - $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- savedefconfig - cp $(KERNEL_OUT)/defconfig kernel/arch/arm/configs/$(KERNEL_DEFCONFIG) + $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) savedefconfig + cp $(KERNEL_OUT)/defconfig kernel/arch/$(KERNEL_ARCH)/configs/$(KERNEL_DEFCONFIG) endif diff --git a/Documentation/devicetree/bindings/arm/msm/msm_tspp2.txt b/Documentation/devicetree/bindings/arm/msm/msm_tspp2.txt index c3039671a38..cd801580261 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm_tspp2.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm_tspp2.txt @@ -18,13 +18,6 @@ Required properties: TSIF_TSPP2, TSIF0, TSIF1, TSIF_BAM. - interrupt-names: TSPP2, TSIF and BAM interrupt names. - vdd-supply: power regulator (GDSC) supplying power to the broadcast subsystem. -- qcom,tspp2-ahb-clk: TSPP2 AHB clock name. -- qcom,tspp2-core-clk: TSPP2 core clock name. -- qcom,tspp2-vbif-clk: TSPP2 VBIF clock name. -- qcom,tspp2-klm-ahb-clk: TSPP2 key ladder AHB clock name. -- qcom,tsif-ref-clk: TSIF reference clock name. - The driver uses clk_get to get the clocks by name. The clocks - should be defined in the relevant clock file (e.g. clock-8092.c). Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for more information on the following four properties: - qcom,msm-bus,name: String representing the client name ("tspp2"). @@ -34,18 +27,18 @@ for more information on the following four properties: - qcom,msm-bus,vectors-KBps: represents the bandwidths required for the above usecases. - qcom,iommu-hlos-group: Name of the Broadcast HLOS IOMMU domain as defined in - <target>-iommu-domains.dtsi, (e.g. mpq8092-iommu-domains.dtsi). + <target>-iommu-domains.dtsi. The Broadcast HLOS IOMMU domain includes a context bank and virtual address pools definitions, used for mapping non-secured pipe memory buffers. - qcom,iommu-hlos-partition: Partition number in the HLOS IOMMU domain. - qcom,iommu-cpz-group: Name of the Broadcast CPZ IOMMU domain as defined in - <target>-iommu-domains.dtsi, (e.g. mpq8092-iommu-domains.dtsi). + <target>-iommu-domains.dtsi. The Broadcast CPZ IOMMU domain includes a context bank and virtual address pool definitions, used for mapping secured pipe memory buffers. - qcom,iommu-cpz-partition: Partition number in the CPZ IOMMU domain. -Example (for MPQ8092 platform, avaialble at mpq8092.dtsi): +Example: tspp2: msm_tspp2@fc724000 { compatible = "qcom,msm_tspp2"; @@ -67,11 +60,6 @@ Example (for MPQ8092 platform, avaialble at mpq8092.dtsi): "TSIF1", "TSPP2_BAM"; vdd-supply = <&gdsc_bcss>; - qcom,tspp2-ahb-clk = "bcc_tspp2_ahb_clk"; - qcom,tspp2-core-clk = "bcc_tspp2_core_clk"; - qcom,tspp2-vbif-clk = "bcc_vbif_tspp2_clk"; - qcom,tspp2-klm-ahb-clk = "bcc_klm_ahb_clk"; - qcom,tsif-ref-clk = "gcc_tsif_ref_clk"; qcom,msm-bus,name = "tspp2"; qcom,msm-bus,num-cases = <3>; qcom,msm-bus,num-paths = <1>; diff --git a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt index 01cc798719b..1bb465953f9 100644 --- a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt +++ b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt @@ -16,6 +16,13 @@ Required properties: Optional properties: - qcom,ce-hw-shared : optional, indicates if the hardware is shared between EE. - qcom,ce-hw-key : optional, indicates if the hardware supports use of HW KEY. + - qcom,use-sw-aes-cbc-ecb-ctr-algo : optional, indicates if use SW aes-cbc/ecb/ctr algorithm. + - qcom,use-sw-aes-xts-algo : optional, indicates if use SW aes-xts algorithm. + - qcom,use-sw-aead-algo : optional, indicates if use SW aead algorithm. + - qcom,use-sw-ahash-algo : optional, indicates if use SW hash algorithm. + - qcom,use-sw-hmac-algo : optional, indicates if use SW hmac algorithm. + - qcom,use-sw-aes-ccm-algo : optional, indicates if use SW aes-ccm algorithm. + - qcom,clk-mgmt-sus-res : optional, indicate if the ce clocks need to be disabled/enabled in suspend/resume function. Example: diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index 4a25c9ffdf4..c3b1c163d68 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -126,6 +126,9 @@ Optional properties: implemented during suspend/resume. "dfps_immediate_clk_mode" = FPS change request is implemented immediately using DSI clocks. + "dfps_immediate_porch_mode" = FPS change request is + implemented immediately by changing panel porch + values. - qcom,mdss-dsi-bl-pmic-control-type: A string that specifies the implementation of backlight control for this panel. "bl_ctrl_pwm" = Backlight controlled by PWM gpio. diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt index 233de0d453c..f95f2a0abc2 100644 --- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt +++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt @@ -27,6 +27,14 @@ Required properties to the respective VIG pipes. Number of xin ids defined should match the number of offsets defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-vig-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off - qcom,mdss-pipe-rgb-off: Array of offsets for MDP source surface pipes of type RGB, the offsets are calculated from register "mdp_phys" defined in reg property. @@ -42,6 +50,14 @@ Required properties to the respective RGB pipes. Number of xin ids defined should match the number of offsets defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-rgb-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off - qcom,mdss-pipe-dma-off: Array of offsets for MDP source surface pipes of type DMA, the offsets are calculated from register "mdp_phys" defined in reg property. @@ -57,19 +73,19 @@ Required properties to the respective DMA pipes. Number of xin ids defined should match the number of offsets defined in property: qcom,mdss-pipe-dma-off +- qcom,mdss-pipe-dma-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off - qcom,mdss-smp-data: Array of shared memory pool data. There should be only two values in this property. The first value corresponds to the number of smp blocks and the second is the size of each block present in the mdss hardware. -- qcom,mdss-sspp-len: Address offset for SSPP pipes from one to the - next. These are calculated using the difference between - successive VIG pipes or RGB pipes or DMA pipes. The offset - is same for any of these three types of pipes hence there - is only one variable. For targets with single VIG pipe or - single RGB pipe or single DMA pipe this value has been taken - from targets with similar architecture but having multiple - SSPP pipes. - qcom,mdss-ctl-off: Array of offset addresses for the available ctl hw blocks within MDP, these offsets are calculated from register "mdp_phys" defined in @@ -115,21 +131,6 @@ Required properties defined in reg property. The number of offsets defiend should reflect the number of progammable interface blocks available in hardware. -- qcom,mdss-ctl-len: Address offset from one CTL to the next. These - offsets are calculated using difference of successive CTL - offsets. The offset is constant for successive CTL. -- qcom,mdss-mixer-intf-len: Address offset from one layer mixer to the next. - These are calculated using difference of successive layer - mixer offsets. The offset is constant for successive layer - mixers. For targets with single layer mixer this value has - been taken from targets with multiple layer mixers with - similar architecture. -- qcom,mdss-dspp-len: Address offset from one DSPP to the next. These - offsets are calculated using difference of successive DSPP - base addresses. The offset is constant for successive DSPP - pipes. For targets with single DSPP this value has been taken - from targets with multiple DSPP pipes with similar - architecture. - qcom,mdss-pref-prim-intf: A string which indicates the configured hardware interface between MDP and the primary panel. Individual panel controller drivers initialize @@ -259,6 +260,21 @@ Optional properties: total numbers of MMBs per pipe while values, if any, following first one denotes indexes of MMBs to that RGB pipe. +- qcom,mdss-pipe-sw-reset-off: Property to indicate offset to the register which + holds sw_reset bitmap for different MDSS + components. +- qcom,mdss-pipe-vig-sw-reset-map: Array of bit offsets for vig pipes within + sw_reset register bitmap. Number of offsets + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-rgb-sw-reset-map: Array of bit offsets for rgb pipes within + sw_reset register bitmap. Number of offsets + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-dma-sw-reset-map: Array of bit offsets for dma pipes within + sw_reset register bitmap. Number of offsets + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off Fudge Factors: Fudge factors are used to boost demand for resources like bus bandswidth, clk rate etc. to @@ -355,7 +371,6 @@ Example: /* Fudge factors */ qcom,mdss-ab-factor = <2 1>; /* 2 times */ qcom,mdss-ib-factor = <3 2>; /* 1.5 times */ - qcom,mdss-high-ib-factor = <2 1>; /* 2 times */ qcom,mdss-clk-factor = <5 4>; /* 1.25 times */ qcom,max-bandwidth-low-kbps = <2300000>; @@ -379,7 +394,6 @@ Example: <2 4 5>, <2 6 7>; qcom,mdss-smp-data = <22 4096>; - qcom,mdss-sspp-len = <0x00000400>; qcom,mdss-rot-block-size = <64>; qcom,mdss-smp-mb-per-pipe = <2>; qcom,mdss-pref-prim-intf = "dsi"; @@ -391,6 +405,24 @@ Example: qcom,mdss-pipe-rgb-xin-id = <1 5 9>; qcom,mdss-pipe-dma-xin-id = <2 10>; + qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>, + <0x3B4 0 0>, + <0x3BC 0 0>, + <0x3C4 0 0>; + + qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>, + <0x3B4 4 8>, + <0x3BC 4 8>, + <0x3C4 4 8>; + + qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>, + <0x3B4 8 12>; + + qcom,mdss-pipe-sw-reset-off = <0x0128>; + qcom,mdss-pipe-vig-sw-reset-map = <5 6 7 8>; + qcom,mdss-pipe-rgb-sw-reset-map = <9 10 11 12>; + qcom,mdss-pipe-dma-sw-reset-map = <13 14>; + qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800 0x00000900 0x0000A00>; qcom,mdss-mixer-intf-off = <0x00003200 0x00003600 @@ -402,9 +434,6 @@ Example: 0x00017100 0x00019100>; qcom,mdss-intf-off = <0x00021100 0x00021300 0x00021500 0x00021700>; - qcom,mdss-ctl-len = <0x00000100>; - qcom,mdss-mixer-intf-len = <0x00000400>; - qcom,mdss-dspp-len = <0x00000400>; /* buffer parameters to calculate prefill bandwidth */ qcom,mdss-prefill-outstanding-buffer-bytes = <1024>; diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt index 1d8f31d9ed7..7b0d42a086c 100644 --- a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt +++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt @@ -31,6 +31,7 @@ Optional properties: - qcom,hdmi-tx-mux-sel: gpio required to toggle HDMI output between docking station, type A, and liquid device, type D, ports. Required property for liquid devices. +- qcom,hdmi-tx-ddc-mux-sel: gpio for ddc mux select. - qcom,hdmi-tx-mux-en: gpio required to enable mux for HDMI output on liquid devices. Required property for liquid devices. - qcom,hdmi-tx-mux-lpm: gpio required for hdmi mux configuration @@ -66,6 +67,7 @@ Example: qcom,enable-load = <0 0 0 1800000 0>; qcom,disable-load = <0 0 0 0 0>; + qcom,hdmi-tx-ddc-mux-sel = <&pma8084_gpios 6 0>; qcom,hdmi-tx-cec = <&msmgpio 31 0>; qcom,hdmi-tx-ddc-clk = <&msmgpio 32 0>; qcom,hdmi-tx-ddc-data = <&msmgpio 33 0>; diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt index 6621605e737..83403ba8628 100644 --- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt +++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt @@ -52,6 +52,7 @@ Required properties: 2 : {1, 4} 3 : {1, 6} 4 : {1, 20} + 5 : {1, 8} - qcom,calibration-type : Reference voltage to use for channel calibration. Channel calibration is dependendent on the channel. Certain channels like XO_THERM, BATT_THERM use ratiometric diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt index f2ca95b0e34..d0c2b7de9b0 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt @@ -29,7 +29,7 @@ Optional properties: It is a four tuple consisting of min x, min y, max x and max y values. - goodix,i2c-pull-up : To specify pull up is required. - - goodix,no-force-update : To specify force update is allowed. + - goodix,force-update : To specify force update is allowed. - goodix,enable-power-off : Power off touchscreen during suspend. - goodix,button-map : Button map of key codes. The number of key codes depend on panel. diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt index 3ee245ee8ef..b28bd82aa40 100644 --- a/Documentation/devicetree/bindings/memory.txt +++ b/Documentation/devicetree/bindings/memory.txt @@ -34,17 +34,18 @@ wit the following convention: (name): region@(base-address) { reg = <(baseaddr) (size)>; - (linux,contiguous-region); + (linux,reserve-contiguous-region); (linux,default-contiguous-region); (linux,reserve-region); (linux,memory-limit); + (linux,remove-completely); label = (unique_name); }; name: an name given to the defined region. base-address: the base address of the defined region. size: the size of the memory region. -linux,contiguous-region: property indicating that the defined memory +linux,reserve-contiguous-region: property indicating that the defined memory region is used for contiguous memory allocations, Linux specific (optional) linux,default-contiguous-region: property indicating that the region @@ -58,6 +59,10 @@ linux,memory-limit: property specifying an upper bound on the physical address is specificed, the region may be placed anywhere in the physical address space. 0 may be used to specify lowmem (i.e. the region will be placed in the direct mapped lowmem region) +linux,remove-completely: property indicating the memory will be removed from the + linux page allocator completely. This means that page structures + associated with the memory will not be valid. This binding is + expected to be used in conjunction with linux,reserve-region. label: an internal name used for automatically associating the cma region with a given device. The label is optional; if the label is not given the client is responsible for @@ -98,13 +103,13 @@ logo appears. 0x70000000 0x10000000>; contig_mem: region@72000000 { - linux,contiguous-region; + linux,reserve-contiguous-region; linux,default-contiguous-region; reg = <0x72000000 0x4000000>; }; display_mem: region@78000000 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0x78000000 0x1000000>; }; }; diff --git a/Documentation/devicetree/bindings/nfc/nfc-nci.txt b/Documentation/devicetree/bindings/nfc/nfc-nci.txt index 6ebd4aa3df4..2c06599902a 100644 --- a/Documentation/devicetree/bindings/nfc/nfc-nci.txt +++ b/Documentation/devicetree/bindings/nfc/nfc-nci.txt @@ -8,13 +8,15 @@ Required properties: - reg: NCI i2c slave address. - qcom,dis-gpio: specific gpio for hardware reset. - qcom,irq-gpio: specific gpio for read interrupt. -- qcom,clk-src: nfc clock source ("BBCLK2", "RFCLK3", "GPCLK", "GPCLK2" ...) -- qcom,clk-en-gpio: msm gpio clock,used ony if clock source is msm gpio +- qcom,clk-src: nfc clock source ("BBCLK2", "RFCLK3", "GPCLK", "GPCLK2", ...) +- qcom,clk-src-gpio: msm gpio clock,used ony if clock source is msm gpio +- qcom,clk-req-gpio: clk-req input gpio for MSM based clocks. + not used for pmic implementation - vlogic-supply: LDO for power supply - interrupt-parent: Should be phandle for the interrupt controller that services interrupts for this device. -- interrupts: should contain the NFC interrupt. NFC has one read interrupt. -- qcom,clk-gpio: pmic gpio on which bbclk2 signal is coming. +- interrupts: Nfc read interrupt,gpio-clk-req interrupt +- qcom,clk-gpio: pmic or msm gpio on which bbclk2 signal is coming. LDO example: @@ -24,8 +26,8 @@ LDO example: reg = <0x0e>; qcom,irq-gpio = <&msmgpio 77 0x00>; qcom,dis-gpio = <&msmgpio 93 0x00>; - qcom,clk-en-gpio = <&msmgpio 78 0x00>; - qcom,clk-src = "GPCLK"; + qcom,clk-src-gpio = <&msmgpio 78 0x00>; + qcom,clk-src = "GPCLK2"; interrupt-parent = <&msmgpio>; interrupts = <77 0>; qcom,clk-gpio = <&msmgpio 75 0x00>; diff --git a/Documentation/devicetree/bindings/pil/pil-bcss.txt b/Documentation/devicetree/bindings/pil/pil-bcss.txt deleted file mode 100644 index d4a983480dd..00000000000 --- a/Documentation/devicetree/bindings/pil/pil-bcss.txt +++ /dev/null @@ -1,20 +0,0 @@ -* Broadcast Subsystem Peripheral Image Loader - -pil-bcss is a peripheral image loading (PIL) driver. It is used for loading -and authenticating broadcast demodulator firmware images. - -Required properties: -- compatible: "pil-bcss" -- qcom,firmware-name: Base name of the firmware image. Ex. "bcss" - -Optional properties: -- qcom,restart-group: List of subsystems that will need to restart together. - -Example: - - qcom,pil-bcss { - compatible = "qcom,pil-bcss"; - - qcom,firmware-name = "bcss"; - }; - diff --git a/Documentation/devicetree/bindings/pil/pil-venus.txt b/Documentation/devicetree/bindings/pil/pil-venus.txt deleted file mode 100644 index 1632446d3f5..00000000000 --- a/Documentation/devicetree/bindings/pil/pil-venus.txt +++ /dev/null @@ -1,28 +0,0 @@ -* Qualcomm Venus Video Subsystem Peripheral Image Loader - -pil-venus is a peripheral image loading (PIL) driver. It is used for loading -venus firmware images for video codec into memory and preparing the subsystem's -processor to execute code. It is also used for shutting down the processor when -it's not needed. - -Required properties: -- compatible: "pil-venus" -- reg: offset and length of the register set for the device. -- reg-names: names of the bases for the above registers. "wrapper_base" and - "vbif_base" are expected. -- vdd-supply: regulator to supply venus. -- qcom,firmware-name: Base name of the firmware image. Ex. "venus" - -Optional properties: -- qcom,restart-group: List of subsystems that will need to restart together. - -Example: - qcom,venus@fdce0000 { - compatible = "qcom,pil-venus"; - reg = <0xfdce0000 0x4000>, - <0xfdc80208 0x8>; - reg-names = "wrapper_base", "vbif_base"; - vdd-supply = <&gdsc_venus>; - - qcom,firmware-name = "venus"; - }; diff --git a/Documentation/devicetree/bindings/pil/pil-vpu.txt b/Documentation/devicetree/bindings/pil/pil-vpu.txt deleted file mode 100644 index 4393f95282d..00000000000 --- a/Documentation/devicetree/bindings/pil/pil-vpu.txt +++ /dev/null @@ -1,28 +0,0 @@ -* Qualcomm Video Processing Unit Subsystem Peripheral Image Loader - -pil-vpu is a peripheral image loading (PIL) driver. It is used for loading -vpu firmware images for video processing into memory and preparing the subsystem's -processor to execute code. It is also used for shutting down the processor when -it's not needed. - -Required properties: -- compatible: "pil-vpu" -- reg: offset and length of the register set for the device. -- reg-names: names of the bases for the above registers. "maple_csr_base". -- vdd-supply: regulator to supply vpu. -- qcom,firmware-name: Base name of the firmware image. Ex. "vpu" - -Optional properties: -- qcom,restart-group: List of subsystems that will need to restart together. - -Example: - - qcom,vpu@fde0b000{ - compatible = "qcom,pil-vpu"; - reg = <0xfde0b000 0x80>; - reg-names = "maple_csr_base"; - vdd-supply = <&gdsc_vpu>; - - qcom,firmware-name = "vpu"; - }; - diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 5ea740518f6..7542bface3f 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -524,6 +524,11 @@ Optional properties: for headset detection. - qcom,dock-plug-det-irq: Interrupt line to detect Docking/Undocking of Liquid device +- qcom,mbhc-audio-jack-type : String to indicate the jack type on the hardware. + Possible Values: + 4-pole-jack : Jack on the hardware is 4-pole. + 5-pole-jack : Jack on the hardware is 5-pole. + 6-pole-jack : Jack on the hardware is 6-pole. * APQ8074 ASoC Machine driver @@ -589,6 +594,7 @@ sound { qcom,sec-auxpcm-gpio-sync = <&msmgpio 80 0>; qcom,sec-auxpcm-gpio-din = <&msmgpio 81 0>; qcom,sec-auxpcm-gpio-dout = <&msmgpio 82 0>; + qcom,mbhc-audio-jack-type = "4-pole-jack"; }; * msm-dai-mi2s diff --git a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt index e1681ca7462..e4e05d16620 100644 --- a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt +++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt @@ -53,6 +53,7 @@ Required properties: 2 : pre-div ratio of {1, 4} 3 : pre-div ratio of {1, 6} 4 : pre-div ratio of {1, 20} + 5 : pre-div ratio of {1, 8} - qcom,calibration-type : Reference voltage to use for channel calibration. Channel calibration is dependendent on the channel. Certain channels like XO_THERM, BATT_THERM use ratiometric diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt index 682281af26a..6ce1c4d7ab4 100644 --- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt +++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt @@ -135,14 +135,20 @@ SMSC HSIC HUB Required properties : - compatible : should be "qcom,hsic-smsc-hub" - smsc,model-id : should be either <3503> or <4604> depending on hub model -- smsc,<gpio-name>-gpio : handle to the GPIO node, see "gpios property" - in Documentation/devicetree/bindings/gpio/gpio.txt. - Required "gpio-name" is "reset" and optionally - "refclk", "int". -- <supply-name>-supply: handle to the regulator device tree node - Required "supply-name" is "hub_init" and optionally - "hub_vbus". +- smsc,reset-gpio: this output gpio is used to assert/de-assert the hub reset - Sub node for "MSM HSIC EHCI controller". Sub node has the required properties mentioned above. +Optional properties : +- smsc,int-gpio: this input gpio indicate HUB suspend status and signal remote + wakeup interrupt +- smsc,refclk-gpio: this gpio is used to supply the reference clock +- hub-vbus-supply: this regulator is used to supply the power to + downstream ports +- hub-int-supply: this regulator is used to bias the interrupt gpio +- ext-hub-vddio-supply: this regulator is used to supply the power to one of + the hub's VDD. + Example SMSC HSIC HUB : hsic_hub { compatible = "qcom,hsic-smsc-hub"; @@ -151,8 +157,8 @@ Example SMSC HSIC HUB : smsc,reset-gpio = <&pm8941_gpios 8 0x00>; smsc,refclk-gpio = <&pm8941_gpios 16 0x00>; smsc,int-gpio = <&msmgpio 50 0x00>; - hub_int-supply = <&pm8941_l10>; - hub_vbus-supply = <&pm8941_mvs1>; + hub-int-supply = <&pm8941_l10>; + hub-vbus-supply = <&pm8941_mvs1>; hsic@f9a00000 { compatible = "qcom,hsic-host"; diff --git a/arch/arm/boot/dts/qcom/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/qcom/apq8074-dragonboard.dtsi index a92a5800aa2..df3c254a865 100644 --- a/arch/arm/boot/dts/qcom/apq8074-dragonboard.dtsi +++ b/arch/arm/boot/dts/qcom/apq8074-dragonboard.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -73,7 +73,7 @@ /* Dragonboard has an always-on VBUS supply for HSIC hub, * providing a dummy regulator for the hub driver */ - hub_vbus-supply = <&vph_pwr_vreg>; + hub-vbus-supply = <&vph_pwr_vreg>; hsic_host: hsic@f9a00000 { compatible = "qcom,hsic-host"; diff --git a/arch/arm/boot/dts/qcom/apq8084-bus.dtsi b/arch/arm/boot/dts/qcom/apq8084-bus.dtsi index 9aaf9825613..8c3384ca531 100644 --- a/arch/arm/boot/dts/qcom/apq8084-bus.dtsi +++ b/arch/arm/boot/dts/qcom/apq8084-bus.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -1318,6 +1318,8 @@ qcom,rpm-en; qcom,nfab = <6>; qcom,virt; + qcom,fabclk-dual = "bus_clk"; + qcom,fabclk-active = "bus_a_clk"; mas-v-ocmem-gfx3d { cell-id = <89>; @@ -1352,8 +1354,6 @@ qcom,tier = <2>; qcom,buswidth = <16>; qcom,slv-hw-id = <18>; - qcom,slaveclk-dual = "ocmemgx_clk"; - qcom,slaveclk-active = "ocmemgx_a_clk"; }; fab-snoc { diff --git a/arch/arm/boot/dts/qcom/apq8084-liquid.dtsi b/arch/arm/boot/dts/qcom/apq8084-liquid.dtsi index 3cf9cf820c6..95f20a30e0c 100644 --- a/arch/arm/boot/dts/qcom/apq8084-liquid.dtsi +++ b/arch/arm/boot/dts/qcom/apq8084-liquid.dtsi @@ -143,6 +143,8 @@ #include "dsi-panel-jdi-dualmipi0-video.dtsi" #include "dsi-panel-jdi-dualmipi1-video.dtsi" +#include "dsi-panel-jdi-dualmipi0-cmd.dtsi" +#include "dsi-panel-jdi-dualmipi1-cmd.dtsi" &dsi_dual_jdi_video_0 { qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; @@ -156,6 +158,18 @@ qcom,cont-splash-enabled; }; + +&dsi_dual_jdi_cmd_0 { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <50>; + qcom,mdss-dsi-bl-pmic-bank-select = <2>; + qcom,mdss-dsi-pwm-gpio = <&pma8084_gpios 7 0>; +}; + +&dsi_dual_jdi_cmd_1 { +}; + + &mdss_mdp { qcom,mdss-pref-prim-intf = "dsi"; }; @@ -172,6 +186,7 @@ &mdss_dsi0 { qcom,dsi-pref-prim-pan = <&dsi_dual_jdi_video_0>; + qcom,platform-te-gpio = <&msmgpio 12 0>; qcom,platform-reset-gpio = <&msmgpio 96 0>; qcom,platform-enable-gpio = <&msmgpio 137 0>; qcom,platform-bklight-en-gpio = <&msmgpio 86 0>; diff --git a/arch/arm/boot/dts/qcom/apq8084-mdss.dtsi b/arch/arm/boot/dts/qcom/apq8084-mdss.dtsi index 93d22e90126..1ad489a8c9e 100644 --- a/arch/arm/boot/dts/qcom/apq8084-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/apq8084-mdss.dtsi @@ -57,8 +57,23 @@ <2 4 5>, <2 6 7>; + qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>, + <0x3B4 0 0>, + <0x3BC 0 0>, + <0x3C4 0 0>; + qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>, + <0x3B4 4 8>, + <0x3BC 4 8>, + <0x3C4 4 8>; + qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>, + <0x3B4 8 12>; + + qcom,mdss-pipe-sw-reset-off = <0x0128>; + qcom,mdss-pipe-vig-sw-reset-map = <5 6 7 8>; + qcom,mdss-pipe-rgb-sw-reset-map = <9 10 11 12>; + qcom,mdss-pipe-dma-sw-reset-map = <13 14>; + qcom,mdss-smp-data = <44 8192>; - qcom,mdss-sspp-len = <0x00000400>; qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800 0x00000900 0x0000A00>; @@ -75,9 +90,6 @@ 0x00013200>; qcom,mdss-ad-off = <0x0013500 0x00013700 0x00013900>; qcom,mdss-highest-bank-bit = <0x3>; - qcom,mdss-ctl-len = <0x00000100>; - qcom,mdss-mixer-intf-len = <0x00000400>; - qcom,mdss-dspp-len = <0x00000400>; qcom,mdss-has-bwc; qcom,mdss-has-decimation; diff --git a/arch/arm/boot/dts/qcom/apq8084-mtp.dtsi b/arch/arm/boot/dts/qcom/apq8084-mtp.dtsi index c1066f35b95..ff121b89c3b 100644 --- a/arch/arm/boot/dts/qcom/apq8084-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/apq8084-mtp.dtsi @@ -193,11 +193,11 @@ }; &ufsphy1 { - status = "disabled"; + status = "ok"; }; &ufs1 { - status = "disabled"; + status = "ok"; }; &sdhc_1 { diff --git a/arch/arm/boot/dts/qcom/apq8084-pm.dtsi b/arch/arm/boot/dts/qcom/apq8084-pm.dtsi index 8dfca837137..593f4619933 100644 --- a/arch/arm/boot/dts/qcom/apq8084-pm.dtsi +++ b/arch/arm/boot/dts/qcom/apq8084-pm.dtsi @@ -212,6 +212,8 @@ qcom,gic-parent = <&intc>; qcom,gic-map = <2 216>, /* tsens_upper_lower_int */ + <48 165>, /* usb30_hs_phy_irq */ + <49 165>, /* usb30_hs_phy_irq */ <50 172>, /* usb1_hs_async_wakeup_irq */ <53 104>, /* mdss_irq */ <62 222>, /* ee0_krait_hlos_spmi_periph_irq */ @@ -222,7 +224,6 @@ <0xff 105>, /* mdss_mmu_pmirpt */ <0xff 116>, /* mdss_vbif_irpt */ <0xff 64>, /* usb30_hsic_ee1_irq */ - <0xff 165>, /* usb30_hs_phy_irq */ <0xff 57>, /* o_vpu_vpu_apps_irq_out */ <0xff 58>, /* o_vpu_maple_apps_irq_out */ diff --git a/arch/arm/boot/dts/qcom/apq8084-regulator.dtsi b/arch/arm/boot/dts/qcom/apq8084-regulator.dtsi index e43fe631636..1baf25c4cdc 100644 --- a/arch/arm/boot/dts/qcom/apq8084-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/apq8084-regulator.dtsi @@ -176,6 +176,8 @@ regulator-min-microvolt = <1225000>; regulator-max-microvolt = <1225000>; qcom,init-voltage = <1225000>; + qcom,init-current = <200000>; + regulator-boot-on; status = "okay"; }; }; @@ -186,6 +188,8 @@ regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1000000>; qcom,init-voltage = <1000000>; + qcom,init-current = <50000>; + regulator-boot-on; status = "okay"; }; }; @@ -315,6 +319,8 @@ regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; qcom,init-voltage = <2950000>; + qcom,init-current = <460000>; + regulator-boot-on; status = "okay"; }; }; @@ -325,6 +331,8 @@ regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; qcom,init-voltage = <2950000>; + qcom,init-current = <500000>; + regulator-boot-on; status = "okay"; }; }; diff --git a/arch/arm/boot/dts/qcom/apq8084-sbc.dtsi b/arch/arm/boot/dts/qcom/apq8084-sbc.dtsi index a025a2e931e..4c65990a7d8 100644 --- a/arch/arm/boot/dts/qcom/apq8084-sbc.dtsi +++ b/arch/arm/boot/dts/qcom/apq8084-sbc.dtsi @@ -15,6 +15,12 @@ serial0 = &blsp2_uart1; }; + memory { + fb_mem: fb_region@0 { + reg = <0 0 0 0x4400000>; + }; + }; + bt_qca6174 { compatible = "qca,qca6174"; qca,bt-reset-gpio = <&pma8084_gpios 4 0>; /* BT_EN */ @@ -85,6 +91,7 @@ }; &mdss_hdmi_tx { + qcom,primary_panel = <1>; qcom,mdss-fb-map = <&mdss_fb0>; hpd-5v-en-supply = <&vph_pwr_vreg>; qcom,supply-names = "hpd-gdsc", "hpd-5v", "core-vdda", "core-vcc"; @@ -92,6 +99,7 @@ qcom,max-voltage-level = <0 0 1800000 1800000>; qcom,enable-load = <0 0 300000 0>; qcom,disable-load = <0 0 0 0>; + status = "ok"; }; &uart6 { diff --git a/arch/arm/boot/dts/qcom/apq8084.dtsi b/arch/arm/boot/dts/qcom/apq8084.dtsi index a66082ef276..18fb92529f0 100644 --- a/arch/arm/boot/dts/qcom/apq8084.dtsi +++ b/arch/arm/boot/dts/qcom/apq8084.dtsi @@ -31,20 +31,20 @@ #size-cells = <2>; qsecom_mem: qsecom_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0 0 0x1100000>; label = "qseecom_mem"; }; fb_mem: fb_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0 0 0x1000000>; label = "fb_mem"; linux,memory-limit = <0xffffffff>; }; secure_mem: secure_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0 0 0xfc00000>; label = "secure_mem"; }; @@ -660,6 +660,9 @@ qcom,msm-bus,name = "qcrypto-noc"; qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-ahash-algo; qcom,msm-bus,vectors-KBps = <56 512 0 0>, <56 512 3936000 393600>; @@ -2842,12 +2845,26 @@ }; qcom,venus@fdce0000 { - compatible = "qcom,pil-venus"; - reg = <0xfdce0000 0x4000>, - <0xfdc80000 0x400>; - reg-names = "wrapper_base", "vbif_base"; + compatible = "qcom,pil-tz-generic"; + reg = <0xfdce0000 0x4000>; + vdd-supply = <&gdsc_venus>; + proxy-reg-names = "vdd"; + clock-names = "core_clk", "iface_clk", + "bus_clk", "mem_clk"; + proxy-clock-names = "core_clk", "iface_clk", + "bus_clk", "mem_clk"; + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only = <0>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + + qcom,pas-id = <9>; + qcom,proxy-timeout-ms = <2000>; qcom,firmware-name = "venus"; }; @@ -3454,13 +3471,21 @@ }; qcom,pil-vpu@fde0b000{ - compatible = "qcom,pil-vpu"; + compatible = "qcom,pil-tz-generic"; reg = <0xfde0b000 0x80>; - reg-names = "maple_csr_base"; - vdd-supply = <&gdsc_vpu>; - clock-names = "core_clk", "iface_clk", "bus_clk", "vdp_clk", - "vdp_bus_clk", "cxo_clk", "sleep_clk", "maple_bus_clk"; + vdd-supply = <&gdsc_vpu>; + proxy-reg-names = "vdd"; + active-reg-names = "vdd"; + clock-names = "core_clk", "iface_clk", "bus_clk", + "vdp_clk", "vdp_bus_clk", "cxo_clk", + "sleep_clk", "maple_bus_clk"; + proxy-clock-names = "core_clk", "iface_clk", "bus_clk", + "vdp_clk", "vdp_bus_clk", "cxo_clk", + "sleep_clk", "maple_bus_clk"; + + qcom,pas-id = <10>; + qcom,proxy-timeout-ms = <10000>; qcom,firmware-name = "vpu"; }; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-jdi-dualmipi0-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-jdi-dualmipi0-cmd.dtsi new file mode 100644 index 00000000000..b6acd33ede2 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-jdi-dualmipi0-cmd.dtsi @@ -0,0 +1,91 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_dual_jdi_cmd_0: qcom,mdss_dsi_jdi_qhd_dualmipi0_cmd{ + qcom,mdss-dsi-panel-name = "Dual 0 cmd mode dsi panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <1280>; + qcom,mdss-dsi-panel-height = <1440>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <44>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + 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-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-panel-broadcast-mode; + 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 = [cd 32 22 00 60 64 26 34 29 03 + 04 00]; + qcom,mdss-dsi-reset-sequence = <1 200>, <0 200>, <1 20>; + qcom,mdss-dsi-t-clk-post = <0x03>; + qcom,mdss-dsi-t-clk-pre = <0x27>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>; + qcom,mdss-dsi-te-v-sync-continues-lines = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-jdi-dualmipi1-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-jdi-dualmipi1-cmd.dtsi new file mode 100644 index 00000000000..3430c40b93c --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-jdi-dualmipi1-cmd.dtsi @@ -0,0 +1,91 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_dual_jdi_cmd_1: qcom,mdss_dsi_jdi_qhd_dualmipi1_cmd{ + qcom,mdss-dsi-panel-name = "Dual 1 cmd mode dsi panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi1>; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-destination = "display_2"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <1280>; + qcom,mdss-dsi-panel-height = <1440>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <44>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + 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-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-panel-broadcast-mode; + 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 = [cd 32 22 00 60 64 26 34 29 03 + 04 00]; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>; + qcom,mdss-dsi-t-clk-post = <0x03>; + qcom,mdss-dsi-t-clk-pre = <0x27>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>; + qcom,mdss-dsi-te-v-sync-continues-lines = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/mdm9630.dtsi b/arch/arm/boot/dts/qcom/mdm9630.dtsi index 775700cd4a7..7a2e63a04c3 100644 --- a/arch/arm/boot/dts/qcom/mdm9630.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9630.dtsi @@ -26,7 +26,7 @@ memory { audio_mem: audio_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; linux,reserve-region; reg = <0 0xAF000>; label = "audio_mem"; @@ -519,6 +519,7 @@ reg-names = "ssusb"; interrupts = <0 132 0>; interrupt-names = "ssusb"; + qcom,usb-bam-fifo-baseaddr = <0xfe803000>; qcom,usb-bam-num-pipes = <16>; qcom,ignore-core-reset-ack; qcom,disable-clk-gating; @@ -553,7 +554,7 @@ }; qcom,pipe2 { label = "ssusb-qdss-in-0"; - qcom,usb-bam-mem-type = <2>; + qcom,usb-bam-mem-type = <3>; qcom,bam-type = <0>; qcom,dir = <1>; qcom,pipe-num = <0>; @@ -562,8 +563,10 @@ qcom,src-bam-pipe-index = <0>; qcom,dst-bam-physical-address = <0xf9304000>; qcom,dst-bam-pipe-index = <2>; - qcom,data-fifo-size = <0x700>; - qcom,descriptor-fifo-size = <0x100>; + qcom,data-fifo-offset = <0x0>; + qcom,data-fifo-size = <0xC00>; + qcom,descriptor-fifo-offset = <0xC00>; + qcom,descriptor-fifo-size = <0x400>; qcom,reset-bam-on-connect; }; qcom,pipe3 { diff --git a/arch/arm/boot/dts/qcom/mpq8092-cdp.dtsi b/arch/arm/boot/dts/qcom/mpq8092-cdp.dtsi index 7c5a7f45043..54dfd4457cc 100644 --- a/arch/arm/boot/dts/qcom/mpq8092-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/mpq8092-cdp.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -66,6 +66,14 @@ status = "ok"; }; +&sataphy0 { + status = "ok"; +}; + +&sata0 { + status = "ok"; +}; + &sdhc_1 { vdd-supply = <&pma8084_l20>; qcom,vdd-voltage-level = <2950000 2950000>; @@ -139,6 +147,12 @@ }; gpio@c500 { /* GPIO 6 */ + qcom,mode = <1>; /* Digital output */ + qcom,pull = <1>; /* QPNP_PIN_GPIO_PULL_UP_1P5 */ + qcom,vin-sel = <2>; /* VIN2 */ + qcom,src_sel = <0>; /* GPIO */ + qcom,out-strength = <1>; /* Low */ + qcom,master-en = <1>; /* Enable GPIO */ }; gpio@c600 { /* GPIO 7 */ @@ -248,3 +262,51 @@ }; }; +/* CoreSight */ +&tpiu { + qcom,seta-gpios = <&msmgpio 32 0>, + <&msmgpio 33 0>, + <&msmgpio 34 0>, + <&msmgpio 35 0>, + <&msmgpio 26 0>, + <&msmgpio 52 0>, + <&msmgpio 53 0>, + <&msmgpio 54 0>, + <&msmgpio 47 0>, + <&msmgpio 48 0>, + <&msmgpio 49 0>, + <&msmgpio 50 0>, + <&msmgpio 55 0>, + <&msmgpio 56 0>, + <&msmgpio 57 0>, + <&msmgpio 58 0>, + <&msmgpio 17 0>, + <&msmgpio 18 0>; + qcom,seta-gpios-func = <5 5 5 5 5 4 3 3 8 8 8 8 8 8 8 8 7 6>; + qcom,seta-gpios-drv = <7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7>; + qcom,seta-gpios-pull = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>; + qcom,seta-gpios-dir = <2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2>; + + qcom,setb-gpios = <&msmgpio 2 0>, + <&msmgpio 8 0>, + <&msmgpio 9 0>, + <&msmgpio 10 0>, + <&msmgpio 19 0>, + <&msmgpio 20 0>, + <&msmgpio 21 0>, + <&msmgpio 22 0>, + <&msmgpio 28 0>, + <&msmgpio 29 0>, + <&msmgpio 30 0>, + <&msmgpio 31 0>, + <&msmgpio 37 0>, + <&msmgpio 38 0>, + <&msmgpio 39 0>, + <&msmgpio 40 0>, + <&msmgpio 51 0>, + <&msmgpio 7 0>; + qcom,setb-gpios-func = <6 8 8 8 4 2 2 2 6 6 6 6 5 4 4 4 7 6>; + qcom,setb-gpios-drv = <7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7>; + qcom,setb-gpios-pull = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>; + qcom,setb-gpios-dir = <2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2>; +}; diff --git a/arch/arm/boot/dts/qcom/mpq8092-dtv.dtsi b/arch/arm/boot/dts/qcom/mpq8092-dtv.dtsi index 445cfb089aa..a48ddd9a5d2 100644 --- a/arch/arm/boot/dts/qcom/mpq8092-dtv.dtsi +++ b/arch/arm/boot/dts/qcom/mpq8092-dtv.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -12,7 +12,7 @@ / { aliases { - serial0 = &blsp1_uart5; + serial0 = &blsp1_uart4; }; }; @@ -68,20 +68,48 @@ label = "ioexp-gpio"; }; }; + + sound { + qcom,model = "mpq8092-tabla-dtv-snd-card"; + qcom,hdmi-audio-rx; + qcom,cdc-micbias2-headset-only; + qcom,ext-mclk-gpio = <&msmgpio 42 0>; + }; +}; + +&blsp1_uart4 { + status = "ok"; +}; + +&smb211_vreg { + status = "ok"; +}; + +&smb210_vreg { + status = "ok"; +}; + +&hsusb1_otg { + status = "ok"; }; -&blsp1_uart5 { +&usb3_otg { status = "ok"; }; + &pma8084_gpios { gpio@c000 { /* GPIO 1 */ + /* SMB210 DBU4 5.0 V regulator enable - no software control */ + status = "disabled"; }; gpio@c100 { /* GPIO 2 */ }; gpio@c200 { /* GPIO 3 */ + /* SMB211 DBU2 3.3 V regulator enable - no software control */ + status = "disabled"; }; gpio@c300 { /* GPIO 4 */ @@ -96,10 +124,22 @@ gpio@c600 { /* GPIO 7 */ }; - gpio@c700 { /* GPIO 8 */ + gpio@c700 { /* GPIO 8 - USB OTG 3.0 */ + qcom,mode = <1>; /* Digital output */ + qcom,vin-sel = <2>; /* PMA8084 S4 = 1.8V */ + qcom,src_sel = <0>; /* Constant Function */ + qcom,out-strength = <1>;/* Low */ + qcom,invert = <0>; /* Output low initially */ + qcom,master-en = <1>; /* Enable GPIO */ }; - gpio@c800 { /* GPIO 9 */ + gpio@c800 { /* GPIO 9 - USB OTG 2.0 (Port-1) */ + qcom,mode = <1>; /* Digital output */ + qcom,vin-sel = <2>; /* PMA8084 S4 = 1.8V */ + qcom,src_sel = <0>; /* Constant Function */ + qcom,out-strength = <1>;/* Low */ + qcom,invert = <0>; /* Output low initially */ + qcom,master-en = <1>; /* Enable GPIO */ }; gpio@c900 { /* GPIO 10 */ @@ -167,3 +207,8 @@ mpp@a700 { /* MPP 8 */ }; }; + +&slim_msm { + tabla_codec { + }; +}; diff --git a/arch/arm/boot/dts/qcom/mpq8092-mdss.dtsi b/arch/arm/boot/dts/qcom/mpq8092-mdss.dtsi new file mode 100644 index 00000000000..9be5a3615fb --- /dev/null +++ b/arch/arm/boot/dts/qcom/mpq8092-mdss.dtsi @@ -0,0 +1,141 @@ +/* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + mdss_mdp: qcom,mdss_mdp@fd900000 { + compatible = "qcom,mdss_mdp"; + reg = <0xfd900000 0x24000>, + <0xfd926000 0x1000>; + reg-names = "mdp_phys", "vbif_phys"; + interrupts = <0 72 0>; + vdd-supply = <&gdsc_mdss>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_mdp"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, + <22 512 0 6400000>, + <22 512 0 6400000>; + + /* Fudge factors */ + qcom,mdss-ab-factor = <2 1>; /* 2 times */ + qcom,mdss-ib-factor = <6 5>; /* 1.2 times */ + qcom,mdss-clk-factor = <105 100>; /* 1.05 times */ + + qcom,mdss-mdp-reg-offset = <0x00000100>; + qcom,max-clk-rate = <340000000>; + qcom,mdss-pipe-vig-off = <0x00001200 0x00001e00 + 0x00002A00 0x00003600>; + qcom,mdss-pipe-rgb-off = <0x00004200 0x00004600>; + qcom,mdss-pipe-vig-fetch-id = <1 4 7 10>; + qcom,mdss-pipe-rgb-fetch-id = <13 14>; + qcom,mdss-smp-data = <22 4096>; + + qcom,mdss-pipe-vig-xin-id = <0 1 2 3>; + qcom,mdss-pipe-rgb-xin-id = <4 5>; + + qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>, + <0x3B4 0 0>, + <0x3BC 0 0>, + <0x3BC 24 16>; + qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>, + <0x3B4 4 8>; + + qcom,mdss-ctl-off = <0x00000600 0x00000700>; + qcom,mdss-mixer-intf-off = <0x00004a00 0x00004e00>; + qcom,mdss-mixer-wb-off = <0>; + qcom,mdss-dspp-off = <0x00005200 0x00005e00>; + qcom,mdss-wb-off = <0x00011100 0x00013100>; + qcom,mdss-intf-off = <0x00021100 0x00021300 + 0x00021500 0x00021700>; + qcom,mdss-pingpong-off = <0x00021b00 0x00021c00>; + qcom,mdss-has-decimation; + + qcom,vbif-settings = <0x0004 0x00000001>, + <0x0020 0x00002222>, + <0x0024 0x00002222>, + <0x0028 0x00002222>, + <0x002c 0x00002222>, + <0x00e4 0x00000000>, + <0x0124 0x00000003>; + + qcom,mdp-settings = <0x03ac 0xc00000cd>, + <0x03b4 0xc00000cc>, + <0x03bc 0x0ccc00cc>, + <0x04a8 0x00ccc000>, + <0x04b0 0xc0ccc000>, + <0x04b8 0xcc000000>; + + /* buffer parameters to calculate prefill bandwidth */ + qcom,mdss-prefill-outstanding-buffer-bytes = <1024>; + qcom,mdss-prefill-y-buffer-bytes = <0>; + qcom,mdss-prefill-scaler-buffer-lines-bilinear = <0>; + qcom,mdss-prefill-scaler-buffer-lines-caf = <0>; + qcom,mdss-prefill-post-scaler-buffer-pixels = <512>; + qcom,mdss-prefill-pingpong-buffer-pixels = <4096>; + qcom,mdss-prefill-fbc-lines = <0>; + + qcom,mdss-pref-prim-intf = "hdmi"; + + mdss_fb0: qcom,mdss_fb_primary { + cell-index = <0>; + compatible = "qcom,mdss-fb"; + linux,contiguous-region = <&fb_mem>; + }; + + mdss_fb1: qcom,mdss_fb_wfd { + cell-index = <1>; + compatible = "qcom,mdss-fb"; + }; + }; + + mdss_hdmi_tx: qcom,hdmi_tx@fd924100 { + cell-index = <0>; + status = "ok"; + compatible = "qcom,hdmi-tx"; + reg = <0xfd924100 0x700>, + <0xfd924500 0x9c>, + <0xfc4b8000 0x7000>; + reg-names = "core_physical", "phy_physical", "qfprom_physical"; + + hpd-gdsc-supply = <&gdsc_mdss>; + hpd-5v-supply = <&pma8084_mvs1>; + core-vdda-supply = <&pma8084_l22>; + core-vcc-supply = <&pma8084_s4>; + qcom,supply-names = "hpd-gdsc", "hpd-5v", "core-vdda", "core-vcc"; + qcom,min-voltage-level = <0 0 1800000 1800000>; + qcom,max-voltage-level = <0 0 1800000 1800000>; + qcom,enable-load = <0 0 300000 0>; + qcom,disable-load = <0 0 0 0>; + + qcom,hdmi-tx-ddc-mux-sel = <&pma8084_gpios 6 0>; + qcom,hdmi-tx-cec = <&msmgpio 26 0>; + qcom,hdmi-tx-ddc-clk = <&msmgpio 24 0>; + qcom,hdmi-tx-ddc-data = <&msmgpio 27 0>; + qcom,hdmi-tx-hpd = <&msmgpio 25 0>; + qcom,mdss-fb-map = <&mdss_fb0>; + qcom,primary_panel = <1>; + qcom,msm-hdmi-audio-rx { + compatible = "qcom,msm-hdmi-audio-codec-rx"; + }; + }; + + qcom,mdss_wb_panel { + compatible = "qcom,mdss_wb"; + qcom,mdss_pan_res = <640 480>; + qcom,mdss_pan_bpp = <24>; + qcom,mdss-fb-map = <&mdss_fb1>; + }; + +}; diff --git a/arch/arm/boot/dts/qcom/mpq8092-regulator.dtsi b/arch/arm/boot/dts/qcom/mpq8092-regulator.dtsi index 5e70bfaa5cc..c79521cfc95 100644 --- a/arch/arm/boot/dts/qcom/mpq8092-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/mpq8092-regulator.dtsi @@ -289,8 +289,18 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,init-voltage = <1800000>; + proxy-supply = <&pma8084_l22>; + qcom,proxy-consumer-enable; status = "okay"; }; + + pma8084_l22_ao: regulator-l22-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8084_l22_ao"; + qcom,set = <1>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; }; rpm-regulator-ldoa23 { diff --git a/arch/arm/boot/dts/qcom/mpq8092.dtsi b/arch/arm/boot/dts/qcom/mpq8092.dtsi index 9b6636964ec..2f9fd467be5 100644 --- a/arch/arm/boot/dts/qcom/mpq8092.dtsi +++ b/arch/arm/boot/dts/qcom/mpq8092.dtsi @@ -27,30 +27,40 @@ sdhc2 = &sdhc_2; /* SDC2 SD card slot */ serial1 = &blsp2_uart0; serial2 = &blsp2_uart3; + spi12 = &spi_12; }; memory { audio_mem: audio_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; linux,reserve-region; reg = <0 0x614000>; label = "audio_mem"; }; qseecom_mem: qseecom_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0x1100000>; label = "qseecom_mem"; }; secure_mem: secure_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0xfc00000>; label = "secure_mem"; }; }; soc: soc { }; + + memory { + fb_mem: fb_region { + linux,contiguous-region; + reg = <0 0x1800000>; + label = "fb_mem"; + linux,memory-limit = <0xffffffff>; + }; + }; }; #include "mpq8092-iommu.dtsi" @@ -63,6 +73,7 @@ #include "mpq8092-coresight.dtsi" #include "mpq8092-bus.dtsi" #include "mpq8092-pm.dtsi" +#include "mpq8092-mdss.dtsi" &soc { #address-cells = <1>; @@ -264,6 +275,453 @@ }; }; + qcom,clock-krait@f9016000 { + compatible = "qcom,clock-krait-8974"; + reg = <0xf9016000 0x20>, + <0xf908a000 0x20>, + <0xf909a000 0x20>, + <0xf90aa000 0x20>, + <0xf90ba000 0x20>, + <0xfc4b80b0 0x08>, + <0xf9011000 0x50>; + reg-names = "hfpll_l2_clk", "hfpll0_clk", + "hfpll1_clk", "hfpll2_clk", + "hfpll3_clk", "efuse", "meas"; + cpu0-supply = <&krait0_vreg>; + cpu1-supply = <&krait1_vreg>; + cpu2-supply = <&krait2_vreg>; + cpu3-supply = <&krait3_vreg>; + l2-dig-supply = <&pma8084_s8_corner_ao>; + hfpll-dig-supply = <&pma8084_s8_corner_ao>; + hfpll-analog-supply = <&pma8084_l22_ao>; + qcom,hfpll-config-val = <0x04D0405D>; + qcom,hfpll-user-vco-mask = <0x00100000>; + qcom,pvs-config-ver = <1>; + + qcom,l2-fmax = + < 0 0 >, + < 576000000 4 /* SVS_SOC */ >, + < 1651200000 7 /* NORMAL & TURBO same for MPQ8092 */ >; + + qcom,speed0-pvs0-bin-v0 = + < 0 0 0 >, + < 300000000 850000 75 >, + < 345600000 860000 87 >, + < 422400000 870000 107 >, + < 499200000 880000 128 >, + < 576000000 890000 149 >, + < 652800000 900000 169 >, + < 729600000 910000 191 >, + < 806400000 920000 213 >, + < 883200000 930000 235 >, + < 960000000 940000 257 >, + < 1036800000 950000 280 >, + < 1113600000 965000 304 >, + < 1190400000 980000 329 >, + < 1267200000 995000 354 >, + < 1344000000 1010000 380 >, + < 1420800000 1025000 406 >, + < 1497600000 1040000 432 >, + < 1574400000 1055000 461 >, + < 1651200000 1070000 490 >, + < 1728000000 1085000 520 >, + < 1804800000 1100000 551 >; + + qcom,speed0-pvs1-bin-v0 = + < 0 0 0 >, + < 300000000 850000 75 >, + < 345600000 855000 87 >, + < 422400000 865000 107 >, + < 499200000 875000 128 >, + < 576000000 885000 149 >, + < 652800000 895000 169 >, + < 729600000 905000 191 >, + < 806400000 915000 213 >, + < 883200000 925000 235 >, + < 960000000 935000 257 >, + < 1036800000 945000 280 >, + < 1113600000 955000 304 >, + < 1190400000 970000 329 >, + < 1267200000 985000 354 >, + < 1344000000 1000000 380 >, + < 1420800000 1015000 406 >, + < 1497600000 1030000 432 >, + < 1574400000 1045000 461 >, + < 1651200000 1060000 490 >, + < 1728000000 1075000 520 >, + < 1804800000 1090000 551 >; + + qcom,speed0-pvs2-bin-v0 = + < 0 0 0 >, + < 300000000 825000 75 >, + < 345600000 835000 87 >, + < 422400000 845000 107 >, + < 499200000 855000 128 >, + < 576000000 865000 149 >, + < 652800000 875000 169 >, + < 729600000 885000 191 >, + < 806400000 895000 213 >, + < 883200000 905000 235 >, + < 960000000 915000 257 >, + < 1036800000 930000 280 >, + < 1113600000 945000 304 >, + < 1190400000 960000 329 >, + < 1267200000 975000 354 >, + < 1344000000 990000 380 >, + < 1420800000 1005000 406 >, + < 1497600000 1020000 432 >, + < 1574400000 1035000 461 >, + < 1651200000 1050000 490 >, + < 1728000000 1065000 520 >, + < 1804800000 1080000 551 >; + + qcom,speed0-pvs3-bin-v0 = + < 0 0 0 >, + < 300000000 825000 75 >, + < 345600000 830000 87 >, + < 422400000 840000 107 >, + < 499200000 850000 128 >, + < 576000000 860000 149 >, + < 652800000 870000 169 >, + < 729600000 880000 191 >, + < 806400000 890000 213 >, + < 883200000 900000 235 >, + < 960000000 910000 257 >, + < 1036800000 920000 280 >, + < 1113600000 935000 304 >, + < 1190400000 950000 329 >, + < 1267200000 965000 354 >, + < 1344000000 980000 380 >, + < 1420800000 995000 406 >, + < 1497600000 1010000 432 >, + < 1574400000 1025000 461 >, + < 1651200000 1040000 490 >, + < 1728000000 1055000 520 >, + < 1804800000 1070000 551 >; + + qcom,speed0-pvs4-bin-v0 = + < 0 0 0 >, + < 300000000 825000 75 >, + < 345600000 825000 87 >, + < 422400000 835000 107 >, + < 499200000 845000 128 >, + < 576000000 855000 149 >, + < 652800000 865000 169 >, + < 729600000 875000 191 >, + < 806400000 885000 213 >, + < 883200000 895000 235 >, + < 960000000 905000 257 >, + < 1036800000 915000 280 >, + < 1113600000 925000 304 >, + < 1190400000 940000 329 >, + < 1267200000 955000 354 >, + < 1344000000 970000 380 >, + < 1420800000 985000 406 >, + < 1497600000 1000000 432 >, + < 1574400000 1015000 461 >, + < 1651200000 1030000 490 >, + < 1728000000 1045000 520 >, + < 1804800000 1060000 551 >; + + qcom,speed0-pvs5-bin-v0 = + < 0 0 0 >, + < 300000000 800000 75 >, + < 345600000 810000 87 >, + < 422400000 820000 107 >, + < 499200000 830000 128 >, + < 576000000 840000 149 >, + < 652800000 850000 169 >, + < 729600000 860000 191 >, + < 806400000 870000 213 >, + < 883200000 880000 235 >, + < 960000000 890000 257 >, + < 1036800000 900000 280 >, + < 1113600000 915000 304 >, + < 1190400000 930000 329 >, + < 1267200000 945000 354 >, + < 1344000000 960000 380 >, + < 1420800000 975000 406 >, + < 1497600000 990000 432 >, + < 1574400000 1005000 461 >, + < 1651200000 1020000 490 >, + < 1728000000 1035000 520 >, + < 1804800000 1050000 551 >; + + qcom,speed0-pvs6-bin-v0 = + < 0 0 0 >, + < 300000000 800000 75 >, + < 345600000 805000 87 >, + < 422400000 815000 107 >, + < 499200000 825000 128 >, + < 576000000 835000 149 >, + < 652800000 845000 169 >, + < 729600000 855000 191 >, + < 806400000 865000 213 >, + < 883200000 875000 235 >, + < 960000000 885000 257 >, + < 1036800000 895000 280 >, + < 1113600000 905000 304 >, + < 1190400000 920000 329 >, + < 1267200000 935000 354 >, + < 1344000000 950000 380 >, + < 1420800000 965000 406 >, + < 1497600000 980000 432 >, + < 1574400000 995000 461 >, + < 1651200000 1010000 490 >, + < 1728000000 1025000 520 >, + < 1804800000 1040000 551 >; + + qcom,speed0-pvs7-bin-v0 = + < 0 0 0 >, + < 300000000 800000 75 >, + < 345600000 800000 87 >, + < 422400000 805000 107 >, + < 499200000 815000 128 >, + < 576000000 825000 149 >, + < 652800000 835000 169 >, + < 729600000 845000 191 >, + < 806400000 855000 213 >, + < 883200000 865000 235 >, + < 960000000 875000 257 >, + < 1036800000 885000 280 >, + < 1113600000 895000 304 >, + < 1190400000 910000 329 >, + < 1267200000 925000 354 >, + < 1344000000 940000 380 >, + < 1420800000 955000 406 >, + < 1497600000 970000 432 >, + < 1574400000 985000 461 >, + < 1651200000 1000000 490 >, + < 1728000000 1015000 520 >, + < 1804800000 1030000 551 >; + + qcom,speed0-pvs8-bin-v0 = + < 0 0 0 >, + < 300000000 775000 75 >, + < 345600000 780000 87 >, + < 422400000 790000 107 >, + < 499200000 800000 128 >, + < 576000000 810000 149 >, + < 652800000 820000 169 >, + < 729600000 830000 191 >, + < 806400000 840000 213 >, + < 883200000 850000 235 >, + < 960000000 860000 257 >, + < 1036800000 870000 280 >, + < 1113600000 885000 304 >, + < 1190400000 900000 329 >, + < 1267200000 915000 354 >, + < 1344000000 930000 380 >, + < 1420800000 945000 406 >, + < 1497600000 960000 432 >, + < 1574400000 975000 461 >, + < 1651200000 990000 490 >, + < 1728000000 1005000 520 >, + < 1804800000 1020000 551 >; + + qcom,speed0-pvs9-bin-v0 = + < 0 0 0 >, + < 300000000 775000 75 >, + < 345600000 775000 87 >, + < 422400000 785000 107 >, + < 499200000 795000 128 >, + < 576000000 805000 149 >, + < 652800000 815000 169 >, + < 729600000 825000 191 >, + < 806400000 835000 213 >, + < 883200000 845000 235 >, + < 960000000 855000 257 >, + < 1036800000 865000 280 >, + < 1113600000 875000 304 >, + < 1190400000 890000 329 >, + < 1267200000 905000 354 >, + < 1344000000 920000 380 >, + < 1420800000 935000 406 >, + < 1497600000 950000 432 >, + < 1574400000 965000 461 >, + < 1651200000 980000 490 >, + < 1728000000 995000 520 >, + < 1804800000 1010000 551 >; + + qcom,speed0-pvs10-bin-v0 = + < 0 0 0 >, + < 300000000 775000 75 >, + < 345600000 775000 87 >, + < 422400000 780000 107 >, + < 499200000 790000 128 >, + < 576000000 800000 149 >, + < 652800000 810000 169 >, + < 729600000 820000 191 >, + < 806400000 830000 213 >, + < 883200000 840000 235 >, + < 960000000 850000 257 >, + < 1036800000 860000 280 >, + < 1113600000 870000 304 >, + < 1190400000 880000 329 >, + < 1267200000 895000 354 >, + < 1344000000 910000 380 >, + < 1420800000 925000 406 >, + < 1497600000 940000 432 >, + < 1574400000 955000 461 >, + < 1651200000 970000 490 >, + < 1728000000 985000 520 >, + < 1804800000 1000000 551 >; + + qcom,speed0-pvs11-bin-v0 = + < 0 0 0 >, + < 300000000 750000 75 >, + < 345600000 755000 87 >, + < 422400000 765000 107 >, + < 499200000 775000 128 >, + < 576000000 785000 149 >, + < 652800000 795000 169 >, + < 729600000 805000 191 >, + < 806400000 815000 213 >, + < 883200000 825000 235 >, + < 960000000 835000 257 >, + < 1036800000 845000 280 >, + < 1113600000 855000 304 >, + < 1190400000 870000 329 >, + < 1267200000 885000 354 >, + < 1344000000 900000 380 >, + < 1420800000 915000 406 >, + < 1497600000 930000 432 >, + < 1574400000 945000 461 >, + < 1651200000 960000 490 >, + < 1728000000 975000 520 >, + < 1804800000 990000 551 >; + + qcom,speed0-pvs12-bin-v0 = + < 0 0 0 >, + < 300000000 750000 75 >, + < 345600000 750000 87 >, + < 422400000 755000 107 >, + < 499200000 765000 128 >, + < 576000000 775000 149 >, + < 652800000 785000 169 >, + < 729600000 795000 191 >, + < 806400000 805000 213 >, + < 883200000 815000 235 >, + < 960000000 825000 257 >, + < 1036800000 835000 280 >, + < 1113600000 845000 304 >, + < 1190400000 860000 329 >, + < 1267200000 875000 354 >, + < 1344000000 890000 380 >, + < 1420800000 905000 406 >, + < 1497600000 920000 432 >, + < 1574400000 935000 461 >, + < 1651200000 950000 490 >, + < 1728000000 965000 520 >, + < 1804800000 980000 551 >; + + qcom,speed0-pvs13-bin-v0 = + < 0 0 0 >, + < 300000000 750000 75 >, + < 345600000 750000 87 >, + < 422400000 750000 107 >, + < 499200000 760000 128 >, + < 576000000 770000 149 >, + < 652800000 780000 169 >, + < 729600000 790000 191 >, + < 806400000 800000 213 >, + < 883200000 810000 235 >, + < 960000000 820000 257 >, + < 1036800000 830000 280 >, + < 1113600000 840000 304 >, + < 1190400000 850000 329 >, + < 1267200000 865000 354 >, + < 1344000000 880000 380 >, + < 1420800000 895000 406 >, + < 1497600000 910000 432 >, + < 1574400000 925000 461 >, + < 1651200000 940000 490 >, + < 1728000000 955000 520 >, + < 1804800000 970000 551 >; + + qcom,speed0-pvs14-bin-v0 = + < 0 0 0 >, + < 300000000 750000 75 >, + < 345600000 750000 87 >, + < 422400000 750000 107 >, + < 499200000 750000 128 >, + < 576000000 760000 149 >, + < 652800000 770000 169 >, + < 729600000 780000 191 >, + < 806400000 790000 213 >, + < 883200000 800000 235 >, + < 960000000 810000 257 >, + < 1036800000 820000 280 >, + < 1113600000 830000 304 >, + < 1190400000 840000 329 >, + < 1267200000 855000 354 >, + < 1344000000 870000 380 >, + < 1420800000 885000 406 >, + < 1497600000 900000 432 >, + < 1574400000 915000 461 >, + < 1651200000 930000 490 >, + < 1728000000 945000 520 >, + < 1804800000 960000 551 >; + + qcom,speed0-pvs15-bin-v0 = + < 0 0 0 >, + < 300000000 750000 75 >, + < 345600000 750000 87 >, + < 422400000 750000 107 >, + < 499200000 750000 128 >, + < 576000000 750000 149 >, + < 652800000 760000 169 >, + < 729600000 770000 191 >, + < 806400000 780000 213 >, + < 883200000 790000 235 >, + < 960000000 800000 257 >, + < 1036800000 810000 280 >, + < 1113600000 820000 304 >, + < 1190400000 830000 329 >, + < 1267200000 845000 354 >, + < 1344000000 860000 380 >, + < 1420800000 875000 406 >, + < 1497600000 890000 432 >, + < 1574400000 905000 461 >, + < 1651200000 920000 490 >, + < 1728000000 935000 520 >, + < 1804800000 950000 551 >; + }; + + qcom,cpubw { + compatible = "qcom,cpubw"; + qcom,cpu-mem-ports = <1 512>; + qcom,bw-tbl = + < 8117 /* 532 MHz */ >; + }; + + qcom,msm-cpufreq@0 { + reg = <0 4>; + compatible = "qcom,msm-cpufreq"; + qcom,cpufreq-table = + < 300000 300000 8117 >, + < 345600 345600 8117 >, + < 422400 422400 8117 >, + < 499200 499400 8117 >, + < 576000 576000 8117 >, + < 652800 652800 8117 >, + < 729600 729600 8117 >, + < 806400 806400 8117 >, + < 883200 883200 8117 >, + < 960000 960000 8117 >, + < 1036800 1036800 8117 >, + < 1113600 1113600 8117 >, + < 1190400 1190400 8117 >, + < 1267200 1267200 8117 >, + < 1344000 1344000 8117 >, + < 1420800 1420800 8117 >, + < 1497600 1497600 8117 >, + < 1574400 1574400 8117 >, + < 1651200 1651200 8117 >, + < 1728000 1651200 8117 >, + < 1804800 1651200 8117 >; + }; + usb_otg: usb@f9a55000 { compatible = "qcom,hsusb-otg"; reg = <0xf9a55000 0x400>, @@ -560,6 +1018,33 @@ qcom,vreg-0.9-voltage-level = <950000 950000 24000>; }; + sataphy0: sataphy@0xfc581000 { + compatible = "qcom,sataphy"; + reg = <0xfc581000 0x400>; + reg-names = "phy_mem"; + #phy-cells = <0>; + vdda-phy-supply = <&pma8084_l19>; + vdda-pll-supply = <&pma8084_l22>; + vdda-phy-max-microamp = <50000>; + vdda-pll-max-microamp = <12000>; + + status = "disabled"; + }; + + sata0: sata@0xfc580000 { + compatible = "qcom,msm-ahci"; + reg = <0xfc580000 0x400>; + interrupts = <0 292 0>; + + phys = <&sataphy0>; + phy-names = "sata-6g"; + clock-names = "core_clk", "iface_clk", "pmalive_clk", + "rxoob_clk", "asic0_clk", "rbc0_clk"; + max-clock-frequency-hz = <0 0 100000000 + 100000000 300000000 300000000>; + status = "disabled"; + }; + qcom,wdt@f9017000 { compatible = "qcom,msm-watchdog"; reg = <0xf9017000 0x1000>; @@ -935,11 +1420,6 @@ "TSIF1", "TSPP2_BAM"; vdd-supply = <&gdsc_bcss>; - qcom,tspp2-ahb-clk = "bcc_tspp2_ahb_clk"; - qcom,tspp2-core-clk = "bcc_tspp2_core_clk"; - qcom,tspp2-vbif-clk = "bcc_vbif_tspp2_clk"; - qcom,tspp2-klm-ahb-clk = "bcc_klm_ahb_clk"; - qcom,tsif-ref-clk = "gcc_tsif_ref_clk"; qcom,msm-bus,name = "tspp2"; qcom,msm-bus,num-cases = <3>; qcom,msm-bus,num-paths = <1>; @@ -1008,12 +1488,26 @@ }; qcom,venus@fdce0000 { - compatible = "qcom,pil-venus"; - reg = <0xfdce0000 0x4000>, - <0xfdc80000 0x400>; - reg-names = "wrapper_base", "vbif_base"; + compatible = "qcom,pil-tz-generic"; + reg = <0xfdce0000 0x4000>; + vdd-supply = <&gdsc_venus>; + proxy-reg-names = "vdd"; + clock-names = "core_clk", "iface_clk", + "bus_clk", "mem_clk"; + proxy-clock-names = "core_clk", "iface_clk", + "bus_clk", "mem_clk"; + + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only = <0>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + qcom,pas-id = <9>; + qcom,proxy-timeout-ms = <2000>; qcom,firmware-name = "venus"; }; @@ -1046,19 +1540,26 @@ }; qcom,pil-vpu@fde0b000 { - compatible = "qcom,pil-vpu"; + compatible = "qcom,pil-tz-generic"; reg = <0xfde0b000 0x80>; - reg-names = "maple_csr_base"; + vdd-supply = <&gdsc_vpu>; + proxy-reg-names = "vdd"; + active-reg-names = "vdd"; clock-names = "core_clk", "iface_clk", "bus_clk", "vdp_clk", - "vdp_bus_clk", "sleep_clk"; - + "vdp_bus_clk", "sleep_clk", "maple_bus_clk"; + proxy-clock-names = "core_clk", "iface_clk", "bus_clk", "vdp_clk", + "vdp_bus_clk", "sleep_clk", "maple_bus_clk"; + qcom,pas-id = <10>; + qcom,proxy-timeout-ms = <10000>; qcom,firmware-name = "vpu"; }; qcom,pil-bcss { - compatible = "qcom,pil-bcss"; + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <11>; + qcom,proxy-timeout-ms = <0>; qcom,firmware-name = "bcss"; }; @@ -1152,6 +1653,9 @@ }; }; + qcom,wfd { + compatible = "qcom,msm-wfd"; + }; tsens: tsens@fc4a8000 { compatible = "qcom,msm-tsens"; @@ -1217,6 +1721,29 @@ reg-name = "ramdump"; vdd-wlan-supply = <&wlan_vreg>; }; + + spi_12: spi@f9968000 { /* BLSP2 QUP6 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0xf9968000 0x1000>, + <0xf9944000 0x19000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 106 0>, <0 239 0>; + spi-max-frequency = <19200000>; + qcom,gpio-mosi = <&msmgpio 87 0>; + qcom,gpio-miso = <&msmgpio 88 0>; + qcom,gpio-clk = <&msmgpio 90 0>; + qcom,gpio-cs0 = <&msmgpio 89 0>; + + qcom,infinite-mode = <0>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <22>; + qcom,bam-producer-pipe-index = <23>; + qcom,master-id = <84>; + }; }; &gdsc_venus { diff --git a/arch/arm/boot/dts/qcom/msm8226-1080p-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8226-1080p-cdp.dtsi index 6fde890b2fd..0255230ce39 100644 --- a/arch/arm/boot/dts/qcom/msm8226-1080p-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8226-1080p-cdp.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -129,6 +129,7 @@ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>; qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>; qcom,headset-jack-type-NC; + qcom,mbhc-audio-jack-type = "6-pole-jack"; }; sound-9302 { diff --git a/arch/arm/boot/dts/qcom/msm8226-720p-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8226-720p-cdp.dtsi index ab5595def95..c98996bd96c 100644 --- a/arch/arm/boot/dts/qcom/msm8226-720p-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8226-720p-cdp.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -120,6 +120,7 @@ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>; qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>; qcom,headset-jack-type-NC; + qcom,mbhc-audio-jack-type = "6-pole-jack"; }; sound-9302 { diff --git a/arch/arm/boot/dts/qcom/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8226-camera-sensor-qrd.dtsi index c7604f15605..3dd7f49e5fd 100644 --- a/arch/arm/boot/dts/qcom/msm8226-camera-sensor-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8226-camera-sensor-qrd.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -450,7 +450,7 @@ qcom,csid-sd-index = <0>; qcom,mount-angle = <270>; qcom,actuator-src = <&actuator0>; - qcom,eeprom-src = <&eeprom0>; + qcom,eeprom-src = <&eeprom0 &eeprom1>; qcom,led-flash-src = <&led_flash0>; cam_vdig-supply = <&pm8226_l5>; cam_vana-supply = <&pm8226_l19>; diff --git a/arch/arm/boot/dts/qcom/msm8226-mdss.dtsi b/arch/arm/boot/dts/qcom/msm8226-mdss.dtsi index 49c45ccdc6f..4d43add91eb 100644 --- a/arch/arm/boot/dts/qcom/msm8226-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/msm8226-mdss.dtsi @@ -48,8 +48,16 @@ qcom,mdss-pipe-rgb-xin-id = <1>; qcom,mdss-pipe-dma-xin-id = <2>; + qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>; + qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>; + qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>; + + qcom,mdss-pipe-sw-reset-off = <0x01A8>; + qcom,mdss-pipe-vig-sw-reset-map = <0>; + qcom,mdss-pipe-rgb-sw-reset-map = <1>; + qcom,mdss-pipe-dma-sw-reset-map = <2>; + qcom,mdss-smp-data = <7 4096>; - qcom,mdss-sspp-len = <0x00000400>; qcom,mdss-ctl-off = <0x00000600 0x00000700>; qcom,mdss-mixer-intf-off = <0x00003200>; @@ -59,11 +67,8 @@ qcom,mdss-wb-off = <0x00011100 0x00013100>; qcom,mdss-intf-off = <0x00000000 0x00021300>; qcom,mdss-rot-block-size = <64>; - qcom,mdss-smp-mb-per-pipe = <4>; + qcom,mdss-smp-mb-per-pipe = <3>; vdd-cx-supply = <&pm8226_s1_corner>; - qcom,mdss-ctl-len = <0x00000100>; - qcom,mdss-mixer-intf-len = <0x00000400>; - qcom,mdss-dspp-len = <0x00000400>; qcom,vbif-settings = <0x004 0x00000001>, <0x0D8 0x00000707>, diff --git a/arch/arm/boot/dts/qcom/msm8226.dtsi b/arch/arm/boot/dts/qcom/msm8226.dtsi index 971a960be3d..3389a7fe802 100644 --- a/arch/arm/boot/dts/qcom/msm8226.dtsi +++ b/arch/arm/boot/dts/qcom/msm8226.dtsi @@ -26,31 +26,31 @@ memory { secure_mem: secure_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0x6D00000>; label = "secure_mem"; }; adsp_mem: adsp_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0x2a00000>; label = "adsp_mem"; }; qsecom_mem: qsecom_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0xd00000>; label = "qsecom_mem"; }; fb_mem: fb_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0x800000>; label = "fb_mem"; }; audio_mem: audio_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; linux,reserve-region; reg = <0 0x314000>; label = "audio_mem"; @@ -1117,12 +1117,26 @@ }; qcom,venus@fdce0000 { - compatible = "qcom,pil-venus"; - reg = <0xfdce0000 0x4000>, - <0xfdc80000 0x400>; - reg-names = "wrapper_base", "vbif_base"; + compatible = "qcom,pil-tz-generic"; + reg = <0xfdce0000 0x4000>; + vdd-supply = <&gdsc_venus>; + proxy-reg-names = "vdd"; + clock-names = "core_clk", "iface_clk", + "bus_clk", "mem_clk"; + proxy-clock-names = "core_clk", "iface_clk", + "bus_clk", "mem_clk"; + + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only = <0>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + qcom,pas-id = <9>; + qcom,proxy-timeout-ms = <2000>; qcom,firmware-name = "venus"; }; diff --git a/arch/arm/boot/dts/qcom/msm8610-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8610-gpu.dtsi index 7e3ee0dcb42..de480df02ac 100644 --- a/arch/arm/boot/dts/qcom/msm8610-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msm8610-gpu.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -38,7 +38,7 @@ <26 512 0 0>, <26 512 0 800000>, <26 512 0 1600000>, - <26 512 0 2128000>; + <26 512 0 2664000>; /* GDSC oxili regulators */ vdd-supply = <&gdsc_oxili_cx>; diff --git a/arch/arm/boot/dts/qcom/msm8610-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8610-mtp.dtsi index bd80e513746..b434330713b 100644 --- a/arch/arm/boot/dts/qcom/msm8610-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8610-mtp.dtsi @@ -39,36 +39,36 @@ /* Object 6, Instance = 0 */ 00 00 00 00 00 00 /* Object 38, Instance = 0 */ - 1D 05 01 0D 01 0E 00 00 + 1d 13 00 17 01 0e 00 00 /* Object 7, Instance = 0 */ - 20 08 32 + 20 0a 32 /* Object 8, Instance = 0 */ - 19 00 14 14 00 00 FF 00 00 00 + 19 00 14 14 00 00 ff 00 00 00 /* Object 9, Instance = 0 */ - 83 00 00 13 0B 00 20 32 01 03 - 00 32 05 30 05 05 0A 00 70 03 - FC 01 04 2F F8 DC 00 00 40 00 - 00 0A 00 00 02 + 83 00 00 13 0b 00 20 32 01 03 + 00 0a 05 30 05 05 0a 00 70 03 + fc 01 04 2f f8 dc 00 00 40 00 + 00 0a 00 00 02 /* Object 18, Instance = 0 */ 00 00 /* Object 19, Instance = 0 */ 00 00 00 00 00 00 /* Object 25, Instance = 0 */ - 03 00 18 79 A8 61 + 03 00 18 79 a8 61 /* Object 58, Instance = 0 */ 00 00 00 00 00 00 00 00 00 00 00 /* Object 42, Instance = 0 */ - 00 00 00 00 00 00 00 00 + 03 19 1e 14 80 05 00 00 /* Object 46, Instance = 0 */ 04 03 08 10 00 00 00 00 00 /* Object 47, Instance = 0 */ 00 00 00 00 00 00 00 00 00 00 /* Object 48, Instance = 0 */ - 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 + 1d c0 22 00 00 00 00 00 00 00 + 20 19 00 06 06 00 00 64 04 40 + 00 00 00 05 00 2a 00 00 00 19 + 34 0c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 /* Object 55, Instance = 0 */ @@ -151,10 +151,11 @@ reg = <0x0e>; qcom,irq-gpio = <&msmgpio 77 0x00>; qcom,dis-gpio = <&msmgpio 93 0x00>; - qcom,clk-en-gpio = <&msmgpio 78 0x00>; + qcom,clk-req-gpio = <&msmgpio 75 0x00>; + qcom,clk-src-gpio = <&msmgpio 78 0x00>; qcom,clk-src = "GPCLK"; interrupt-parent = <&msmgpio>; - interrupts = <77 0>; + interrupts = <77 75 0>; qcom,clk-gpio = <&pm8110_gpios 1 0>; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8610-qrd-camera-sensor.dtsi b/arch/arm/boot/dts/qcom/msm8610-qrd-camera-sensor.dtsi index bdcb285d9e7..6a203d8fdef 100644 --- a/arch/arm/boot/dts/qcom/msm8610-qrd-camera-sensor.dtsi +++ b/arch/arm/boot/dts/qcom/msm8610-qrd-camera-sensor.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -82,5 +82,65 @@ qcom,cci-master = <0>; status = "ok"; }; + + qcom,camera@1 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x01>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <90>; + qcom,sensor-name = "hi256"; + cam_vdig-supply = <&pm8110_l2>; + cam_vana-supply = <&pm8110_l19>; + cam_vio-supply = <&pm8110_l14>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; + qcom,cam-vreg-type = <0 0 0>; + qcom,cam-vreg-min-voltage = <1200000 1800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 1800000 2850000>; + qcom,cam-vreg-op-mode = <200000 8000 80000>; + qcom,gpio-no-mux = <0>; + gpios = <&msmgpio 13 0>, + <&msmgpio 21 0>, + <&msmgpio 20 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET1", + "CAM_STANDBY"; + qcom,cci-master = <0>; + }; + + qcom,camera@2 { + cell-index = <1>; + compatible = "qcom,camera"; + reg = <0x02>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <180>; + cam_vdig-supply = <&pm8110_l14>; + cam_vana-supply = <&pm8110_l19>; + cam_vio-supply = <&pm8110_l14>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; + qcom,cam-vreg-type = <0 1 0>; + qcom,cam-vreg-min-voltage = <1800000 1800000 2850000>; + qcom,cam-vreg-max-voltage = <1800000 1800000 2850000>; + qcom,cam-vreg-op-mode = <200000 0 80000>; + qcom,gpio-no-mux = <0>; + gpios = <&msmgpio 14 0>, + <&msmgpio 15 0>, + <&msmgpio 88 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET", + "CAM_STANDBY"; + qcom,cci-master = <0>; + status = "ok"; + }; }; diff --git a/arch/arm/boot/dts/qcom/msm8610-qrd-skuaa.dtsi b/arch/arm/boot/dts/qcom/msm8610-qrd-skuaa.dtsi index 92b6ded620e..8b518770804 100644 --- a/arch/arm/boot/dts/qcom/msm8610-qrd-skuaa.dtsi +++ b/arch/arm/boot/dts/qcom/msm8610-qrd-skuaa.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -28,18 +28,18 @@ qcom,ext-spk-amp-gpio = <&msmgpio 92 0x0>; }; - i2c@f9925000 { /* BLSP-1 QUP-3 */ + i2c@f9924000 { /* BLSP-1 QUP-2 */ nfc-nci@e { compatible = "qcom,nfc-nci"; reg = <0x0e>; qcom,irq-gpio = <&msmgpio 77 0x00>; + qcom,clk-req-gpio = <&msmgpio 75 0x00>; qcom,dis-gpio = <&msmgpio 93 0x00>; - qcom,clk-en-gpio = <&msmgpio 78 0x00>; - qcom,clk-src = "GPCLK"; + qcom,clk-src-gpio = <&msmgpio 78 0x00>; + qcom,clk-src = "GPCLK2"; interrupt-parent = <&msmgpio>; - interrupts = <77 0>; + interrupts = <77 75 0>; qcom,clk-gpio = <&msmgpio 75 0x00>; - vlogic-supply = <&pm8110_l14>; }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8610.dtsi b/arch/arm/boot/dts/qcom/msm8610.dtsi index e48188bd0d0..0dad02eeead 100644 --- a/arch/arm/boot/dts/qcom/msm8610.dtsi +++ b/arch/arm/boot/dts/qcom/msm8610.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -27,7 +27,7 @@ memory { qsecom_mem: qsecom_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0x100000>; label = "qsecom_mem"; }; @@ -646,6 +646,7 @@ qcom,i2c-src-freq = <19200000>; qcom,sda-gpio = <&msmgpio 10 0>; qcom,scl-gpio = <&msmgpio 11 0>; + qcom,clk-ctl-xfer; qcom,master-id = <86>; }; @@ -1134,7 +1135,7 @@ label = "vchg_sns"; reg = <2>; qcom,decimation = <0>; - qcom,pre-div-channel-scaling = <2>; + qcom,pre-div-channel-scaling = <5>; qcom,calibration-type = "absolute"; qcom,scale-function = <0>; qcom,hw-settle-time = <0>; diff --git a/arch/arm/boot/dts/qcom/msm8612-qrd-camera-sensor.dtsi b/arch/arm/boot/dts/qcom/msm8612-qrd-camera-sensor.dtsi index 205e7498907..d2c224d74ec 100644 --- a/arch/arm/boot/dts/qcom/msm8612-qrd-camera-sensor.dtsi +++ b/arch/arm/boot/dts/qcom/msm8612-qrd-camera-sensor.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -95,4 +95,63 @@ qcom,cci-master = <0>; status = "ok"; }; + + qcom,camera@1 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x01>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <90>; + cam_vdig-supply = <&pm8110_l2>; + cam_vana-supply = <&pm8110_l19>; + cam_vio-supply = <&pm8110_l14>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; + qcom,cam-vreg-type = <0 0 0>; + qcom,cam-vreg-min-voltage = <1200000 1800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 1800000 2850000>; + qcom,cam-vreg-op-mode = <200000 8000 80000>; + qcom,gpio-no-mux = <0>; + gpios = <&msmgpio 13 0>, + <&msmgpio 21 0>, + <&msmgpio 20 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET1", + "CAM_STANDBY"; + qcom,cci-master = <0>; + }; + + qcom,camera@2 { + cell-index = <1>; + compatible = "qcom,camera"; + reg = <0x02>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <270>; + cam_vdig-supply = <&pm8110_l14>; + cam_vana-supply = <&pm8110_l19>; + cam_vio-supply = <&pm8110_l14>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; + qcom,cam-vreg-type = <0 1 0>; + qcom,cam-vreg-min-voltage = <1800000 1800000 2850000>; + qcom,cam-vreg-max-voltage = <1800000 1800000 2850000>; + qcom,cam-vreg-op-mode = <200000 0 80000>; + qcom,gpio-no-mux = <0>; + gpios = <&msmgpio 14 0>, + <&msmgpio 15 0>, + <&msmgpio 85 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET", + "CAM_STANDBY"; + qcom,cci-master = <0>; + status = "ok"; + }; }; diff --git a/arch/arm/boot/dts/qcom/msm8974-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8974-cdp.dtsi index 6b2d5130fcf..461ae04b456 100644 --- a/arch/arm/boot/dts/qcom/msm8974-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8974-cdp.dtsi @@ -220,6 +220,7 @@ qcom,hdmi-audio-rx; qcom,us-euro-gpios = <&pm8941_gpios 20 0>; qcom,cdc-micbias2-headset-only; + qcom,mbhc-audio-jack-type = "6-pole-jack"; }; usb2_otg_sw: regulator-tpd4s214 { diff --git a/arch/arm/boot/dts/qcom/msm8974-fluid.dtsi b/arch/arm/boot/dts/qcom/msm8974-fluid.dtsi index 64f03d382c2..05f80b378c7 100644 --- a/arch/arm/boot/dts/qcom/msm8974-fluid.dtsi +++ b/arch/arm/boot/dts/qcom/msm8974-fluid.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -271,6 +271,7 @@ qcom,hdmi-audio-rx; qcom,ext-ult-lo-amp-gpio = <&pm8941_gpios 6 0>; qcom,cdc-micbias2-headset-only; + qcom,mbhc-audio-jack-type = "6-pole-jack"; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8974-mdss.dtsi b/arch/arm/boot/dts/qcom/msm8974-mdss.dtsi index 8f310e92d56..9ccacc8f2ab 100644 --- a/arch/arm/boot/dts/qcom/msm8974-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/msm8974-mdss.dtsi @@ -50,8 +50,16 @@ qcom,mdss-pipe-rgb-xin-id = <1 5 9>; qcom,mdss-pipe-dma-xin-id = <2 10>; + qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>, + <0x3B4 0 0>, + <0x3BC 0 0>; + qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>, + <0x3B4 4 8>, + <0x3BC 4 8>; + qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>, + <0x3B4 8 12>; + qcom,mdss-smp-data = <22 4096>; - qcom,mdss-sspp-len = <0x00000400>; qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800 0x00000900 0x0000A00>; @@ -63,9 +71,6 @@ 0x00017100 0x00019100>; qcom,mdss-intf-off = <0x00021100 0x00021300 0x00021500 0x00021700>; - qcom,mdss-ctl-len = <0x00000100>; - qcom,mdss-mixer-intf-len = <0x00000400>; - qcom,mdss-dspp-len = <0x00000400>; qcom,mdss-has-wfd-blk; qcom,vbif-settings = <0x0004 0x00000001>, diff --git a/arch/arm/boot/dts/qcom/msm8974-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8974-mtp.dtsi index 734c650ba91..0ed96fc5595 100644 --- a/arch/arm/boot/dts/qcom/msm8974-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8974-mtp.dtsi @@ -214,6 +214,7 @@ sound { qcom,model = "msm8974-taiko-mtp-snd-card"; qcom,cdc-micbias2-headset-only; + qcom,mbhc-audio-jack-type = "6-pole-jack"; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8974.dtsi b/arch/arm/boot/dts/qcom/msm8974.dtsi index 2c008e6d240..e3045f91948 100644 --- a/arch/arm/boot/dts/qcom/msm8974.dtsi +++ b/arch/arm/boot/dts/qcom/msm8974.dtsi @@ -71,31 +71,31 @@ memory { secure_mem: secure_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0xFC00000>; label = "secure_mem"; }; adsp_mem: adsp_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0x3F00000>; label = "adsp_mem"; }; qsecom_mem: qsecom_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0x1100000>; label = "qseecom_mem"; }; fb_mem: fb_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0x800000>; label = "fb_mem"; }; audio_mem: audio_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; linux,reserve-region; reg = <0 0x614000>; lable = "audio_mem"; @@ -269,7 +269,7 @@ venus-supply = <&gdsc_venus>; qcom,hfi = "venus"; qcom,ocmem-size = <524288>; /* 512 * 1024*/ - qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/ + qcom,max-hw-load = <1216800>; /* 3840 x 2160 @ 30 + 1080p @ 30*/ qcom,clock-names = "core_clk", "iface_clk", "bus_clk", "mem_clk"; qcom,clock-configs = <0x3 0x0 0x0 0x0>; }; @@ -2139,12 +2139,26 @@ }; qcom,venus@fdce0000 { - compatible = "qcom,pil-venus"; - reg = <0xfdce0000 0x4000>, - <0xfdc80000 0x400>; - reg-names = "wrapper_base", "vbif_base"; + compatible = "qcom,pil-tz-generic"; + reg = <0xfdce0000 0x4000>; + vdd-supply = <&gdsc_venus>; + proxy-reg-names = "vdd"; + clock-names = "core_clk", "iface_clk", + "bus_clk", "mem_clk"; + proxy-clock-names = "core_clk", "iface_clk", + "bus_clk", "mem_clk"; + + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only = <0>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + qcom,pas-id = <9>; + qcom,proxy-timeout-ms = <2000>; qcom,firmware-name = "venus"; }; @@ -2234,9 +2248,13 @@ interrupts = <0 236 0>; qcom,bam-pipe-pair = <2>; qcom,ce-hw-instance = <1>; + qcom,clk-mgmt-sus-res; qcom,msm-bus,name = "qcrypto-noc"; qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-ahash-algo; qcom,msm-bus,vectors-KBps = <56 512 0 0>, <56 512 3936000 393600>; diff --git a/arch/arm/boot/dts/qcom/msmsamarium-mdss.dtsi b/arch/arm/boot/dts/qcom/msmsamarium-mdss.dtsi index cc78dc74fb1..fb8bc37d309 100644 --- a/arch/arm/boot/dts/qcom/msmsamarium-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/msmsamarium-mdss.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -42,7 +42,6 @@ qcom,mdss-pipe-rgb-fetch-id = <10 11>; qcom,mdss-pipe-dma-fetch-id = <7>; qcom,mdss-smp-data = <12 8192>; - qcom,mdss-sspp-len = <0x00000400>; qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800>; qcom,mdss-mixer-intf-off = <0x00003200 0x00003600>; @@ -52,9 +51,6 @@ qcom,mdss-intf-off = <0x00000000 0x00012700>; qcom,mdss-pingpong-off = <0x00012d00 0x00012e00>; qcom,mdss-ad-off = <0x00013100>; - qcom,mdss-ctl-len = <0x00000100>; - qcom,mdss-mixer-intf-len = <0x00000400>; - qcom,mdss-dspp-len = <0x00000400>; qcom,mdss-has-wfd-blk; qcom,mdp-settings = <0x02E0 0x000000A9>, diff --git a/arch/arm/boot/dts/qcom/msmsamarium.dtsi b/arch/arm/boot/dts/qcom/msmsamarium.dtsi index 0f706b33f53..51ea3abd7c1 100644 --- a/arch/arm/boot/dts/qcom/msmsamarium.dtsi +++ b/arch/arm/boot/dts/qcom/msmsamarium.dtsi @@ -27,7 +27,7 @@ memory { fb_mem: fb_region@0 { - linux,contiguous-region; + linux,reserve-contiguous-region; reg = <0 0x1400000>; label = "fb_mem"; }; diff --git a/arch/arm/configs/apq8084-perf_defconfig b/arch/arm/configs/apq8084-perf_defconfig index d73b53b5b32..2412483eb9f 100644 --- a/arch/arm/configs/apq8084-perf_defconfig +++ b/arch/arm/configs/apq8084-perf_defconfig @@ -48,9 +48,8 @@ CONFIG_EXTERNAL_MDM=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_LPASS_QDSP6V5=y -CONFIG_MSM_PIL_VENUS=y -CONFIG_MSM_PIL_VPU=y CONFIG_MSM_BUSPM_DEV=m CONFIG_MSM_TZ_LOG=y CONFIG_MSM_DIRECT_SCLK_ACCESS=y @@ -549,6 +548,7 @@ CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_PHY_MSM_SATA=y CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig index 239b54ed109..4f398fe42ba 100644 --- a/arch/arm/configs/apq8084_defconfig +++ b/arch/arm/configs/apq8084_defconfig @@ -47,9 +47,8 @@ CONFIG_EXTERNAL_MDM=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_LPASS_QDSP6V5=y -CONFIG_MSM_PIL_VENUS=y -CONFIG_MSM_PIL_VPU=y CONFIG_MSM_BUSPM_DEV=m CONFIG_MSM_TZ_LOG=y CONFIG_MSM_DIRECT_SCLK_ACCESS=y @@ -564,6 +563,7 @@ CONFIG_CORESIGHT_RPM_ETM=y CONFIG_CORESIGHT_EVENT=y CONFIG_PHY_MSM_SATA=y CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/fsm9900-perf_defconfig b/arch/arm/configs/fsm9900-perf_defconfig index 62c79d9c3ad..7801c82c798 100644 --- a/arch/arm/configs/fsm9900-perf_defconfig +++ b/arch/arm/configs/fsm9900-perf_defconfig @@ -52,7 +52,6 @@ CONFIG_MSM_MEMORY_DUMP=y CONFIG_MSM_DLOAD_MODE=y CONFIG_MSM_SPM_V2=y CONFIG_MSM_L2_SPM=y -CONFIG_MSM_MULTIMEDIA_USE_ION=y CONFIG_MSM_OCMEM=y CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y CONFIG_MSM_OCMEM_DEBUG=y @@ -205,8 +204,6 @@ CONFIG_THERMAL_QPNP_ADC_TM=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_STUB=y CONFIG_REGULATOR_QPNP=y -CONFIG_ION=y -CONFIG_ION_MSM=y CONFIG_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y @@ -232,6 +229,11 @@ CONFIG_MMC_SDHCI_MSM=y CONFIG_SWITCH=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y +CONFIG_STAGING=y +CONFIG_ANDROID=y +CONFIG_ION=y +CONFIG_ION_TEST=y +CONFIG_ION_MSM=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_POWER_ON=y @@ -239,8 +241,9 @@ CONFIG_QPNP_CLKDIV=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_PWM=y CONFIG_PWM_QPNP=y -CONFIG_MSM_SMEM=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/fsm9900_defconfig b/arch/arm/configs/fsm9900_defconfig index deb20836650..3f80f901a15 100644 --- a/arch/arm/configs/fsm9900_defconfig +++ b/arch/arm/configs/fsm9900_defconfig @@ -51,7 +51,6 @@ CONFIG_MSM_MEMORY_DUMP=y CONFIG_MSM_DLOAD_MODE=y CONFIG_MSM_SPM_V2=y CONFIG_MSM_L2_SPM=y -CONFIG_MSM_MULTIMEDIA_USE_ION=y CONFIG_MSM_OCMEM=y CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y CONFIG_MSM_OCMEM_DEBUG=y @@ -205,8 +204,6 @@ CONFIG_THERMAL_QPNP_ADC_TM=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_STUB=y CONFIG_REGULATOR_QPNP=y -CONFIG_ION=y -CONFIG_ION_MSM=y CONFIG_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y @@ -232,6 +229,11 @@ CONFIG_MMC_SDHCI_MSM=y CONFIG_SWITCH=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y +CONFIG_STAGING=y +CONFIG_ANDROID=y +CONFIG_ION=y +CONFIG_ION_TEST=y +CONFIG_ION_MSM=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_POWER_ON=y @@ -239,8 +241,9 @@ CONFIG_QPNP_CLKDIV=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_PWM=y CONFIG_PWM_QPNP=y -CONFIG_MSM_SMEM=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/mdm9630_defconfig b/arch/arm/configs/mdm9630_defconfig index 08090a869c3..c2e1212fae6 100644 --- a/arch/arm/configs/mdm9630_defconfig +++ b/arch/arm/configs/mdm9630_defconfig @@ -299,6 +299,7 @@ CONFIG_CORESIGHT_AUDIO_ETM=y CONFIG_CORESIGHT_MODEM_ETM=y CONFIG_CORESIGHT_RPM_ETM=y CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_EXT3_FS=y CONFIG_VFAT_FS=y diff --git a/arch/arm/configs/mpq8092_defconfig b/arch/arm/configs/mpq8092_defconfig index 5173f7df8a2..37f4d595757 100644 --- a/arch/arm/configs/mpq8092_defconfig +++ b/arch/arm/configs/mpq8092_defconfig @@ -43,11 +43,9 @@ CONFIG_MSM_SMP2P_TEST=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_LPASS_QDSP6V5=y -CONFIG_MSM_PIL_VENUS=y -CONFIG_MSM_PIL_VPU=y -CONFIG_MSM_PIL_BCSS=y CONFIG_MSM_TZ_LOG=y CONFIG_MSM_DIRECT_SCLK_ACCESS=y CONFIG_MSM_BUS_SCALING=y @@ -289,6 +287,7 @@ CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_WFD=y CONFIG_DVB_MPQ=m CONFIG_DVB_MPQ_DEMUX=m CONFIG_DVB_MPQ_VIDEO=m @@ -408,6 +407,7 @@ CONFIG_CORESIGHT_ETM_PCSAVE_DEFAULT_ENABLE=y CONFIG_CORESIGHT_AUDIO_ETM=y CONFIG_CORESIGHT_RPM_ETM=y CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig index 7a69f3c0e57..5c518468298 100644 --- a/arch/arm/configs/msm8226-perf_defconfig +++ b/arch/arm/configs/msm8226-perf_defconfig @@ -46,9 +46,9 @@ CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_SMCMOD=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_LPASS_QDSP6V5=y CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_PIL_VENUS=y CONFIG_MSM_PIL_PRONTO=y CONFIG_MSM_BUSPM_DEV=m CONFIG_MSM_TZ_LOG=y @@ -326,6 +326,7 @@ CONFIG_RADIO_IRIS_TRANSPORT=m CONFIG_ION=y CONFIG_ION_MSM=y CONFIG_MSM_KGSL=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y CONFIG_FB=y CONFIG_FB_MSM=y # CONFIG_FB_MSM_BACKLIGHT is not set @@ -417,6 +418,7 @@ CONFIG_PWM_QPNP=y CONFIG_MOBICORE_SUPPORT=m CONFIG_MOBICORE_API=m CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig index 7123116eeb0..2f2ebd12f82 100644 --- a/arch/arm/configs/msm8226_defconfig +++ b/arch/arm/configs/msm8226_defconfig @@ -45,9 +45,9 @@ CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_SMCMOD=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_LPASS_QDSP6V5=y CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_PIL_VENUS=y CONFIG_MSM_PIL_PRONTO=y CONFIG_MSM_BUSPM_DEV=m CONFIG_MSM_TZ_LOG=y @@ -327,6 +327,7 @@ CONFIG_RADIO_IRIS_TRANSPORT=m CONFIG_ION=y CONFIG_ION_MSM=y CONFIG_MSM_KGSL=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y CONFIG_FB=y CONFIG_FB_MSM=y # CONFIG_FB_MSM_BACKLIGHT is not set @@ -432,6 +433,7 @@ CONFIG_CORESIGHT_WCN_ETM=y CONFIG_CORESIGHT_RPM_ETM=y CONFIG_CORESIGHT_EVENT=y CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig index 436afdd4436..fc5342cc82c 100644 --- a/arch/arm/configs/msm8610-perf_defconfig +++ b/arch/arm/configs/msm8610-perf_defconfig @@ -49,7 +49,6 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y CONFIG_MSM_PIL_LPASS_QDSP6V5=y CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_PIL_VENUS=y CONFIG_MSM_PIL_PRONTO=y CONFIG_MSM_BUSPM_DEV=m CONFIG_MSM_TZ_LOG=y @@ -296,15 +295,9 @@ CONFIG_MSM_CSID=y CONFIG_MSM_EEPROM=y CONFIG_MSM_ISPIF=y CONFIG_MSM_ISPIF_V1=y -CONFIG_IMX134=y -CONFIG_OV9724=y CONFIG_HI256=y -CONFIG_OV5648=y CONFIG_SP1628=y CONFIG_GC0339=y -CONFIG_OV8825=y -CONFIG_s5k4e1=y -CONFIG_OV12830=y CONFIG_MSM_VIDC_V4L2=y CONFIG_MSM_WFD=y CONFIG_RADIO_IRIS=y @@ -385,6 +378,7 @@ CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_SENSORS=y CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig index f60cc605d17..40218894c68 100644 --- a/arch/arm/configs/msm8610_defconfig +++ b/arch/arm/configs/msm8610_defconfig @@ -46,7 +46,6 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y CONFIG_MSM_PIL_LPASS_QDSP6V5=y CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_PIL_VENUS=y CONFIG_MSM_PIL_PRONTO=y CONFIG_MSM_BUSPM_DEV=m CONFIG_MSM_TZ_LOG=y @@ -293,15 +292,9 @@ CONFIG_MSM_CSID=y CONFIG_MSM_EEPROM=y CONFIG_MSM_ISPIF=y CONFIG_MSM_ISPIF_V1=y -CONFIG_IMX134=y -CONFIG_OV9724=y CONFIG_HI256=y -CONFIG_OV5648=y CONFIG_SP1628=y CONFIG_GC0339=y -CONFIG_OV8825=y -CONFIG_s5k4e1=y -CONFIG_OV12830=y CONFIG_MSM_VIDC_V4L2=y CONFIG_MSM_WFD=y CONFIG_RADIO_IRIS=y @@ -394,6 +387,7 @@ CONFIG_CORESIGHT_RPM_ETM=y CONFIG_CORESIGHT_EVENT=y CONFIG_SENSORS=y CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig index cdfcf99a872..f1bd2056733 100644 --- a/arch/arm/configs/msm8974-perf_defconfig +++ b/arch/arm/configs/msm8974-perf_defconfig @@ -49,9 +49,9 @@ CONFIG_MSM_SMP2P_TEST=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_LPASS_QDSP6V5=y CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_PIL_VENUS=y CONFIG_MSM_PIL_PRONTO=y CONFIG_MSM_BUSPM_DEV=m CONFIG_MSM_TZ_LOG=y @@ -458,6 +458,7 @@ CONFIG_MOBICORE_API=m CONFIG_BIF=y CONFIG_BIF_QPNP=y CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig index 8b12d43bd21..3386e3393fd 100644 --- a/arch/arm/configs/msm8974_defconfig +++ b/arch/arm/configs/msm8974_defconfig @@ -48,9 +48,9 @@ CONFIG_MSM_SMP2P_TEST=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_LPASS_QDSP6V5=y CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_PIL_VENUS=y CONFIG_MSM_PIL_PRONTO=y CONFIG_MSM_BUSPM_DEV=m CONFIG_MSM_TZ_LOG=y @@ -482,6 +482,7 @@ CONFIG_CORESIGHT_EVENT=y CONFIG_BIF=y CONFIG_BIF_QPNP=y CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 9fdf690194c..be3e535d503 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -10,7 +10,6 @@ config ARCH_MSM8974 select CPU_V7 select MSM_SCM select MSM_GPIOMUX - select MSM_MULTIMEDIA_USE_ION select PM_DEVFREQ select MSM_DEVFREQ_CPUBW select MSM_PIL @@ -71,7 +70,6 @@ config ARCH_APQ8084 select MSM_PIL select ENABLE_VMALLOC_SAVINGS select MSM_ULTRASOUND_B - select MSM_MULTIMEDIA_USE_ION select MSM_IRQ select PINCTRL select PINCTRL_MSM_TLMM_V3 @@ -100,7 +98,6 @@ config ARCH_MPQ8092 select REGULATOR_RPM_SMD select PINCTRL select PINCTRL_MSM_TLMM_V3 - select MSM_MULTIMEDIA_USE_ION select USB_ARCH_HAS_XHCI select MSM_IRQ select MSM_SPM_V2 @@ -200,7 +197,6 @@ config ARCH_MSM8610 select MSM_RPM_STATS_LOG select PINCTRL select PINCTRL_MSM_TLMM_V3 - select MSM_MULTIMEDIA_USE_ION select MSM_IRQ config ARCH_MSM8226 @@ -243,7 +239,6 @@ config ARCH_MSM8226 select PINCTRL select PINCTRL_MSM_TLMM_V3 select ENABLE_VMALLOC_SAVINGS - select MSM_MULTIMEDIA_USE_ION select MSM_IRQ config ARCH_MSMSAMARIUM @@ -274,7 +269,6 @@ config ARCH_MSMSAMARIUM select QMI_ENCDEC select PINCTRL select PINCTRL_MSM_TLMM_V3 - select MSM_MULTIMEDIA_USE_ION select MSM_IRQ endmenu @@ -679,27 +673,6 @@ config MSM_SMP2P_TEST are used to verify the local and remote implementations. -config MSM_SMD_LOGGING - depends on MSM_SMD - default y - bool "MSM Shared Memory Logger" - help - This option exposes the shared memory logger at /dev/smem_log - and a debugfs node named smem_log. - - If in doubt, say yes. - -config MSM_QMI_INTERFACE - depends on IPC_ROUTER - depends on QMI_ENCDEC - default n - bool "MSM QMI Interface Library" - help - Library to send and receive QMI messages over IPC Router. - This library provides interface functions to the kernel drivers - to perform QMI message marshaling and transport them over IPC - Router. - config MSM_TEST_QMI_CLIENT depends on MSM_QMI_INTERFACE bool "MSM TEST QMI CLIENT" @@ -978,32 +951,6 @@ config MSM_PIL_MSS_QDSP6V5 If unsure, say N. -config MSM_PIL_VENUS - tristate "VENUS (Video) Boot Support" - depends on MSM_PIL && MSM_SUBSYSTEM_RESTART - help - Support for booting and shutting down the VENUS processor (Video). - Venus is the Video subsystem processor used for video codecs. - -config MSM_PIL_VPU - tristate "VPU Boot Support" - depends on MSM_PIL && MSM_SUBSYSTEM_RESTART - help - Support for booting and shutting down the VPU (Video Processing Unit) - processor. - - VPU is the Video Processing subsystem processor used for - video processing. - -config MSM_PIL_BCSS - tristate "BCSS (Broadcast Subsystem Boot Support)" - depends on MSM_PIL && MSM_SUBSYSTEM_RESTART - help - Support for booting and shutdown the Broadcast subsystem demodulator. - - BCSS is the Broadcast subsystem processor to receive and process the - Analog/Digital broadcast data from tuners / external demodulator. - config MSM_PIL_PRONTO tristate "PRONTO (WCNSS) Boot Support" depends on MSM_PIL && MSM_SUBSYSTEM_RESTART @@ -1223,14 +1170,6 @@ config MSM_L2_SPM Enabling this driver allows configuring L2 SPM for low power modes on supported chipsets. -config MSM_MULTIMEDIA_USE_ION - bool "Multimedia suport using Ion" - depends on ION_MSM - help - Enable support for multimedia drivers using Ion for buffer management - instead of pmem. Selecting this may also involve userspace - dependencies as well. - config MSM_OCMEM bool "MSM On-Chip memory driver (OCMEM)" help diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 0a551e0fc76..3007f9b93c1 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -1,10 +1,7 @@ -CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) - obj-y += io.o dma.o memory.o ifndef CONFIG_ARM_ARCH_TIMER obj-y += timer.o endif -obj-y += clock-voter.o obj-$(CONFIG_USE_OF) += board-dt.o obj-$(CONFIG_DEBUG_FS) += nohlt.o @@ -27,7 +24,7 @@ obj-$(CONFIG_MSM_JTAG_MM) += jtag-fuse.o jtag-mm.o obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o smd_private.o smd_init_dt.o smsm_debug.o obj-$(CONFIG_MSM_SMP2P) += smp2p.o smp2p_debug.o smp2p_gpio.o obj-$(CONFIG_MSM_SMP2P_TEST) += smp2p_loopback.o smp2p_test.o smp2p_gpio_test.o smp2p_spinlock_test.o -obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o +obj-$(CONFIG_MSM_SCM) += scm-boot.o obj-$(CONFIG_MSM_XPU_ERR_FATAL) += scm-xpu.o obj-$(CONFIG_MSM_PIL) += peripheral-loader.o obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o @@ -35,14 +32,9 @@ obj-$(CONFIG_MSM_PIL) += scm-pas.o obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V5) += pil-q6v5.o pil-q6v5-lpass.o obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-msa.o pil-q6v5-mss.o obj-$(CONFIG_MSM_PIL_PRONTO) += pil-pronto.o -obj-$(CONFIG_MSM_PIL_VENUS) += pil-venus.o -obj-$(CONFIG_MSM_PIL_VPU) += pil-vpu.o obj-$(CONFIG_MSM_PIL_FEMTO) += pil-q6v5.o pil-msa.o pil-femto-modem.o -obj-$(CONFIG_MSM_PIL_BCSS) += pil-bcss.o obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o -obj-$(CONFIG_MSM_SMD_LOGGING) += smem_log.o obj-y += socinfo.o -obj-$(CONFIG_MSM_QMI_INTERFACE) += msm_qmi_interface.o obj-$(CONFIG_MSM_TEST_QMI_CLIENT) += kernel_test_service_v01.o test_qmi_client.o obj-y += qdsp6v2/ obj-$(CONFIG_PM) += pm-boot.o @@ -68,7 +60,7 @@ endif obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o obj-$(CONFIG_ARCH_FSM9900) += board-fsm9900.o board-fsm9900-gpiomux.o -obj-$(CONFIG_ARCH_FSM9900) += clock-local2.o clock-pll.o clock-fsm9900.o clock-rpm.o clock-voter.o +obj-$(CONFIG_ARCH_FSM9900) += clock-fsm9900.o obj-$(CONFIG_ARCH_FSM9900) += clock-krait-8974.o obj-$(CONFIG_ARCH_FSM9900) += rfic-fsm9900.o bbif-fsm9900.o obj-$(CONFIG_MSM_WATCHDOG_V2) += msm_watchdog_v2.o @@ -76,24 +68,24 @@ obj-$(CONFIG_MSM_MEMORY_DUMP) += msm_memory_dump.o obj-$(CONFIG_QPNP_BMS) += bms-batterydata.o bms-batterydata-desay.o obj-$(CONFIG_QPNP_BMS) += bms-batterydata-oem.o bms-batterydata-qrd-4v35-2000mah.o bms-batterydata-qrd-4v2-1300mah.o obj-$(CONFIG_ARCH_APQ8084) += board-8084.o board-8084-gpiomux.o -obj-$(CONFIG_ARCH_APQ8084) += clock-local2.o clock-pll.o clock-8084.o clock-rpm.o clock-voter.o clock-mdss-8974.o +obj-$(CONFIG_ARCH_APQ8084) += clock-8084.o clock-mdss-8974.o obj-$(CONFIG_ARCH_APQ8084) += clock-krait-8974.o obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-8974-gpiomux.o obj-$(CONFIG_ARCH_MSM8974) += clock-krait-8974.o -obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-rpm-8974.o clock-gcc-8974.o clock-mmss-8974.o clock-lpass-8974.o clock-rpm.o clock-voter.o clock-mdss-8974.o +obj-$(CONFIG_ARCH_MSM8974) += clock-rpm-8974.o clock-gcc-8974.o clock-mmss-8974.o clock-lpass-8974.o clock-mdss-8974.o obj-$(CONFIG_KRAIT_REGULATOR) += krait-regulator.o krait-regulator-pmic.o obj-$(CONFIG_ARCH_MDM9630) += board-9630.o board-9630-gpiomux.o obj-$(CONFIG_ARCH_MSMSAMARIUM) += board-samarium.o board-samarium-gpiomux.o -obj-$(CONFIG_ARCH_MSMSAMARIUM) += clock-local2.o clock-pll.o clock-rpm.o clock-samarium.o clock-krait-8974.o clock-mdss-8974.o +obj-$(CONFIG_ARCH_MSMSAMARIUM) += clock-samarium.o clock-krait-8974.o clock-mdss-8974.o obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o -obj-$(CONFIG_ARCH_MPQ8092) += clock-local2.o clock-pll.o clock-rpm.o clock-voter.o clock-8092.o clock-vcap-8092.o clock-mdss-8974.o +obj-$(CONFIG_ARCH_MPQ8092) += clock-8092.o clock-vcap-8092.o clock-mdss-8974.o +obj-$(CONFIG_ARCH_MPQ8092) += clock-krait-8974.o obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o -obj-$(CONFIG_ARCH_MSM8226) += clock-local2.o clock-pll.o clock-8226.o clock-rpm.o clock-voter.o clock-mdss-8974.o +obj-$(CONFIG_ARCH_MSM8226) += clock-8226.o clock-mdss-8974.o obj-$(CONFIG_ARCH_MSM8610) += board-8610.o board-8610-gpiomux.o -obj-$(CONFIG_ARCH_MSM8610) += clock-local2.o clock-pll.o clock-8610.o clock-rpm.o clock-voter.o +obj-$(CONFIG_ARCH_MSM8610) += clock-8610.o obj-$(CONFIG_ARCH_MSM8610) += clock-dsi-8610.o -obj-$(CONFIG_ARCH_MDM9630) += clock-local2.o clock-pll.o clock-9630.o clock-rpm.o clock-voter.o -obj-$(CONFIG_ARCH_MDM9630) += clock-alpha-pll.o +obj-$(CONFIG_ARCH_MDM9630) += clock-9630.o obj-$(CONFIG_MSM_PM) += msm-pm.o pm-data.o lpm_levels.o diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c index 0ffd22eb85c..4bc31e10d23 100644 --- a/arch/arm/mach-msm/bam_dmux.c +++ b/arch/arm/mach-msm/bam_dmux.c @@ -30,12 +30,12 @@ #include <linux/of.h> #include <linux/ipc_logging.h> #include <linux/srcu.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/subsystem_notif.h> #include <mach/sps.h> #include <mach/bam_dmux.h> #include <mach/msm_smsm.h> -#include <mach/subsystem_notif.h> #include <mach/socinfo.h> -#include <mach/subsystem_restart.h> #include "bam_dmux_private.h" diff --git a/arch/arm/mach-msm/board-8092-gpiomux.c b/arch/arm/mach-msm/board-8092-gpiomux.c index 75fd6dd77ef..507294388fb 100644 --- a/arch/arm/mach-msm/board-8092-gpiomux.c +++ b/arch/arm/mach-msm/board-8092-gpiomux.c @@ -63,6 +63,12 @@ static struct gpiomux_setting ioexp_suspend_config = { .pull = GPIOMUX_PULL_NONE, }; +static struct gpiomux_setting gpio_spi_config = { + .func = GPIOMUX_FUNC_1, + .drv = GPIOMUX_DRV_6MA, + .pull = GPIOMUX_PULL_NONE, +}; + static struct gpiomux_setting ioexp_active_config = { .func = GPIOMUX_FUNC_GPIO, .drv = GPIOMUX_DRV_16MA, @@ -164,6 +170,30 @@ static struct msm_gpiomux_config msm_blsp_configs[] __initdata = { [GPIOMUX_SUSPENDED] = &gpio_i2c_config, }, }, + { + .gpio = 87, /* BLSP2 QUP6 SPI_DATA_MOSI */ + .settings = { + [GPIOMUX_SUSPENDED] = &gpio_spi_config, + }, + }, + { + .gpio = 88, /* BLSP2 QUP6 SPI_DATA_MISO */ + .settings = { + [GPIOMUX_SUSPENDED] = &gpio_spi_config, + }, + }, + { + .gpio = 90, /* BLSP2 QUP6 SPI_CLK */ + .settings = { + [GPIOMUX_SUSPENDED] = &gpio_spi_config, + }, + }, + { + .gpio = 89, /* BLSP2 QUP6 SPI_CS */ + .settings = { + [GPIOMUX_SUSPENDED] = &gpio_spi_config, + }, + }, }; static struct gpiomux_setting ehci_reset_sus_cfg = { @@ -255,6 +285,61 @@ static struct msm_gpiomux_config mpq_hdmi_mux_configs[] __initdata = { }, }; +static struct gpiomux_setting hdmi_suspend_cfg = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct gpiomux_setting hdmi_active_cec_cfg = { + .func = GPIOMUX_FUNC_4, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting hdmi_active_ddc_cfg = { + .func = GPIOMUX_FUNC_5, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_UP, +}; + +static struct gpiomux_setting hdmi_active_hpd_cfg = { + .func = GPIOMUX_FUNC_5, + .drv = GPIOMUX_DRV_16MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static struct msm_gpiomux_config msm_hdmi_configs[] __initdata = { + { + .gpio = 26, /* cec */ + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_cec_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, + { + .gpio = 24, /* ddc clk */ + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_ddc_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, + { + .gpio = 27, /* ddc data */ + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_ddc_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, + { + .gpio = 25, /* hpd */ + .settings = { + [GPIOMUX_ACTIVE] = &hdmi_active_hpd_cfg, + [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg, + }, + }, +}; + void __init mpq8092_init_gpiomux(void) { int rc; @@ -276,4 +361,5 @@ void __init mpq8092_init_gpiomux(void) ARRAY_SIZE(mpq8092_spdif_config)); msm_gpiomux_install(mpq_hdmi_mux_configs, ARRAY_SIZE(mpq_hdmi_mux_configs)); + msm_gpiomux_install(msm_hdmi_configs, ARRAY_SIZE(msm_hdmi_configs)); } diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c index b4d87693d81..6fcf5cc27e2 100644 --- a/arch/arm/mach-msm/board-8610-gpiomux.c +++ b/arch/arm/mach-msm/board-8610-gpiomux.c @@ -614,6 +614,13 @@ static struct gpiomux_setting interrupt_gpio_suspend_pulldown = { static struct msm_gpiomux_config msm_interrupt_configs[] __initdata = { { + .gpio = 75, /* NFC_CLK_REQ_IRQ*/ + .settings = { + [GPIOMUX_ACTIVE] = &interrupt_gpio_active, + [GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pullup, + }, + }, + { .gpio = 77, /* NFC_IRQ */ .settings = { [GPIOMUX_ACTIVE] = &interrupt_gpio_active, diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c index 664b3dcf7a8..4016c4dac4c 100644 --- a/arch/arm/mach-msm/board-dt.c +++ b/arch/arm/mach-msm/board-dt.c @@ -13,9 +13,9 @@ #include <linux/kernel.h> #include <linux/of.h> #include <linux/of_fdt.h> +#include <soc/qcom/scm.h> #include <asm/mach/map.h> #include <mach/msm_iomap.h> -#include <mach/scm.h> #include "board-dt.h" diff --git a/arch/arm/mach-msm/clock-8084.c b/arch/arm/mach-msm/clock-8084.c index ff5d5b4f642..c3636f3028e 100644 --- a/arch/arm/mach-msm/clock-8084.c +++ b/arch/arm/mach-msm/clock-8084.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -22,14 +22,14 @@ #include <linux/regulator/consumer.h> #include <linux/regulator/rpm-smd-regulator.h> #include <linux/clk/msm-clock-generic.h> +#include <soc/qcom/clock-local2.h> +#include <soc/qcom/clock-pll.h> +#include <soc/qcom/clock-rpm.h> +#include <soc/qcom/clock-voter.h> #include <mach/socinfo.h> #include <mach/rpm-smd.h> -#include "clock-local2.h" -#include "clock-pll.h" -#include "clock-rpm.h" -#include "clock-voter.h" #include "clock.h" #include "clock-mdss-8974.h" #include "clock-krait.h" @@ -5849,8 +5849,8 @@ static struct clk_lookup apq_clocks_8084[] = { CLK_LOOKUP("mem_clk", bimc_msmbus_clk.c, "msm_bimc"), CLK_LOOKUP("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc"), CLK_LOOKUP("mem_clk", bimc_acpu_a_clk.c, ""), - CLK_LOOKUP("ocmemgx_clk", ocmemgx_msmbus_clk.c, "msm_bus"), - CLK_LOOKUP("ocmemgx_a_clk", ocmemgx_msmbus_a_clk.c, "msm_bus"), + CLK_LOOKUP("bus_clk", ocmemgx_msmbus_clk.c, "msm-ocmem-vnoc"), + CLK_LOOKUP("bus_a_clk", ocmemgx_msmbus_a_clk.c, "msm-ocmem-vnoc"), CLK_LOOKUP("ocmemvs_clk", ocmemnoc_clk_src.c, "msm_bus"), CLK_LOOKUP("ocmemvs_a_clk", ocmemnoc_clk_src.c, "msm_bus"), CLK_LOOKUP("bus_clk", mmss_s0_axi_clk.c, "msm_mmss_noc"), diff --git a/arch/arm/mach-msm/clock-8092.c b/arch/arm/mach-msm/clock-8092.c index 3f129c77700..03d2164db23 100644 --- a/arch/arm/mach-msm/clock-8092.c +++ b/arch/arm/mach-msm/clock-8092.c @@ -22,14 +22,14 @@ #include <linux/regulator/consumer.h> #include <linux/regulator/rpm-smd-regulator.h> #include <linux/clk/msm-clock-generic.h> +#include <soc/qcom/clock-local2.h> +#include <soc/qcom/clock-pll.h> +#include <soc/qcom/clock-rpm.h> +#include <soc/qcom/clock-voter.h> #include <mach/socinfo.h> #include <mach/rpm-smd.h> -#include "clock-local2.h" -#include "clock-pll.h" -#include "clock-rpm.h" -#include "clock-voter.h" #include "clock.h" #include "clock-mdss-8974.h" @@ -5758,6 +5758,8 @@ static struct gate_clk vby1_gpio_ldo = { }, }; +static DEFINE_CLK_VOTER(scm_ce1_clk_src, &ce1_clk_src.c, 100000000); + static DEFINE_CLK_MEASURE(l2_m_clk); static DEFINE_CLK_MEASURE(krait0_m_clk); static DEFINE_CLK_MEASURE(krait1_m_clk); @@ -6625,7 +6627,7 @@ static struct clk_lookup mpq_clocks_8092[] = { CLK_LOOKUP("mem_clk", bimc_a_clk.c, ""), CLK_LOOKUP("mem_clk", ocmemgx_a_clk.c, ""), CLK_LOOKUP("xo_clk", xo_clk_src.c, ""), - CLK_LOOKUP("xo_clk", xo_a_clk_src.c, ""), + CLK_LOOKUP("hfpll_src", xo_a_clk_src.c, "f9016000.qcom,clock-krait"), CLK_LOOKUP("bus_clk", mmssnoc_ahb_clk.c, ""), CLK_LOOKUP("core_clk", gfx3d_clk_src.c, ""), CLK_LOOKUP("core_clk", gfx3d_a_clk_src.c, ""), @@ -6633,7 +6635,7 @@ static struct clk_lookup mpq_clocks_8092[] = { /* PLL */ CLK_LOOKUP("gpll0", gpll0_clk_src.c, ""), - CLK_LOOKUP("gpll0_ao", gpll0_ao_clk_src.c, ""), + CLK_LOOKUP("aux_clk", gpll0_ao_clk_src.c, "f9016000.qcom,clock-krait"), /* Voter clocks */ CLK_LOOKUP("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc"), @@ -6689,6 +6691,7 @@ static struct clk_lookup mpq_clocks_8092[] = { CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f995d000.serial"), CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9960000.serial"), CLK_LOOKUP("core_clk", gcc_blsp2_qup1_i2c_apps_clk.c, "f9963000.i2c"), + CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9968000.spi"), CLK_LOOKUP("", gcc_blsp2_qup1_spi_apps_clk.c, ""), CLK_LOOKUP("", gcc_blsp2_qup2_i2c_apps_clk.c, ""), CLK_LOOKUP("", gcc_blsp2_qup2_spi_apps_clk.c, ""), @@ -6699,7 +6702,7 @@ static struct clk_lookup mpq_clocks_8092[] = { CLK_LOOKUP("core_clk", gcc_blsp2_qup5_i2c_apps_clk.c, "f9967000.i2c"), CLK_LOOKUP("", gcc_blsp2_qup5_spi_apps_clk.c, ""), CLK_LOOKUP("", gcc_blsp2_qup6_i2c_apps_clk.c, ""), - CLK_LOOKUP("", gcc_blsp2_qup6_spi_apps_clk.c, ""), + CLK_LOOKUP("core_clk", gcc_blsp2_qup6_spi_apps_clk.c, "f9968000.spi"), CLK_LOOKUP("core_clk", gcc_blsp2_uart1_apps_clk.c, "f995d000.serial"), CLK_LOOKUP("", gcc_blsp2_uart2_apps_clk.c, ""), CLK_LOOKUP("", gcc_blsp2_uart3_apps_clk.c, ""), @@ -6710,9 +6713,11 @@ static struct clk_lookup mpq_clocks_8092[] = { CLK_LOOKUP("", gcc_boot_rom_ahb_clk.c, ""), /* CE */ - CLK_LOOKUP("", gcc_ce1_ahb_clk.c, ""), - CLK_LOOKUP("", gcc_ce1_axi_clk.c, ""), - CLK_LOOKUP("", gcc_ce1_clk.c, ""), + CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "scm"), + CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "scm"), + CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "scm"), + CLK_LOOKUP("core_clk_src", scm_ce1_clk_src.c, "scm"), + CLK_LOOKUP("", gcc_ce2_ahb_clk.c, ""), CLK_LOOKUP("", gcc_ce2_axi_clk.c, ""), CLK_LOOKUP("", gcc_ce2_clk.c, ""), @@ -6891,6 +6896,8 @@ static struct clk_lookup mpq_clocks_8092[] = { CLK_LOOKUP("vdp_bus_clk", vpu_bus_clk.c, "fde0b000.qcom,pil-vpu"), CLK_LOOKUP("core_clk", vpu_maple_clk.c, "fde0b000.qcom,pil-vpu"), CLK_LOOKUP("sleep_clk", vpu_sleep_clk.c, "fde0b000.qcom,pil-vpu"), + CLK_LOOKUP("maple_bus_clk", gcc_mmss_a5ss_axi_clk.c, + "fde0b000.qcom,pil-vpu"), CLK_LOOKUP("iface_clk", vpu_ahb_clk.c, "fde0b000.qcom,vpu"), CLK_LOOKUP("bus_clk", vpu_axi_clk.c, "fde0b000.qcom,vpu"), diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c index 6c24b1b0c8c..3b2cf3a0f8c 100644 --- a/arch/arm/mach-msm/clock-8226.c +++ b/arch/arm/mach-msm/clock-8226.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -22,14 +22,14 @@ #include <linux/regulator/consumer.h> #include <linux/regulator/rpm-smd-regulator.h> #include <linux/clk/msm-clock-generic.h> +#include <soc/qcom/clock-local2.h> +#include <soc/qcom/clock-pll.h> +#include <soc/qcom/clock-rpm.h> +#include <soc/qcom/clock-voter.h> #include <mach/socinfo.h> #include <mach/rpm-smd.h> -#include "clock-local2.h" -#include "clock-pll.h" -#include "clock-rpm.h" -#include "clock-voter.h" #include "clock-mdss-8974.h" #include "clock.h" diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c index 22c4b449970..11ef04f6f76 100644 --- a/arch/arm/mach-msm/clock-8610.c +++ b/arch/arm/mach-msm/clock-8610.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -22,14 +22,14 @@ #include <linux/regulator/consumer.h> #include <linux/regulator/rpm-smd-regulator.h> #include <linux/clk/msm-clock-generic.h> +#include <soc/qcom/clock-local2.h> +#include <soc/qcom/clock-pll.h> +#include <soc/qcom/clock-rpm.h> +#include <soc/qcom/clock-voter.h> #include <mach/socinfo.h> #include <mach/rpm-smd.h> -#include "clock-local2.h" -#include "clock-pll.h" -#include "clock-rpm.h" -#include "clock-voter.h" #include "clock.h" #include "clock-dsi-8610.h" diff --git a/arch/arm/mach-msm/clock-9630.c b/arch/arm/mach-msm/clock-9630.c index da150cb3b66..b9beba4b52e 100644 --- a/arch/arm/mach-msm/clock-9630.c +++ b/arch/arm/mach-msm/clock-9630.c @@ -22,15 +22,15 @@ #include <linux/regulator/rpm-smd-regulator.h> #include <linux/iopoll.h> #include <linux/clk/msm-clk.h> +#include <soc/qcom/clock-alpha-pll.h> +#include <soc/qcom/clock-local2.h> +#include <soc/qcom/clock-pll.h> +#include <soc/qcom/clock-rpm.h> +#include <soc/qcom/clock-voter.h> #include <mach/socinfo.h> -#include "clock-local2.h" -#include "clock-pll.h" -#include "clock-rpm.h" -#include "clock-voter.h" #include "clock.h" -#include "clock-alpha-pll.h" enum { GCC_BASE, diff --git a/arch/arm/mach-msm/clock-a7.c b/arch/arm/mach-msm/clock-a7.c index 0f94b02c553..c5cf111b1f4 100644 --- a/arch/arm/mach-msm/clock-a7.c +++ b/arch/arm/mach-msm/clock-a7.c @@ -24,8 +24,7 @@ #include <linux/regulator/consumer.h> #include <linux/of.h> #include <linux/clk/msm-clock-generic.h> - -#include "clock-local2.h" +#include <soc/qcom/clock-local2.h> #define UPDATE_CHECK_MAX_LOOPS 200 diff --git a/arch/arm/mach-msm/clock-fsm9900.c b/arch/arm/mach-msm/clock-fsm9900.c index 7d0d5a1bddc..636fede03f3 100644 --- a/arch/arm/mach-msm/clock-fsm9900.c +++ b/arch/arm/mach-msm/clock-fsm9900.c @@ -22,14 +22,14 @@ #include <linux/regulator/consumer.h> #include <linux/regulator/machine.h> #include <linux/regulator/rpm-smd-regulator.h> +#include <soc/qcom/clock-local2.h> +#include <soc/qcom/clock-pll.h> +#include <soc/qcom/clock-rpm.h> +#include <soc/qcom/clock-voter.h> #include <mach/socinfo.h> #include <mach/rpm-smd.h> -#include "clock-local2.h" -#include "clock-pll.h" -#include "clock-rpm.h" -#include "clock-voter.h" #include "clock.h" #include "clock-krait.h" diff --git a/arch/arm/mach-msm/clock-gcc-8974.c b/arch/arm/mach-msm/clock-gcc-8974.c index 56f0c4728fc..add69f0e1b2 100644 --- a/arch/arm/mach-msm/clock-gcc-8974.c +++ b/arch/arm/mach-msm/clock-gcc-8974.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -23,12 +23,12 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/clk/msm-clock-generic.h> +#include <soc/qcom/clock-local2.h> +#include <soc/qcom/clock-pll.h> +#include <soc/qcom/clock-voter.h> #include <dt-bindings/clock/msm-clocks-8974.h> -#include "clock-local2.h" -#include "clock-pll.h" -#include "clock-voter.h" #include "clock.h" enum { diff --git a/arch/arm/mach-msm/clock-krait-8974.c b/arch/arm/mach-msm/clock-krait-8974.c index 0acb3faeb97..a41ad0ba5d6 100644 --- a/arch/arm/mach-msm/clock-krait-8974.c +++ b/arch/arm/mach-msm/clock-krait-8974.c @@ -25,11 +25,11 @@ #include <linux/clk/msm-clk-provider.h> #include <linux/clk/msm-clk.h> #include <linux/clk/msm-clock-generic.h> +#include <soc/qcom/clock-local2.h> #include <asm/cputype.h> #include "clock-krait.h" -#include "clock-local2.h" #include "clock.h" /* Clock inputs coming into Krait subsystem */ diff --git a/arch/arm/mach-msm/clock-lpass-8974.c b/arch/arm/mach-msm/clock-lpass-8974.c index f13ace02d18..36c7c4b809f 100644 --- a/arch/arm/mach-msm/clock-lpass-8974.c +++ b/arch/arm/mach-msm/clock-lpass-8974.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -23,10 +23,10 @@ #include <linux/platform_device.h> #include <linux/module.h> #include <linux/clk/msm-clock-generic.h> +#include <soc/qcom/clock-local2.h> #include <dt-bindings/clock/msm-clocks-8974.h> -#include "clock-local2.h" #include "clock.h" enum { diff --git a/arch/arm/mach-msm/clock-mmss-8974.c b/arch/arm/mach-msm/clock-mmss-8974.c index 6e93c3f5a8d..83e6a160a7e 100644 --- a/arch/arm/mach-msm/clock-mmss-8974.c +++ b/arch/arm/mach-msm/clock-mmss-8974.c @@ -24,13 +24,13 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/clk/msm-clock-generic.h> +#include <soc/qcom/clock-local2.h> +#include <soc/qcom/clock-pll.h> +#include <soc/qcom/clock-rpm.h> +#include <soc/qcom/clock-voter.h> #include <dt-bindings/clock/msm-clocks-8974.h> -#include "clock-local2.h" -#include "clock-pll.h" -#include "clock-rpm.h" -#include "clock-voter.h" #include "clock-mdss-8974.h" #include "clock.h" diff --git a/arch/arm/mach-msm/clock-rpm-8974.c b/arch/arm/mach-msm/clock-rpm-8974.c index f5e5b0a997c..26af383a107 100644 --- a/arch/arm/mach-msm/clock-rpm-8974.c +++ b/arch/arm/mach-msm/clock-rpm-8974.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -20,14 +20,14 @@ #include <linux/platform_device.h> #include <linux/module.h> #include <linux/clk/msm-clock-generic.h> +#include <soc/qcom/clock-local2.h> +#include <soc/qcom/clock-rpm.h> +#include <soc/qcom/clock-voter.h> #include <mach/rpm-smd.h> #include <dt-bindings/clock/msm-clocks-8974.h> -#include "clock-local2.h" -#include "clock-rpm.h" -#include "clock-voter.h" #include "clock.h" #define GCC_DEBUG_CLK_CTL_REG 0x1880 diff --git a/arch/arm/mach-msm/clock-samarium.c b/arch/arm/mach-msm/clock-samarium.c index 10db9760532..38c886c83fe 100644 --- a/arch/arm/mach-msm/clock-samarium.c +++ b/arch/arm/mach-msm/clock-samarium.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -22,13 +22,13 @@ #include <linux/regulator/consumer.h> #include <linux/regulator/rpm-smd-regulator.h> #include <linux/clk/msm-clock-generic.h> +#include <soc/qcom/clock-local2.h> +#include <soc/qcom/clock-pll.h> +#include <soc/qcom/clock-rpm.h> +#include <soc/qcom/clock-voter.h> #include <mach/rpm-smd.h> -#include "clock-local2.h" -#include "clock-pll.h" -#include "clock-rpm.h" -#include "clock-voter.h" #include "clock.h" #include "clock-krait.h" #include "clock-mdss-8974.h" diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c index ce6dbe3f9cf..f9452c32ce7 100644 --- a/arch/arm/mach-msm/cpr-regulator.c +++ b/arch/arm/mach-msm/cpr-regulator.c @@ -29,8 +29,8 @@ #include <linux/regulator/driver.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/cpr-regulator.h> +#include <soc/qcom/scm.h> #include <asm/uaccess.h> -#include <mach/scm.h> /* Register Offsets for RB-CPR and Bit Definitions */ diff --git a/arch/arm/mach-msm/early_random.c b/arch/arm/mach-msm/early_random.c index e315b86a431..94989ed1d45 100644 --- a/arch/arm/mach-msm/early_random.c +++ b/arch/arm/mach-msm/early_random.c @@ -12,8 +12,8 @@ */ #include <linux/kernel.h> +#include <soc/qcom/scm.h> -#include <mach/scm.h> #include <asm/io.h> #include <asm/cacheflush.h> diff --git a/arch/arm/mach-msm/hsic_sysmon.c b/arch/arm/mach-msm/hsic_sysmon.c index 744864b1f37..02ee89ca6bf 100644 --- a/arch/arm/mach-msm/hsic_sysmon.c +++ b/arch/arm/mach-msm/hsic_sysmon.c @@ -23,9 +23,9 @@ #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/debugfs.h> -#include <mach/sysmon.h> +#include <soc/qcom/hsic_sysmon.h> +#include <soc/qcom/sysmon.h> -#include "hsic_sysmon.h" #define DRIVER_DESC "HSIC System monitor driver" diff --git a/arch/arm/mach-msm/hsic_sysmon_test.c b/arch/arm/mach-msm/hsic_sysmon_test.c index 3bdd9e3ee6b..fdf107f9cd9 100644 --- a/arch/arm/mach-msm/hsic_sysmon_test.c +++ b/arch/arm/mach-msm/hsic_sysmon_test.c @@ -19,9 +19,9 @@ #include <linux/device.h> #include <linux/debugfs.h> #include <linux/uaccess.h> -#include <mach/sysmon.h> +#include <soc/qcom/hsic_sysmon.h> +#include <soc/qcom/sysmon.h> -#include "hsic_sysmon.h" #define DRIVER_DESC "HSIC System monitor driver test" diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h index be2c80915fc..3cda8041361 100644 --- a/arch/arm/mach-msm/include/mach/msm_smd.h +++ b/arch/arm/mach-msm/include/mach/msm_smd.h @@ -340,7 +340,7 @@ static inline void smd_disable_read_intr(smd_channel_t *ch) { } -static inline int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask +static inline int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask, const struct cpumask *cpumask) { return -ENODEV; diff --git a/arch/arm/mach-msm/include/mach/msm_tspp2.h b/arch/arm/mach-msm/include/mach/msm_tspp2.h index aa7f3c3e566..9e1e7d7377b 100644 --- a/arch/arm/mach-msm/include/mach/msm_tspp2.h +++ b/arch/arm/mach-msm/include/mach/msm_tspp2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -30,22 +30,12 @@ /** * struct msm_tspp2_platform_data - TSPP2 platform data * - * @tspp2_ahb_clk: TSPP2 device AHB clock name. - * @tspp2_core_clk: TSPP2 device core clock name. - * @tspp2_vbif_clk: TSPP2 VBIF clock name. - * @tspp2_klm_ahb_clk: TSPP2 key ladder AHB clock name. - * @tsif_ref_clk: TSIF device reference clock name. * @hlos_group: IOMMU HLOS group name. * @cpz_group: IOMMU CPZ group name. * @hlos_partition: IOMMU HLOS partition number. * @cpz_partition: IOMMU CPZ partition number. */ struct msm_tspp2_platform_data { - const char *tspp2_ahb_clk; - const char *tspp2_core_clk; - const char *tspp2_vbif_clk; - const char *tspp2_klm_ahb_clk; - const char *tsif_ref_clk; const char *hlos_group; const char *cpz_group; int hlos_partition; diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h index 6cd4a2ee8cb..c2d2b4a5365 100644 --- a/arch/arm/mach-msm/include/mach/sps.h +++ b/arch/arm/mach-msm/include/mach/sps.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -177,6 +177,8 @@ enum sps_option { SPS_O_IRQ_MTI = 0x00020000, /* NWD bit written with EOT for BAM2BAM producer pipe */ SPS_O_WRITE_NWD = 0x00040000, + /* EOT set after pipe SW offset advanced */ + SPS_O_LATE_EOT = 0x00080000, /* Options to enable software features */ /* Do not disable a pipe during disconnection */ diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h index d54c825c6ea..1049799ea01 100644 --- a/arch/arm/mach-msm/include/mach/subsystem_restart.h +++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,124 +10,8 @@ * GNU General Public License for more details. * */ - -#ifndef __SUBSYS_RESTART_H -#define __SUBSYS_RESTART_H - -#include <linux/spinlock.h> -#include <linux/interrupt.h> - -#define SUBSYS_NAME_MAX_LENGTH 40 - -struct subsys_device; - -enum { - RESET_SOC = 0, - RESET_SUBSYS_COUPLED, - RESET_LEVEL_MAX -}; - -struct device; -struct module; - -/** - * struct subsys_desc - subsystem descriptor - * @name: name of subsystem - * @depends_on: subsystem this subsystem depends on to operate - * @dev: parent device - * @owner: module the descriptor belongs to - * @shutdown: Stop a subsystem - * @powerup: Start a subsystem - * @crash_shutdown: Shutdown a subsystem when the system crashes (can't sleep) - * @ramdump: Collect a ramdump of the subsystem - * @is_not_loadable: Indicate if subsystem firmware is not loadable via pil - * framework +/* + * This header is deprecated and will be deleted soon. Please include + * the header below instead. */ -struct subsys_desc { - const char *name; - const char *depends_on; - struct device *dev; - struct module *owner; - - int (*shutdown)(const struct subsys_desc *desc, bool force_stop); - int (*powerup)(const struct subsys_desc *desc); - void (*crash_shutdown)(const struct subsys_desc *desc); - int (*ramdump)(int, const struct subsys_desc *desc); - irqreturn_t (*err_fatal_handler) (int irq, void *dev_id); - irqreturn_t (*stop_ack_handler) (int irq, void *dev_id); - irqreturn_t (*wdog_bite_handler) (int irq, void *dev_id); - int is_not_loadable; - unsigned int err_fatal_irq; - unsigned int err_ready_irq; - unsigned int stop_ack_irq; - unsigned int wdog_bite_irq; - int force_stop_gpio; -}; - -#if defined(CONFIG_MSM_SUBSYSTEM_RESTART) - -extern int subsys_get_restart_level(struct subsys_device *dev); -extern int subsystem_restart_dev(struct subsys_device *dev); -extern int subsystem_restart(const char *name); -extern int subsystem_crashed(const char *name); - -extern void *subsystem_get(const char *name); -extern void subsystem_put(void *subsystem); - -extern struct subsys_device *subsys_register(struct subsys_desc *desc); -extern void subsys_unregister(struct subsys_device *dev); - -extern void subsys_default_online(struct subsys_device *dev); -extern void subsys_set_crash_status(struct subsys_device *dev, bool crashed); -extern bool subsys_get_crash_status(struct subsys_device *dev); -void notify_proxy_vote(struct device *device); -void notify_proxy_unvote(struct device *device); -#else - -static inline int subsys_get_restart_level(struct subsys_device *dev) -{ - return 0; -} - -static inline int subsystem_restart_dev(struct subsys_device *dev) -{ - return 0; -} - -static inline int subsystem_restart(const char *name) -{ - return 0; -} - -static inline int subsystem_crashed(const char *name) -{ - return 0; -} - -static inline void *subsystem_get(const char *name) -{ - return NULL; -} - -static inline void subsystem_put(void *subsystem) { } - -static inline -struct subsys_device *subsys_register(struct subsys_desc *desc) -{ - return NULL; -} - -static inline void subsys_unregister(struct subsys_device *dev) { } - -static inline void subsys_default_online(struct subsys_device *dev) { } -static inline -void subsys_set_crash_status(struct subsys_device *dev, bool crashed) { } -static inline bool subsys_get_crash_status(struct subsys_device *dev) -{ - return false; -} -void notify_proxy_vote(struct device *device) { } -void notify_proxy_unvote(struct device *device) { } -#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */ - -#endif +#include <soc/qcom/subsystem_restart.h> diff --git a/arch/arm/mach-msm/jtag-mm.c b/arch/arm/mach-msm/jtag-mm.c index 2a980727b02..3df64368a70 100644 --- a/arch/arm/mach-msm/jtag-mm.c +++ b/arch/arm/mach-msm/jtag-mm.c @@ -26,7 +26,7 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/bitops.h> -#include <mach/scm.h> +#include <soc/qcom/scm.h> #include <mach/jtag.h> /* Coresight management registers */ diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c index 840449c584e..faa38cfbae2 100644 --- a/arch/arm/mach-msm/jtag.c +++ b/arch/arm/mach-msm/jtag.c @@ -20,8 +20,8 @@ #include <linux/printk.h> #include <linux/ratelimit.h> #include <linux/coresight.h> +#include <soc/qcom/scm.h> #include <asm/hardware/cp14.h> -#include <mach/scm.h> #include <mach/jtag.h> /* DBGv7 with baseline CP14 registers implemented */ diff --git a/arch/arm/mach-msm/kernel_test_service_v01.c b/arch/arm/mach-msm/kernel_test_service_v01.c index 498e0466267..bc4702e163e 100644 --- a/arch/arm/mach-msm/kernel_test_service_v01.c +++ b/arch/arm/mach-msm/kernel_test_service_v01.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -13,7 +13,7 @@ #include <linux/qmi_encdec.h> -#include <mach/msm_qmi_interface.h> +#include <soc/qcom/msm_qmi_interface.h> #include "kernel_test_service_v01.h" diff --git a/arch/arm/mach-msm/kernel_test_service_v01.h b/arch/arm/mach-msm/kernel_test_service_v01.h index 79c18452878..4cb594f445d 100644 --- a/arch/arm/mach-msm/kernel_test_service_v01.h +++ b/arch/arm/mach-msm/kernel_test_service_v01.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -13,7 +13,7 @@ #ifndef MSM_QMI_TEST_SERVICE_V01_H #define MSM_QMI_TEST_SERVICE_V01_H -#include <mach/msm_qmi_interface.h> +#include <soc/qcom/msm_qmi_interface.h> #define TEST_MED_DATA_SIZE_V01 8192 #define TEST_MAX_NAME_SIZE_V01 255 diff --git a/arch/arm/mach-msm/krait-scm.c b/arch/arm/mach-msm/krait-scm.c index 9290f211623..d1316632cc2 100644 --- a/arch/arm/mach-msm/krait-scm.c +++ b/arch/arm/mach-msm/krait-scm.c @@ -16,8 +16,8 @@ #include <linux/cpu.h> #include <linux/smp.h> #include <linux/sysfs.h> +#include <soc/qcom/scm.h> -#include <mach/scm.h> #define CPU_CONFIG_CMD 5 #define CPU_CONFIG_QUERY_CMD 6 diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c index 7f58629785a..8d922601226 100644 --- a/arch/arm/mach-msm/lpm_levels.c +++ b/arch/arm/mach-msm/lpm_levels.c @@ -261,7 +261,7 @@ static int lpm_system_mode_select(struct lpm_system_state *system_state, { int best_level = -1; int i; - uint32_t best_level_pwr = ~0UL; + uint32_t best_level_pwr = ~0U; uint32_t pwr; uint32_t latency_us = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); @@ -504,7 +504,7 @@ static void msm_pm_set_timer(uint32_t modified_time_us) static int lpm_cpu_power_select(struct cpuidle_device *dev, int *index) { int best_level = -1; - uint32_t best_level_pwr = ~0UL; + uint32_t best_level_pwr = ~0U; uint32_t latency_us = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); uint32_t sleep_us = (uint32_t)(ktime_to_us(tick_nohz_get_sleep_length())); @@ -739,8 +739,6 @@ static void lpm_enter_low_power(struct lpm_system_state *system_state, int idx; struct lpm_cpu_level *cpu_level = &system_state->cpu_level[cpu_index]; - cpu_level = &system_state->cpu_level[cpu_index]; - lpm_cpu_prepare(system_state, cpu_index, from_idle); idx = lpm_system_select(system_state, cpu_index, from_idle); diff --git a/arch/arm/mach-msm/msm-pm.c b/arch/arm/mach-msm/msm-pm.c index d0f80ea423c..3de452ce2b9 100644 --- a/arch/arm/mach-msm/msm-pm.c +++ b/arch/arm/mach-msm/msm-pm.c @@ -25,13 +25,13 @@ #include <linux/platform_device.h> #include <linux/of_platform.h> #include <linux/cpu_pm.h> +#include <soc/qcom/scm.h> #include <asm/suspend.h> #include <asm/cacheflush.h> #include <asm/outercache.h> #ifdef CONFIG_VFP #include <asm/vfp.h> #endif -#include <mach/scm.h> #include <mach/msm_bus.h> #include <mach/jtag.h> #include <mach/avs.h> diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c index 696103c33d6..72e3ec39cfc 100644 --- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c +++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c @@ -299,12 +299,16 @@ static int getpath(int src, int dest) static uint64_t get_node_maxib(struct msm_bus_inode_info *info) { - int i; + int i, ctx; uint64_t maxib = 0; - for (i = 0; i <= info->num_pnodes; i++) - maxib = max(*info->pnode[i].sel_clk, maxib); + for (i = 0; i <= info->num_pnodes; i++) { + for (ctx = 0; ctx < NUM_CTX; ctx++) + maxib = max(info->pnode[i].clk[ctx], maxib); + } + MSM_BUS_DBG("%s: Node %d numpnodes %d maxib %llu", __func__, + info->num_pnodes, info->node_info->id, maxib); return maxib; } diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_of.c b/arch/arm/mach-msm/msm_bus/msm_bus_of.c index a6b1395b916..b1c77210fba 100644 --- a/arch/arm/mach-msm/msm_bus/msm_bus_of.c +++ b/arch/arm/mach-msm/msm_bus/msm_bus_of.c @@ -173,7 +173,7 @@ struct msm_bus_scale_pdata *msm_bus_cl_get_pdata(struct platform_device *pdev) of_node = pdev->dev.of_node; pdata = get_pdata(pdev, of_node); if (!pdata) { - pr_err("Error getting bus pdata!\n"); + pr_err("client has to provide missing entry for successful registration\n"); return NULL; } @@ -214,7 +214,7 @@ struct msm_bus_scale_pdata *msm_bus_pdata_from_node( pdata = get_pdata(pdev, of_node); if (!pdata) { - pr_err("Error getting bus pdata!\n"); + pr_err("client has to provide missing entry for successful registration\n"); return NULL; } diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c index 32cefb77642..f21860b744d 100644 --- a/arch/arm/mach-msm/msm_cache_dump.c +++ b/arch/arm/mach-msm/msm_cache_dump.c @@ -23,7 +23,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/dma-mapping.h> -#include <mach/scm.h> +#include <soc/qcom/scm.h> #include <mach/msm_cache_dump.h> #include <mach/msm_iomap.h> #include <mach/msm_memory_dump.h> diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c index b547156aa9f..8a8ff6b4e6e 100644 --- a/arch/arm/mach-msm/msm_watchdog_v2.c +++ b/arch/arm/mach-msm/msm_watchdog_v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -25,7 +25,7 @@ #include <linux/of.h> #include <linux/cpu.h> #include <linux/platform_device.h> -#include <mach/scm.h> +#include <soc/qcom/scm.h> #include <mach/msm_memory_dump.h> #define MODULE_NAME "msm_watchdog" @@ -476,10 +476,13 @@ static int msm_wdog_dt_to_pdata(struct platform_device *pdev, int ret; wdog_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!wdog_resource) + return -ENODEV; pdata->size = resource_size(wdog_resource); pdata->phys_base = wdog_resource->start; - if (unlikely(!(devm_request_region(&pdev->dev, pdata->phys_base, - pdata->size, "msm-watchdog")))) { + if (unlikely(!(devm_request_mem_region(&pdev->dev, pdata->phys_base, + pdata->size, "msm-watchdog")))) { + dev_err(&pdev->dev, "%s cannot reserve watchdog region\n", __func__); return -ENXIO; diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c index c186a5ee7df..aa7b7d50734 100644 --- a/arch/arm/mach-msm/ocmem_core.c +++ b/arch/arm/mach-msm/ocmem_core.c @@ -14,10 +14,10 @@ #include <linux/mutex.h> #include <linux/kernel.h> #include <linux/platform_device.h> +#include <soc/qcom/scm.h> #include <mach/ocmem_priv.h> #include <mach/rpm-smd.h> -#include <mach/scm.h> static unsigned num_regions; static unsigned num_macros; diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c index c8a2e5264b5..0717a41506d 100644 --- a/arch/arm/mach-msm/peripheral-loader.c +++ b/arch/arm/mach-msm/peripheral-loader.c @@ -33,14 +33,14 @@ #include <linux/of_gpio.h> #include <linux/of_address.h> #include <linux/io.h> +#include <soc/qcom/ramdump.h> +#include <soc/qcom/subsystem_restart.h> #include <asm/uaccess.h> #include <asm/setup.h> #include <asm-generic/io-64-nonatomic-lo-hi.h> #include <mach/msm_iomap.h> -#include <mach/ramdump.h> -#include <mach/subsystem_restart.h> #include "peripheral-loader.h" @@ -599,7 +599,7 @@ static int pil_load_seg(struct pil_desc *desc, struct pil_seg *seg) return ret; } -static void pil_parse_devicetree(struct pil_desc *desc) +static int pil_parse_devicetree(struct pil_desc *desc) { int clk_ready = 0; @@ -614,7 +614,7 @@ static void pil_parse_devicetree(struct pil_desc *desc) dev_err(desc->dev, "[%s]: Error getting proxy unvoting gpio\n", desc->name); - return; + return clk_ready; } clk_ready = gpio_to_irq(clk_ready); @@ -622,10 +622,11 @@ static void pil_parse_devicetree(struct pil_desc *desc) dev_err(desc->dev, "[%s]: Error getting proxy unvote IRQ\n", desc->name); - return; + return clk_ready; } } desc->proxy_unvote_irq = clk_ready; + return 0; } /* Synchronize request_firmware() with suspend */ @@ -805,7 +806,9 @@ int pil_desc_init(struct pil_desc *desc) __iowrite32_copy(priv->info->name, buf, sizeof(buf) / 4); } - pil_parse_devicetree(desc); + ret = pil_parse_devicetree(desc); + if (ret) + goto err_parse_dt; /* Ignore users who don't make any sense */ WARN(desc->ops->proxy_unvote && desc->proxy_unvote_irq == 0 @@ -841,6 +844,8 @@ int pil_desc_init(struct pil_desc *desc) desc->unmap_fw_mem = unmap_fw_mem; return 0; +err_parse_dt: + ida_simple_remove(&pil_ida, priv->id); err: kfree(priv); return ret; diff --git a/arch/arm/mach-msm/pil-bcss.c b/arch/arm/mach-msm/pil-bcss.c deleted file mode 100644 index 6700f5e2c1d..00000000000 --- a/arch/arm/mach-msm/pil-bcss.c +++ /dev/null @@ -1,182 +0,0 @@ -/* Copyright (c) 2013, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/of.h> -#include <linux/delay.h> - -#include <mach/subsystem_restart.h> -#include <mach/ramdump.h> - -#include "peripheral-loader.h" -#include "scm-pas.h" - -struct bcss_data { - struct pil_desc desc; - struct subsys_device *subsys; - struct subsys_desc subsys_desc; - bool is_booted; - void *ramdump_dev; -}; - -static int pil_bcss_init_image(struct pil_desc *pil, - const u8 *metadata, size_t size) -{ - return pas_init_image(PAS_BCSS, metadata, size); -} - -static int pil_bcss_mem_setup(struct pil_desc *pil, phys_addr_t addr, - size_t size) -{ - return pas_mem_setup(PAS_BCSS, addr, size); -} - -static int pil_bcss_auth(struct pil_desc *pil) -{ - return pas_auth_and_reset(PAS_BCSS); -} - -static int pil_bcss_shutdown(struct pil_desc *pil) -{ - return pas_shutdown(PAS_BCSS); -} - -static struct pil_reset_ops pil_bcss_ops = { - .init_image = pil_bcss_init_image, - .mem_setup = pil_bcss_mem_setup, - .auth_and_reset = pil_bcss_auth, - .shutdown = pil_bcss_shutdown, -}; - -#define subsys_to_drv(d) container_of(d, struct bcss_data, subsys_desc) - -static int bcss_shutdown(const struct subsys_desc *subsys, bool force_stop) -{ - struct bcss_data *drv = subsys_to_drv(subsys); - - pil_shutdown(&drv->desc); - - return 0; -} - -static int bcss_powerup(const struct subsys_desc *subsys) -{ - struct bcss_data *drv = subsys_to_drv(subsys); - - return pil_boot(&drv->desc); -} - -static int bcss_ramdump(int enable, const struct subsys_desc *subsys) -{ - struct bcss_data *drv = subsys_to_drv(subsys); - - if (!enable) - return 0; - - return pil_do_ramdump(&drv->desc, drv->ramdump_dev); -} - -static int pil_bcss_driver_probe(struct platform_device *pdev) -{ - struct bcss_data *drv; - struct pil_desc *desc; - int ret; - - drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); - if (!drv) - return -ENOMEM; - platform_set_drvdata(pdev, drv); - - desc = &drv->desc; - ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name", - &desc->name); - if (ret) - return ret; - - desc->dev = &pdev->dev; - desc->owner = THIS_MODULE; - - ret = pas_supported(PAS_BCSS); - if (ret > 0) { - desc->ops = &pil_bcss_ops; - dev_info(&pdev->dev, "using secure boot\n"); - } else { - dev_err(&pdev->dev, "Secure boot is not supported\n"); - return ret; - } - - ret = pil_desc_init(desc); - if (ret) - return ret; - - drv->subsys_desc.name = desc->name; - drv->subsys_desc.dev = &pdev->dev; - drv->subsys_desc.owner = THIS_MODULE; - drv->subsys_desc.shutdown = bcss_shutdown; - drv->subsys_desc.powerup = bcss_powerup; - drv->subsys_desc.ramdump = bcss_ramdump; - - drv->ramdump_dev = create_ramdump_device("bcss", &pdev->dev); - if (!drv->ramdump_dev) { - ret = -ENOMEM; - goto err_ramdump; - } - - drv->subsys = subsys_register(&drv->subsys_desc); - if (IS_ERR(drv->subsys)) { - ret = PTR_ERR(drv->subsys); - goto err_subsys; - } - return ret; - -err_subsys: - destroy_ramdump_device(drv->ramdump_dev); -err_ramdump: - pil_desc_release(desc); - - return ret; -} - -static int pil_bcss_driver_remove(struct platform_device *pdev) -{ - struct bcss_data *drv = platform_get_drvdata(pdev); - - subsys_unregister(drv->subsys); - destroy_ramdump_device(drv->ramdump_dev); - pil_desc_release(&drv->desc); - - return 0; -} - -static const struct of_device_id msm_pil_bcss_match[] = { - {.compatible = "qcom,pil-bcss"}, - {} -}; - -static struct platform_driver pil_bcss_driver = { - .probe = pil_bcss_driver_probe, - .remove = pil_bcss_driver_remove, - .driver = { - .name = "pil-bcss", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(msm_pil_bcss_match), - }, -}; - -module_platform_driver(pil_bcss_driver); - -MODULE_DESCRIPTION("Support for booting broadcast subsystem"); -MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c index 36a35f503b7..ff0c8b22d32 100644 --- a/arch/arm/mach-msm/pil-pronto.c +++ b/arch/arm/mach-msm/pil-pronto.c @@ -26,10 +26,10 @@ #include <linux/workqueue.h> #include <linux/wcnss_wlan.h> #include <linux/of_gpio.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/ramdump.h> -#include <mach/subsystem_restart.h> #include <mach/msm_smsm.h> -#include <mach/ramdump.h> #include <mach/msm_bus_board.h> #include <soc/qcom/smem.h> diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c index 98bae909588..1f91347568b 100644 --- a/arch/arm/mach-msm/pil-q6v5-lpass.c +++ b/arch/arm/mach-msm/pil-q6v5-lpass.c @@ -24,13 +24,13 @@ #include <linux/sysfs.h> #include <linux/of_gpio.h> #include <linux/clk/msm-clk.h> +#include <soc/qcom/sysmon.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/subsystem_notif.h> +#include <soc/qcom/ramdump.h> +#include <soc/qcom/scm.h> -#include <mach/subsystem_restart.h> -#include <mach/subsystem_notif.h> -#include <mach/scm.h> -#include <mach/ramdump.h> #include <mach/msm_bus_board.h> -#include <mach/sysmon.h> #include <soc/qcom/smem.h> diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c index 8b25ef92a77..b2075f5370b 100644 --- a/arch/arm/mach-msm/pil-q6v5-mss.c +++ b/arch/arm/mach-msm/pil-q6v5-mss.c @@ -27,11 +27,11 @@ #include <linux/dma-mapping.h> #include <linux/of_gpio.h> #include <linux/clk/msm-clk.h> +#include <soc/qcom/sysmon.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/ramdump.h> -#include <mach/subsystem_restart.h> #include <mach/msm_smsm.h> -#include <mach/ramdump.h> -#include <mach/sysmon.h> #include <soc/qcom/smem.h> diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c deleted file mode 100644 index cc9cf17fdb6..00000000000 --- a/arch/arm/mach-msm/pil-venus.c +++ /dev/null @@ -1,617 +0,0 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/kernel.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/platform_device.h> -#include <linux/iommu.h> -#include <linux/iopoll.h> -#include <linux/of.h> -#include <linux/regulator/consumer.h> - -#include <asm/page.h> -#include <asm/sizes.h> - -#include <mach/iommu.h> -#include <linux/msm_iommu_domains.h> -#include <mach/subsystem_restart.h> -#include <mach/msm_bus_board.h> -#include <mach/msm_bus.h> -#include <mach/ramdump.h> - -#include "peripheral-loader.h" -#include "scm-pas.h" - -/* VENUS WRAPPER registers */ -#define VENUS_WRAPPER_HW_VERSION 0x0 -#define VENUS_WRAPPER_CLOCK_CONFIG 0x4 - -#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v1 0x1018 -#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v1 0x101C -#define VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v1 0x1020 -#define VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v1 0x1024 - -#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v2 0x1020 -#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v2 0x1024 -#define VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v2 0x1028 -#define VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v2 0x102C - -#define VENUS_WRAPPER_CPU_CLOCK_CONFIG 0x2000 -#define VENUS_WRAPPER_SW_RESET 0x3000 - -/* VENUS VBIF registers */ -#define VENUS_VBIF_CLKON 0x4 -#define VENUS_VBIF_CLKON_FORCE_ON BIT(0) - -#define VENUS_VBIF_AXI_HALT_CTRL0 0x208 -#define VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ BIT(0) - -#define VENUS_VBIF_AXI_HALT_CTRL1 0x20C -#define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK BIT(0) -#define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US 500000 - - -/* PIL proxy vote timeout */ -#define VENUS_PROXY_TIMEOUT 2000 - -/* Poll interval in uS */ -#define POLL_INTERVAL_US 50 - -static const char * const clk_names[] = { - "core_clk", - "iface_clk", - "bus_clk", - "mem_clk", -}; - -struct venus_data { - void __iomem *venus_wrapper_base; - void __iomem *venus_vbif_base; - struct pil_desc desc; - struct subsys_device *subsys; - struct subsys_desc subsys_desc; - struct regulator *gdsc; - struct clk *clks[ARRAY_SIZE(clk_names)]; - struct device *iommu_fw_ctx; - struct iommu_domain *iommu_fw_domain; - int venus_domain_num; - bool is_booted; - bool hw_ver_checked; - void *ramdump_dev; - u32 fw_sz; - u32 fw_min_paddr; - u32 fw_max_paddr; - u32 bus_perf_client; - u32 hw_ver_major; - u32 hw_ver_minor; -}; - -#define subsys_to_drv(d) container_of(d, struct venus_data, subsys_desc) - -static int venus_register_domain(u32 fw_max_sz) -{ - struct msm_iova_partition venus_fw_partition = { - .start = 0, - .size = fw_max_sz, - }; - struct msm_iova_layout venus_fw_layout = { - .partitions = &venus_fw_partition, - .npartitions = 1, - .client_name = "pil_venus", - .domain_flags = 0, - }; - - return msm_register_domain(&venus_fw_layout); -} - -/* Get venus clocks and set rates for rate-settable clocks */ -static int venus_clock_setup(struct device *dev) -{ - struct venus_data *drv = dev_get_drvdata(dev); - int i; - - for (i = 0; i < ARRAY_SIZE(drv->clks); i++) { - drv->clks[i] = devm_clk_get(dev, clk_names[i]); - if (IS_ERR(drv->clks[i])) { - dev_err(dev, "failed to get %s\n", - clk_names[i]); - return PTR_ERR(drv->clks[i]); - } - /* Make sure rate-settable clocks' rates are set */ - if (clk_get_rate(drv->clks[i]) == 0) - clk_set_rate(drv->clks[i], - clk_round_rate(drv->clks[i], 0)); - } - - return 0; -} - -static int venus_clock_prepare_enable(struct device *dev) -{ - struct venus_data *drv = dev_get_drvdata(dev); - int rc, i; - - for (i = 0; i < ARRAY_SIZE(drv->clks); i++) { - rc = clk_prepare_enable(drv->clks[i]); - if (rc) { - dev_err(dev, "failed to enable %s\n", - clk_names[i]); - for (i--; i >= 0; i--) - clk_disable_unprepare(drv->clks[i]); - return rc; - } - } - - return 0; -} - -static void venus_clock_disable_unprepare(struct device *dev) -{ - struct venus_data *drv = dev_get_drvdata(dev); - int i; - - for (i = 0; i < ARRAY_SIZE(drv->clks); i++) - clk_disable_unprepare(drv->clks[i]); -} - -static struct msm_bus_vectors pil_venus_unvote_bw_vector[] = { - { - .src = MSM_BUS_MASTER_VIDEO_P0, - .dst = MSM_BUS_SLAVE_EBI_CH0, - .ab = 0, - .ib = 0, - }, -}; - -static struct msm_bus_vectors pil_venus_vote_bw_vector[] = { - { - .src = MSM_BUS_MASTER_VIDEO_P0, - .dst = MSM_BUS_SLAVE_EBI_CH0, - .ab = 0, - .ib = 16 * 19 * 1000000UL, /* At least 19.2MHz on bus. */ - }, -}; - -static struct msm_bus_paths pil_venus_bw_tbl[] = { - { - .num_paths = ARRAY_SIZE(pil_venus_unvote_bw_vector), - .vectors = pil_venus_unvote_bw_vector, - }, - { - .num_paths = ARRAY_SIZE(pil_venus_vote_bw_vector), - .vectors = pil_venus_vote_bw_vector, - }, -}; - -static struct msm_bus_scale_pdata pil_venus_client_pdata = { - .usecase = pil_venus_bw_tbl, - .num_usecases = ARRAY_SIZE(pil_venus_bw_tbl), - .name = "pil-venus", -}; - -static int pil_venus_make_proxy_vote(struct pil_desc *pil) -{ - struct venus_data *drv = dev_get_drvdata(pil->dev); - int rc; - - /* - * Clocks need to be proxy voted to be able to pass control - * of clocks from PIL driver to the Venus driver. But GDSC - * needs to be turned on before clocks can be turned on. So - * enable the GDSC here. - */ - rc = regulator_enable(drv->gdsc); - if (rc) { - dev_err(pil->dev, "GDSC enable failed\n"); - goto err_regulator; - } - - rc = venus_clock_prepare_enable(pil->dev); - if (rc) { - dev_err(pil->dev, "clock prepare and enable failed\n"); - goto err_clock; - } - - rc = msm_bus_scale_client_update_request(drv->bus_perf_client, 1); - if (rc) { - dev_err(pil->dev, "bandwith request failed\n"); - goto err_bw; - } - - return 0; - -err_bw: - venus_clock_disable_unprepare(pil->dev); -err_clock: - regulator_disable(drv->gdsc); -err_regulator: - return rc; -} - -static void pil_venus_remove_proxy_vote(struct pil_desc *pil) -{ - struct venus_data *drv = dev_get_drvdata(pil->dev); - - msm_bus_scale_client_update_request(drv->bus_perf_client, 0); - - venus_clock_disable_unprepare(pil->dev); - - /* Disable GDSC */ - regulator_disable(drv->gdsc); -} - -static int pil_venus_mem_setup(struct pil_desc *pil, phys_addr_t addr, - size_t size) -{ - int domain; - struct venus_data *drv = dev_get_drvdata(pil->dev); - - /* TODO: unregister? */ - if (!drv->venus_domain_num) { - size = round_up(size, SZ_4K); - domain = venus_register_domain(size); - if (domain < 0) { - dev_err(pil->dev, "Venus fw iommu domain register failed\n"); - return -ENODEV; - } - drv->iommu_fw_domain = msm_get_iommu_domain(domain); - if (!drv->iommu_fw_domain) { - dev_err(pil->dev, "No iommu fw domain found\n"); - return -ENODEV; - } - drv->venus_domain_num = domain; - drv->fw_sz = size; - } - - return 0; -} - -static int pil_venus_reset(struct pil_desc *pil) -{ - int rc; - struct venus_data *drv = dev_get_drvdata(pil->dev); - void __iomem *wrapper_base = drv->venus_wrapper_base; - phys_addr_t pa = pil_get_entry_addr(pil); - dma_addr_t iova; - u32 ver, cpa_start_addr, cpa_end_addr, fw_start_addr, fw_end_addr; - - /* Get Venus version number */ - if (!drv->hw_ver_checked) { - ver = readl_relaxed(wrapper_base + VENUS_WRAPPER_HW_VERSION); - drv->hw_ver_minor = (ver & 0x0FFF0000) >> 16; - drv->hw_ver_major = (ver & 0xF0000000) >> 28; - drv->hw_ver_checked = 1; - } - - /* Get the cpa and fw start/end addr based on Venus version */ - if (drv->hw_ver_major == 0x1 && drv->hw_ver_minor <= 1) { - cpa_start_addr = VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v1; - cpa_end_addr = VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v1; - fw_start_addr = VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v1; - fw_end_addr = VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v1; - } else { - cpa_start_addr = VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v2; - cpa_end_addr = VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v2; - fw_start_addr = VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v2; - fw_end_addr = VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v2; - } - - /* Program CPA start and end address */ - writel_relaxed(0, wrapper_base + cpa_start_addr); - writel_relaxed(drv->fw_sz, wrapper_base + cpa_end_addr); - - /* Program FW start and end address */ - writel_relaxed(0, wrapper_base + fw_start_addr); - writel_relaxed(drv->fw_sz, wrapper_base + fw_end_addr); - - /* Enable all Venus internal clocks */ - writel_relaxed(0, wrapper_base + VENUS_WRAPPER_CLOCK_CONFIG); - writel_relaxed(0, wrapper_base + VENUS_WRAPPER_CPU_CLOCK_CONFIG); - - /* Make sure clocks are enabled */ - mb(); - - /* - * Need to wait 10 cycles of internal clocks before bringing ARM9 - * out of reset. - */ - udelay(1); - - rc = iommu_attach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx); - if (rc) { - dev_err(pil->dev, "venus fw iommu attach failed\n"); - return rc; - } - - /* Map virtual addr space 0 - fw_sz to firmware physical addr space */ - rc = msm_iommu_map_contig_buffer(pa, drv->venus_domain_num, 0, - drv->fw_sz, SZ_4K, 0, &iova); - - if (rc || (iova != 0)) { - dev_err(pil->dev, "Failed to setup IOMMU\n"); - goto err_iommu_map; - } - - /* Bring Arm9 out of reset */ - writel_relaxed(0, wrapper_base + VENUS_WRAPPER_SW_RESET); - - drv->is_booted = 1; - - return 0; - -err_iommu_map: - iommu_detach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx); - - return rc; -} - -static int pil_venus_shutdown(struct pil_desc *pil) -{ - struct venus_data *drv = dev_get_drvdata(pil->dev); - void __iomem *vbif_base = drv->venus_vbif_base; - void __iomem *wrapper_base = drv->venus_wrapper_base; - u32 reg; - int rc; - - if (!drv->is_booted) - return 0; - - venus_clock_prepare_enable(pil->dev); - - /* Assert the reset to ARM9 */ - reg = readl_relaxed(wrapper_base + VENUS_WRAPPER_SW_RESET); - reg |= BIT(4); - writel_relaxed(reg, wrapper_base + VENUS_WRAPPER_SW_RESET); - - /* Make sure reset is asserted before the mapping is removed */ - mb(); - - msm_iommu_unmap_contig_buffer(0, drv->venus_domain_num, - 0, drv->fw_sz); - - iommu_detach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx); - - /* - * Force the VBIF clk to be on to avoid AXI bridge halt ack failure - * for certain Venus version. - */ - if (drv->hw_ver_major == 0x1 && - (drv->hw_ver_minor == 0x2 || drv->hw_ver_minor == 0x3)) { - reg = readl_relaxed(vbif_base + VENUS_VBIF_CLKON); - reg |= VENUS_VBIF_CLKON_FORCE_ON; - writel_relaxed(reg, vbif_base + VENUS_VBIF_CLKON); - } - - /* Halt AXI and AXI OCMEM VBIF Access */ - reg = readl_relaxed(vbif_base + VENUS_VBIF_AXI_HALT_CTRL0); - reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ; - writel_relaxed(reg, vbif_base + VENUS_VBIF_AXI_HALT_CTRL0); - - /* Request for AXI bus port halt */ - rc = readl_poll_timeout(vbif_base + VENUS_VBIF_AXI_HALT_CTRL1, - reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK, - POLL_INTERVAL_US, - VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US); - if (rc) - dev_err(pil->dev, "Port halt timeout\n"); - - venus_clock_disable_unprepare(pil->dev); - - drv->is_booted = 0; - - return 0; -} - -static struct pil_reset_ops pil_venus_ops = { - .mem_setup = pil_venus_mem_setup, - .auth_and_reset = pil_venus_reset, - .shutdown = pil_venus_shutdown, - .proxy_vote = pil_venus_make_proxy_vote, - .proxy_unvote = pil_venus_remove_proxy_vote, -}; - -static int pil_venus_init_image_trusted(struct pil_desc *pil, - const u8 *metadata, size_t size) -{ - return pas_init_image(PAS_VIDC, metadata, size); -} - -static int pil_venus_mem_setup_trusted(struct pil_desc *pil, phys_addr_t addr, - size_t size) -{ - return pas_mem_setup(PAS_VIDC, addr, size); -} - -static int pil_venus_reset_trusted(struct pil_desc *pil) -{ - int rc; - - rc = pas_auth_and_reset(PAS_VIDC); - - return rc; -} - -static int pil_venus_shutdown_trusted(struct pil_desc *pil) -{ - int rc; - - venus_clock_prepare_enable(pil->dev); - - rc = pas_shutdown(PAS_VIDC); - - venus_clock_disable_unprepare(pil->dev); - - return rc; -} - -static struct pil_reset_ops pil_venus_ops_trusted = { - .init_image = pil_venus_init_image_trusted, - .mem_setup = pil_venus_mem_setup_trusted, - .auth_and_reset = pil_venus_reset_trusted, - .shutdown = pil_venus_shutdown_trusted, - .proxy_vote = pil_venus_make_proxy_vote, - .proxy_unvote = pil_venus_remove_proxy_vote, -}; - -static int venus_shutdown(const struct subsys_desc *desc, bool force_stop) -{ - struct venus_data *drv = subsys_to_drv(desc); - pil_shutdown(&drv->desc); - return 0; -} - -static int venus_powerup(const struct subsys_desc *desc) -{ - struct venus_data *drv = subsys_to_drv(desc); - return pil_boot(&drv->desc); -} - -static int venus_ramdump(int enable, const struct subsys_desc *desc) -{ - struct venus_data *drv = subsys_to_drv(desc); - - if (!enable) - return 0; - - return pil_do_ramdump(&drv->desc, drv->ramdump_dev); -} - -static int pil_venus_probe(struct platform_device *pdev) -{ - struct venus_data *drv; - struct resource *res; - struct pil_desc *desc; - int rc; - - drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); - if (!drv) - return -ENOMEM; - platform_set_drvdata(pdev, drv); - - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "wrapper_base"); - drv->venus_wrapper_base = devm_request_and_ioremap(&pdev->dev, res); - if (!drv->venus_wrapper_base) - return -ENOMEM; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vbif_base"); - drv->venus_vbif_base = devm_request_and_ioremap(&pdev->dev, res); - if (!drv->venus_vbif_base) - return -ENOMEM; - - drv->gdsc = devm_regulator_get(&pdev->dev, "vdd"); - if (IS_ERR(drv->gdsc)) { - dev_err(&pdev->dev, "Failed to get Venus GDSC\n"); - return -ENODEV; - } - - rc = venus_clock_setup(&pdev->dev); - if (rc) - return rc; - - drv->bus_perf_client = - msm_bus_scale_register_client(&pil_venus_client_pdata); - if (!drv->bus_perf_client) { - dev_err(&pdev->dev, "Failed to register bus client\n"); - return -EINVAL; - } - - drv->iommu_fw_ctx = msm_iommu_get_ctx("venus_fw"); - if (!drv->iommu_fw_ctx) { - dev_err(&pdev->dev, "No iommu fw context found\n"); - return -ENODEV; - } - - desc = &drv->desc; - rc = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name", - &desc->name); - if (rc) - return rc; - - - desc->dev = &pdev->dev; - desc->owner = THIS_MODULE; - desc->proxy_timeout = VENUS_PROXY_TIMEOUT; - - if (pas_supported(PAS_VIDC) > 0) { - desc->ops = &pil_venus_ops_trusted; - dev_info(&pdev->dev, "using secure boot\n"); - } else { - desc->ops = &pil_venus_ops; - dev_info(&pdev->dev, "using non-secure boot\n"); - } - - drv->ramdump_dev = create_ramdump_device("venus", &pdev->dev); - if (!drv->ramdump_dev) - return -ENOMEM; - - scm_pas_init(MSM_BUS_MASTER_CRYPTO_CORE0); - - rc = pil_desc_init(desc); - if (rc) - goto err_ramdump; - - drv->subsys_desc.name = desc->name; - drv->subsys_desc.owner = THIS_MODULE; - drv->subsys_desc.dev = &pdev->dev; - drv->subsys_desc.shutdown = venus_shutdown; - drv->subsys_desc.powerup = venus_powerup; - drv->subsys_desc.ramdump = venus_ramdump; - - drv->subsys = subsys_register(&drv->subsys_desc); - if (IS_ERR(drv->subsys)) { - rc = PTR_ERR(drv->subsys); - goto err_subsys; - } - return rc; -err_subsys: - pil_desc_release(desc); -err_ramdump: - destroy_ramdump_device(drv->ramdump_dev); - return rc; -} - -static int pil_venus_remove(struct platform_device *pdev) -{ - struct venus_data *drv = platform_get_drvdata(pdev); - subsys_unregister(drv->subsys); - pil_desc_release(&drv->desc); - - return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id msm_pil_venus_match[] = { - {.compatible = "qcom,pil-venus"}, - {} -}; -#endif - -static struct platform_driver pil_venus_driver = { - .probe = pil_venus_probe, - .remove = pil_venus_remove, - .driver = { - .name = "pil_venus", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(msm_pil_venus_match), - }, -}; - -module_platform_driver(pil_venus_driver); - -MODULE_DESCRIPTION("Support for booting VENUS processors"); -MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/pil-vpu.c b/arch/arm/mach-msm/pil-vpu.c deleted file mode 100644 index b9c335637bd..00000000000 --- a/arch/arm/mach-msm/pil-vpu.c +++ /dev/null @@ -1,349 +0,0 @@ -/* Copyright (c)2013, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/kernel.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/platform_device.h> -#include <linux/of.h> -#include <linux/clk.h> -#include <linux/regulator/consumer.h> -#include <linux/clk/msm-clk-provider.h> - -#include <mach/subsystem_restart.h> -#include <mach/msm_bus_board.h> -#include <mach/msm_bus.h> -#include <mach/ramdump.h> - -#include "peripheral-loader.h" -#include "scm-pas.h" - -/* PIL proxy vote timeout */ -#define VPU_PROXY_TIMEOUT_MS 10000 - -struct vpu_data { - struct pil_desc desc; - struct subsys_device *subsys; - struct subsys_desc subsys_desc; - struct regulator *gdsc; - struct clk **clks; - void *ramdump_dev; - int clock_count; -}; - -#define subsys_to_drv(d) container_of(d, struct vpu_data, subsys_desc) - -/* Get vpu clocks and set rates for rate-settable clocks */ -static int vpu_clock_setup(struct device *dev) -{ - struct vpu_data *drv = dev_get_drvdata(dev); - int i; - - if (!of_find_property(dev->of_node, "clock-names", NULL)) { - dev_err(dev, "missing clock-names property\n"); - return -EINVAL; - } - - drv->clock_count = of_property_count_strings(dev->of_node, - "clock-names"); - if (IS_ERR_VALUE(drv->clock_count)) { - dev_err(dev, "Failed to get clock names\n"); - return -EINVAL; - } - - drv->clks = devm_kzalloc(dev, - sizeof(struct clk *) * drv->clock_count, GFP_KERNEL); - if (!drv->clks) - return -ENOMEM; - for (i = 0; i < drv->clock_count; i++) { - const char *clock_name; - of_property_read_string_index(dev->of_node, - "clock-names", i, &clock_name); - drv->clks[i] = devm_clk_get(dev, clock_name); - if (IS_ERR(drv->clks[i])) { - int rc = PTR_ERR(drv->clks[i]); - if (rc != -EPROBE_DEFER) - dev_err(dev, "Failed to get %s\n", clock_name); - return rc; - } - /* Make sure rate-settable clocks' rates are set */ - if (clk_get_rate(drv->clks[i]) == 0) - clk_set_rate(drv->clks[i], - clk_round_rate(drv->clks[i], 0)); - } - - return 0; -} - -static int vpu_clock_prepare_enable(struct device *dev) -{ - struct vpu_data *drv = dev_get_drvdata(dev); - int rc, i; - - for (i = 0; i < drv->clock_count; i++) { - rc = clk_prepare_enable(drv->clks[i]); - if (rc) { - dev_err(dev, "failed to enable %s\n", - drv->clks[i]->dbg_name); - for (i--; i >= 0; i--) - clk_disable_unprepare(drv->clks[i]); - return rc; - } - } - - return 0; -} - -static void vpu_clock_disable_unprepare(struct device *dev) -{ - struct vpu_data *drv = dev_get_drvdata(dev); - int i; - - for (i = 0; i < drv->clock_count; i++) - clk_disable_unprepare(drv->clks[i]); -} - -static int pil_vpu_make_proxy_vote(struct pil_desc *pil) -{ - struct vpu_data *drv = dev_get_drvdata(pil->dev); - int rc; - - /* - * Clocks need to be proxy voted to be able to pass control - * of clocks from PIL driver to the VPU driver. But GDSC - * needs to be turned on before clocks can be turned on. So - * enable the GDSC here. - */ - rc = regulator_enable(drv->gdsc); - if (rc) { - dev_err(pil->dev, "GDSC enable failed\n"); - goto err_regulator; - } - - rc = vpu_clock_prepare_enable(pil->dev); - if (rc) { - dev_err(pil->dev, "clock prepare and enable failed\n"); - goto err_clock; - } - - return 0; - -err_clock: - regulator_disable(drv->gdsc); -err_regulator: - return rc; -} - -static void pil_vpu_remove_proxy_vote(struct pil_desc *pil) -{ - struct vpu_data *drv = dev_get_drvdata(pil->dev); - - vpu_clock_disable_unprepare(pil->dev); - - /* Disable GDSC */ - regulator_disable(drv->gdsc); -} - -static int pil_vpu_init_image_trusted(struct pil_desc *pil, - const u8 *metadata, size_t size) -{ - return pas_init_image(PAS_VPU, metadata, size); -} - -static int pil_vpu_mem_setup_trusted(struct pil_desc *pil, phys_addr_t addr, - size_t size) -{ - return pas_mem_setup(PAS_VPU, addr, size); -} - -static int pil_vpu_reset_trusted(struct pil_desc *pil) -{ - int rc; - struct vpu_data *drv = dev_get_drvdata(pil->dev); - - /* - * GDSC needs to remain on till VPU is shutdown. So, enable - * the GDSC here again to make sure it remains on beyond the - * expiry of the proxy vote timer. - */ - rc = regulator_enable(drv->gdsc); - if (rc) { - dev_err(pil->dev, "GDSC enable failed\n"); - return rc; - } - - rc = pas_auth_and_reset(PAS_VPU); - if (rc) - regulator_disable(drv->gdsc); - - - return rc; -} - -static int pil_vpu_shutdown_trusted(struct pil_desc *pil) -{ - int rc; - struct vpu_data *drv = dev_get_drvdata(pil->dev); - - vpu_clock_prepare_enable(pil->dev); - - rc = pas_shutdown(PAS_VPU); - - vpu_clock_disable_unprepare(pil->dev); - - regulator_disable(drv->gdsc); - - return rc; -} - -static struct pil_reset_ops pil_vpu_ops_trusted = { - .init_image = pil_vpu_init_image_trusted, - .mem_setup = pil_vpu_mem_setup_trusted, - .auth_and_reset = pil_vpu_reset_trusted, - .shutdown = pil_vpu_shutdown_trusted, - .proxy_vote = pil_vpu_make_proxy_vote, - .proxy_unvote = pil_vpu_remove_proxy_vote, -}; - -static int vpu_shutdown(const struct subsys_desc *desc, bool force_stop) -{ - struct vpu_data *drv = subsys_to_drv(desc); - - pil_shutdown(&drv->desc); - - return 0; -} - -static int vpu_powerup(const struct subsys_desc *desc) -{ - struct vpu_data *drv = subsys_to_drv(desc); - - return pil_boot(&drv->desc); -} - -static int vpu_ramdump(int enable, const struct subsys_desc *desc) -{ - struct vpu_data *drv = subsys_to_drv(desc); - - if (!enable) - return 0; - - return pil_do_ramdump(&drv->desc, drv->ramdump_dev); -} - -static int pil_vpu_probe(struct platform_device *pdev) -{ - struct vpu_data *drv; - struct pil_desc *desc; - int rc; - - drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); - if (!drv) - return -ENOMEM; - platform_set_drvdata(pdev, drv); - - drv->gdsc = devm_regulator_get(&pdev->dev, "vdd"); - if (IS_ERR(drv->gdsc)) { - dev_err(&pdev->dev, "Failed to get VPU GDSC\n"); - return -ENODEV; - } - - rc = vpu_clock_setup(&pdev->dev); - if (rc) { - dev_err(&pdev->dev, "Failed to setup VPU clocks\n"); - return rc; - } - - desc = &drv->desc; - rc = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name", - &desc->name); - if (rc) { - dev_err(&pdev->dev, "Failed to read the firmware name\n"); - return rc; - } - - desc->dev = &pdev->dev; - desc->owner = THIS_MODULE; - desc->proxy_timeout = VPU_PROXY_TIMEOUT_MS; - - rc = pas_supported(PAS_VPU); - if (rc > 0) { - desc->ops = &pil_vpu_ops_trusted; - dev_info(&pdev->dev, "using secure boot\n"); - } else { - dev_err(&pdev->dev, "Secure boot is not supported\n"); - return rc; - } - - drv->ramdump_dev = create_ramdump_device("vpu", &pdev->dev); - if (!drv->ramdump_dev) - return -ENOMEM; - - rc = pil_desc_init(desc); - if (rc) - goto err_ramdump; - - scm_pas_init(MSM_BUS_MASTER_CRYPTO_CORE0); - - drv->subsys_desc.name = desc->name; - drv->subsys_desc.owner = THIS_MODULE; - drv->subsys_desc.dev = &pdev->dev; - drv->subsys_desc.shutdown = vpu_shutdown; - drv->subsys_desc.powerup = vpu_powerup; - drv->subsys_desc.ramdump = vpu_ramdump; - - drv->subsys = subsys_register(&drv->subsys_desc); - if (IS_ERR(drv->subsys)) { - rc = PTR_ERR(drv->subsys); - goto err_subsys; - } - return rc; - -err_subsys: - pil_desc_release(desc); -err_ramdump: - destroy_ramdump_device(drv->ramdump_dev); - - return rc; -} - -static int pil_vpu_remove(struct platform_device *pdev) -{ - struct vpu_data *drv = platform_get_drvdata(pdev); - subsys_unregister(drv->subsys); - pil_desc_release(&drv->desc); - - return 0; -} - -static const struct of_device_id msm_pil_vpu_match[] = { - {.compatible = "qcom,pil-vpu"}, - {} -}; - -static struct platform_driver pil_vpu_driver = { - .probe = pil_vpu_probe, - .remove = pil_vpu_remove, - .driver = { - .name = "pil_vpu", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(msm_pil_vpu_match), - }, -}; - -module_platform_driver(pil_vpu_driver); - -MODULE_DESCRIPTION("Support for booting Maple processors"); -MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/ramdump.c b/arch/arm/mach-msm/ramdump.c index 5417271e190..bca0997c7d8 100644 --- a/arch/arm/mach-msm/ramdump.c +++ b/arch/arm/mach-msm/ramdump.c @@ -24,8 +24,8 @@ #include <linux/uaccess.h> #include <linux/elf.h> #include <linux/wait.h> +#include <soc/qcom/ramdump.h> -#include <mach/ramdump.h> #define RAMDUMP_WAIT_MSECS 120000 diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c index 40a515cfe81..0f1ed24e0d5 100644 --- a/arch/arm/mach-msm/restart.c +++ b/arch/arm/mach-msm/restart.c @@ -26,6 +26,7 @@ #include <linux/mfd/pm8xxx/misc.h> #include <linux/qpnp/power-on.h> #include <linux/of_address.h> +#include <soc/qcom/scm.h> #include <asm/cacheflush.h> @@ -33,7 +34,6 @@ #include <mach/restart.h> #include <mach/socinfo.h> #include <mach/irqs.h> -#include <mach/scm.h> #include "msm_watchdog.h" #include "timer.h" #include "wdog_debug.h" diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c index d178254f9f8..38734e63b7b 100644 --- a/arch/arm/mach-msm/rpm-smd.c +++ b/arch/arm/mach-msm/rpm-smd.c @@ -1363,6 +1363,8 @@ static int msm_rpm_dev_probe(struct platform_device *pdev) key = "rpm-standalone"; standalone = of_property_read_bool(pdev->dev.of_node, key); + if (standalone) + goto skip_smd_init; msm_rpm_smd_remote_driver.driver.name = msm_rpm_data.ch_name; init_completion(&msm_rpm_data.remote_open); @@ -1383,22 +1385,19 @@ static int msm_rpm_dev_probe(struct platform_device *pdev) pr_info("Cannot open RPM channel %s %d\n", msm_rpm_data.ch_name, msm_rpm_data.ch_type); - BUG_ON(!standalone); - complete(&msm_rpm_data.smd_open); } wait_for_completion(&msm_rpm_data.smd_open); smd_disable_read_intr(msm_rpm_data.ch_info); - if (!standalone) { - msm_rpm_smd_wq = alloc_workqueue("rpm-smd", - WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI, 1); - if (!msm_rpm_smd_wq) - return -EINVAL; - queue_work(msm_rpm_smd_wq, &msm_rpm_data.work); - } + msm_rpm_smd_wq = alloc_workqueue("rpm-smd", + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI, 1); + if (!msm_rpm_smd_wq) + return -EINVAL; + queue_work(msm_rpm_smd_wq, &msm_rpm_data.work); +skip_smd_init: of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); if (standalone) diff --git a/arch/arm/mach-msm/scm-boot.c b/arch/arm/mach-msm/scm-boot.c index ae5bd041040..795ad5a0d22 100644 --- a/arch/arm/mach-msm/scm-boot.c +++ b/arch/arm/mach-msm/scm-boot.c @@ -12,8 +12,8 @@ #include <linux/module.h> #include <linux/slab.h> +#include <soc/qcom/scm.h> -#include <mach/scm.h> #include "scm-boot.h" /* diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c index c3e075210b9..0ddde3d3dac 100644 --- a/arch/arm/mach-msm/scm-pas.c +++ b/arch/arm/mach-msm/scm-pas.c @@ -17,10 +17,10 @@ #include <linux/string.h> #include <linux/clk.h> #include <linux/dma-mapping.h> +#include <soc/qcom/scm.h> #include <asm/cacheflush.h> -#include <mach/scm.h> #include <mach/socinfo.h> #include <mach/msm_bus.h> #include <mach/msm_bus_board.h> diff --git a/arch/arm/mach-msm/scm-xpu.c b/arch/arm/mach-msm/scm-xpu.c index 0c38842045f..e05c7b371cd 100644 --- a/arch/arm/mach-msm/scm-xpu.c +++ b/arch/arm/mach-msm/scm-xpu.c @@ -12,8 +12,8 @@ #include <linux/init.h> #include <linux/kernel.h> +#include <soc/qcom/scm.h> -#include <mach/scm.h> #define ERR_FATAL_ENABLE 0x0 #define ERR_FATAL_DISABLE 0x1 diff --git a/arch/arm/mach-msm/sensors_adsp.c b/arch/arm/mach-msm/sensors_adsp.c index 77aef54f24a..97870ed0be7 100644 --- a/arch/arm/mach-msm/sensors_adsp.c +++ b/arch/arm/mach-msm/sensors_adsp.c @@ -29,8 +29,8 @@ #include <linux/of_device.h> #include <linux/msm_dsps.h> #include <linux/uaccess.h> +#include <soc/qcom/subsystem_restart.h> #include <asm/arch_timer.h> -#include <mach/subsystem_restart.h> #include <mach/ocmem.h> #include <mach/msm_smd.h> #include <mach/sensors_adsp.h> diff --git a/arch/arm/mach-msm/smcmod.c b/arch/arm/mach-msm/smcmod.c index 683fb322f3f..f0c81a27d7c 100644 --- a/arch/arm/mach-msm/smcmod.c +++ b/arch/arm/mach-msm/smcmod.c @@ -27,8 +27,8 @@ #include <linux/slab.h> #include <linux/printk.h> #include <linux/msm_ion.h> +#include <soc/qcom/scm.h> #include <asm/smcmod.h> -#include <mach/scm.h> #include <mach/socinfo.h> static DEFINE_MUTEX(ioctl_lock); diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c index 934381bbe5f..97aec5678dd 100644 --- a/arch/arm/mach-msm/smd.c +++ b/arch/arm/mach-msm/smd.c @@ -38,11 +38,11 @@ #include <linux/of.h> #include <linux/of_irq.h> #include <linux/ipc_logging.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/subsystem_notif.h> +#include <soc/qcom/ramdump.h> #include <mach/msm_smd.h> -#include <mach/subsystem_notif.h> -#include <mach/subsystem_restart.h> -#include <mach/ramdump.h> #include <soc/qcom/smem.h> diff --git a/arch/arm/mach-msm/smp2p_test.c b/arch/arm/mach-msm/smp2p_test.c index af83bdcfae2..270abd5d159 100644 --- a/arch/arm/mach-msm/smp2p_test.c +++ b/arch/arm/mach-msm/smp2p_test.c @@ -16,7 +16,7 @@ #include <linux/jiffies.h> #include <linux/delay.h> #include <linux/completion.h> -#include <mach/subsystem_restart.h> +#include <soc/qcom/subsystem_restart.h> #include "smp2p_private.h" #include "smp2p_test_common.h" diff --git a/arch/arm/mach-msm/subsys-pil-tz.c b/arch/arm/mach-msm/subsys-pil-tz.c index d8dbd25e55d..332791f7fa3 100644 --- a/arch/arm/mach-msm/subsys-pil-tz.c +++ b/arch/arm/mach-msm/subsys-pil-tz.c @@ -24,8 +24,8 @@ #include <mach/msm_bus_board.h> #include <mach/msm_bus.h> -#include <mach/subsystem_restart.h> -#include <mach/ramdump.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/ramdump.h> #include <soc/qcom/smem.h> diff --git a/arch/arm/mach-msm/subsystem_notif.c b/arch/arm/mach-msm/subsystem_notif.c index f0db0e977ad..431bbd8cee6 100644 --- a/arch/arm/mach-msm/subsystem_notif.c +++ b/arch/arm/mach-msm/subsystem_notif.c @@ -26,8 +26,8 @@ #include <linux/stringify.h> #include <linux/delay.h> #include <linux/slab.h> +#include <soc/qcom/subsystem_notif.h> -#include <mach/subsystem_notif.h> struct subsys_notif_info { char name[50]; diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c index 9e289cd3bea..29f4baeca5f 100644 --- a/arch/arm/mach-msm/subsystem_restart.c +++ b/arch/arm/mach-msm/subsystem_restart.c @@ -34,12 +34,12 @@ #include <linux/of_gpio.h> #include <linux/cdev.h> #include <linux/platform_device.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/subsystem_notif.h> #include <asm/current.h> #include <mach/socinfo.h> -#include <mach/subsystem_notif.h> -#include <mach/subsystem_restart.h> static int enable_debug; module_param(enable_debug, int, S_IRUGO | S_IWUSR); diff --git a/arch/arm/mach-msm/sysmon.c b/arch/arm/mach-msm/sysmon.c index ea93bbb442f..3dd4989fa8f 100644 --- a/arch/arm/mach-msm/sysmon.c +++ b/arch/arm/mach-msm/sysmon.c @@ -20,11 +20,11 @@ #include <linux/string.h> #include <linux/completion.h> #include <linux/platform_device.h> +#include <soc/qcom/hsic_sysmon.h> +#include <soc/qcom/sysmon.h> +#include <soc/qcom/subsystem_notif.h> #include <mach/msm_smd.h> -#include <mach/subsystem_notif.h> -#include <mach/sysmon.h> -#include "hsic_sysmon.h" #define TX_BUF_SIZE 50 #define RX_BUF_SIZE 500 diff --git a/arch/arm/mach-msm/test_qmi_client.c b/arch/arm/mach-msm/test_qmi_client.c index 8600afbba38..8f77005e1e2 100644 --- a/arch/arm/mach-msm/test_qmi_client.c +++ b/arch/arm/mach-msm/test_qmi_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -20,7 +20,7 @@ #include <asm/uaccess.h> -#include <mach/msm_qmi_interface.h> +#include <soc/qcom/msm_qmi_interface.h> #include "kernel_test_service_v01.h" diff --git a/arch/arm/mach-msm/tz_log.c b/arch/arm/mach-msm/tz_log.c index 4759dc390cf..72e8373567d 100644 --- a/arch/arm/mach-msm/tz_log.c +++ b/arch/arm/mach-msm/tz_log.c @@ -22,7 +22,7 @@ #include <linux/string.h> #include <linux/types.h> #include <linux/uaccess.h> -#include <mach/scm.h> +#include <soc/qcom/scm.h> #include <mach/qseecomi.h> #define DEBUG_MAX_RW_BUF 4096 diff --git a/arch/arm/mach-msm/wdog_debug.c b/arch/arm/mach-msm/wdog_debug.c index 95a85f26f23..aee269e7cd9 100644 --- a/arch/arm/mach-msm/wdog_debug.c +++ b/arch/arm/mach-msm/wdog_debug.c @@ -12,7 +12,7 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <mach/scm.h> +#include <soc/qcom/scm.h> #define SCM_WDOG_DEBUG_BOOT_PART 0x9 #define BOOT_PART_EN_VAL 0x5D1 diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 66df085b715..9a428a1a33f 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -580,13 +580,16 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, { unsigned long order = get_order(size); size_t count = size >> PAGE_SHIFT; + unsigned long pfn; struct page *page; void *ptr; - page = dma_alloc_from_contiguous(dev, count, order); - if (!page) + pfn = dma_alloc_from_contiguous(dev, count, order); + if (!pfn) return NULL; + page = pfn_to_page(pfn); + __dma_clear_buffer(page, size); if (PageHighMem(page)) { @@ -601,7 +604,7 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, caller); if (!ptr) { - dma_release_from_contiguous(dev, page, count); + dma_release_from_contiguous(dev, pfn, count); return NULL; } } @@ -620,7 +623,7 @@ static void __free_from_contiguous(struct device *dev, struct page *page, __dma_free_remap(cpu_addr, size, true); else __dma_remap(page, size, pgprot_kernel, false); - dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT); + dma_release_from_contiguous(dev, page_to_pfn(page), size >> PAGE_SHIFT); } static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot) @@ -1127,11 +1130,14 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, { unsigned long order = get_order(size); struct page *page; + unsigned long pfn; - page = dma_alloc_from_contiguous(dev, count, order); - if (!page) + pfn = dma_alloc_from_contiguous(dev, count, order); + if (!pfn) goto error; + pfn = pfn_to_page(pfn); + __dma_clear_buffer(page, size); for (i = 0; i < count; i++) @@ -1186,7 +1192,7 @@ static int __iommu_free_buffer(struct device *dev, struct page **pages, int i; if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) { - dma_release_from_contiguous(dev, pages[0], count); + dma_release_from_contiguous(dev, page_to_pfn(pages[0]), count); } else { for (i = 0; i < count; i++) if (pages[i]) diff --git a/block/test-iosched.c b/block/test-iosched.c index 75db610e6e6..a648c321f60 100644 --- a/block/test-iosched.c +++ b/block/test-iosched.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -315,7 +315,7 @@ struct test_request *test_iosched_create_test_req(int is_err_expcted, return NULL; } - buf_size = sizeof(unsigned int) * BIO_U32_SIZE * num_bios; + buf_size = TEST_BIO_SIZE * num_bios; test_rq->bios_buffer = kzalloc(buf_size, GFP_KERNEL); if (!test_rq->bios_buffer) { pr_err("%s: Failed to allocate the data buf", __func__); diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 4e22ce3ed73..c75d762258a 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -6,7 +6,7 @@ obj-y := core.o bus.o dd.o syscore.o \ attribute_container.o transport_class.o \ topology.o obj-$(CONFIG_DEVTMPFS) += devtmpfs.o -obj-$(CONFIG_CMA) += dma-contiguous.o +obj-$(CONFIG_CMA) += dma-contiguous.o dma-removed.o obj-y += power/ obj-$(CONFIG_HAS_DMA) += dma-mapping.o obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 46e93e5d477..3b51cc4ebc7 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -38,6 +38,7 @@ #include <linux/swap.h> #include <linux/mm_types.h> #include <linux/dma-contiguous.h> +#include <linux/dma-removed.h> #include <trace/events/kmem.h> struct cma { @@ -220,11 +221,12 @@ int __init cma_fdt_scan(unsigned long node, const char *uname, __be32 *prop; char *name; bool in_system; + bool remove; unsigned long size_cells = dt_root_size_cells; unsigned long addr_cells = dt_root_addr_cells; phys_addr_t limit = MEMBLOCK_ALLOC_ANYWHERE; - if (!of_get_flat_dt_prop(node, "linux,contiguous-region", NULL)) + if (!of_get_flat_dt_prop(node, "linux,reserve-contiguous-region", NULL)) return 0; prop = of_get_flat_dt_prop(node, "#size-cells", NULL); @@ -250,10 +252,13 @@ int __init cma_fdt_scan(unsigned long node, const char *uname, if (prop) limit = be32_to_cpu(prop[0]); + remove = + of_get_flat_dt_prop(node, "linux,remove-completely", NULL) ? 1 : 0; + pr_info("Found %s, memory base %pa, size %ld MiB, limit %pa\n", uname, &base, (unsigned long)size / SZ_1M, &limit); dma_contiguous_reserve_area(size, &base, limit, name, - in_system); + in_system, remove); return 0; } @@ -295,7 +300,7 @@ void __init dma_contiguous_reserve(phys_addr_t limit) (unsigned long)sel_size / SZ_1M); if (dma_contiguous_reserve_area(sel_size, &base, limit, NULL, - CMA_RESERVE_AREA) == 0) + CMA_RESERVE_AREA, false) == 0) dma_contiguous_def_base = base; } #ifdef CONFIG_OF @@ -319,7 +324,7 @@ void __init dma_contiguous_reserve(phys_addr_t limit) */ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base, phys_addr_t limit, const char *name, - bool to_system) + bool to_system, bool remove) { phys_addr_t base = *res_base; phys_addr_t alignment; @@ -365,6 +370,15 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base, } } + if (remove) { + if (!to_system) { + memblock_free(base, size); + memblock_remove(base, size); + } else { + WARN(1, "Removing is incompatible with staying in the system\n"); + } + } + /* * Each reserved area must be initialised later, when more kernel * subsystems (like slab allocator) are available. @@ -380,7 +394,8 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base, &base); /* Architecture specific contiguous memory fixup. */ - dma_contiguous_early_fixup(base, size); + if (!remove) + dma_contiguous_early_fixup(base, size); return 0; err: pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M); @@ -430,6 +445,10 @@ static void cma_assign_device_from_dt(struct device *dev) return; dev_set_cma_area(dev, cma); + + if (of_property_read_bool(node, "linux,remove-completely")) + set_dma_ops(dev, &removed_dma_ops); + pr_info("Assigned CMA region at %lx to %s device\n", (unsigned long)value, dev_name(dev)); } @@ -494,17 +513,16 @@ phys_addr_t cma_get_base(struct device *dev) * global one. Requires architecture specific get_dev_cma_area() helper * function. */ -struct page *dma_alloc_from_contiguous(struct device *dev, int count, +unsigned long dma_alloc_from_contiguous(struct device *dev, int count, unsigned int align) { - unsigned long mask, pfn, pageno, start = 0; + unsigned long mask, pfn = 0, pageno, start = 0; struct cma *cma = dev_get_cma_area(dev); - struct page *page = NULL; int ret = 0; int tries = 0; if (!cma || !cma->count) - return NULL; + return 0; if (align > CONFIG_CMA_ALIGNMENT) align = CONFIG_CMA_ALIGNMENT; @@ -513,7 +531,7 @@ struct page *dma_alloc_from_contiguous(struct device *dev, int count, count, align); if (!count) - return NULL; + return 0; mask = (1 << align) - 1; @@ -530,7 +548,6 @@ struct page *dma_alloc_from_contiguous(struct device *dev, int count, ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA); if (ret == 0) { bitmap_set(cma->bitmap, pageno, count); - page = pfn_to_page(pfn); break; } else if (ret != -EBUSY) { break; @@ -545,8 +562,8 @@ struct page *dma_alloc_from_contiguous(struct device *dev, int count, } mutex_unlock(&cma_mutex); - pr_debug("%s(): returned %p\n", __func__, page); - return page; + pr_debug("%s(): returned %lx\n", __func__, pfn); + return pfn; } /** @@ -559,18 +576,15 @@ struct page *dma_alloc_from_contiguous(struct device *dev, int count, * It returns false when provided pages do not belong to contiguous area and * true otherwise. */ -bool dma_release_from_contiguous(struct device *dev, struct page *pages, +bool dma_release_from_contiguous(struct device *dev, unsigned long pfn, int count) { struct cma *cma = dev_get_cma_area(dev); - unsigned long pfn; - if (!cma || !pages) + if (!cma || !pfn) return false; - pr_debug("%s(page %p)\n", __func__, (void *)pages); - - pfn = page_to_pfn(pages); + pr_debug("%s(pfn %lx)\n", __func__, pfn); if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count) return false; diff --git a/drivers/base/dma-removed.c b/drivers/base/dma-removed.c new file mode 100644 index 00000000000..004827a65e4 --- /dev/null +++ b/drivers/base/dma-removed.c @@ -0,0 +1,153 @@ +/* + * + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (C) 2000-2004 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/gfp.h> +#include <linux/errno.h> +#include <linux/list.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/dma-contiguous.h> +#include <linux/highmem.h> +#include <linux/memblock.h> +#include <linux/slab.h> +#include <linux/iommu.h> +#include <linux/io.h> +#include <linux/vmalloc.h> +#include <linux/sizes.h> + +#define NO_KERNEL_MAPPING_DUMMY 0x2222 + +void *removed_alloc(struct device *dev, size_t size, dma_addr_t *handle, + gfp_t gfp, struct dma_attrs *attrs) +{ + bool no_kernel_mapping = dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, + attrs); + unsigned long pfn; + unsigned long order = get_order(size); + void *addr = NULL; + + size = PAGE_ALIGN(size); + + if (!(gfp & __GFP_WAIT)) + return NULL; + + pfn = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT, order); + + if (pfn) { + addr = ioremap(__pfn_to_phys(pfn), size); + memset(addr, 0, size); + if (no_kernel_mapping) { + iounmap(addr); + addr = (void *)NO_KERNEL_MAPPING_DUMMY; + } + if (addr) + *handle = __pfn_to_phys(pfn); + + } + + return addr; +} + + +int removed_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + struct dma_attrs *attrs) +{ + return -ENXIO; +} + +void removed_free(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t handle, struct dma_attrs *attrs) +{ + bool no_kernel_mapping = dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, + attrs); + + if (!no_kernel_mapping) + iounmap(cpu_addr); + dma_release_from_contiguous(dev, __phys_to_pfn(handle), + size >> PAGE_SHIFT); +} + +static dma_addr_t removed_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + return ~(dma_addr_t)0; +} + +static void removed_unmap_page(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + return; +} + +static int removed_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + return 0; +} + +static void removed_unmap_sg(struct device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + return; +} + +static void removed_sync_single_for_cpu(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction dir) +{ + return; +} + +void removed_sync_single_for_device(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction dir) +{ + return; +} + +void removed_sync_sg_for_cpu(struct device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction dir) +{ + return; +} + +void removed_sync_sg_for_device(struct device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction dir) +{ + return; +} + +struct dma_map_ops removed_dma_ops = { + .alloc = removed_alloc, + .free = removed_free, + .mmap = removed_mmap, + .map_page = removed_map_page, + .unmap_page = removed_unmap_page, + .map_sg = removed_map_sg, + .unmap_sg = removed_unmap_sg, + .sync_single_for_cpu = removed_sync_single_for_cpu, + .sync_single_for_device = removed_sync_single_for_device, + .sync_sg_for_cpu = removed_sync_sg_for_cpu, + .sync_sg_for_device = removed_sync_sg_for_device, +}; +EXPORT_SYMBOL(removed_dma_ops); + + diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index f78c2e2a1ed..77643ea10c0 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -35,22 +35,30 @@ #include "diagfwd.h" #include "diagfwd_cntl.h" #include "diag_dci.h" +#include "diagfwd_hsic.h" static struct timer_list dci_drain_timer; static int dci_timer_in_progress; static struct work_struct dci_data_drain_work; +struct dci_ops_tbl_t *dci_ops_tbl; +struct diag_dci_partial_pkt_t partial_pkt; + unsigned int dci_max_reg = 100; unsigned int dci_max_clients = 10; -unsigned char dci_cumulative_log_mask[DCI_LOG_MASK_SIZE]; -unsigned char dci_cumulative_event_mask[DCI_EVENT_MASK_SIZE]; struct mutex dci_log_mask_mutex; struct mutex dci_event_mask_mutex; -struct mutex dci_health_mutex; spinlock_t ws_lock; unsigned long ws_lock_flags; +#define VALID_DCI_TOKEN(x) ((x >= 0 && x < NUM_DCI_PROC) ? 1 : 0) + +#ifdef CONFIG_DIAGFWD_BRIDGE_CODE +#define VALID_DCI_BRIDGE(x) ((x < 0 || x > NUM_DCI_PROC - 1) ? 0 : 1) +static int dci_remote_proc_token[NUM_DCI_PROC] = { -1, 0 }; +#endif + /* Number of milliseconds anticipated to process the DCI data */ #define DCI_WAKEUP_TIMEOUT 1 @@ -58,34 +66,58 @@ unsigned long ws_lock_flags; (buf && buf->data && !buf->in_busy && buf->data_len > 0) \ #ifdef CONFIG_DEBUG_FS -struct diag_dci_data_info *dci_data_smd; +struct diag_dci_data_info *dci_traffic; struct mutex dci_stat_mutex; - -void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type, - uint8_t peripheral) +void diag_dci_record_traffic(int read_bytes, uint8_t ch_type, + uint8_t peripheral, uint8_t proc) { - static int curr_dci_data_smd; + static int curr_dci_data; static unsigned long iteration; - struct diag_dci_data_info *temp_data = dci_data_smd; + struct diag_dci_data_info *temp_data = dci_traffic; if (!temp_data) return; mutex_lock(&dci_stat_mutex); - if (curr_dci_data_smd == DIAG_DCI_DEBUG_CNT) - curr_dci_data_smd = 0; - temp_data += curr_dci_data_smd; + if (curr_dci_data == DIAG_DCI_DEBUG_CNT) + curr_dci_data = 0; + temp_data += curr_dci_data; temp_data->iteration = iteration + 1; temp_data->data_size = read_bytes; temp_data->peripheral = peripheral; temp_data->ch_type = ch_type; + temp_data->proc = proc; diag_get_timestamp(temp_data->time_stamp); - curr_dci_data_smd++; + curr_dci_data++; iteration++; mutex_unlock(&dci_stat_mutex); } #else -void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type, - uint8_t peripheral) { } +void diag_dci_record_traffic(int read_bytes, uint8_t ch_type, + uint8_t peripheral, uint8_t proc) { } #endif +static void create_dci_log_mask_tbl(unsigned char *mask, uint8_t dirty) +{ + unsigned char *temp = mask; + uint8_t i; + + if (!mask) + return; + + /* create hard coded table for log mask with 16 categories */ + for (i = 0; i < DCI_MAX_LOG_CODES; i++) { + *temp = i; + temp++; + *temp = dirty ? 1 : 0; + temp++; + memset(temp, 0, DCI_MAX_ITEMS_PER_LOG_CODE); + temp += DCI_MAX_ITEMS_PER_LOG_CODE; + } +} + +static void create_dci_event_mask_tbl(unsigned char *tbl_buf) +{ + if (tbl_buf) + memset(tbl_buf, 0, DCI_EVENT_MASK_SIZE); +} static void dci_drain_data(unsigned long data) { @@ -244,7 +276,7 @@ void dci_data_drain_work_fn(struct work_struct *work) list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); - for (i = 0; i < NUM_DCI_PROC; i++) { + for (i = 0; i < entry->num_buffers; i++) { proc_buf = &entry->buffers[i]; buf_temp = proc_buf->buf_primary; @@ -274,10 +306,46 @@ void dci_data_drain_work_fn(struct work_struct *work) dci_timer_in_progress = 0; } +static int diag_process_single_dci_pkt(unsigned char *buf, int len, + int data_source, int token) +{ + uint8_t cmd_code = 0; + + if (!buf || len < 0) { + pr_err("diag: Invalid input in %s, buf: %p, len: %d\n", + __func__, buf, len); + return -EIO; + } + + cmd_code = *(uint8_t *)buf; + + switch (cmd_code) { + case LOG_CMD_CODE: + extract_dci_log(buf, len, data_source, token); + break; + case EVENT_CMD_CODE: + extract_dci_events(buf, len, data_source, token); + break; + case DCI_PKT_RSP_CODE: + case DCI_DELAYED_RSP_CODE: + extract_dci_pkt_rsp(buf, len, data_source, token); + break; + case DCI_CONTROL_PKT_CODE: + extract_dci_ctrl_pkt(buf, len, token); + break; + default: + pr_err("diag: Unable to process single DCI packet, cmd_code: %d, data_source: %d", + cmd_code, data_source); + return -EINVAL; + } + + return 0; +} + /* Process the data read from apps userspace client */ void diag_process_apps_dci_read_data(int data_type, void *buf, int recd_bytes) { - uint8_t cmd_code; + int err = 0; if (!buf) { pr_err_ratelimited("diag: In %s, Null buf pointer\n", __func__); @@ -291,38 +359,133 @@ void diag_process_apps_dci_read_data(int data_type, void *buf, int recd_bytes) return; } - cmd_code = *(uint8_t *)buf; - - switch (cmd_code) { - case LOG_CMD_CODE: - extract_dci_log(buf, recd_bytes, APPS_DATA); - break; - case EVENT_CMD_CODE: - extract_dci_events(buf, recd_bytes, APPS_DATA); - break; - case DCI_PKT_RSP_CODE: - case DCI_DELAYED_RSP_CODE: - extract_dci_pkt_rsp(buf, recd_bytes, APPS_DATA, NULL); - break; - default: - pr_err("diag: In %s, unsupported command code: 0x%x, not log or event\n", - __func__, cmd_code); + err = diag_process_single_dci_pkt(buf, recd_bytes, APPS_DATA, + DCI_LOCAL_PROC); + if (err) return; + /* wake up all sleeping DCI clients which have some data */ + diag_dci_wakeup_clients(); + dci_check_drain_timer(); +} + +int diag_process_hsic_dci_read_data(int index, void *buf, int recd_bytes) +{ + int read_bytes = 0, err = 0; + uint16_t dci_pkt_len; + struct diag_dci_header_t *header = NULL; + int header_len = sizeof(struct diag_dci_header_t); + + if (!buf) + return -EIO; + + diag_dci_record_traffic(recd_bytes, 0, 0, DCI_MDM_PROC + index); + + if (!partial_pkt.processing) + goto start; + + if (partial_pkt.remaining > recd_bytes) { + if ((partial_pkt.read_len + recd_bytes) > + (MAX_DCI_PACKET_SZ)) { + pr_err("diag: Invalid length %d, %d received in %s\n", + partial_pkt.read_len, recd_bytes, __func__); + goto end; + } + memcpy(partial_pkt.data + partial_pkt.read_len, buf, + recd_bytes); + read_bytes += recd_bytes; + buf += read_bytes; + partial_pkt.read_len += recd_bytes; + partial_pkt.remaining -= recd_bytes; + } else { + if ((partial_pkt.read_len + partial_pkt.remaining) > + (MAX_DCI_PACKET_SZ)) { + pr_err("diag: Invalid length during partial read %d, %d received in %s\n", + partial_pkt.read_len, + partial_pkt.remaining, __func__); + goto end; + } + memcpy(partial_pkt.data + partial_pkt.read_len, buf, + partial_pkt.remaining); + read_bytes += partial_pkt.remaining; + buf += read_bytes; + partial_pkt.read_len += partial_pkt.remaining; + partial_pkt.remaining = 0; + } + + if (partial_pkt.remaining == 0) { + /* + * Retrieve from the DCI control packet after the header = start + * (1 byte) + version (1 byte) + length (2 bytes) + */ + diag_process_single_dci_pkt(partial_pkt.data + 4, + partial_pkt.read_len - header_len, + DCI_REMOTE_DATA, DCI_MDM_PROC + index); + partial_pkt.read_len = 0; + partial_pkt.total_len = 0; + partial_pkt.processing = 0; + goto start; } + goto end; + +start: + while (read_bytes < recd_bytes) { + header = (struct diag_dci_header_t *)buf; + dci_pkt_len = header->length; + if (header->cmd_code != DCI_CONTROL_PKT_CODE && + driver->num_dci_client == 0) { + read_bytes += header_len + dci_pkt_len; + buf += header_len + dci_pkt_len; + continue; + } + + if (dci_pkt_len + header_len > MAX_DCI_PACKET_SZ) { + pr_err("diag: Invalid length in the dci packet field %d\n", + dci_pkt_len); + break; + } + + if ((dci_pkt_len + header_len) > (recd_bytes - read_bytes)) { + partial_pkt.read_len = recd_bytes - read_bytes; + partial_pkt.total_len = dci_pkt_len + header_len; + partial_pkt.remaining = partial_pkt.total_len - + partial_pkt.read_len; + partial_pkt.processing = 1; + memcpy(partial_pkt.data, buf, partial_pkt.read_len); + break; + } + /* + * Retrieve from the DCI control packet after the header = start + * (1 byte) + version (1 byte) + length (2 bytes) + */ + err = diag_process_single_dci_pkt(buf + 4, dci_pkt_len, + DCI_REMOTE_DATA, DCI_MDM_PROC); + if (err) + break; + read_bytes += header_len + dci_pkt_len; + buf += header_len + dci_pkt_len; /* advance to next DCI pkt */ + } +end: /* wake up all sleeping DCI clients which have some data */ diag_dci_wakeup_clients(); dci_check_drain_timer(); + diag_dci_try_deactivate_wakeup_source(); + return 0; } /* Process the data read from the smd dci channel */ int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf, int recd_bytes) { - int read_bytes, dci_pkt_len; + int read_bytes = 0, err = 0; + uint16_t dci_pkt_len; + struct diag_dci_pkt_header_t *header = NULL; uint8_t recv_pkt_cmd_code; + if (!buf) + return -EIO; + /* * Release wakeup source when there are no more clients to * process DCI data @@ -332,42 +495,33 @@ int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf, return 0; } - diag_dci_smd_record_info(recd_bytes, (uint8_t)smd_info->type, - (uint8_t)smd_info->peripheral); - /* Each SMD read can have multiple DCI packets */ - read_bytes = 0; + diag_dci_record_traffic(recd_bytes, (uint8_t)smd_info->type, + (uint8_t)smd_info->peripheral, DCI_LOCAL_PROC); while (read_bytes < recd_bytes) { - /* read actual length of dci pkt */ - dci_pkt_len = *(uint16_t *)(buf+2); + header = (struct diag_dci_pkt_header_t *)buf; + recv_pkt_cmd_code = header->pkt_code; + dci_pkt_len = header->len; - /* Check if the length of the current packet is lesser than the + /* + * Check if the length of the current packet is lesser than the * remaining bytes in the received buffer. This includes space * for the Start byte (1), Version byte (1), length bytes (2) * and End byte (1) */ - if ((dci_pkt_len+5) > (recd_bytes-read_bytes)) { + if ((dci_pkt_len + 5) > (recd_bytes - read_bytes)) { pr_err("diag: Invalid length in %s, len: %d, dci_pkt_len: %d", - __func__, recd_bytes, dci_pkt_len); + __func__, recd_bytes, dci_pkt_len); diag_dci_try_deactivate_wakeup_source(); return 0; } - /* process one dci packet */ - pr_debug("diag: dci: peripheral = %d bytes read = %d, single dci pkt len = %d\n", - smd_info->peripheral, read_bytes, dci_pkt_len); - /* print_hex_dump(KERN_DEBUG, "Single DCI packet :", - DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1); */ - recv_pkt_cmd_code = *(uint8_t *)(buf+4); - if (recv_pkt_cmd_code == LOG_CMD_CODE) { - /* Don't include the 4 bytes for command code */ - extract_dci_log(buf + 4, recd_bytes - 4, - smd_info->peripheral); - } else if (recv_pkt_cmd_code == EVENT_CMD_CODE) { - /* Don't include the 4 bytes for command code */ - extract_dci_events(buf + 4, recd_bytes - 4, - smd_info->peripheral); - } else - extract_dci_pkt_rsp(buf + 4, dci_pkt_len, - smd_info->peripheral, smd_info); + /* + * Retrieve from the DCI control packet after the header = start + * (1 byte) + version (1 byte) + length (2 bytes) + */ + err = diag_process_single_dci_pkt(buf + 4, dci_pkt_len, + smd_info->peripheral, DCI_LOCAL_PROC); + if (err) + break; read_bytes += 5 + dci_pkt_len; buf += 5 + dci_pkt_len; /* advance to next DCI pkt */ } @@ -546,8 +700,68 @@ static int diag_dci_remove_req_entry(unsigned char *buf, int len, return 0; } +void extract_dci_ctrl_pkt(unsigned char *buf, int len, int token) +{ + + struct diag_ctrl_dci_status *header = NULL; + unsigned char *temp = buf; + uint32_t ctrl_pkt_id = 0, read_len = 0; + uint8_t i; + int peripheral_mask, status; + + if (!buf) { + pr_err("diag: Invalid buffer in %s\n", __func__); + return; + } + + /* Skip the Control packet command code */ + temp += sizeof(uint8_t); + ctrl_pkt_id = *(uint32_t *)temp; + if (ctrl_pkt_id != DIAG_CTRL_MSG_DCI_CONNECTION_STATUS) { + pr_alert("diag: Unknown control packet through DCI channel : %d\n", + ctrl_pkt_id); + return; + } + + header = (struct diag_ctrl_dci_status *)temp; + temp += sizeof(struct diag_ctrl_dci_status); + read_len += sizeof(struct diag_ctrl_dci_status); + + for (i = 0; i < header->count; i++) { + if (read_len > len) { + pr_err("diag: Invalid length len: %d in %s\n", len, + __func__); + return; + } + + switch (*(uint8_t *)temp) { + case MODEM_DATA: + peripheral_mask = DIAG_CON_MPSS; + break; + case LPASS_DATA: + peripheral_mask = DIAG_CON_LPASS; + break; + case WCNSS_DATA: + peripheral_mask = DIAG_CON_WCNSS; + break; + default: + pr_err("diag: In %s, unknown peripheral, peripheral: %d\n", + __func__, *(uint8_t *)temp); + return; + } + temp += sizeof(uint8_t); + read_len += sizeof(uint8_t); + + status = (*(uint8_t *)temp) ? DIAG_STATUS_OPEN : + DIAG_STATUS_CLOSED; + temp += sizeof(uint8_t); + read_len += sizeof(uint8_t); + diag_dci_notify_client(peripheral_mask, status, token); + } +} + void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, - struct diag_smd_info *smd_info) + int token) { int tag; struct diag_dci_client_tbl *entry = NULL; @@ -581,11 +795,6 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, * code, the tag (int) */ rsp_len = len - (cmd_code_len + sizeof(int)); - /* - * Check if the length embedded in the packet is correct. - * Include the start (1), version (1), length (2) and the end - * (1) bytes while checking. Total = 5 bytes - */ if ((rsp_len == 0) || (rsp_len > (len - 5))) { pr_err("diag: Invalid length in %s, len: %d, rsp_len: %d", __func__, len, rsp_len); @@ -643,8 +852,15 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, memcpy(rsp_buf->data + rsp_buf->data_len, temp, rsp_len); rsp_buf->data_len += rsp_len; rsp_buf->data_source = data_source; - if (smd_info) - smd_info->in_busy_1 = 1; + + if (token == DCI_LOCAL_PROC && data_source < NUM_SMD_DCI_CHANNELS) { + if (driver->separate_cmdrsp[data_source] && + data_source < NUM_SMD_DCI_CMD_CHANNELS) + driver->smd_dci_cmd[data_source].in_busy_1 = 1; + else + driver->smd_dci[data_source].in_busy_1 = 1; + } + mutex_unlock(&rsp_buf->data_mutex); /* @@ -699,7 +915,7 @@ static void copy_dci_event(unsigned char *buf, int len, } -void extract_dci_events(unsigned char *buf, int len, int data_source) +void extract_dci_events(unsigned char *buf, int len, int data_source, int token) { uint16_t event_id, event_id_packet, length, temp_len; uint8_t payload_len, payload_len_field; @@ -787,6 +1003,8 @@ void extract_dci_events(unsigned char *buf, int len, int data_source) list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); + if (entry->client_info.token != token) + continue; if (diag_dci_query_event_mask(entry, event_id)) { /* copy to client buffer */ copy_dci_event(event_data, total_event_len, @@ -860,7 +1078,7 @@ static void copy_dci_log(unsigned char *buf, int len, mutex_unlock(&data_buffer->data_mutex); } -void extract_dci_log(unsigned char *buf, int len, int data_source) +void extract_dci_log(unsigned char *buf, int len, int data_source, int token) { uint16_t log_code, read_bytes = 0; struct list_head *start, *temp; @@ -886,6 +1104,8 @@ void extract_dci_log(unsigned char *buf, int len, int data_source) /* parse through log mask table of each client and check mask */ list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); + if (entry->client_info.token != token) + continue; if (diag_dci_query_log_mask(entry, log_code)) { pr_debug("\t log code %x needed by client %d", log_code, entry->client->tgid); @@ -918,6 +1138,8 @@ void diag_update_smd_dci_work_fn(struct work_struct *work) */ list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); + if (entry->client_info.token != DCI_LOCAL_PROC) + continue; client_log_mask_ptr = entry->dci_log_mask; for (j = 0; j < 16; j++) { if (*(client_log_mask_ptr+1)) @@ -928,7 +1150,7 @@ void diag_update_smd_dci_work_fn(struct work_struct *work) mutex_lock(&dci_log_mask_mutex); /* Update the appropriate dirty bits in the cumulative mask */ - log_mask_ptr = dci_cumulative_log_mask; + log_mask_ptr = dci_ops_tbl[DCI_LOCAL_PROC].log_mask_composite; for (i = 0; i < 16; i++) { if (dirty_bits[i]) *(log_mask_ptr+1) = dirty_bits[i]; @@ -940,17 +1162,17 @@ void diag_update_smd_dci_work_fn(struct work_struct *work) /* Send updated mask to userspace clients */ diag_update_userspace_clients(DCI_LOG_MASKS_TYPE); /* Send updated log mask to peripherals */ - ret = diag_send_dci_log_mask(); + ret = dci_ops_tbl[DCI_LOCAL_PROC].send_log_mask(DCI_LOCAL_PROC); /* Send updated event mask to userspace clients */ diag_update_userspace_clients(DCI_EVENT_MASKS_TYPE); /* Send updated event mask to peripheral */ - ret = diag_send_dci_event_mask(); + ret = dci_ops_tbl[DCI_LOCAL_PROC].send_event_mask(DCI_LOCAL_PROC); smd_info->notify_context = 0; } -void diag_dci_notify_client(int peripheral_mask, int data) +void diag_dci_notify_client(int peripheral_mask, int data, int proc) { int stat; struct siginfo info; @@ -960,10 +1182,16 @@ void diag_dci_notify_client(int peripheral_mask, int data) memset(&info, 0, sizeof(struct siginfo)); info.si_code = SI_QUEUE; info.si_int = (peripheral_mask | data); + if (data == DIAG_STATUS_OPEN) + dci_ops_tbl[proc].peripheral_status |= peripheral_mask; + else + dci_ops_tbl[proc].peripheral_status &= !peripheral_mask; /* Notify the DCI process that the peripheral DCI Channel is up */ list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); + if (entry->client_info.token != proc) + continue; if (entry->client_info.notification_list & peripheral_mask) { info.si_signo = entry->client_info.signal_type; stat = send_sig_info(entry->client_info.signal_type, @@ -1036,6 +1264,114 @@ static int diag_send_dci_pkt(struct diag_master_table entry, return status; } +#ifdef CONFIG_DIAGFWD_BRIDGE_CODE +unsigned char *dci_get_buffer_from_bridge(int index) +{ + uint8_t retries = 0, max_retries = 3; + unsigned char *buf = NULL; + + do { + buf = diagmem_alloc(driver, WRITE_HSIC_BUF_SIZE_DCI, + POOL_TYPE_HSIC_DCI_WRITE + index); + if (!buf) { + usleep_range(5000, 5100); + retries++; + } else + break; + } while (retries < max_retries); + + return buf; +} + +int diag_dci_write_bridge(int index, unsigned char *buf, int len) +{ + int err = -EAGAIN; + uint8_t retries = 0, max_retries = 3; + + do { + if (diag_hsic_dci[index].in_busy_hsic_write) { + usleep_range(5000, 5100); + retries++; + } else { + diag_hsic_dci[index].in_busy_hsic_write = 1; + err = diag_bridge_write(hsic_dci_bridge_map[index], + buf, len); + if (err) + diag_hsic_dci[index].in_busy_hsic_write = 0; + else + err = len; + break; + } + } while (retries < max_retries); + + return err; +} +#endif + +#ifdef CONFIG_DIAGFWD_BRIDGE_CODE +static int diag_send_dci_pkt_remote(unsigned char *data, int len, int tag, + int token) +{ + unsigned char *buf = NULL; + struct diag_dci_header_t dci_header; + int dci_header_size = sizeof(struct diag_dci_header_t); + int ret = DIAG_DCI_NO_ERROR; + uint32_t write_len = 0; + int b_index = dci_remote_proc_token[token]; + + if (!data) + return -EIO; + + if (!VALID_DCI_BRIDGE(b_index)) { + pr_err("diag: Invalid bridge index %d in %s\n", b_index, + __func__); + return -EIO; + } + + buf = dci_get_buffer_from_bridge(b_index); + if (!buf) { + pr_err("diag: In %s, unable to get dci buffers to write data\n", + __func__); + return -EAGAIN; + } + + dci_header.start = CONTROL_CHAR; + dci_header.version = 1; + /* + * The Length of the DCI packet = length of the command + tag (int) + + * the command code size (uint8_t) + */ + dci_header.length = len + sizeof(int) + sizeof(uint8_t); + dci_header.cmd_code = DCI_PKT_RSP_CODE; + + memcpy(buf + write_len, &dci_header, dci_header_size); + write_len += dci_header_size; + *(int *)(buf + write_len) = tag; + write_len += sizeof(int); + memcpy(buf + write_len, data, len); + write_len += len; + *(buf + write_len) = CONTROL_CHAR; /* End Terminator */ + write_len += sizeof(uint8_t); + + ret = diag_dci_write_bridge(b_index, buf, write_len); + if (ret != write_len) { + pr_err("diag: In %s, unable to write to DCI HSIC channel, err: %d\n", + __func__, ret); + diagmem_free(driver, buf, POOL_TYPE_HSIC_DCI_WRITE + b_index); + } else { + ret = DIAG_DCI_NO_ERROR; + } + + return ret; +} +#else +static int diag_send_dci_pkt_remote(unsigned char *data, int len, int tag, + int token) +{ + return DIAG_DCI_NO_ERROR; +} +#endif + static int diag_dci_process_apps_pkt(struct diag_pkt_header_t *pkt_header, unsigned char *req_buf, int tag) { @@ -1181,6 +1517,7 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len) uint32_t read_len = 0, req_len = len; struct diag_master_table entry; struct dci_pkt_req_entry_t *req_entry = NULL; + struct diag_dci_client_tbl *dci_entry = NULL; if (!buf) return -EIO; @@ -1207,6 +1544,12 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len) return -EIO; } + dci_entry = diag_dci_get_client_entry(client_id); + if (!dci_entry) { + pr_err("diag: Invalid client %d in %s\n", client_id, __func__); + return DIAG_DCI_NO_REG; + } + /* Check if the command is allowed on DCI */ if (diag_dci_filter_commands(header)) { pr_debug("diag: command not supported %d %d %d", @@ -1240,6 +1583,16 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len) return DIAG_DCI_NO_REG; } + /* + * If the client has registered for remote data, route the packet to the + * remote processor + */ + if (dci_entry->client_info.token > 0) { + ret = diag_send_dci_pkt_remote(req_buf, req_len, req_entry->tag, + dci_entry->client_info.token); + return ret; + } + /* Check if it is a dedicated Apps command */ ret = diag_dci_process_apps_pkt(header, req_buf, req_entry->tag); if (ret == DIAG_DCI_NO_ERROR || ret < 0) @@ -1291,7 +1644,7 @@ int diag_process_dci_transaction(unsigned char *buf, int len) { unsigned char *temp = buf; uint16_t log_code, item_num; - int ret = -1, found = 0, client_id = 0; + int ret = -1, found = 0, client_id = 0, client_token = 0; int count, set_mask, num_codes, bit_index, event_id, offset = 0; unsigned int byte_index, read_len = 0; uint8_t equip_id, *log_mask_ptr, *head_log_mask_ptr, byte_mask; @@ -1333,6 +1686,7 @@ int diag_process_dci_transaction(unsigned char *buf, int len) pr_err("diag: In %s, invalid client\n", __func__); return ret; } + client_token = dci_entry->client_info.token; if (num_codes == 0 || (num_codes >= (USER_SPACE_DATA - 8)/2)) { pr_err("diag: dci: Invalid number of log codes %d\n", @@ -1348,6 +1702,7 @@ int diag_process_dci_transaction(unsigned char *buf, int len) } pr_debug("diag: head of dci log mask %p\n", head_log_mask_ptr); count = 0; /* iterator for extracting log codes */ + while (count < num_codes) { if (read_len >= USER_SPACE_DATA) { pr_err("diag: dci: Invalid length for log type in %s", @@ -1396,16 +1751,17 @@ int diag_process_dci_transaction(unsigned char *buf, int len) /* add to cumulative mask */ update_dci_cumulative_log_mask( offset, byte_index, - byte_mask); + byte_mask, client_token); temp += 2; read_len += 2; count++; ret = DIAG_DCI_NO_ERROR; } /* send updated mask to userspace clients */ - diag_update_userspace_clients(DCI_LOG_MASKS_TYPE); + if (client_token == DCI_LOCAL_PROC) + diag_update_userspace_clients(DCI_LOG_MASKS_TYPE); /* send updated mask to peripherals */ - ret = diag_send_dci_log_mask(); + ret = dci_ops_tbl[client_token].send_log_mask(client_token); } else if (*(int *)temp == DCI_EVENT_TYPE) { /* Minimum length of a event mask config is 12 + 4 bytes for atleast one event id to be set or reset. */ @@ -1414,7 +1770,7 @@ int diag_process_dci_transaction(unsigned char *buf, int len) return -EIO; } - /* Extract each log code and put in client table */ + /* Extract each event id and put in client table */ temp += sizeof(int); read_len += sizeof(int); client_id = *(int *)temp; @@ -1433,6 +1789,7 @@ int diag_process_dci_transaction(unsigned char *buf, int len) pr_err("diag: In %s, invalid client\n", __func__); return ret; } + client_token = dci_entry->client_info.token; /* Check for positive number of event ids. Also, the number of event ids should fit in the buffer along with set_mask and @@ -1474,16 +1831,18 @@ int diag_process_dci_transaction(unsigned char *buf, int len) else *(event_mask_ptr + byte_index) &= ~byte_mask; /* add to cumulative mask */ - update_dci_cumulative_event_mask(byte_index, byte_mask); + update_dci_cumulative_event_mask(byte_index, byte_mask, + client_token); temp += sizeof(int); read_len += sizeof(int); count++; ret = DIAG_DCI_NO_ERROR; } /* send updated mask to userspace clients */ - diag_update_userspace_clients(DCI_EVENT_MASKS_TYPE); + if (dci_entry->client_info.token == DCI_LOCAL_PROC) + diag_update_userspace_clients(DCI_EVENT_MASKS_TYPE); /* send updated mask to peripherals */ - ret = diag_send_dci_event_mask(); + ret = dci_ops_tbl[client_token].send_event_mask(client_token); } else { pr_alert("diag: Incorrect DCI transaction\n"); } @@ -1515,10 +1874,10 @@ struct diag_dci_client_tbl *dci_lookup_client_entry_pid(int pid) return NULL; } -void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask) +void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask, int token) { uint8_t *event_mask_ptr; - uint8_t *update_ptr = dci_cumulative_event_mask; + uint8_t *update_ptr = dci_ops_tbl[token].event_mask_composite; struct list_head *start, *temp; struct diag_dci_client_tbl *entry = NULL; bool is_set = false; @@ -1527,6 +1886,8 @@ void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask) update_ptr += offset; list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); + if (entry->client_info.token != token) + continue; event_mask_ptr = entry->dci_event_mask; event_mask_ptr += offset; if ((*event_mask_ptr & byte_mask) == byte_mask) { @@ -1542,17 +1903,23 @@ void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask) mutex_unlock(&dci_event_mask_mutex); } -void diag_dci_invalidate_cumulative_event_mask() +void diag_dci_invalidate_cumulative_event_mask(int token) { int i = 0; struct list_head *start, *temp; struct diag_dci_client_tbl *entry = NULL; uint8_t *update_ptr, *event_mask_ptr; - update_ptr = dci_cumulative_event_mask; + update_ptr = dci_ops_tbl[token].event_mask_composite; + + if (!update_ptr) + return; mutex_lock(&dci_event_mask_mutex); + create_dci_event_mask_tbl(update_ptr); list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); + if (entry->client_info.token != token) + continue; event_mask_ptr = entry->dci_event_mask; for (i = 0; i < DCI_EVENT_MASK_SIZE; i++) *(update_ptr+i) |= *(event_mask_ptr+i); @@ -1560,11 +1927,79 @@ void diag_dci_invalidate_cumulative_event_mask() mutex_unlock(&dci_event_mask_mutex); } -int diag_send_dci_event_mask() +#ifdef CONFIG_DIAGFWD_BRIDGE_CODE +int diag_send_dci_event_mask_remote(int token) +{ + unsigned char *buf = NULL; + struct diag_dci_header_t dci_header; + struct diag_ctrl_event_mask event_mask; + int dci_header_size = sizeof(struct diag_dci_header_t); + int event_header_size = sizeof(struct diag_ctrl_event_mask); + int i, ret = DIAG_DCI_NO_ERROR, err = DIAG_DCI_NO_ERROR; + unsigned char *event_mask_ptr = dci_ops_tbl[token]. + event_mask_composite; + uint32_t write_len = 0; + int b_index = dci_remote_proc_token[token]; + + if (!VALID_DCI_BRIDGE(b_index)) { + pr_err("diag: Invalid bridge index %d in %s\n", b_index, + __func__); + return -EIO; + } + + buf = dci_get_buffer_from_bridge(b_index); + if (!buf) { + pr_err("diag: In %s, unable to get dci buffers to write data\n", + __func__); + return -EAGAIN; + } + + /* Frame the DCI header */ + dci_header.start = CONTROL_CHAR; + dci_header.version = 1; + dci_header.length = event_header_size + DCI_EVENT_MASK_SIZE + 1; + dci_header.cmd_code = DCI_CONTROL_PKT_CODE; + + event_mask.cmd_type = DIAG_CTRL_MSG_EVENT_MASK; + event_mask.data_len = 7 + DCI_EVENT_MASK_SIZE; + event_mask.stream_id = DCI_MASK_STREAM; + event_mask.status = 3; /* status for valid mask */ + event_mask.event_config = 0; /* event config */ + event_mask.event_mask_size = DCI_EVENT_MASK_SIZE; + for (i = 0; i < DCI_EVENT_MASK_SIZE; i++) { + if (event_mask_ptr[i] != 0) { + event_mask.event_config = 1; + break; + } + } + memcpy(buf + write_len, &dci_header, dci_header_size); + write_len += dci_header_size; + memcpy(buf + write_len, &event_mask, event_header_size); + write_len += event_header_size; + memcpy(buf + write_len, event_mask_ptr, DCI_EVENT_MASK_SIZE); + write_len += DCI_EVENT_MASK_SIZE; + *(buf + write_len) = CONTROL_CHAR; /* End Terminator */ + write_len += sizeof(uint8_t); + err = diag_dci_write_bridge(b_index, buf, write_len); + if (err != write_len) { + pr_err("diag: error writing to hsic channel, err: %d\n", err); + diagmem_free(driver, buf, POOL_TYPE_HSIC_DCI_WRITE + b_index); + ret = err; + } else { + ret = DIAG_DCI_NO_ERROR; + } + + return ret; +} +#endif + +int diag_send_dci_event_mask(int token) { void *buf = driver->buf_event_mask_update; int header_size = sizeof(struct diag_ctrl_event_mask); int ret = DIAG_DCI_NO_ERROR, err = DIAG_DCI_NO_ERROR, i; + unsigned char *event_mask_ptr = dci_ops_tbl[DCI_LOCAL_PROC]. + event_mask_composite; mutex_lock(&driver->diag_cntl_mutex); /* send event mask update */ @@ -1575,13 +2010,13 @@ int diag_send_dci_event_mask() driver->event_mask->event_config = 0; /* event config */ driver->event_mask->event_mask_size = DCI_EVENT_MASK_SIZE; for (i = 0; i < DCI_EVENT_MASK_SIZE; i++) { - if (dci_cumulative_event_mask[i] != 0) { + if (event_mask_ptr[i] != 0) { driver->event_mask->event_config = 1; break; } } memcpy(buf, driver->event_mask, header_size); - memcpy(buf+header_size, dci_cumulative_event_mask, DCI_EVENT_MASK_SIZE); + memcpy(buf+header_size, event_mask_ptr, DCI_EVENT_MASK_SIZE); for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) { /* * Don't send to peripheral if its regular channel @@ -1601,27 +2036,23 @@ int diag_send_dci_event_mask() } void update_dci_cumulative_log_mask(int offset, unsigned int byte_index, - uint8_t byte_mask) + uint8_t byte_mask, int token) { - int i; - uint8_t *update_ptr = dci_cumulative_log_mask; + uint8_t *update_ptr = dci_ops_tbl[token].log_mask_composite; uint8_t *log_mask_ptr; bool is_set = false; struct list_head *start, *temp; struct diag_dci_client_tbl *entry = NULL; mutex_lock(&dci_log_mask_mutex); - *update_ptr = 0; - /* set the equipment IDs */ - for (i = 0; i < 16; i++) - *(update_ptr + (i*514)) = i; - update_ptr += offset; /* update the dirty bit */ *(update_ptr+1) = 1; update_ptr = update_ptr + byte_index; list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); + if (entry->client_info.token != token) + continue; log_mask_ptr = entry->dci_log_mask; log_mask_ptr = log_mask_ptr + offset + byte_index; if ((*log_mask_ptr & byte_mask) == byte_mask) { @@ -1638,17 +2069,21 @@ void update_dci_cumulative_log_mask(int offset, unsigned int byte_index, mutex_unlock(&dci_log_mask_mutex); } -void diag_dci_invalidate_cumulative_log_mask() +void diag_dci_invalidate_cumulative_log_mask(int token) { int i = 0; struct list_head *start, *temp; struct diag_dci_client_tbl *entry = NULL; uint8_t *update_ptr, *log_mask_ptr; - update_ptr = dci_cumulative_log_mask; + update_ptr = dci_ops_tbl[token].log_mask_composite; + /* Clear the composite mask and redo all the masks */ mutex_lock(&dci_log_mask_mutex); + create_dci_log_mask_tbl(update_ptr, DCI_LOG_MASK_DIRTY); list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); + if (entry->client_info.token != token) + continue; log_mask_ptr = entry->dci_log_mask; for (i = 0; i < DCI_LOG_MASK_SIZE; i++) *(update_ptr+i) |= *(log_mask_ptr+i); @@ -1656,28 +2091,105 @@ void diag_dci_invalidate_cumulative_log_mask() mutex_unlock(&dci_log_mask_mutex); } -int diag_send_dci_log_mask() +static int dci_fill_log_mask(unsigned char *dest_ptr, unsigned char *src_ptr) +{ + struct diag_ctrl_log_mask header; + int header_len = sizeof(struct diag_ctrl_log_mask); + + header.cmd_type = DIAG_CTRL_MSG_LOG_MASK; + header.num_items = DCI_MAX_ITEMS_PER_LOG_CODE; + header.data_len = 11 + DCI_MAX_ITEMS_PER_LOG_CODE; + header.stream_id = DCI_MASK_STREAM; + header.status = 3; + header.equip_id = *src_ptr; + header.log_mask_size = DCI_MAX_ITEMS_PER_LOG_CODE; + memcpy(dest_ptr, &header, header_len); + memcpy(dest_ptr + header_len, src_ptr + 2, DCI_MAX_ITEMS_PER_LOG_CODE); + + return header_len + DCI_MAX_ITEMS_PER_LOG_CODE; +} + +#ifdef CONFIG_DIAGFWD_BRIDGE_CODE +int diag_send_dci_log_mask_remote(int token) +{ + + unsigned char *buf = NULL; + struct diag_dci_header_t dci_header; + int dci_header_size = sizeof(struct diag_dci_header_t); + int log_header_size = sizeof(struct diag_ctrl_log_mask); + uint8_t *log_mask_ptr = dci_ops_tbl[token].log_mask_composite; + int i, ret = DIAG_DCI_NO_ERROR, err = DIAG_DCI_NO_ERROR; + int updated; + uint32_t write_len = 0; + int b_index = dci_remote_proc_token[token]; + + if (!VALID_DCI_BRIDGE(b_index)) { + pr_err("diag: Invalid bridge index %d in %s\n", b_index, + __func__); + return -EIO; + } + + /* DCI header is common to all equipment IDs */ + dci_header.start = CONTROL_CHAR; + dci_header.version = 1; + dci_header.length = log_header_size + DCI_MAX_ITEMS_PER_LOG_CODE + 1; + dci_header.cmd_code = DCI_CONTROL_PKT_CODE; + + for (i = 0; i < DCI_MAX_LOG_CODES; i++) { + updated = 1; + write_len = 0; + if (!*(log_mask_ptr + 1)) { + log_mask_ptr += 514; + continue; + } + + buf = dci_get_buffer_from_bridge(b_index); + if (!buf) { + pr_err("diag: In %s, unable to get dci buffers to write data\n", + __func__); + return -EAGAIN; + } + + memcpy(buf + write_len, &dci_header, dci_header_size); + write_len += dci_header_size; + write_len += dci_fill_log_mask(buf + write_len, log_mask_ptr); + *(buf + write_len) = CONTROL_CHAR; /* End Terminator */ + write_len += sizeof(uint8_t); + err = diag_dci_write_bridge(b_index, buf, write_len); + if (err != write_len) { + pr_err("diag: error writing log mask to MDM hsic channel, equip_id: %d, err: %d\n", + i, err); + diagmem_free(driver, buf, + POOL_TYPE_HSIC_DCI_WRITE + b_index); + updated = 0; + } + if (updated) + *(log_mask_ptr + 1) = 0; /* clear dirty byte */ + log_mask_ptr += 514; + } + + return ret; +} +#endif + +int diag_send_dci_log_mask(int token) { void *buf = driver->buf_log_mask_update; - int header_size = sizeof(struct diag_ctrl_log_mask); - uint8_t *log_mask_ptr = dci_cumulative_log_mask; + int write_len = 0; + uint8_t *log_mask_ptr = dci_ops_tbl[DCI_LOCAL_PROC].log_mask_composite; int i, j, ret = DIAG_DCI_NO_ERROR, err = DIAG_DCI_NO_ERROR; int updated; mutex_lock(&driver->diag_cntl_mutex); for (i = 0; i < 16; i++) { updated = 1; - driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK; - driver->log_mask->num_items = 512; - driver->log_mask->data_len = 11 + 512; - driver->log_mask->stream_id = DCI_MASK_STREAM; - driver->log_mask->status = 3; /* status for valid mask */ - driver->log_mask->equip_id = *log_mask_ptr; - driver->log_mask->log_mask_size = 512; - memcpy(buf, driver->log_mask, header_size); - memcpy(buf+header_size, log_mask_ptr+2, 512); - /* if dirty byte is set and channel is valid */ - for (j = 0; j < NUM_SMD_DCI_CHANNELS; j++) { + /* Dirty bit is set don't update the mask for this equip id */ + if (!(*(log_mask_ptr + 1))) { + log_mask_ptr += 514; + continue; + } + write_len = dci_fill_log_mask(buf, log_mask_ptr); + for (j = 0; j < NUM_SMD_DCI_CHANNELS && write_len; j++) { /* * Don't send to peripheral if its regular channel * is down. It may also mean that the peripheral @@ -1685,11 +2197,8 @@ int diag_send_dci_log_mask() */ if (!driver->smd_dci[j].ch) continue; - - if (!(*(log_mask_ptr+1))) - continue; err = diag_dci_write_proc(j, DIAG_CNTL_TYPE, buf, - header_size + DCI_MAX_ITEMS_PER_LOG_CODE); + write_len); if (err != DIAG_DCI_NO_ERROR) { updated = 0; ret = DIAG_DCI_SEND_DATA_FAIL; @@ -1704,28 +2213,6 @@ int diag_send_dci_log_mask() return ret; } -void create_dci_log_mask_tbl(unsigned char *tbl_buf) -{ - uint8_t i; int count = 0; - - if (!tbl_buf) - return; - - /* create hard coded table for log mask with 16 categories */ - for (i = 0; i < 16; i++) { - *(uint8_t *)tbl_buf = i; - pr_debug("diag: put value %x at %p\n", i, tbl_buf); - memset(tbl_buf+1, 0, 513); /* set dirty bit as 0 */ - tbl_buf += 514; - count += 514; - } -} - -void create_dci_event_mask_tbl(unsigned char *tbl_buf) -{ - memset(tbl_buf, 0, 512); -} - static int diag_dci_probe(struct platform_device *pdev) { int err = 0; @@ -1818,6 +2305,78 @@ struct platform_driver msm_diag_dci_cmd_driver = { }, }; +static int diag_dci_init_local(void) +{ + struct dci_ops_tbl_t *temp = &dci_ops_tbl[DCI_LOCAL_PROC]; + + create_dci_log_mask_tbl(temp->log_mask_composite, DCI_LOG_MASK_CLEAN); + create_dci_event_mask_tbl(temp->event_mask_composite); + temp->peripheral_status = 0; + temp->peripheral_status |= DIAG_CON_APSS; + temp->send_log_mask = diag_send_dci_log_mask; + temp->send_event_mask = diag_send_dci_event_mask; + + return 0; +} + +#ifdef CONFIG_DIAGFWD_BRIDGE_CODE +static int diag_dci_init_remote(void) +{ + int i; + struct dci_ops_tbl_t *temp = NULL; + + for (i = 1; i < MAX_HSIC_DCI_CH; i++) { + temp = &dci_ops_tbl[i]; + create_dci_log_mask_tbl(temp->log_mask_composite, + DCI_LOG_MASK_CLEAN); + create_dci_event_mask_tbl(temp->event_mask_composite); + temp->peripheral_status = 0; + temp->send_log_mask = diag_send_dci_log_mask_remote; + temp->send_event_mask = diag_send_dci_event_mask_remote; + } + + partial_pkt.data = kzalloc(MAX_DCI_PACKET_SZ, GFP_KERNEL); + if (!partial_pkt.data) { + pr_err("diag: Unable to create partial pkt data\n"); + return -ENOMEM; + } + + partial_pkt.total_len = 0; + partial_pkt.read_len = 0; + partial_pkt.remaining = 0; + partial_pkt.processing = 0; + return 0; +} +#else +static int diag_dci_init_remote(void) +{ + return 0; +} +#endif + +static int diag_dci_init_ops_tbl(void) +{ + int err = 0; + + dci_ops_tbl = kzalloc(sizeof(struct dci_ops_tbl_t) * NUM_DCI_PROC, + GFP_KERNEL); + if (!dci_ops_tbl) + return -ENOMEM; + + err = diag_dci_init_local(); + if (err) + goto err; + err = diag_dci_init_remote(); + if (err) + goto err; + + return 0; + +err: + kfree(dci_ops_tbl); + return -ENOMEM; +} + int diag_dci_init(void) { int success = 0; @@ -1829,9 +2388,12 @@ int diag_dci_init(void) mutex_init(&driver->dci_mutex); mutex_init(&dci_log_mask_mutex); mutex_init(&dci_event_mask_mutex); - mutex_init(&dci_health_mutex); spin_lock_init(&ws_lock); + success = diag_dci_init_ops_tbl(); + if (success) + goto err; + for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) { success = diag_smd_constructor(&driver->smd_dci[i], i, SMD_DCI_TYPE); @@ -1884,10 +2446,11 @@ err: if (driver->diag_dci_wq) destroy_workqueue(driver->diag_dci_wq); + kfree(dci_ops_tbl); + kfree(partial_pkt.data); mutex_destroy(&driver->dci_mutex); mutex_destroy(&dci_log_mask_mutex); mutex_destroy(&dci_event_mask_mutex); - mutex_destroy(&dci_health_mutex); return DIAG_DCI_NO_REG; } @@ -1906,19 +2469,19 @@ void diag_dci_exit(void) platform_driver_unregister(&msm_diag_dci_cmd_driver); } + kfree(dci_ops_tbl); + kfree(partial_pkt.data); kfree(driver->apps_dci_buf); mutex_destroy(&driver->dci_mutex); mutex_destroy(&dci_log_mask_mutex); mutex_destroy(&dci_event_mask_mutex); - mutex_destroy(&dci_health_mutex); destroy_workqueue(driver->diag_dci_wq); } int diag_dci_clear_log_mask(int client_id) { - int j, k, err = DIAG_DCI_NO_ERROR; - uint8_t *log_mask_ptr, *update_ptr; - struct list_head *start, *temp; + int err = DIAG_DCI_NO_ERROR, token = DCI_LOCAL_PROC; + uint8_t *update_ptr; struct diag_dci_client_tbl *entry = NULL; entry = diag_dci_get_client_entry(client_id); @@ -1926,39 +2489,27 @@ int diag_dci_clear_log_mask(int client_id) pr_err("diag: In %s, invalid client entry\n", __func__); return DIAG_DCI_TABLE_ERR; } + token = entry->client_info.token; + update_ptr = dci_ops_tbl[token].log_mask_composite; - mutex_lock(&dci_log_mask_mutex); - create_dci_log_mask_tbl(entry->dci_log_mask); - memset(dci_cumulative_log_mask, 0x0, DCI_LOG_MASK_SIZE); - list_for_each_safe(start, temp, &driver->dci_client_list) { - entry = list_entry(start, struct diag_dci_client_tbl, track); - update_ptr = dci_cumulative_log_mask; - log_mask_ptr = entry->dci_log_mask; - for (j = 0; j < 16; j++) { - *update_ptr = j; - *(update_ptr + 1) = 1; - update_ptr += 2; - log_mask_ptr += 2; - for (k = 0; k < 513; k++) { - *update_ptr |= *log_mask_ptr; - update_ptr++; - log_mask_ptr++; - } - } - } - mutex_unlock(&dci_log_mask_mutex); - /* send updated mask to userspace clients */ - diag_update_userspace_clients(DCI_LOG_MASKS_TYPE); + create_dci_log_mask_tbl(entry->dci_log_mask, DCI_LOG_MASK_CLEAN); + diag_dci_invalidate_cumulative_log_mask(token); + + /* + * Send updated mask to userspace clients only if the client + * is registered on the local processor + */ + if (token == DCI_LOCAL_PROC) + diag_update_userspace_clients(DCI_LOG_MASKS_TYPE); /* Send updated mask to peripherals */ - err = diag_send_dci_log_mask(); + err = dci_ops_tbl[token].send_log_mask(token); return err; } int diag_dci_clear_event_mask(int client_id) { - int j, err = DIAG_DCI_NO_ERROR; - uint8_t *event_mask_ptr, *update_ptr; - struct list_head *start, *temp; + int err = DIAG_DCI_NO_ERROR, token = DCI_LOCAL_PROC; + uint8_t *update_ptr; struct diag_dci_client_tbl *entry = NULL; entry = diag_dci_get_client_entry(client_id); @@ -1966,27 +2517,24 @@ int diag_dci_clear_event_mask(int client_id) pr_err("diag: In %s, invalid client entry\n", __func__); return DIAG_DCI_TABLE_ERR; } + token = entry->client_info.token; + update_ptr = dci_ops_tbl[token].event_mask_composite; - mutex_lock(&dci_event_mask_mutex); - memset(entry->dci_event_mask, 0x0, DCI_EVENT_MASK_SIZE); - memset(dci_cumulative_event_mask, 0x0, DCI_EVENT_MASK_SIZE); - update_ptr = dci_cumulative_event_mask; + create_dci_event_mask_tbl(entry->dci_event_mask); + diag_dci_invalidate_cumulative_event_mask(token); - list_for_each_safe(start, temp, &driver->dci_client_list) { - entry = list_entry(start, struct diag_dci_client_tbl, track); - event_mask_ptr = entry->dci_event_mask; - for (j = 0; j < DCI_EVENT_MASK_SIZE; j++) - *(update_ptr + j) |= *(event_mask_ptr + j); - } - mutex_unlock(&dci_event_mask_mutex); - /* send updated mask to userspace clients */ - diag_update_userspace_clients(DCI_EVENT_MASKS_TYPE); + /* + * Send updated mask to userspace clients only if the client is + * registerted on the local processor + */ + if (token == DCI_LOCAL_PROC) + diag_update_userspace_clients(DCI_EVENT_MASKS_TYPE); /* Send updated mask to peripherals */ - err = diag_send_dci_event_mask(); + err = dci_ops_tbl[token].send_event_mask(token); return err; } -uint8_t diag_dci_get_cumulative_real_time() +uint8_t diag_dci_get_cumulative_real_time(int token) { uint8_t real_time = MODE_NONREALTIME; struct list_head *start, *temp; @@ -1994,7 +2542,8 @@ uint8_t diag_dci_get_cumulative_real_time() list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); - if (entry->real_time == MODE_REALTIME) { + if (entry->real_time == MODE_REALTIME && + entry->client_info.token == token) { real_time = 1; break; } @@ -2002,10 +2551,8 @@ uint8_t diag_dci_get_cumulative_real_time() return real_time; } -int diag_dci_set_real_time(int client_id, uint8_t real_time) +int diag_dci_set_real_time(struct diag_dci_client_tbl *entry, uint8_t real_time) { - struct diag_dci_client_tbl *entry = NULL; - entry = diag_dci_get_client_entry(client_id); if (!entry) { pr_err("diag: In %s, invalid client entry\n", __func__); return 0; @@ -2037,6 +2584,11 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) if (!reg_entry) return DIAG_DCI_NO_REG; + if (!VALID_DCI_TOKEN(reg_entry->token)) { + pr_alert("diag: Invalid DCI client token, %d\n", + reg_entry->token); + return DIAG_DCI_NO_REG; + } if (driver->dci_state == DIAG_DCI_NO_REG) return DIAG_DCI_NO_REG; @@ -2064,6 +2616,15 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) reg_entry->notification_list; new_entry->client_info.signal_type = reg_entry->signal_type; + new_entry->client_info.token = reg_entry->token; + switch (reg_entry->token) { + case DCI_LOCAL_PROC: + new_entry->num_buffers = NUM_DCI_PERIPHERALS; + break; + case DCI_MDM_PROC: + new_entry->num_buffers = 1; + break; + } new_entry->real_time = MODE_REALTIME; new_entry->in_service = 0; INIT_LIST_HEAD(&new_entry->list_write_buf); @@ -2074,7 +2635,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) driver->dci_client_id); goto fail_alloc; } - create_dci_log_mask_tbl(new_entry->dci_log_mask); + create_dci_log_mask_tbl(new_entry->dci_log_mask, DCI_LOG_MASK_CLEAN); new_entry->dci_event_mask = kzalloc(DCI_EVENT_MASK_SIZE, GFP_KERNEL); if (!new_entry->dci_event_mask) { @@ -2084,7 +2645,16 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) } create_dci_event_mask_tbl(new_entry->dci_event_mask); - for (i = 0; i < NUM_DCI_PROC; i++) { + new_entry->buffers = kzalloc(new_entry->num_buffers * + sizeof(struct diag_dci_buf_peripheral_t), + GFP_KERNEL); + if (!new_entry->buffers) { + pr_err("diag: Unable to allocate buffers for peripherals in %s\n", + __func__); + goto fail_alloc; + } + + for (i = 0; i < new_entry->num_buffers; i++) { proc_buf = &new_entry->buffers[i]; if (!proc_buf) goto fail_alloc; @@ -2120,7 +2690,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) reg_entry->client_id = driver->dci_client_id; driver->num_dci_client++; if (driver->num_dci_client == 1) - diag_update_proc_vote(DIAG_PROC_DCI, VOTE_UP); + diag_update_proc_vote(DIAG_PROC_DCI, VOTE_UP, reg_entry->token); queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work); mutex_unlock(&driver->dci_mutex); @@ -2128,7 +2698,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) fail_alloc: if (new_entry) { - for (i = 0; i < NUM_DCI_PROC; i++) { + for (i = 0; i < new_entry->num_buffers; i++) { proc_buf = &new_entry->buffers[i]; mutex_destroy(&proc_buf->health_mutex); mutex_destroy(&proc_buf->buf_primary->data_mutex); @@ -2156,10 +2726,13 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) struct list_head *start, *req_temp; struct dci_pkt_req_entry_t *req_entry = NULL; struct diag_smd_info *smd_info = NULL; + int token = DCI_LOCAL_PROC; if (!entry) return DIAG_DCI_NOT_SUPPORTED; + token = entry->client_info.token; + mutex_lock(&driver->dci_mutex); /* * Remove the entry from the list before freeing the buffers @@ -2172,17 +2745,19 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) * masks and send the masks to peripherals */ kfree(entry->dci_log_mask); - diag_update_userspace_clients(DCI_LOG_MASKS_TYPE); - diag_dci_invalidate_cumulative_log_mask(); - ret = diag_send_dci_event_mask(); + diag_dci_invalidate_cumulative_log_mask(token); + if (token == DCI_LOCAL_PROC) + diag_update_userspace_clients(DCI_LOG_MASKS_TYPE); + ret = dci_ops_tbl[token].send_log_mask(token); if (ret != DIAG_DCI_NO_ERROR) { mutex_unlock(&driver->dci_mutex); return ret; } kfree(entry->dci_event_mask); - diag_update_userspace_clients(DCI_EVENT_MASKS_TYPE); - diag_dci_invalidate_cumulative_event_mask(); - ret = diag_send_dci_log_mask(); + diag_dci_invalidate_cumulative_event_mask(token); + if (token == DCI_LOCAL_PROC) + diag_update_userspace_clients(DCI_EVENT_MASKS_TYPE); + ret = dci_ops_tbl[token].send_event_mask(token); if (ret != DIAG_DCI_NO_ERROR) { mutex_unlock(&driver->dci_mutex); return ret; @@ -2223,7 +2798,7 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) } mutex_unlock(&entry->write_buf_mutex); - for (i = 0; i < NUM_DCI_PROC; i++) { + for (i = 0; i < entry->num_buffers; i++) { proc_buf = &entry->buffers[i]; buf_entry = proc_buf->buf_curr; mutex_lock(&proc_buf->buf_mutex); @@ -2258,10 +2833,10 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) kfree(entry); if (driver->num_dci_client == 0) { - diag_update_proc_vote(DIAG_PROC_DCI, VOTE_DOWN); + diag_update_proc_vote(DIAG_PROC_DCI, VOTE_DOWN, token); } else { - real_time = diag_dci_get_cumulative_real_time(); - diag_update_real_time_vote(DIAG_PROC_DCI, real_time); + real_time = diag_dci_get_cumulative_real_time(token); + diag_update_real_time_vote(DIAG_PROC_DCI, real_time, token); } queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work); @@ -2346,6 +2921,13 @@ int diag_dci_copy_health_stats(struct diag_dci_health_stats_proc *stats_proc) if (!entry) return DIAG_DCI_NOT_SUPPORTED; + /* + * If the client has registered for remote processor, the + * proc field doesn't have any effect as they have only one buffer. + */ + if (entry->client_info.token) + proc = 0; + stats->stats.dropped_logs = 0; stats->stats.dropped_events = 0; stats->stats.received_logs = 0; @@ -2368,7 +2950,7 @@ int diag_dci_copy_health_stats(struct diag_dci_health_stats_proc *stats_proc) return DIAG_DCI_NO_ERROR; } - for (i = 0; i < NUM_DCI_PROC; i++) { + for (i = 0; i < entry->num_buffers; i++) { health = &entry->buffers[i].health; stats->stats.dropped_logs += health->dropped_logs; stats->stats.dropped_events += health->dropped_events; @@ -2385,3 +2967,15 @@ int diag_dci_copy_health_stats(struct diag_dci_health_stats_proc *stats_proc) } return DIAG_DCI_NO_ERROR; } + +int diag_dci_get_support_list(struct diag_dci_peripherals_t *support_list) +{ + if (!support_list) + return -ENOMEM; + + if (!VALID_DCI_TOKEN(support_list->proc)) + return -EIO; + + support_list->list = dci_ops_tbl[support_list->proc].peripheral_status; + return DIAG_DCI_NO_ERROR; +} diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h index 7c728403bff..809a93ef035 100644 --- a/drivers/char/diag/diag_dci.h +++ b/drivers/char/diag/diag_dci.h @@ -15,6 +15,7 @@ #define MAX_DCI_CLIENTS 10 #define DCI_PKT_RSP_CODE 0x93 #define DCI_DELAYED_RSP_CODE 0x94 +#define DCI_CONTROL_PKT_CODE 0x9A #define LOG_CMD_CODE 0x10 #define EVENT_CMD_CODE 0x60 #define DCI_PKT_RSP_TYPE 0 @@ -49,13 +50,26 @@ #define DCI_MAX_LOG_CODES 16 #define DCI_MAX_ITEMS_PER_LOG_CODE 512 +#define DCI_LOG_MASK_CLEAN 0 +#define DCI_LOG_MASK_DIRTY 1 + #define MIN_DELAYED_RSP_LEN 12 +/* + * Maximum data size that peripherals send = 8.5K log + + * DCI header + footer (6 bytes) + */ +#define MAX_DCI_PACKET_SZ 8710 + +#define DCI_LOCAL_PROC 0 +#define DCI_MDM_PROC 1 + +#define DCI_BRIDGE_MDM_IDX 1 +#define DCI_HSIC_CH_IDX 0 + +#define DCI_REMOTE_DATA 0 extern unsigned int dci_max_reg; extern unsigned int dci_max_clients; -extern unsigned char dci_cumulative_log_mask[DCI_LOG_MASK_SIZE]; -extern unsigned char dci_cumulative_event_mask[DCI_EVENT_MASK_SIZE]; -extern struct mutex dci_health_mutex; struct dci_pkt_req_entry_t { int client_id; @@ -68,7 +82,8 @@ struct diag_dci_reg_tbl_t { uint32_t client_id; uint16_t notification_list; int signal_type; -}; + int token; +} __packed; struct diag_dci_health_t { int dropped_logs; @@ -77,6 +92,14 @@ struct diag_dci_health_t { int received_events; }; +struct diag_dci_partial_pkt_t { + unsigned char *data; + uint32_t total_len; + uint32_t read_len; + uint32_t remaining; + uint8_t processing; +} __packed; + struct diag_dci_buffer_t { unsigned char *data; unsigned int data_len; @@ -105,7 +128,8 @@ struct diag_dci_client_tbl { unsigned char *dci_event_mask; uint8_t real_time; struct list_head track; - struct diag_dci_buf_peripheral_t buffers[NUM_DCI_PROC]; + struct diag_dci_buf_peripheral_t *buffers; + uint8_t num_buffers; uint8_t in_service; struct list_head list_write_buf; struct mutex write_buf_mutex; @@ -120,7 +144,12 @@ struct diag_dci_health_stats_proc { int client_id; struct diag_dci_health_stats health; int proc; -}; +} __packed; + +struct diag_dci_peripherals_t { + int proc; + uint16_t list; +} __packed; /* This is used for querying DCI Log or Event Mask */ @@ -138,6 +167,23 @@ struct diag_dci_pkt_header_t { int tag; } __packed; +struct diag_dci_header_t { + uint8_t start; + uint8_t version; + uint16_t length; + uint8_t cmd_code; +} __packed; + +struct dci_ops_tbl_t { + unsigned char log_mask_composite[DCI_LOG_MASK_SIZE]; + unsigned char event_mask_composite[DCI_EVENT_MASK_SIZE]; + int (*send_log_mask)(int token); + int (*send_event_mask)(int token); + uint16_t peripheral_status; +} __packed; + +extern struct dci_ops_tbl_t *dci_ops_tbl; + enum { DIAG_DCI_NO_ERROR = 1001, /* No error */ DIAG_DCI_NO_REG, /* Could not register */ @@ -156,9 +202,10 @@ struct diag_dci_data_info { char time_stamp[DIAG_TS_SIZE]; uint8_t peripheral; uint8_t ch_type; + uint8_t proc; }; -extern struct diag_dci_data_info *dci_data_smd; +extern struct diag_dci_data_info *dci_traffic; extern struct mutex dci_stat_mutex; #endif @@ -167,42 +214,53 @@ void diag_dci_exit(void); int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry); int diag_dci_deinit_client(struct diag_dci_client_tbl *entry); void diag_update_smd_dci_work_fn(struct work_struct *); -void diag_dci_notify_client(int peripheral_mask, int data); +void diag_dci_notify_client(int peripheral_mask, int data, int proc); void diag_dci_wakeup_clients(void); void diag_process_apps_dci_read_data(int data_type, void *buf, int recd_bytes); int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf, int recd_bytes); int diag_process_dci_transaction(unsigned char *buf, int len); void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, - struct diag_smd_info *smd_info); + int token); +void extract_dci_ctrl_pkt(unsigned char *buf, int len, int token); struct diag_dci_client_tbl *diag_dci_get_client_entry(int client_id); struct diag_dci_client_tbl *dci_lookup_client_entry_pid(int pid); +int diag_process_hsic_dci_read_data(int index, void *buf, int recd_bytes); +int diag_dci_get_support_list(struct diag_dci_peripherals_t *support_list); /* DCI Log streaming functions */ -void create_dci_log_mask_tbl(unsigned char *tbl_buf); void update_dci_cumulative_log_mask(int offset, unsigned int byte_index, - uint8_t byte_mask); -void diag_dci_invalidate_cumulative_log_mask(void); -int diag_send_dci_log_mask(void); -void extract_dci_log(unsigned char *buf, int len, int data_source); + uint8_t byte_mask, int token); +void diag_dci_invalidate_cumulative_log_mask(int token); +int diag_send_dci_log_mask(int token); +void extract_dci_log(unsigned char *buf, int len, int data_source, int token); int diag_dci_clear_log_mask(int client_id); int diag_dci_query_log_mask(struct diag_dci_client_tbl *entry, uint16_t log_code); /* DCI event streaming functions */ -void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask); -void diag_dci_invalidate_cumulative_event_mask(void); -int diag_send_dci_event_mask(void); -void extract_dci_events(unsigned char *buf, int len, int data_source); -void create_dci_event_mask_tbl(unsigned char *tbl_buf); +void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask, int token); +void diag_dci_invalidate_cumulative_event_mask(int token); +int diag_send_dci_event_mask(int token); +void extract_dci_events(unsigned char *buf, int len, int data_source, + int token); int diag_dci_clear_event_mask(int client_id); int diag_dci_query_event_mask(struct diag_dci_client_tbl *entry, uint16_t event_id); -void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type, - uint8_t peripheral); -uint8_t diag_dci_get_cumulative_real_time(void); -int diag_dci_set_real_time(int client_id, uint8_t real_time); +void diag_dci_record_traffic(int read_bytes, uint8_t ch_type, + uint8_t peripheral, uint8_t proc); +uint8_t diag_dci_get_cumulative_real_time(int token); +int diag_dci_set_real_time(struct diag_dci_client_tbl *entry, + uint8_t real_time); int diag_dci_copy_health_stats(struct diag_dci_health_stats_proc *stats_proc); /* Functions related to DCI wakeup sources */ void diag_dci_try_activate_wakeup_source(void); void diag_dci_try_deactivate_wakeup_source(void); int diag_dci_write_proc(int peripheral, int pkt_type, char *buf, int len); + +#ifdef CONFIG_DIAGFWD_BRIDGE_CODE +int diag_send_dci_log_mask_remote(int token); +int diag_send_dci_event_mask_remote(int token); +unsigned char *dci_get_buffer_from_bridge(int index); +int diag_dci_write_bridge(int index, unsigned char *buf, int len); +#endif + #endif diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c index d63d34bda18..b1d867591ff 100644 --- a/drivers/char/diag/diag_debugfs.c +++ b/drivers/char/diag/diag_debugfs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -33,14 +33,14 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf, { char *buf; int ret; - + unsigned int buf_size; buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL); if (!buf) { pr_err("diag: %s, Error allocating memory\n", __func__); return -ENOMEM; } - - ret = scnprintf(buf, DEBUG_BUF_SIZE, + buf_size = ksize(buf); + ret = scnprintf(buf, buf_size, "modem ch: 0x%p\n" "lpass ch: 0x%p\n" "riva ch: 0x%p\n" @@ -180,10 +180,10 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf, driver->rcvd_feature_mask[LPASS_DATA], driver->rcvd_feature_mask[WCNSS_DATA], driver->logging_mode, - driver->real_time_mode); + driver->real_time_mode[DIAG_LOCAL_PROC]); #ifdef CONFIG_DIAG_OVER_USB - ret += scnprintf(buf+ret, DEBUG_BUF_SIZE, + ret += scnprintf(buf+ret, buf_size-ret, "usb_connected: %d\n", driver->usb_connected); #endif @@ -199,8 +199,9 @@ static ssize_t diag_dbgfs_read_dcistats(struct file *file, char *buf = NULL; unsigned int bytes_remaining, bytes_written = 0; unsigned int bytes_in_buf = 0, i = 0; - struct diag_dci_data_info *temp_data = dci_data_smd; - int buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count; + struct diag_dci_data_info *temp_data = dci_traffic; + unsigned int buf_size; + buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count; if (diag_dbgfs_dci_finished) { diag_dbgfs_dci_finished = 0; @@ -213,6 +214,7 @@ static ssize_t diag_dbgfs_read_dcistats(struct file *file, return -ENOMEM; } + buf_size = ksize(buf); bytes_remaining = buf_size; if (diag_dbgfs_dci_data_index == 0) { @@ -223,7 +225,8 @@ static ssize_t diag_dbgfs_read_dcistats(struct file *file, "dci real time vote: %d\n", driver->num_dci_client, (driver->proc_active_mask & DIAG_PROC_DCI) ? 1 : 0, - (driver->proc_rt_vote_mask & DIAG_PROC_DCI) ? 1 : 0); + (driver->proc_rt_vote_mask[DIAG_LOCAL_PROC] & + DIAG_PROC_DCI) ? 1 : 0); bytes_in_buf += bytes_written; bytes_remaining -= bytes_written; #ifdef CONFIG_DIAG_OVER_USB @@ -252,11 +255,13 @@ static ssize_t diag_dbgfs_read_dcistats(struct file *file, "i %-5ld\t" "s %-5d\t" "p %-5d\t" + "r %-5d\t" "c %-5d\t" "t %-15s\n", temp_data->iteration, temp_data->data_size, temp_data->peripheral, + temp_data->proc, temp_data->ch_type, temp_data->time_stamp); bytes_in_buf += bytes_written; @@ -281,6 +286,7 @@ static ssize_t diag_dbgfs_read_workpending(struct file *file, { char *buf; int ret; + unsigned int buf_size; buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL); if (!buf) { @@ -288,7 +294,8 @@ static ssize_t diag_dbgfs_read_workpending(struct file *file, return -ENOMEM; } - ret = scnprintf(buf, DEBUG_BUF_SIZE, + buf_size = ksize(buf); + ret = scnprintf(buf, buf_size, "Pending status for work_stucts:\n" "diag_drain_work: %d\n" "Modem data diag_read_smd_work: %d\n" @@ -336,7 +343,7 @@ static ssize_t diag_dbgfs_read_workpending(struct file *file, diag_notify_update_smd_work))); #ifdef CONFIG_DIAG_OVER_USB - ret += scnprintf(buf+ret, DEBUG_BUF_SIZE, + ret += scnprintf(buf+ret, buf_size-ret, "diag_proc_hdlc_work: %d\n" "diag_read_work: %d\n", work_pending(&(driver->diag_proc_hdlc_work)), @@ -357,7 +364,8 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf, unsigned int bytes_remaining; unsigned int bytes_in_buffer = 0; unsigned int bytes_written; - int buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count; + unsigned int buf_size; + buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count; if (diag_dbgfs_table_index >= diag_max_reg) { /* Done. Reset to prepare for future requests */ @@ -370,7 +378,7 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf, pr_err("diag: %s, Error allocating memory\n", __func__); return -ENOMEM; } - + buf_size = ksize(buf); bytes_remaining = buf_size; if (diag_dbgfs_table_index == 0) { @@ -379,6 +387,7 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf, "WCNSS: %d, APPS: %d\n", MODEM_DATA, LPASS_DATA, WCNSS_DATA, APPS_DATA); bytes_in_buffer += bytes_written; + bytes_remaining -= bytes_written; } for (i = diag_dbgfs_table_index; i < diag_max_reg; i++) { @@ -422,14 +431,15 @@ static ssize_t diag_dbgfs_read_mempool(struct file *file, char __user *ubuf, { char *buf = NULL; int ret = 0, i = 0; - + unsigned int buf_size; buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL); if (ZERO_OR_NULL_PTR(buf)) { pr_err("diag: %s, Error allocating memory\n", __func__); return -ENOMEM; } + buf_size = ksize(buf); - ret = scnprintf(buf, DEBUG_BUF_SIZE, + ret = scnprintf(buf, buf_size, "POOL_TYPE_COPY: [0x%p : 0x%p] count = %d\n" "POOL_TYPE_HDLC: [0x%p : 0x%p] count = %d\n" "POOL_TYPE_USER: [0x%p : 0x%p] count = %d\n" @@ -451,10 +461,10 @@ static ssize_t diag_dbgfs_read_mempool(struct file *file, char __user *ubuf, diag_pools_array[POOL_DCI_IDX], driver->count_dci_pool); - for (i = 0; i < MAX_HSIC_CH; i++) { + for (i = 0; i < MAX_HSIC_DATA_CH; i++) { if (!diag_hsic[i].hsic_inited) continue; - ret += scnprintf(buf+ret, DEBUG_BUF_SIZE-ret, + ret += scnprintf(buf+ret, buf_size-ret, "POOL_TYPE_HSIC_%d: [0x%p : 0x%p] count = %d\n", i+1, diag_hsic[i].diag_hsic_pool, @@ -462,10 +472,10 @@ static ssize_t diag_dbgfs_read_mempool(struct file *file, char __user *ubuf, diag_hsic[i].count_hsic_pool); } - for (i = 0; i < MAX_HSIC_CH; i++) { + for (i = 0; i < MAX_HSIC_DATA_CH; i++) { if (!diag_hsic[i].hsic_inited) continue; - ret += scnprintf(buf+ret, DEBUG_BUF_SIZE-ret, + ret += scnprintf(buf+ret, buf_size-ret, "POOL_TYPE_HSIC_%d_WRITE: [0x%p : 0x%p] count = %d\n", i+1, diag_hsic[i].diag_hsic_write_pool, @@ -484,6 +494,7 @@ static ssize_t diag_dbgfs_read_mempool(struct file *file, char __user *ubuf, { char *buf = NULL; int ret = 0; + unsigned int buf_size; buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL); if (ZERO_OR_NULL_PTR(buf)) { @@ -491,7 +502,8 @@ static ssize_t diag_dbgfs_read_mempool(struct file *file, char __user *ubuf, return -ENOMEM; } - ret = scnprintf(buf, DEBUG_BUF_SIZE, + buf_size = ksize(buf); + ret = scnprintf(buf, buf_size, "POOL_TYPE_COPY: [0x%p : 0x%p] count = %d\n" "POOL_TYPE_HDLC: [0x%p : 0x%p] count = %d\n" "POOL_TYPE_USER: [0x%p : 0x%p] count = %d\n" @@ -530,10 +542,12 @@ static ssize_t diag_dbgfs_read_bridge(struct file *file, char __user *ubuf, unsigned int bytes_remaining; unsigned int bytes_in_buffer = 0; unsigned int bytes_written; - int buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count; + unsigned int buf_size; int bytes_hsic_inited = 45; int bytes_hsic_not_inited = 410; + buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count; + if (diag_dbgfs_finished) { diag_dbgfs_finished = 0; return 0; @@ -545,6 +559,7 @@ static ssize_t diag_dbgfs_read_bridge(struct file *file, char __user *ubuf, return -ENOMEM; } + buf_size = ksize(buf); bytes_remaining = buf_size; /* Only one smux for now */ @@ -569,7 +584,7 @@ static ssize_t diag_dbgfs_read_bridge(struct file *file, char __user *ubuf, bytes_in_buffer += bytes_written; bytes_remaining = buf_size - bytes_in_buffer; - for (i = 0; i < MAX_HSIC_CH; i++) { + for (i = 0; i < MAX_HSIC_DATA_CH; i++) { if (diag_hsic[i].hsic_inited) { /* Check if there is room to add another HSIC entry */ if (bytes_remaining < bytes_hsic_inited) @@ -696,9 +711,9 @@ void diag_debugfs_init(void) diag_dbgfs_dci_finished = 0; /* DCI related structures */ - dci_data_smd = kzalloc(sizeof(struct diag_dci_data_info) * + dci_traffic = kzalloc(sizeof(struct diag_dci_data_info) * DIAG_DCI_DEBUG_CNT, GFP_KERNEL); - if (ZERO_OR_NULL_PTR(dci_data_smd)) + if (ZERO_OR_NULL_PTR(dci_traffic)) pr_warn("diag: could not allocate memory for dci debug info\n"); mutex_init(&dci_stat_mutex); @@ -711,7 +726,7 @@ void diag_debugfs_cleanup(void) diag_dbgfs_dent = NULL; } - kfree(dci_data_smd); + kfree(dci_traffic); mutex_destroy(&dci_stat_mutex); } #else diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index efdd902cb07..a6161abe09b 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-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 @@ -334,7 +334,7 @@ void diag_mask_update_fn(struct work_struct *work) if (smd_info->notify_context == SMD_EVENT_OPEN) diag_send_diag_mode_update_by_smd(smd_info, - driver->real_time_mode); + driver->real_time_mode[DIAG_LOCAL_PROC]); smd_info->notify_context = 0; } diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index 207f77d5943..3284aba4c65 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -41,8 +41,12 @@ #define POOL_TYPE_WRITE_STRUCT 4 #define POOL_TYPE_HSIC 5 #define POOL_TYPE_HSIC_2 6 +#define POOL_TYPE_HSIC_DCI 7 +#define POOL_TYPE_HSIC_DCI_2 8 #define POOL_TYPE_HSIC_WRITE 11 #define POOL_TYPE_HSIC_2_WRITE 12 +#define POOL_TYPE_HSIC_DCI_WRITE 13 +#define POOL_TYPE_HSIC_DCI_2_WRITE 14 #define POOL_TYPE_ALL 10 #define POOL_TYPE_DCI 20 @@ -53,11 +57,11 @@ #define POOL_DCI_IDX 4 #define POOL_BRIDGE_BASE POOL_DCI_IDX #define POOL_HSIC_IDX (POOL_BRIDGE_BASE + 1) -#define POOL_HSIC_2_IDX (POOL_BRIDGE_BASE + 2) +#define POOL_HSIC_DCI_IDX (POOL_BRIDGE_BASE + 2) #define POOL_HSIC_3_IDX (POOL_BRIDGE_BASE + 3) #define POOL_HSIC_4_IDX (POOL_BRIDGE_BASE + 4) #define POOL_HSIC_WRITE_IDX (POOL_BRIDGE_BASE + 5) -#define POOL_HSIC_2_WRITE_IDX (POOL_BRIDGE_BASE + 6) +#define POOL_HSIC_DCI_WRITE_IDX (POOL_BRIDGE_BASE + 6) #define POOL_HSIC_3_WRITE_IDX (POOL_BRIDGE_BASE + 7) #define POOL_HSIC_4_WRITE_IDX (POOL_BRIDGE_BASE + 8) @@ -152,7 +156,10 @@ * processor. This doesn't mean that a peripheral has the * feature. */ -#define NUM_DCI_PROC (NUM_SMD_DATA_CHANNELS + 1) +#define NUM_DCI_PERIPHERALS (NUM_SMD_DATA_CHANNELS + 1) + +/* Indicates the number of processors that support DCI */ +#define NUM_DCI_PROC 2 #define SMD_DATA_TYPE 0 #define SMD_CNTL_TYPE 1 @@ -170,6 +177,19 @@ #define DIAG_TS_SIZE 50 +#define MAX_HSIC_DATA_CH 2 +#define MAX_HSIC_DCI_CH 2 +#define MAX_HSIC_CH (MAX_HSIC_DATA_CH + MAX_HSIC_DCI_CH) + +#define DIAG_LOCAL_PROC 0 +#ifdef CONFIG_DIAGFWD_BRIDGE_CODE +/* Local Processor + HSIC channels */ +#define DIAG_NUM_PROC (1 + MAX_HSIC_DATA_CH) +#else +/* Local Processor only */ +#define DIAG_NUM_PROC 1 +#endif + /* Maximum number of pkt reg supported at initialization*/ extern int diag_max_reg; extern int diag_threshold_reg; @@ -185,8 +205,6 @@ do { \ enum remote_procs { MDM = 1, MDM2 = 2, - MDM3 = 3, - MDM4 = 4, QSC = 5, }; @@ -249,6 +267,11 @@ struct real_time_vote_t { uint8_t real_time_vote; } __packed; +struct real_time_query_t { + int real_time; + int proc; +} __packed; + /* This structure is defined in USB header file */ #ifndef CONFIG_DIAG_OVER_USB struct diag_request { @@ -403,10 +426,10 @@ struct diagchar_dev { unsigned hdlc_escape; int in_busy_pktdata; /* Variables for non real time mode */ - int real_time_mode; + int real_time_mode[DIAG_NUM_PROC]; int real_time_update_busy; uint16_t proc_active_mask; - uint16_t proc_rt_vote_mask; + uint16_t proc_rt_vote_mask[DIAG_NUM_PROC]; struct mutex real_time_mutex; struct work_struct diag_real_time_work; struct workqueue_struct *diag_real_time_wq; @@ -471,7 +494,9 @@ struct diagchar_dev { }; extern struct diag_bridge_dev *diag_bridge; +extern struct diag_bridge_dci_dev *diag_bridge_dci; extern struct diag_hsic_dev *diag_hsic; +extern struct diag_hsic_dci_dev *diag_hsic_dci; extern struct diagchar_dev *driver; extern int wrap_enabled; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 9bbf90bb269..691a98ee3e9 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -165,7 +165,7 @@ void diag_clear_hsic_tbl(void) int i, j; /* Clear for all active HSIC bridges */ - for (j = 0; j < MAX_HSIC_CH; j++) { + for (j = 0; j < MAX_HSIC_DATA_CH; j++) { if (diag_hsic[j].hsic_ch) { diag_hsic[j].num_hsic_buf_tbl_entries = 0; for (i = 0; i < diag_hsic[j].poolsize_hsic_write; i++) { @@ -290,12 +290,14 @@ static int diagchar_close(struct inode *inode, struct file *file) if (driver->socket_process && (driver->socket_process->tgid == current->tgid)) { driver->socket_process = NULL; - diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN); + diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN, + ALL_PROC); } if (driver->callback_process && (driver->callback_process->tgid == current->tgid)) { driver->callback_process = NULL; - diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN); + diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN, + ALL_PROC); } mutex_unlock(&driver->diagchar_mutex); @@ -303,7 +305,8 @@ static int diagchar_close(struct inode *inode, struct file *file) /* If the SD logging process exits, change logging to USB mode */ if (driver->logging_process_id == current->tgid) { driver->logging_mode = USB_MODE; - diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN); + diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN, + ALL_PROC); diagfwd_connect(); #ifdef CONFIG_DIAGFWD_BRIDGE_CODE diag_clear_hsic_tbl(); @@ -359,6 +362,9 @@ int diag_find_polling_reg(int i) else if (subsys_id == 0x32 && cmd_code_hi >= 0x03 && cmd_code_lo <= 0x03) return 1; + else if (subsys_id == 0x57 && cmd_code_hi >= 0x0E && + cmd_code_lo <= 0x0E) + return 1; } return 0; } @@ -428,8 +434,6 @@ static int diag_get_remote(int remote_info) switch (val) { case MDM: case MDM2: - case MDM3: - case MDM4: case QSC: remote_val = -remote_info; break; @@ -448,7 +452,7 @@ uint16_t diag_get_remote_device_mask(void) int i; /* Check for MDM processor */ - for (i = 0; i < MAX_HSIC_CH; i++) + for (i = 0; i < MAX_HSIC_DATA_CH; i++) if (diag_hsic[i].hsic_inited) remote_dev |= 1 << i; @@ -471,7 +475,7 @@ int diag_copy_remote(char __user *buf, size_t count, int *pret, int *pnum_data) struct diag_write_device hsic_buf_tbl[NUM_HSIC_BUF_TBL_ENTRIES]; remote_token = diag_get_remote(MDM); - for (index = 0; index < MAX_HSIC_CH; index++) { + for (index = 0; index < MAX_HSIC_DATA_CH; index++) { if (!diag_hsic[index].hsic_inited) { remote_token--; continue; @@ -630,7 +634,7 @@ drop: if (total_data_len > 0) { /* Copy the total data length */ - COPY_USER_SPACE_OR_EXIT(buf+4, total_data_len, 4); + COPY_USER_SPACE_OR_EXIT(buf+8, total_data_len, 4); ret -= 4; } else { pr_debug("diag: In %s, Trying to copy ZERO bytes, total_data_len: %d\n", @@ -784,7 +788,7 @@ void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode) } else if (old_mode == NO_LOGGING_MODE && new_mode == MEMORY_DEVICE_MODE) { int i; - for (i = 0; i < MAX_HSIC_CH; i++) + for (i = 0; i < MAX_HSIC_DATA_CH; i++) if (diag_hsic[i].hsic_inited) diag_hsic[i].hsic_data_requested = driver->real_time_mode ? 1 : 0; @@ -851,10 +855,9 @@ void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode) } #endif -int diag_switch_logging(unsigned long ioarg) +int diag_switch_logging(int requested_mode) { int temp = 0, success = -EINVAL, status = 0; - int requested_mode = (int)ioarg; switch (requested_mode) { case USB_MODE: @@ -878,10 +881,10 @@ int diag_switch_logging(unsigned long ioarg) return 0; } - diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_UP); + diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_UP, ALL_PROC); if (requested_mode != MEMORY_DEVICE_MODE) diag_update_real_time_vote(DIAG_PROC_MEMORY_DEVICE, - MODE_REALTIME); + MODE_REALTIME, ALL_PROC); if (!(requested_mode == MEMORY_DEVICE_MODE && driver->logging_mode == USB_MODE)) @@ -970,14 +973,16 @@ long diagchar_ioctl(struct file *filp, unsigned int iocmd, unsigned long ioarg) { int i, result = -EINVAL, interim_size = 0, client_id = 0, real_time = 0; - int retry_count = 0, timer = 0; - uint16_t support_list = 0, interim_rsp_id, remote_dev; + int retry_count = 0, timer = 0, req_logging_mode = 0; + uint16_t interim_rsp_id, remote_dev; struct diag_dci_reg_tbl_t *dci_reg_params; struct diag_dci_health_stats_proc stats; struct diag_log_event_stats le_stats; struct diagpkt_delay_params delay_params; - struct real_time_vote_t rt_vote; + struct real_time_vote_t vote; struct diag_dci_client_tbl *dci_client = NULL; + struct diag_dci_peripherals_t dci_support; + struct real_time_query_t rt_query; switch (iocmd) { case DIAG_IOCTL_COMMAND_REG: @@ -1027,16 +1032,16 @@ long diagchar_ioctl(struct file *filp, result = diag_dci_deinit_client(dci_client); break; case DIAG_IOCTL_DCI_SUPPORT: - support_list |= DIAG_CON_APSS; - for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) { - if (driver->smd_dci[i].ch) - support_list |= - driver->smd_dci[i].peripheral_mask; - } - if (copy_to_user((void *)ioarg, &support_list, - sizeof(uint16_t))) + if (copy_from_user(&dci_support, (void *)ioarg, + sizeof(struct diag_dci_peripherals_t))) return -EFAULT; - result = DIAG_DCI_NO_ERROR; + result = diag_dci_get_support_list(&dci_support); + if (result != DIAG_DCI_NO_ERROR) + break; + if (copy_to_user((void *)ioarg, &dci_support, + sizeof(struct diag_dci_peripherals_t))) + return -EFAULT; + break; case DIAG_IOCTL_DCI_HEALTH_STATS: if (copy_from_user(&stats, (void *)ioarg, @@ -1103,7 +1108,10 @@ long diagchar_ioctl(struct file *filp, result = 1; break; case DIAG_IOCTL_SWITCH_LOGGING: - result = diag_switch_logging(ioarg); + if (copy_from_user((void *)&req_logging_mode, (void *)ioarg, + sizeof(int))) + return -EFAULT; + result = diag_switch_logging(req_logging_mode); break; case DIAG_IOCTL_REMOTE_DEV: remote_dev = diag_get_remote_device_mask(); @@ -1113,24 +1121,34 @@ long diagchar_ioctl(struct file *filp, result = 1; break; case DIAG_IOCTL_VOTE_REAL_TIME: - if (copy_from_user(&rt_vote, (void *)ioarg, sizeof(struct + if (copy_from_user(&vote, (void *)ioarg, sizeof(struct real_time_vote_t))) return -EFAULT; driver->real_time_update_busy++; - if (rt_vote.proc == DIAG_PROC_DCI) { - diag_dci_set_real_time(rt_vote.client_id, - rt_vote.real_time_vote); - real_time = diag_dci_get_cumulative_real_time(); + if (vote.proc == DIAG_PROC_DCI) { + dci_client = diag_dci_get_client_entry(vote.client_id); + if (!dci_client) { + driver->real_time_update_busy--; + result = DIAG_DCI_NOT_SUPPORTED; + break; + } + diag_dci_set_real_time(dci_client, vote.real_time_vote); + real_time = diag_dci_get_cumulative_real_time( + dci_client->client_info.token); + diag_update_real_time_vote(vote.proc, real_time, + dci_client->client_info.token); } else { - real_time = rt_vote.real_time_vote; + real_time = vote.real_time_vote; + diag_update_real_time_vote(vote.proc, real_time, + ALL_PROC); } - diag_update_real_time_vote(rt_vote.proc, real_time); queue_work(driver->diag_real_time_wq, - &driver->diag_real_time_work); + &driver->diag_real_time_work); result = 0; break; case DIAG_IOCTL_GET_REAL_TIME: - if (copy_from_user(&real_time, (void *)ioarg, sizeof(int))) + if (copy_from_user(&rt_query, (void *)ioarg, sizeof(struct + real_time_query_t))) return -EFAULT; while (retry_count < 3) { if (driver->real_time_update_busy > 0) { @@ -1141,9 +1159,16 @@ long diagchar_ioctl(struct file *filp, for (timer = 0; timer < 5; timer++) usleep_range(10000, 10100); } else { - real_time = driver->real_time_mode; - if (copy_to_user((void *)ioarg, &real_time, - sizeof(int))) + if (rt_query.proc < 0 || + rt_query.proc > DIAG_NUM_PROC) { + pr_err("diag: Invalid proc %d in %s\n", + rt_query.proc, __func__); + return -EINVAL; + } + real_time = + driver->real_time_mode[rt_query.proc]; + if (copy_to_user((void *)ioarg, &rt_query, + sizeof(struct real_time_query_t))) return -EFAULT; result = 0; break; @@ -1158,6 +1183,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct diag_dci_client_tbl *entry; + struct list_head *start, *temp; int index = -1, i = 0, ret = 0; int num_data = 0, data_type; int remote_token; @@ -1402,8 +1428,8 @@ drop: data_type = driver->data_ready[index] & DCI_EVENT_MASKS_TYPE; COPY_USER_SPACE_OR_EXIT(buf, data_type, 4); COPY_USER_SPACE_OR_EXIT(buf+4, driver->num_dci_client, 4); - COPY_USER_SPACE_OR_EXIT(buf+8, *(dci_cumulative_event_mask), - DCI_EVENT_MASK_SIZE); + COPY_USER_SPACE_OR_EXIT(buf + 8, (dci_ops_tbl[DCI_LOCAL_PROC]. + event_mask_composite), DCI_EVENT_MASK_SIZE); driver->data_ready[index] ^= DCI_EVENT_MASKS_TYPE; goto exit; } @@ -1413,8 +1439,8 @@ drop: data_type = driver->data_ready[index] & DCI_LOG_MASKS_TYPE; COPY_USER_SPACE_OR_EXIT(buf, data_type, 4); COPY_USER_SPACE_OR_EXIT(buf+4, driver->num_dci_client, 4); - COPY_USER_SPACE_OR_EXIT(buf+8, *(dci_cumulative_log_mask), - DCI_LOG_MASK_SIZE); + COPY_USER_SPACE_OR_EXIT(buf+8, (dci_ops_tbl[DCI_LOCAL_PROC]. + log_mask_composite), DCI_LOG_MASK_SIZE); driver->data_ready[index] ^= DCI_LOG_MASKS_TYPE; goto exit; } @@ -1423,12 +1449,17 @@ drop: /* Copy the type of data being passed */ data_type = driver->data_ready[index] & DCI_DATA_TYPE; driver->data_ready[index] ^= DCI_DATA_TYPE; - /* check the current client and copy its data */ - entry = dci_lookup_client_entry_pid(current->tgid); - if (entry) { + list_for_each_safe(start, temp, &driver->dci_client_list) { + entry = list_entry(start, struct diag_dci_client_tbl, + track); + if (entry->client->tgid != current->tgid) + continue; if (!entry->in_service) - goto exit; - COPY_USER_SPACE_OR_EXIT(buf, data_type, 4); + continue; + COPY_USER_SPACE_OR_EXIT(buf + ret, data_type, + sizeof(int)); + COPY_USER_SPACE_OR_EXIT(buf + ret, + entry->client_info.token, sizeof(int)); exit_stat = diag_copy_dci(buf, count, entry, &ret); if (exit_stat == 1) goto exit; @@ -1605,7 +1636,7 @@ static ssize_t diagchar_write(struct file *file, const char __user *buf, #endif #ifdef CONFIG_DIAGFWD_BRIDGE_CODE /* send masks to All 9k */ - if ((remote_proc >= MDM) && (remote_proc <= MDM4)) { + if ((remote_proc >= MDM) && (remote_proc <= MDM2)) { index = remote_proc - MDM; if (diag_hsic[index].hsic_ch && (payload_size > 0)) { /* wait sending mask updates @@ -1618,7 +1649,8 @@ static ssize_t diagchar_write(struct file *file, const char __user *buf, diag_hsic[index].in_busy_hsic_write = 1; diag_hsic[index].in_busy_hsic_read_on_device = 0; - err = diag_bridge_write(index, + err = diag_bridge_write( + hsic_data_bridge_map[index], (char *)buf_hdlc, payload_size + 3); if (err) { pr_err("diag: err sending mask to MDM: %d\n", @@ -1703,7 +1735,7 @@ static ssize_t diagchar_write(struct file *file, const char __user *buf, #endif #ifdef CONFIG_DIAGFWD_BRIDGE_CODE /* send masks to All 9k */ - if ((remote_proc >= MDM) && (remote_proc <= MDM4) && + if ((remote_proc >= MDM) && (remote_proc <= MDM2) && (payload_size > 0)) { index = remote_proc - MDM; /* @@ -1726,7 +1758,8 @@ static ssize_t diagchar_write(struct file *file, const char __user *buf, diag_hsic[index].in_busy_hsic_write = 1; diag_hsic[index].in_busy_hsic_read_on_device = 0; - err = diag_bridge_write(index, + err = diag_bridge_write( + hsic_data_bridge_map[index], driver->user_space_data_buf + token_offset, payload_size); if (err) { @@ -1951,13 +1984,16 @@ fail_free_copy: static void diag_real_time_info_init(void) { + int i; if (!driver) return; - driver->real_time_mode = 1; + for (i = 0; i < DIAG_NUM_PROC; i++) { + driver->real_time_mode[i] = 1; + driver->proc_rt_vote_mask[i] |= DIAG_PROC_DCI; + driver->proc_rt_vote_mask[i] |= DIAG_PROC_MEMORY_DEVICE; + } driver->real_time_update_busy = 0; driver->proc_active_mask = 0; - driver->proc_rt_vote_mask |= DIAG_PROC_DCI; - driver->proc_rt_vote_mask |= DIAG_PROC_MEMORY_DEVICE; driver->diag_real_time_wq = create_singlethread_workqueue( "diag_real_time_wq"); INIT_WORK(&(driver->diag_real_time_work), diag_real_time_work_fn); @@ -2119,8 +2155,10 @@ inline void diag_sdio_fn(int type) {} #ifdef CONFIG_DIAGFWD_BRIDGE_CODE void diagfwd_bridge_fn(int type) { - if (type == EXIT) + if (type == EXIT) { diagfwd_bridge_exit(); + diagfwd_bridge_dci_exit(); + } } #else inline void diagfwd_bridge_fn(int type) { } @@ -2135,14 +2173,26 @@ static int __init diagchar_init(void) ret = 0; driver = kzalloc(sizeof(struct diagchar_dev) + 5, GFP_KERNEL); #ifdef CONFIG_DIAGFWD_BRIDGE_CODE - diag_bridge = kzalloc(MAX_BRIDGES * sizeof(struct diag_bridge_dev), + diag_bridge = kzalloc(MAX_BRIDGES_DATA * sizeof(struct diag_bridge_dev), GFP_KERNEL); if (!diag_bridge) pr_warn("diag: could not allocate memory for bridges\n"); - diag_hsic = kzalloc(MAX_HSIC_CH * sizeof(struct diag_hsic_dev), + diag_bridge_dci = kzalloc(MAX_BRIDGES_DCI * + sizeof(struct diag_bridge_dci_dev), GFP_KERNEL); + if (!diag_bridge_dci) { + pr_warn("diag: could not allocate memory for dci bridges\n"); + goto fail; + } + diag_hsic = kzalloc(MAX_HSIC_DATA_CH * sizeof(struct diag_hsic_dev), GFP_KERNEL); if (!diag_hsic) pr_warn("diag: could not allocate memory for hsic ch\n"); + diag_hsic_dci = kzalloc(MAX_HSIC_DCI_CH * + sizeof(struct diag_hsic_dci_dev), GFP_KERNEL); + if (!diag_hsic_dci) { + pr_warn("diag: could not allocate memory for hsic dci ch\n"); + goto fail; + } #endif if (driver) { @@ -2177,8 +2227,14 @@ static int __init diagchar_init(void) diag_masks_init(); diagfwd_init(); #ifdef CONFIG_DIAGFWD_BRIDGE_CODE - diagfwd_bridge_init(HSIC); - diagfwd_bridge_init(HSIC_2); + diagfwd_bridge_init(HSIC_DATA_CH); + diagfwd_bridge_init(HSIC_DATA_CH_2); + ret = diagfwd_bridge_dci_init(HSIC_DCI_CH); + if (ret) + goto fail; + ret = diagfwd_bridge_dci_init(HSIC_DCI_CH_2); + if (ret) + goto fail; /* register HSIC device */ ret = platform_driver_register(&msm_hsic_ch_driver); if (ret) diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index 5846caa882e..86ed9212ce0 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -2180,7 +2180,8 @@ void diag_smd_notify(void *ctxt, unsigned event) } else if (smd_info->type == SMD_DCI_TYPE) { /* Notify the clients of the close */ diag_dci_notify_client(smd_info->peripheral_mask, - DIAG_STATUS_CLOSED); + DIAG_STATUS_CLOSED, + DCI_LOCAL_PROC); } else if (smd_info->type == SMD_CNTL_TYPE) { diag_cntl_stm_notify(smd_info, CLEAR_PERIPHERAL_STM_STATE); @@ -2200,7 +2201,7 @@ void diag_smd_notify(void *ctxt, unsigned event) &(smd_info->diag_notify_update_smd_work)); /* Notify the clients of the open */ diag_dci_notify_client(smd_info->peripheral_mask, - DIAG_STATUS_OPEN); + DIAG_STATUS_OPEN, DCI_LOCAL_PROC); } } else if (event == SMD_EVENT_DATA && !driver->real_time_mode && smd_info->type == SMD_DATA_TYPE) { @@ -2588,7 +2589,8 @@ void diagfwd_init(void) diag_debug_buf_idx = 0; driver->read_len_legacy = 0; driver->use_device_tree = has_device_tree(); - driver->real_time_mode = 1; + for (i = 0; i < DIAG_NUM_PROC; i++) + driver->real_time_mode[i] = 1; /* * The number of entries in table of buffers * should not be any smaller than hdlc poolsize. diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h index 7b2ded3c9ce..0f912d704bd 100644 --- a/drivers/char/diag/diagfwd.h +++ b/drivers/char/diag/diagfwd.h @@ -47,7 +47,7 @@ void diag_smd_notify(void *ctxt, unsigned event); int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral, int type); void diag_smd_destructor(struct diag_smd_info *smd_info); -int diag_switch_logging(unsigned long); +int diag_switch_logging(int); int diag_command_reg(unsigned long); void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode); void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode); diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c index 142d15a6f21..46a8b369960 100644 --- a/drivers/char/diag/diagfwd_bridge.c +++ b/drivers/char/diag/diagfwd_bridge.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -31,6 +31,7 @@ #include "diagfwd_bridge.h" struct diag_bridge_dev *diag_bridge; +struct diag_bridge_dci_dev *diag_bridge_dci; /* diagfwd_connect_bridge is called when the USB mdm channel is connected */ int diagfwd_connect_bridge(int process_cable) @@ -39,7 +40,7 @@ int diagfwd_connect_bridge(int process_cable) pr_debug("diag: in %s\n", __func__); - for (i = 0; i < MAX_BRIDGES; i++) + for (i = 0; i < MAX_BRIDGES_DATA; i++) if (diag_bridge[i].enabled) connect_bridge(process_cable, i); return 0; @@ -67,7 +68,7 @@ void connect_bridge(int process_cable, uint8_t index) diagfwd_connect_smux(); } } else { - if (index >= MAX_HSIC_CH) { + if (index >= MAX_HSIC_DATA_CH) { pr_err("diag: Invalid hsic channel index %d in %s\n", index, __func__); mutex_unlock(&diag_bridge[index].bridge_mutex); @@ -83,8 +84,9 @@ void connect_bridge(int process_cable, uint8_t index) if (!diag_hsic[index].hsic_device_opened) { hsic_diag_bridge_ops[index].ctxt = (void *)(int)(index); - err = diag_bridge_open(index, - &hsic_diag_bridge_ops[index]); + err = diag_bridge_open( + hsic_data_bridge_map[index], + &hsic_diag_bridge_ops[index]); if (err) { pr_err("diag: HSIC channel open error: %d\n", err); @@ -127,7 +129,7 @@ int diagfwd_disconnect_bridge(int process_cable) int i; pr_debug("diag: In %s, process_cable: %d\n", __func__, process_cable); - for (i = 0; i < MAX_BRIDGES; i++) { + for (i = 0; i < MAX_BRIDGES_DATA; i++) { if (diag_bridge[i].enabled) { mutex_lock(&diag_bridge[i].bridge_mutex); /* If the usb cable is being disconnected */ @@ -271,10 +273,8 @@ void diagfwd_bridge_init(int index) int ret; unsigned char name[20]; - if (index == HSIC) { + if (index == HSIC_DATA_CH) { strlcpy(name, "hsic", sizeof(name)); - } else if (index == HSIC_2) { - strlcpy(name, "hsic_2", sizeof(name)); } else if (index == SMUX) { strlcpy(name, "smux", sizeof(name)); } else { @@ -306,18 +306,15 @@ void diagfwd_bridge_init(int index) goto err; mutex_init(&diag_bridge[index].bridge_mutex); - if (index == HSIC || index == HSIC_2) { + if (index == HSIC_DATA_CH) { INIT_WORK(&(diag_bridge[index].usb_read_complete_work), diag_usb_read_complete_hsic_fn); #ifdef CONFIG_DIAG_OVER_USB INIT_WORK(&(diag_bridge[index].diag_read_work), diag_read_usb_hsic_work_fn); - if (index == HSIC) + if (index == HSIC_DATA_CH) diag_bridge[index].ch = usb_diag_open(DIAG_MDM, (void *)index, diagfwd_bridge_notifier); - else if (index == HSIC_2) - diag_bridge[index].ch = usb_diag_open(DIAG_MDM2, - (void *)index, diagfwd_bridge_notifier); if (IS_ERR(diag_bridge[index].ch)) { pr_err("diag: Unable to open USB MDM ch = %d\n", index); goto err; @@ -360,7 +357,7 @@ void diagfwd_bridge_exit(void) int i; pr_debug("diag: in %s\n", __func__); - for (i = 0; i < MAX_HSIC_CH; i++) { + for (i = 0; i < MAX_HSIC_DATA_CH; i++) { if (diag_hsic[i].hsic_device_enabled) { diag_hsic_close(i); diag_hsic[i].hsic_device_enabled = 0; @@ -379,7 +376,7 @@ void diagfwd_bridge_exit(void) platform_driver_unregister(&msm_hsic_ch_driver); platform_driver_unregister(&msm_diagfwd_smux_driver); /* destroy USB MDM specific variables */ - for (i = 0; i < MAX_BRIDGES; i++) { + for (i = 0; i < MAX_BRIDGES_DATA; i++) { if (diag_bridge[i].enabled) { #ifdef CONFIG_DIAG_OVER_USB usb_diag_close(diag_bridge[i].ch); @@ -392,3 +389,60 @@ void diagfwd_bridge_exit(void) } kfree(driver->write_ptr_mdm); } + +int diagfwd_bridge_dci_init(int index) +{ + unsigned char name[20]; + + if (!diag_bridge_dci) + return -EIO; + + /* + * Don't return an error code if the channel is not supported. The rest + * of the driver initialization should proceed. + * diag_bridge_dci[index].enabled is used to check if a particular + * bridge instance is initialized. + */ + if (index == HSIC_DCI_CH) + strlcpy(name, "hsic_dci", sizeof(name)); + else + return 0; + + strlcpy(diag_bridge_dci[index].name, name, + sizeof(diag_bridge_dci[index].name)); + strlcat(name, "_diag_wq", sizeof(diag_bridge_dci[index].name)); + diag_bridge_dci[index].id = index; + diag_bridge_dci[index].wq = create_singlethread_workqueue(name); + if (!diag_bridge_dci[index].wq) + return -ENOMEM; + diag_bridge_dci[index].read_len = 0; + diag_bridge_dci[index].write_len = 0; + diag_bridge_dci[index].enabled = 1; + mutex_init(&diag_bridge_dci[index].bridge_mutex); + + return 0; +} + +void diagfwd_bridge_dci_exit(void) +{ + int i; + pr_debug("diag: in %s\n", __func__); + + for (i = 0; i < MAX_HSIC_DCI_CH; i++) { + if (diag_hsic_dci[i].hsic_device_enabled) { + diag_hsic_dci_close(i); + diag_hsic_dci[i].hsic_device_enabled = 0; + diag_bridge_dci[i].enabled = 0; + } + diag_hsic_dci[i].hsic_inited = 0; + } + + diagmem_exit(driver, POOL_TYPE_ALL); + + for (i = 0; i < MAX_BRIDGES_DCI; i++) { + if (diag_bridge_dci[i].enabled) { + destroy_workqueue(diag_bridge_dci[i].wq); + diag_bridge_dci[i].enabled = 0; + } + } +} diff --git a/drivers/char/diag/diagfwd_bridge.h b/drivers/char/diag/diagfwd_bridge.h index ae1259b19b9..7c12cf3b7a5 100644 --- a/drivers/char/diag/diagfwd_bridge.h +++ b/drivers/char/diag/diagfwd_bridge.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,16 +15,26 @@ #include "diagfwd.h" -#define MAX_BRIDGES 5 -#define HSIC 0 -#define HSIC_2 1 -#define SMUX 4 +#define MAX_BRIDGES_DATA 3 +#define MAX_BRIDGES_DCI 2 +#define HSIC_DATA_CH 0 +#define HSIC_DATA_CH_2 1 +#define HSIC_DCI_CH 0 +#define HSIC_DCI_CH_2 1 +#define SMUX 2 + +#define DIAG_DATA_BRIDGE_IDX 0 +#define DIAG_DCI_BRIDGE_IDX 1 +#define DIAG_DATA_BRIDGE_IDX_2 2 +#define DIAG_DCI_BRIDGE_IDX_2 3 int diagfwd_connect_bridge(int); void connect_bridge(int, uint8_t); int diagfwd_disconnect_bridge(int); void diagfwd_bridge_init(int index); +int diagfwd_bridge_dci_init(int index); void diagfwd_bridge_exit(void); +void diagfwd_bridge_dci_exit(void); int diagfwd_read_complete_bridge(struct diag_request *diag_read_ptr); /* Diag-Bridge structure, n bridges can be used at same time @@ -46,4 +56,15 @@ struct diag_bridge_dev { struct work_struct usb_read_complete_work; }; +struct diag_bridge_dci_dev { + int id; + char name[20]; + int enabled; + struct mutex bridge_mutex; + int read_len; + int write_len; + struct workqueue_struct *wq; + struct work_struct read_complete_work; +}; + #endif diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index 64399318b83..9add9013675 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -18,6 +18,9 @@ #include "diagchar.h" #include "diagfwd.h" #include "diagfwd_cntl.h" +#include "diagfwd_hsic.h" +#include "diag_dci.h" +#include "diagmem.h" /* tracks which peripheral is undergoing SSR */ static uint16_t reg_dirty; #define HDR_SIZ 8 @@ -247,94 +250,232 @@ int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf, return flag; } -void diag_update_proc_vote(uint16_t proc, uint8_t vote) +static int diag_compute_real_time(int idx) { + int real_time = MODE_REALTIME; + if (driver->proc_active_mask == 0) { + /* + * There are no DCI or Memory Device processes. Diag should + * be in Real Time mode irrespective of USB connection + */ + real_time = MODE_REALTIME; + } else if (driver->proc_rt_vote_mask[idx] & driver->proc_active_mask) { + /* + * Atleast one process is alive and is voting for Real Time + * data - Diag should be in real time mode irrespective of USB + * connection. + */ + real_time = MODE_REALTIME; + } else if (driver->usb_connected) { + /* + * If USB is connected, check individual process. If Memory + * Device Mode is active, set the mode requested by Memory + * Device process. Set to realtime mode otherwise. + */ + if ((driver->proc_rt_vote_mask[idx] & + DIAG_PROC_MEMORY_DEVICE) == 0) + real_time = MODE_NONREALTIME; + else + real_time = MODE_REALTIME; + } else { + /* + * We come here if USB is not connected and the active + * processes are voting for Non realtime mode. + */ + real_time = MODE_NONREALTIME; + } + return real_time; +} + +static void diag_create_diag_mode_ctrl_pkt(unsigned char *dest_buf, + int real_time) +{ + struct diag_ctrl_msg_diagmode diagmode; + int msg_size = sizeof(struct diag_ctrl_msg_diagmode); + + if (!dest_buf) + return; + + diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE; + diagmode.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN; + diagmode.version = 1; + diagmode.sleep_vote = real_time ? 1 : 0; + /* + * 0 - Disables real-time logging (to prevent + * frequent APPS wake-ups, etc.). + * 1 - Enable real-time logging + */ + diagmode.real_time = real_time; + diagmode.use_nrt_values = 0; + diagmode.commit_threshold = 0; + diagmode.sleep_threshold = 0; + diagmode.sleep_time = 0; + diagmode.drain_timer_val = 0; + diagmode.event_stale_timer_val = 0; + + memcpy(dest_buf, &diagmode, msg_size); +} + +void diag_update_proc_vote(uint16_t proc, uint8_t vote, int index) +{ + int i; + mutex_lock(&driver->real_time_mutex); if (vote) driver->proc_active_mask |= proc; else { driver->proc_active_mask &= ~proc; - driver->proc_rt_vote_mask |= proc; + if (index == ALL_PROC) { + for (i = 0; i < DIAG_NUM_PROC; i++) + driver->proc_rt_vote_mask[i] |= proc; + } else { + driver->proc_rt_vote_mask[index] |= proc; + } } mutex_unlock(&driver->real_time_mutex); } -void diag_update_real_time_vote(uint16_t proc, uint8_t real_time) +void diag_update_real_time_vote(uint16_t proc, uint8_t real_time, int index) { + int i; + mutex_lock(&driver->real_time_mutex); - if (real_time) - driver->proc_rt_vote_mask |= proc; - else - driver->proc_rt_vote_mask &= ~proc; + if (index == ALL_PROC) { + for (i = 0; i < DIAG_NUM_PROC; i++) { + if (real_time) + driver->proc_rt_vote_mask[i] |= proc; + else + driver->proc_rt_vote_mask[i] &= ~proc; + } + } else { + if (real_time) + driver->proc_rt_vote_mask[index] |= proc; + else + driver->proc_rt_vote_mask[index] &= ~proc; + } mutex_unlock(&driver->real_time_mutex); } -#ifdef CONFIG_DIAG_OVER_USB -void diag_real_time_work_fn(struct work_struct *work) + +#ifdef CONFIG_DIAGFWD_BRIDGE_CODE +static void diag_send_diag_mode_update_by_hsic(int index, int real_time) { - int temp_real_time = MODE_REALTIME, i; + unsigned char *buf = NULL; + int err = 0; + struct diag_dci_header_t dci_header; + int dci_header_size = sizeof(struct diag_dci_header_t); + int msg_size = sizeof(struct diag_ctrl_msg_diagmode); + uint32_t write_len = 0; - if (driver->proc_active_mask == 0) { - /* There are no DCI or Memory Device processes. Diag should - * be in Real Time mode irrespective of USB connection - */ - temp_real_time = MODE_REALTIME; - } else if (driver->proc_rt_vote_mask & driver->proc_active_mask) { - /* Atleast one process is alive and is voting for Real Time - * data - Diag should be in real time mode irrespective of USB - * connection. - */ - temp_real_time = MODE_REALTIME; - } else if (driver->usb_connected) { - /* If USB is connected, check individual process. If Memory - * Device Mode is active, set the mode requested by Memory - * Device process. Set to realtime mode otherwise. - */ - if ((driver->proc_rt_vote_mask & DIAG_PROC_MEMORY_DEVICE) == 0) - temp_real_time = MODE_NONREALTIME; - else - temp_real_time = MODE_REALTIME; - } else { - /* We come here if USB is not connected and the active - * processes are voting for Non realtime mode. - */ - temp_real_time = MODE_NONREALTIME; + if (index < 0 || index > MAX_HSIC_DCI_CH) { + pr_err("diag: Invalid HSIC channel in %s, index: %d\n", + __func__, index); + return; + } + + if (real_time != MODE_REALTIME && real_time != MODE_NONREALTIME) { + pr_err("diag: Invalid real time value in %s, type: %d\n", + __func__, real_time); + return; + } + + if (!diag_hsic_dci[index].hsic_ch) { + pr_debug("diag: In %s, hsic dci channel %d is not enabled.\n", + __func__, index); + return; } - if (temp_real_time != driver->real_time_mode) { - for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) - diag_send_diag_mode_update_by_smd(&driver->smd_cntl[i], - temp_real_time); + buf = dci_get_buffer_from_bridge(index); + if (!buf) { + pr_err("diag: In %s, unable to get dci buffers to write data\n", + __func__); + return; + } + /* Frame the DCI header */ + dci_header.start = CONTROL_CHAR; + dci_header.version = 1; + dci_header.length = msg_size + 1; + dci_header.cmd_code = DCI_CONTROL_PKT_CODE; + + memcpy(buf + write_len, &dci_header, dci_header_size); + write_len += dci_header_size; + diag_create_diag_mode_ctrl_pkt(buf + write_len, real_time); + write_len += msg_size; + *(buf + write_len) = CONTROL_CHAR; /* End Terminator */ + write_len += sizeof(uint8_t); + err = diag_dci_write_bridge(index, buf, write_len); + if (err != write_len) { + pr_err("diag: cannot send nrt mode ctrl pkt, err: %d\n", err); + diagmem_free(driver, buf, POOL_TYPE_HSIC_DCI_WRITE + index); } else { - pr_debug("diag: did not update real time mode, already in the req mode %d", - temp_real_time); + driver->real_time_mode[index + 1] = real_time; + } +} +#else +static inline void diag_send_diag_mode_update_by_hsic(int index, int real_time) +{ +} +#endif + +#ifdef CONFIG_DIAG_OVER_USB +void diag_real_time_work_fn(struct work_struct *work) +{ + int temp_real_time = MODE_REALTIME, i, j; + + for (i = 0; i < DIAG_NUM_PROC; i++) { + temp_real_time = diag_compute_real_time(i); + if (temp_real_time == driver->real_time_mode[i]) { + pr_debug("diag: did not update real time mode on proc %d, already in the req mode %d", + i, temp_real_time); + continue; + } + + if (i == DIAG_LOCAL_PROC) { + for (j = 0; j < NUM_SMD_CONTROL_CHANNELS; j++) + diag_send_diag_mode_update_by_smd( + &driver->smd_cntl[j], temp_real_time); + } else { + diag_send_diag_mode_update_by_hsic(i - 1, + temp_real_time); + } } + if (driver->real_time_update_busy > 0) driver->real_time_update_busy--; } #else void diag_real_time_work_fn(struct work_struct *work) { - int temp_real_time = MODE_REALTIME, i; + int temp_real_time = MODE_REALTIME, i, j; - if (driver->proc_active_mask == 0) { - /* There are no DCI or Memory Device processes. Diag should - * be in Real Time mode. - */ - temp_real_time = MODE_REALTIME; - } else if (!(driver->proc_rt_vote_mask & driver->proc_active_mask)) { - /* No active process is voting for real time mode */ - temp_real_time = MODE_NONREALTIME; - } + for (i = 0; i < DIAG_NUM_PROC; i++) { + if (driver->proc_active_mask == 0) { + /* + * There are no DCI or Memory Device processes. + * Diag should be in Real Time mode. + */ + temp_real_time = MODE_REALTIME; + } else if (!(driver->proc_rt_vote_mask[i] & + driver->proc_active_mask)) { + /* No active process is voting for real time mode */ + temp_real_time = MODE_NONREALTIME; + } + if (temp_real_time == driver->real_time_mode[i]) { + pr_debug("diag: did not update real time mode on proc %d, already in the req mode %d", + i, temp_real_time); + continue; + } - if (temp_real_time != driver->real_time_mode) { - for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) - diag_send_diag_mode_update_by_smd(&driver->smd_cntl[i], - temp_real_time); - } else { - pr_warn("diag: did not update real time mode, already in the req mode %d", - temp_real_time); + if (i == DIAG_LOCAL_PROC) { + for (j = 0; j < NUM_SMD_CONTROL_CHANNELS; j++) + diag_send_diag_mode_update_by_smd( + &driver->smd_cntl[j], temp_real_time); + } else { + diag_send_diag_mode_update_by_hsic(i - 1, + temp_real_time); + } } + if (driver->real_time_update_busy > 0) driver->real_time_update_busy--; } @@ -343,7 +484,6 @@ void diag_real_time_work_fn(struct work_struct *work) void diag_send_diag_mode_update_by_smd(struct diag_smd_info *smd_info, int real_time) { - struct diag_ctrl_msg_diagmode diagmode; char buf[sizeof(struct diag_ctrl_msg_diagmode)]; int msg_size = sizeof(struct diag_ctrl_msg_diagmode); int wr_size = -ENOMEM, retry_count = 0, timer; @@ -367,26 +507,9 @@ void diag_send_diag_mode_update_by_smd(struct diag_smd_info *smd_info, if (!data) return; - mutex_lock(&driver->diag_cntl_mutex); - diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE; - diagmode.ctrl_pkt_data_len = 36; - diagmode.version = 1; - diagmode.sleep_vote = real_time ? 1 : 0; - /* - * 0 - Disables real-time logging (to prevent - * frequent APPS wake-ups, etc.). - * 1 - Enable real-time logging - */ - diagmode.real_time = real_time; - diagmode.use_nrt_values = 0; - diagmode.commit_threshold = 0; - diagmode.sleep_threshold = 0; - diagmode.sleep_time = 0; - diagmode.drain_timer_val = 0; - diagmode.event_stale_timer_val = 0; - - memcpy(buf, &diagmode, msg_size); + diag_create_diag_mode_ctrl_pkt(buf, real_time); + mutex_lock(&driver->diag_cntl_mutex); if (smd_info->ch) { while (retry_count < 3) { wr_size = smd_write(smd_info->ch, buf, msg_size); @@ -404,7 +527,8 @@ void diag_send_diag_mode_update_by_smd(struct diag_smd_info *smd_info, } else { data = &driver->smd_data[smd_info->peripheral]; - driver->real_time_mode = real_time; + driver->real_time_mode[DIAG_LOCAL_PROC] = + real_time; break; } } diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h index d79195c77c1..b7b382ed33a 100644 --- a/drivers/char/diag/diagfwd_cntl.h +++ b/drivers/char/diag/diagfwd_cntl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -34,7 +34,8 @@ #define DIAG_CTRL_MSG_LOG_MASK_WITH_PRESET_ID 14 #define DIAG_CTRL_MSG_EVENT_MASK_WITH_PRESET_ID 15 #define DIAG_CTRL_MSG_F3_MASK_WITH_PRESET_ID 16 -#define DIAG_CTRL_MSG_LAST DIAG_CTRL_MSG_F3_MASK_WITH_PRESET_ID +#define DIAG_CTRL_MSG_DCI_CONNECTION_STATUS 20 +#define DIAG_CTRL_MSG_LAST DIAG_CTRL_MSG_DCI_CONNECTION_STATUS /* Denotes that we support sending/receiving the feature mask */ #define F_DIAG_INT_FEATURE_MASK 0x01 @@ -63,6 +64,8 @@ #define ENABLE_APPS_HDLC_ENCODING 1 #define DISABLE_APPS_HDLC_ENCODING 0 +#define DIAG_MODE_PKT_LEN 36 + struct cmd_code_range { uint16_t cmd_code_lo; uint16_t cmd_code_hi; @@ -138,6 +141,13 @@ struct diag_ctrl_msg_stm { uint8_t control_data; } __packed; +struct diag_ctrl_dci_status { + uint32_t ctrl_pkt_id; + uint32_t ctrl_pkt_data_len; + uint32_t version; + uint8_t count; +} __packed; + void diagfwd_cntl_init(void); void diagfwd_cntl_exit(void); void diag_read_smd_cntl_work_fn(struct work_struct *); @@ -148,8 +158,8 @@ int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf, int total_recd); void diag_send_diag_mode_update_by_smd(struct diag_smd_info *smd_info, int real_time); -void diag_update_proc_vote(uint16_t proc, uint8_t vote); -void diag_update_real_time_vote(uint16_t proc, uint8_t real_time); +void diag_update_proc_vote(uint16_t proc, uint8_t vote, int index); +void diag_update_real_time_vote(uint16_t proc, uint8_t real_time, int index); void diag_real_time_work_fn(struct work_struct *work); int diag_send_stm_state(struct diag_smd_info *smd_info, uint8_t stm_control_data); diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c index d1f72a8f2bd..2e0f6d41452 100644 --- a/drivers/char/diag/diagfwd_hsic.c +++ b/drivers/char/diag/diagfwd_hsic.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -32,9 +32,38 @@ #include "diagfwd_hsic.h" #include "diagfwd_smux.h" #include "diagfwd_bridge.h" +#include "diag_dci.h" + +#define READ_HSIC_BUF_SIZE 2048 +#define READ_HSIC_BUF_SIZE_DCI 4096 -#define READ_HSIC_BUF_SIZE 2048 struct diag_hsic_dev *diag_hsic; +struct diag_hsic_dci_dev *diag_hsic_dci; + +static struct diag_hsic_bridge_map hsic_map[MAX_HSIC_CH] = { + { 0, HSIC_DATA_TYPE, HSIC_DATA_CH, DIAG_DATA_BRIDGE_IDX }, + { 1, HSIC_DCI_TYPE, HSIC_DCI_CH, DIAG_DCI_BRIDGE_IDX }, + { 2, HSIC_DATA_TYPE, HSIC_DATA_CH_2, DIAG_DATA_BRIDGE_IDX_2 }, + { 3, HSIC_DCI_TYPE, HSIC_DCI_CH_2, DIAG_DCI_BRIDGE_IDX_2 } +}; + +/* + * This array is the inverse of hsic_map indexed by the Bridge index + * for HSIC data channels + */ +int hsic_data_bridge_map[MAX_HSIC_DATA_CH] = { + DIAG_DATA_BRIDGE_IDX, + DIAG_DATA_BRIDGE_IDX_2 +}; + +/* + * This array is the inverse of hsic_map indexed by the Bridge index + * for HSIC DCI channels + */ +int hsic_dci_bridge_map[MAX_HSIC_DCI_CH] = { + DIAG_DCI_BRIDGE_IDX, + DIAG_DCI_BRIDGE_IDX_2 +}; static void diag_read_hsic_work_fn(struct work_struct *work) { @@ -95,8 +124,9 @@ static void diag_read_hsic_work_fn(struct work_struct *work) */ pr_debug("diag: read from HSIC\n"); num_reads_submitted++; - err = diag_bridge_read(index, (char *)buf_in_hsic, - READ_HSIC_BUF_SIZE); + err = diag_bridge_read(hsic_data_bridge_map[index], + (char *)buf_in_hsic, + READ_HSIC_BUF_SIZE); if (err) { num_reads_submitted--; @@ -129,6 +159,102 @@ static void diag_read_hsic_work_fn(struct work_struct *work) &diag_hsic[index].diag_read_hsic_work); } +static void diag_process_hsic_work_fn(struct work_struct *work) +{ + struct diag_hsic_dci_dev *hsic_struct = container_of(work, + struct diag_hsic_dci_dev, + diag_process_hsic_work); + int index = hsic_struct->id; + + if (!diag_hsic_dci[index].data) { + diagmem_free(driver, diag_hsic_dci[index].data_buf, + POOL_TYPE_HSIC_DCI + index); + return; + } + + if (diag_hsic_dci[index].data_len <= 0) { + diagmem_free(driver, diag_hsic_dci[index].data_buf, + POOL_TYPE_HSIC_DCI + index); + return; + } + diag_process_hsic_dci_read_data(index, diag_hsic_dci[index].data, + diag_hsic_dci[index].data_len); + diagmem_free(driver, diag_hsic_dci[index].data_buf, + POOL_TYPE_HSIC_DCI + index); + queue_work(diag_bridge_dci[index].wq, + &diag_hsic_dci[index].diag_read_hsic_work); +} + +static void diag_read_hsic_dci_work_fn(struct work_struct *work) +{ + unsigned char *buf_in_hsic = NULL; + int num_reads_submitted = 0; + int err = 0; + struct diag_hsic_dci_dev *hsic_struct = container_of(work, + struct diag_hsic_dci_dev, + diag_read_hsic_work); + int index = hsic_struct->id; + + if (!diag_hsic_dci[index].hsic_ch) { + pr_err("diag: Invalid HSIC channel in %s\n", __func__); + return; + } + + /* + * Queue up a read on the HSIC for all available buffers in the + * pool, exhausting the pool. + */ + do { + /* + * No sense queuing a read if the HSIC bridge was + * closed in another thread + */ + if (!diag_hsic_dci[index].hsic_ch) + break; + + buf_in_hsic = diagmem_alloc(driver, READ_HSIC_BUF_SIZE_DCI, + POOL_TYPE_HSIC_DCI + index); + if (buf_in_hsic) { + /* + * Initiate the read from the HSIC. The HSIC read is + * asynchronous. Once the read is complete the read + * callback function will be called. + */ + num_reads_submitted++; + err = diag_bridge_read(hsic_dci_bridge_map[index], + (char *)buf_in_hsic, + READ_HSIC_BUF_SIZE_DCI); + if (err) { + num_reads_submitted--; + + /* Return the buffer to the pool */ + diagmem_free(driver, buf_in_hsic, + POOL_TYPE_HSIC_DCI + index); + + pr_err_ratelimited("diag: Error initiating HSIC read, err: %d\n", + err); + /* + * An error occurred, discontinue queuing + * reads + */ + break; + } + } + } while (buf_in_hsic); + + /* + * If there are read buffers available and for some reason the + * read was not queued, and if no unrecoverable error occurred + * (-ENODEV is an unrecoverable error), then set up the next read + */ + if ((diag_hsic_dci[index].count_hsic_pool < + diag_hsic_dci[index].poolsize_hsic) && + (num_reads_submitted == 0) && (err != -ENODEV) && + (diag_hsic_dci[index].hsic_ch != 0)) + queue_work(diag_bridge_dci[index].wq, + &diag_hsic_dci[index].diag_read_hsic_work); +} + static void diag_hsic_read_complete_callback(void *ctxt, char *buf, int buf_size, int actual_size) { @@ -196,6 +322,52 @@ static void diag_hsic_read_complete_callback(void *ctxt, char *buf, } } +static void diag_hsic_dci_read_complete_callback(void *ctxt, char *buf, + int buf_size, int actual_size) +{ + int index = (int)ctxt; + + if (!diag_hsic_dci[index].hsic_ch) { + /* + * The HSIC channel is closed. Return the buffer to + * the pool. Do not send it on. + */ + diagmem_free(driver, buf, POOL_TYPE_HSIC_DCI + index); + pr_debug("diag: In %s: hsic_ch == 0, actual_size: %d\n", + __func__, actual_size); + return; + } + + if (actual_size > 0 && actual_size <= READ_HSIC_BUF_SIZE_DCI) { + if (!buf) { + pr_err("diag: Out of diagmem for HSIC\n"); + } else { + diag_dci_try_activate_wakeup_source(); + diag_hsic_dci[index].data_len = actual_size; + diag_hsic_dci[index].data_buf = buf; + memcpy(diag_hsic_dci[index].data, buf, actual_size); + queue_work(diag_bridge_dci[index].wq, + &diag_hsic_dci[index].diag_process_hsic_work); + } + } else { + /* + * The buffer has an error status associated with it. Do not + * pass it on. Note that -ENOENT is sent when the diag bridge + * is closed. + */ + diagmem_free(driver, buf, POOL_TYPE_HSIC_DCI + index); + pr_debug("diag: In %s: error status: %d\n", __func__, + actual_size); + } + + /* + * If the size of the data received is 0 or if the buffer is invalid, + * queue another read. + */ + queue_work(diag_bridge_dci[index].wq, + &diag_hsic_dci[index].diag_read_hsic_work); +} + static void diag_hsic_write_complete_callback(void *ctxt, char *buf, int buf_size, int actual_size) { @@ -219,6 +391,28 @@ static void diag_hsic_write_complete_callback(void *ctxt, char *buf, &diag_bridge[index].diag_read_work); } +static void diag_hsic_dci_write_complete_callback(void *ctxt, char *buf, + int buf_size, int actual_size) +{ + int index = (int)ctxt; + + /* The write of the data to the HSIC bridge is complete */ + diag_hsic_dci[index].in_busy_hsic_write = 0; + + if (!diag_hsic_dci[index].hsic_ch) { + pr_err("DIAG in %s: hsic_ch == 0, ch = %d\n", __func__, index); + return; + } + + if (actual_size < 0) + pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size); + + diagmem_free(driver, (unsigned char *)buf, POOL_TYPE_HSIC_DCI_WRITE + + index); + queue_work(diag_bridge_dci[index].wq, + &diag_hsic_dci[index].diag_read_hsic_work); +} + static int diag_hsic_suspend(void *ctxt) { int index = (int)ctxt; @@ -241,6 +435,19 @@ static int diag_hsic_suspend(void *ctxt) return 0; } +static int diag_hsic_dci_suspend(void *ctxt) +{ + int index = (int)ctxt; + pr_debug("diag: hsic_suspend\n"); + + /* Don't allow suspend if a write in the HSIC is in progress */ + if (diag_hsic_dci[index].in_busy_hsic_write) + return -EBUSY; + + diag_hsic_dci[index].hsic_suspend = 1; + return 0; +} + static void diag_hsic_resume(void *ctxt) { int index = (int)ctxt; @@ -256,7 +463,20 @@ static void diag_hsic_resume(void *ctxt) &diag_hsic[index].diag_read_hsic_work); } -struct diag_bridge_ops hsic_diag_bridge_ops[MAX_HSIC_CH] = { +static void diag_hsic_dci_resume(void *ctxt) +{ + int index = (int)ctxt; + + pr_debug("diag: hsic_dci_resume\n"); + diag_hsic_dci[index].hsic_suspend = 0; + + if (diag_hsic_dci[index].count_hsic_pool < + diag_hsic_dci[index].poolsize_hsic) + queue_work(diag_bridge_dci[index].wq, + &diag_hsic_dci[index].diag_read_hsic_work); +} + +struct diag_bridge_ops hsic_diag_bridge_ops[MAX_HSIC_DATA_CH] = { { .ctxt = NULL, .read_complete_cb = diag_hsic_read_complete_callback, @@ -273,13 +493,23 @@ struct diag_bridge_ops hsic_diag_bridge_ops[MAX_HSIC_CH] = { } }; +struct diag_bridge_ops hsic_diag_dci_bridge_ops[MAX_HSIC_DCI_CH] = { + { + .ctxt = NULL, + .read_complete_cb = diag_hsic_dci_read_complete_callback, + .write_complete_cb = diag_hsic_dci_write_complete_callback, + .suspend = diag_hsic_dci_suspend, + .resume = diag_hsic_dci_resume, + }, +}; + void diag_hsic_close(int ch_id) { if (diag_hsic[ch_id].hsic_device_enabled) { diag_hsic[ch_id].hsic_ch = 0; if (diag_hsic[ch_id].hsic_device_opened) { diag_hsic[ch_id].hsic_device_opened = 0; - diag_bridge_close(ch_id); + diag_bridge_close(hsic_data_bridge_map[ch_id]); pr_debug("diag: %s: closed successfully ch %d\n", __func__, ch_id); } else { @@ -292,13 +522,36 @@ void diag_hsic_close(int ch_id) } } +void diag_hsic_dci_close(int ch_id) +{ + if (diag_hsic_dci[ch_id].hsic_device_enabled) { + diag_hsic_dci[ch_id].hsic_ch = 0; + if (diag_hsic_dci[ch_id].hsic_device_opened) { + diag_hsic_dci[ch_id].hsic_device_opened = 0; + diag_bridge_close(hsic_dci_bridge_map[ch_id]); + dci_ops_tbl[DCI_MDM_PROC].peripheral_status = 0; + diag_dci_notify_client(DIAG_CON_APSS, + DIAG_STATUS_CLOSED, + DCI_MDM_PROC); + pr_debug("diag: %s: closed successfully ch %d\n", + __func__, ch_id); + } else { + pr_debug("diag: %s: already closed ch %d\n", + __func__, ch_id); + } + } else { + pr_debug("diag: %s: HSIC device already removed ch %d\n", + __func__, ch_id); + } +} + /* diagfwd_cancel_hsic is called to cancel outstanding read/writes */ int diagfwd_cancel_hsic(int reopen) { int err, i; /* Cancel it for all active HSIC bridges */ - for (i = 0; i < MAX_HSIC_CH; i++) { + for (i = 0; i < MAX_HSIC_DATA_CH; i++) { if (!diag_bridge[i].enabled) continue; mutex_lock(&diag_bridge[i].bridge_mutex); @@ -306,11 +559,12 @@ int diagfwd_cancel_hsic(int reopen) if (diag_hsic[i].hsic_device_opened) { diag_hsic[i].hsic_ch = 0; diag_hsic[i].hsic_device_opened = 0; - diag_bridge_close(i); + diag_bridge_close(hsic_data_bridge_map[i]); if (reopen) { hsic_diag_bridge_ops[i].ctxt = (void *)(i); - err = diag_bridge_open(i, + err = diag_bridge_open( + hsic_data_bridge_map[i], &hsic_diag_bridge_ops[i]); if (err) { pr_err("diag: HSIC %d channel open error: %d\n", @@ -409,40 +663,38 @@ void diag_read_usb_hsic_work_fn(struct work_struct *work) &(diag_bridge[index].diag_read_work)); } -static int diag_hsic_probe(struct platform_device *pdev) +static int diag_hsic_probe_data(int pdev_id) { int err = 0; - - /* pdev->Id will indicate which HSIC is working. 0 stands for HSIC - * or CP1 1 indicates HS-USB or CP2 - */ - pr_debug("diag: in %s, ch = %d\n", __func__, pdev->id); - mutex_lock(&diag_bridge[pdev->id].bridge_mutex); - if (!diag_hsic[pdev->id].hsic_inited) { - spin_lock_init(&diag_hsic[pdev->id].hsic_spinlock); - diag_hsic[pdev->id].num_hsic_buf_tbl_entries = 0; - if (diag_hsic[pdev->id].hsic_buf_tbl == NULL) - diag_hsic[pdev->id].hsic_buf_tbl = - kzalloc(NUM_HSIC_BUF_TBL_ENTRIES * - sizeof(struct diag_write_device), GFP_KERNEL); - if (diag_hsic[pdev->id].hsic_buf_tbl == NULL) { - mutex_unlock(&diag_bridge[pdev->id].bridge_mutex); + int index = hsic_map[pdev_id].struct_idx; + int b_index = hsic_map[pdev_id].bridge_idx; + + mutex_lock(&diag_bridge[index].bridge_mutex); + if (!diag_hsic[index].hsic_inited) { + spin_lock_init(&diag_hsic[index].hsic_spinlock); + diag_hsic[index].num_hsic_buf_tbl_entries = 0; + if (diag_hsic[index].hsic_buf_tbl == NULL) + diag_hsic[index].hsic_buf_tbl = + kzalloc(NUM_HSIC_BUF_TBL_ENTRIES * + sizeof(struct diag_write_device), GFP_KERNEL); + if (diag_hsic[index].hsic_buf_tbl == NULL) { + mutex_unlock(&diag_bridge[index].bridge_mutex); return -ENOMEM; } - diag_hsic[pdev->id].id = pdev->id; - diag_hsic[pdev->id].count_hsic_pool = 0; - diag_hsic[pdev->id].count_hsic_write_pool = 0; - diag_hsic[pdev->id].itemsize_hsic = READ_HSIC_BUF_SIZE; - diag_hsic[pdev->id].poolsize_hsic = N_MDM_WRITE; - diag_hsic[pdev->id].itemsize_hsic_write = - sizeof(struct diag_request); - diag_hsic[pdev->id].poolsize_hsic_write = N_MDM_WRITE; - diagmem_hsic_init(pdev->id); - INIT_WORK(&(diag_hsic[pdev->id].diag_read_hsic_work), - diag_read_hsic_work_fn); - diag_hsic[pdev->id].hsic_data_requested = + diag_hsic[index].id = index; + diag_hsic[index].count_hsic_pool = 0; + diag_hsic[index].count_hsic_write_pool = 0; + diag_hsic[index].itemsize_hsic = READ_HSIC_BUF_SIZE; + diag_hsic[index].poolsize_hsic = N_MDM_WRITE; + diag_hsic[index].itemsize_hsic_write = + sizeof(struct diag_request); + diag_hsic[index].poolsize_hsic_write = N_MDM_WRITE; + diagmem_hsic_init(index); + INIT_WORK(&(diag_hsic[index].diag_read_hsic_work), + diag_read_hsic_work_fn); + diag_hsic[index].hsic_data_requested = (driver->logging_mode == MEMORY_DEVICE_MODE) ? 0 : 1; - diag_hsic[pdev->id].hsic_inited = 1; + diag_hsic[index].hsic_inited = 1; } /* * The probe function was called after the usb was connected @@ -450,54 +702,151 @@ static int diag_hsic_probe(struct platform_device *pdev) * requested. Communication over usb mdm and HSIC needs to be * turned on. */ - if ((diag_bridge[pdev->id].usb_connected && + if ((diag_bridge[index].usb_connected && (driver->logging_mode != MEMORY_DEVICE_MODE)) || ((driver->logging_mode == MEMORY_DEVICE_MODE) && - diag_hsic[pdev->id].hsic_data_requested)) { - if (diag_hsic[pdev->id].hsic_device_opened) { + diag_hsic[index].hsic_data_requested)) { + if (diag_hsic[index].hsic_device_opened) { /* should not happen. close it before re-opening */ pr_warn("diag: HSIC channel already opened in probe\n"); - diag_bridge_close(pdev->id); + diag_bridge_close(hsic_data_bridge_map[index]); } - hsic_diag_bridge_ops[pdev->id].ctxt = (void *)(pdev->id); - err = diag_bridge_open(pdev->id, - &hsic_diag_bridge_ops[pdev->id]); + hsic_diag_bridge_ops[index].ctxt = (void *)(index); + err = diag_bridge_open(b_index, + &hsic_diag_bridge_ops[index]); if (err) { pr_err("diag: could not open HSIC, err: %d\n", err); - diag_hsic[pdev->id].hsic_device_opened = 0; - mutex_unlock(&diag_bridge[pdev->id].bridge_mutex); + diag_hsic[index].hsic_device_opened = 0; + mutex_unlock(&diag_bridge[index].bridge_mutex); return err; } - pr_info("diag: opened HSIC bridge, ch = %d\n", pdev->id); - diag_hsic[pdev->id].hsic_device_opened = 1; - diag_hsic[pdev->id].hsic_ch = 1; - diag_hsic[pdev->id].in_busy_hsic_read_on_device = 0; - diag_hsic[pdev->id].in_busy_hsic_write = 0; + pr_info("diag: opened HSIC bridge, ch = %d\n", index); + diag_hsic[index].hsic_device_opened = 1; + diag_hsic[index].hsic_ch = 1; + diag_hsic[index].in_busy_hsic_read_on_device = 0; + diag_hsic[index].in_busy_hsic_write = 0; - if (diag_bridge[pdev->id].usb_connected) { + if (diag_bridge[index].usb_connected) { /* Poll USB mdm channel to check for data */ - queue_work(diag_bridge[pdev->id].wq, - &diag_bridge[pdev->id].diag_read_work); + queue_work(diag_bridge[index].wq, + &diag_bridge[index].diag_read_work); } /* Poll HSIC channel to check for data */ - queue_work(diag_bridge[pdev->id].wq, - &diag_hsic[pdev->id].diag_read_hsic_work); + queue_work(diag_bridge[index].wq, + &diag_hsic[index].diag_read_hsic_work); } /* The HSIC (diag_bridge) platform device driver is enabled */ - diag_hsic[pdev->id].hsic_device_enabled = 1; - mutex_unlock(&diag_bridge[pdev->id].bridge_mutex); + diag_hsic[index].hsic_device_enabled = 1; + mutex_unlock(&diag_bridge[index].bridge_mutex); + return err; +} + +static int diag_hsic_probe_dci(int pdev_id) +{ + int err = 0; + int index = hsic_map[pdev_id].struct_idx; + int b_index = hsic_map[pdev_id].bridge_idx; + + if (!diag_bridge_dci || !diag_hsic_dci) + return -ENOMEM; + + mutex_lock(&diag_bridge_dci[index].bridge_mutex); + if (!diag_hsic_dci[index].hsic_inited) { + diag_hsic_dci[index].data_buf = NULL; + if (diag_hsic_dci[index].data == NULL) + diag_hsic_dci[index].data = + kzalloc(READ_HSIC_BUF_SIZE_DCI, GFP_KERNEL); + if (!diag_hsic_dci[index].data) { + mutex_unlock(&diag_bridge_dci[index].bridge_mutex); + return -ENOMEM; + } + diag_hsic_dci[index].id = index; + diag_hsic_dci[index].count_hsic_pool = 0; + diag_hsic_dci[index].count_hsic_write_pool = 0; + diag_hsic_dci[index].itemsize_hsic = READ_HSIC_BUF_SIZE_DCI; + diag_hsic_dci[index].poolsize_hsic = N_MDM_READ; + diag_hsic_dci[index].itemsize_hsic_write = + WRITE_HSIC_BUF_SIZE_DCI; + diag_hsic_dci[index].poolsize_hsic_write = N_MDM_WRITE; + diagmem_hsic_dci_init(index); + INIT_WORK(&(diag_hsic_dci[index].diag_read_hsic_work), + diag_read_hsic_dci_work_fn); + INIT_WORK(&(diag_hsic_dci[index].diag_process_hsic_work), + diag_process_hsic_work_fn); + diag_hsic_dci[index].hsic_inited = 1; + } + if (!diag_hsic_dci[index].hsic_device_opened) { + hsic_diag_dci_bridge_ops[index].ctxt = + (void *)(int)(index); + err = diag_bridge_open(b_index, + &hsic_diag_dci_bridge_ops[index]); + if (err) { + pr_err("diag: HSIC channel open error: %d\n", err); + } else { + pr_debug("diag: opened DCI HSIC channel at index %d\n", + index); + diag_hsic_dci[index].hsic_device_opened = 1; + diag_hsic_dci[index].hsic_ch = 1; + queue_work(diag_bridge_dci[index].wq, + &diag_hsic_dci[index].diag_read_hsic_work); + diag_send_dci_log_mask_remote(index + 1); + diag_send_dci_event_mask_remote(index + 1); + } + } else { + pr_debug("diag: HSIC DCI channel already open\n"); + queue_work(diag_bridge_dci[index].wq, + &diag_hsic_dci[index].diag_read_hsic_work); + diag_send_dci_log_mask_remote(index + 1); + diag_send_dci_event_mask_remote(index + 1); + } + diag_hsic_dci[index].hsic_device_enabled = 1; + mutex_unlock(&diag_bridge_dci[index].bridge_mutex); + return err; +} + +static int diag_hsic_probe(struct platform_device *pdev) +{ + int err = 0; + + /* + * pdev->Id will indicate which HSIC is working. 0 stands for HSIC + * or CP1 1 indicates HS-USB or CP2 + */ + pr_debug("diag: in %s, ch = %d\n", __func__, pdev->id); + if (pdev->id >= MAX_HSIC_CH) { + pr_alert("diag: No support for HSIC device, %d\n", pdev->id); + return -EIO; + } + + if (hsic_map[pdev->id].type == HSIC_DATA_TYPE) + err = diag_hsic_probe_data(pdev->id); + else + err = diag_hsic_probe_dci(pdev->id); + return err; } static int diag_hsic_remove(struct platform_device *pdev) { - pr_debug("diag: %s called\n", __func__); - if (diag_hsic[pdev->id].hsic_device_enabled) { - mutex_lock(&diag_bridge[pdev->id].bridge_mutex); - diag_hsic_close(pdev->id); - diag_hsic[pdev->id].hsic_device_enabled = 0; - mutex_unlock(&diag_bridge[pdev->id].bridge_mutex); + int index = hsic_map[pdev->id].struct_idx; + + pr_debug("diag: %s called, pdev_id %d\n", __func__, pdev->id); + + if (hsic_map[pdev->id].type == HSIC_DATA_TYPE) { + if (diag_hsic[index].hsic_device_enabled) { + mutex_lock(&diag_bridge[index].bridge_mutex); + diag_hsic_close(index); + diag_hsic[index].hsic_device_enabled = 0; + mutex_unlock(&diag_bridge[index].bridge_mutex); + } + } else { + if (diag_hsic_dci[index].hsic_device_enabled) { + mutex_lock(&diag_bridge_dci[index].bridge_mutex); + diag_hsic_dci_close(index); + diag_hsic_dci[index].hsic_device_enabled = 0; + mutex_unlock(&diag_bridge_dci[index].bridge_mutex); + } } return 0; diff --git a/drivers/char/diag/diagfwd_hsic.h b/drivers/char/diag/diagfwd_hsic.h index 64556f22d9f..acf78e408dc 100644 --- a/drivers/char/diag/diagfwd_hsic.h +++ b/drivers/char/diag/diagfwd_hsic.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -18,19 +18,44 @@ #define N_MDM_WRITE 8 #define N_MDM_READ 1 #define NUM_HSIC_BUF_TBL_ENTRIES N_MDM_WRITE -#define MAX_HSIC_CH 4 #define REOPEN_HSIC 1 #define DONT_REOPEN_HSIC 0 +#define HSIC_DATA_TYPE 0 +#define HSIC_DCI_TYPE 1 + +/* The Maximum request size is 2k + DCI header + footer (6 bytes) */ +#define WRITE_HSIC_BUF_SIZE_DCI (2048+6) + int diagfwd_write_complete_hsic(struct diag_request *, int index); int diagfwd_cancel_hsic(int reopen); void diag_read_usb_hsic_work_fn(struct work_struct *work); void diag_usb_read_complete_hsic_fn(struct work_struct *w); -extern struct diag_bridge_ops hsic_diag_bridge_ops[MAX_HSIC_CH]; +extern struct diag_bridge_ops hsic_diag_bridge_ops[MAX_HSIC_DATA_CH]; +extern struct diag_bridge_ops hsic_diag_dci_bridge_ops[MAX_HSIC_DCI_CH]; extern struct platform_driver msm_hsic_ch_driver; void diag_hsic_close(int); +void diag_hsic_dci_close(int); -/* Diag-HSIC structure, n HSIC bridges can be used at same time - * for instance HSIC(0), HS-USB(1) working at same time +/* + * Structure to hold the HSIC channel mapping information. + * @dev_id: platform device ID + * @type: HSIC type - HSIC_DATA_TYPE or HSIC_DCI_TYPE + * @struct_idx: Index to the corresponding HSIC structure + * @bridge_idx: Index to the corresponding Bridge Entry + */ +struct diag_hsic_bridge_map { + uint8_t dev_id; + uint8_t type; + uint8_t struct_idx; + uint8_t bridge_idx; +}; + +extern int hsic_data_bridge_map[MAX_HSIC_DATA_CH]; +extern int hsic_dci_bridge_map[MAX_HSIC_DCI_CH]; + +/* + * Diag-HSIC structure, n HSIC bridges can be used at same time + * This structure is used for HSIC data channels. */ struct diag_hsic_dev { int id; @@ -56,4 +81,31 @@ struct diag_hsic_dev { spinlock_t hsic_spinlock; }; +/* + * Diag-HSIC DCI structure, n HSIC bridges can be used at same time + * This structure is used for HSIC DCI channels. + */ +struct diag_hsic_dci_dev { + int id; + int hsic_ch; + int hsic_inited; + int hsic_device_enabled; + int hsic_device_opened; + int hsic_suspend; + int in_busy_hsic_write; + struct work_struct diag_read_hsic_work; + int count_hsic_pool; + int count_hsic_write_pool; + unsigned int poolsize_hsic; + unsigned int poolsize_hsic_write; + unsigned int itemsize_hsic; + unsigned int itemsize_hsic_write; + mempool_t *diag_hsic_pool; + mempool_t *diag_hsic_write_pool; + unsigned char *data; + unsigned char *data_buf; + uint32_t data_len; + struct work_struct diag_process_hsic_work; +}; + #endif diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c index 42c4cddcba3..27c28483378 100644 --- a/drivers/char/diag/diagmem.c +++ b/drivers/char/diag/diagmem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-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 @@ -110,6 +110,35 @@ void *diagmem_alloc(struct diagchar_dev *driver, int size, int pool_type) GFP_ATOMIC); } } + } else if (pool_type == POOL_TYPE_HSIC_DCI || + pool_type == POOL_TYPE_HSIC_DCI_2) { + index = pool_type - POOL_TYPE_HSIC_DCI; + if (diag_hsic_dci[index].diag_hsic_pool) { + if ((diag_hsic_dci[index].count_hsic_pool < + diag_hsic_dci[index].poolsize_hsic) && + (size <= diag_hsic_dci[index].itemsize_hsic)) { + atomic_add(1, (atomic_t *) + &diag_hsic_dci[index].count_hsic_pool); + buf = mempool_alloc( + diag_hsic_dci[index].diag_hsic_pool, + GFP_ATOMIC); + } + } + } else if (pool_type == POOL_TYPE_HSIC_DCI_WRITE || + pool_type == POOL_TYPE_HSIC_DCI_2_WRITE) { + index = pool_type - POOL_TYPE_HSIC_DCI_WRITE; + if (diag_hsic_dci[index].diag_hsic_write_pool) { + if (diag_hsic_dci[index].count_hsic_write_pool < + diag_hsic_dci[index].poolsize_hsic_write && + (size <= diag_hsic_dci[index].itemsize_hsic_write)) { + atomic_add(1, (atomic_t *) + &diag_hsic_dci[index]. + count_hsic_write_pool); + buf = mempool_alloc( + diag_hsic_dci[index].diag_hsic_write_pool, + GFP_ATOMIC); + } + } #endif } spin_unlock_irqrestore(&driver->diag_mem_lock, flags); @@ -176,7 +205,7 @@ void diagmem_exit(struct diagchar_dev *driver, int pool_type) } } #ifdef CONFIG_DIAGFWD_BRIDGE_CODE - for (index = 0; index < MAX_HSIC_CH; index++) { + for (index = 0; index < MAX_HSIC_DATA_CH; index++) { if (diag_hsic[index].diag_hsic_pool && (diag_hsic[index].hsic_inited == 0)) { if (diag_hsic[index].count_hsic_pool == 0) { @@ -204,6 +233,36 @@ void diagmem_exit(struct diagchar_dev *driver, int pool_type) , index); } } + + for (index = 0; index < MAX_HSIC_DCI_CH; index++) { + if (diag_hsic_dci[index].diag_hsic_pool && + (diag_hsic_dci[index].hsic_inited == 0)) { + if (diag_hsic_dci[index].count_hsic_pool == 0) { + mempool_destroy( + diag_hsic_dci[index].diag_hsic_pool); + diag_hsic_dci[index].diag_hsic_pool = NULL; + } else if (pool_type == POOL_TYPE_ALL) + pr_err("Unable to destroy HDLC mempool for ch %d", + index); + } + + if (diag_hsic_dci[index].diag_hsic_write_pool && + (diag_hsic_dci[index].hsic_inited == 0)) { + /* + * Free up struct pool ONLY if there are no outstanding + * buffers that are held up in processing DCI data + */ + if (diag_hsic_dci[index].count_hsic_write_pool == 0 && + diag_hsic_dci[index].count_hsic_pool == 0) { + mempool_destroy(diag_hsic_dci[index]. + diag_hsic_write_pool); + diag_hsic_dci[index].diag_hsic_write_pool = + NULL; + } else if (pool_type == POOL_TYPE_ALL) + pr_err("Unable to destroy HSIC DCI struct mempool for ch %d", + index); + } + } #endif spin_unlock_irqrestore(&driver->diag_mem_lock, flags); } @@ -284,6 +343,30 @@ void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type) } else pr_err("diag: Attempt to free up DIAG driver HSIC USB structure mempool which is already free %d, ch = %d", driver->count_write_struct_pool, index); + } else if (pool_type == POOL_TYPE_HSIC_DCI || + pool_type == POOL_TYPE_HSIC_DCI_2) { + index = pool_type - POOL_TYPE_HSIC_DCI; + if (diag_hsic_dci[index].diag_hsic_pool != NULL && + diag_hsic_dci[index].count_hsic_pool > 0) { + mempool_free(buf, diag_hsic_dci[index].diag_hsic_pool); + atomic_add(-1, (atomic_t *) + &diag_hsic_dci[index].count_hsic_pool); + } else + pr_err("diag: Attempt to free up DIAG driver HSIC mempool which is already free %d, ch = %d", + diag_hsic_dci[index].count_hsic_pool, index); + } else if (pool_type == POOL_TYPE_HSIC_DCI_WRITE || + pool_type == POOL_TYPE_HSIC_DCI_2_WRITE) { + index = pool_type - POOL_TYPE_HSIC_DCI_WRITE; + if (diag_hsic_dci[index].diag_hsic_write_pool != NULL && + diag_hsic_dci[index].count_hsic_write_pool > 0) { + mempool_free(buf, + diag_hsic_dci[index].diag_hsic_write_pool); + atomic_add(-1, (atomic_t *) + &diag_hsic_dci[index].count_hsic_write_pool); + } else + pr_err("diag: Attempt to free up DIAG driver HSIC USB structure mempool which is already free %d, ch = %d", + diag_hsic_dci[index].count_hsic_write_pool, + index); #endif } else { pr_err("diag: In %s, unknown pool type: %d\n", @@ -349,7 +432,7 @@ void diagmem_init(struct diagchar_dev *driver) #ifdef CONFIG_DIAGFWD_BRIDGE_CODE void diagmem_hsic_init(int index) { - if (index < 0 || index >= MAX_HSIC_CH) { + if (index < 0 || index >= MAX_HSIC_DATA_CH) { pr_err("diag: Invalid hsic index in %s\n", __func__); return; } @@ -379,5 +462,39 @@ void diagmem_hsic_init(int index) index); } + +void diagmem_hsic_dci_init(int index) +{ + if (index < 0 || index >= MAX_HSIC_DCI_CH) { + pr_err("diag: Invalid hsic index in %s\n", __func__); + return; + } + + if (diag_hsic_dci[index].count_hsic_pool == 0) { + diag_hsic_dci[index].diag_hsic_pool = + mempool_create_kmalloc_pool( + diag_hsic_dci[index].poolsize_hsic, + diag_hsic_dci[index].itemsize_hsic); + diag_pools_array[POOL_HSIC_DCI_IDX + index] = + diag_hsic_dci[index].diag_hsic_pool; + } + + if (diag_hsic_dci[index].count_hsic_write_pool == 0) { + diag_hsic_dci[index].diag_hsic_write_pool = + mempool_create_kmalloc_pool( + diag_hsic_dci[index].poolsize_hsic_write, + diag_hsic_dci[index].itemsize_hsic_write); + diag_pools_array[POOL_HSIC_DCI_WRITE_IDX + index] = + diag_hsic_dci[index].diag_hsic_write_pool; + } + + if (!diag_hsic_dci[index].diag_hsic_pool) + pr_err("Cannot allocate diag HSIC mempool for ch %d\n", index); + + if (!diag_hsic_dci[index].diag_hsic_write_pool) + pr_err("Cannot allocate diag HSIC struct mempool for ch %d\n", + index); + +} #endif diff --git a/drivers/char/diag/diagmem.h b/drivers/char/diag/diagmem.h index 68617902106..16caae93fbc 100644 --- a/drivers/char/diag/diagmem.h +++ b/drivers/char/diag/diagmem.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-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 @@ -22,5 +22,6 @@ void diagmem_init(struct diagchar_dev *driver); void diagmem_exit(struct diagchar_dev *driver, int pool_type); #ifdef CONFIG_DIAGFWD_BRIDGE_CODE void diagmem_hsic_init(int index); +void diagmem_hsic_dci_init(int index); #endif #endif diff --git a/drivers/char/msm_smd_pkt.c b/drivers/char/msm_smd_pkt.c index bf7d181ee1e..2f42720598b 100644 --- a/drivers/char/msm_smd_pkt.c +++ b/drivers/char/msm_smd_pkt.c @@ -30,13 +30,13 @@ #include <linux/completion.h> #include <linux/msm_smd_pkt.h> #include <linux/poll.h> +#include <soc/qcom/subsystem_restart.h> #include <asm/ioctls.h> #include <linux/pm.h> #include <linux/of.h> #include <linux/ipc_logging.h> #include <mach/msm_smd.h> -#include <mach/subsystem_restart.h> #include <mach/msm_smsm.h> #ifdef CONFIG_ARCH_FSM9XXX diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 474720bf434..0456415a72e 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -1,7 +1,14 @@ obj-y += clock.o obj-y += clock-dummy.o obj-y += clock-generic.o +obj-y += clock-local2.o +obj-y += clock-pll.o +obj-y += clock-rpm.o +obj-y += clock-voter.o obj-$(CONFIG_DEBUG_FS) += clock-debug.o +# MDM9630 +obj-$(CONFIG_ARCH_MDM9630) += clock-alpha-pll.o + obj-y += gdsc.o diff --git a/arch/arm/mach-msm/clock-alpha-pll.c b/drivers/clk/qcom/clock-alpha-pll.c index 384bc72e689..1b52b446967 100644 --- a/arch/arm/mach-msm/clock-alpha-pll.c +++ b/drivers/clk/qcom/clock-alpha-pll.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,19 +17,19 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> +#include <soc/qcom/clock-alpha-pll.h> #include "clock.h" -#include "clock-alpha-pll.h" #define WAIT_MAX_LOOPS 100 -#define MODE_REG(pll) (*pll->base + 0x0) -#define LOCK_REG(pll) (*pll->base + 0x0) -#define UPDATE_REG(pll) (*pll->base + 0x0) -#define L_REG(pll) (*pll->base + 0x4) -#define A_REG(pll) (*pll->base + 0x8) -#define VCO_REG(pll) (*pll->base + 0x10) -#define ALPHA_EN_REG(pll) (*pll->base + 0x10) +#define MODE_REG(pll) (*pll->base + pll->offset + 0x0) +#define LOCK_REG(pll) (*pll->base + pll->offset + 0x0) +#define UPDATE_REG(pll) (*pll->base + pll->offset + 0x0) +#define L_REG(pll) (*pll->base + pll->offset + 0x4) +#define A_REG(pll) (*pll->base + pll->offset + 0x8) +#define VCO_REG(pll) (*pll->base + pll->offset + 0x10) +#define ALPHA_EN_REG(pll) (*pll->base + pll->offset + 0x10) #define PLL_BYPASSNL 0x2 #define PLL_RESET_N 0x4 diff --git a/arch/arm/mach-msm/clock-local2.c b/drivers/clk/qcom/clock-local2.c index d0cc7f8f46e..76bca85d7c2 100644 --- a/arch/arm/mach-msm/clock-local2.c +++ b/drivers/clk/qcom/clock-local2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -25,8 +25,7 @@ #include <linux/clk/msm-clk-provider.h> #include <linux/clk/msm-clk.h> #include <linux/clk/msm-clock-generic.h> - -#include "clock-local2.h" +#include <soc/qcom/clock-local2.h> /* * When enabling/disabling a clock, check the halt bit up to this number diff --git a/arch/arm/mach-msm/clock-pll.c b/drivers/clk/qcom/clock-pll.c index 65bac679e7d..6270a6a3975 100644 --- a/arch/arm/mach-msm/clock-pll.c +++ b/drivers/clk/qcom/clock-pll.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,9 +17,9 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> +#include <soc/qcom/clock-pll.h> #include "clock.h" -#include "clock-pll.h" #define PLL_OUTCTRL BIT(0) #define PLL_BYPASSNL BIT(1) @@ -41,13 +41,6 @@ static DEFINE_SPINLOCK(pll_reg_lock); #define ENABLE_WAIT_MAX_LOOPS 200 #define PLL_LOCKED_BIT BIT(16) -static int fixed_pll_clk_set_rate(struct clk *c, unsigned long rate) -{ - if (rate != c->rate) - return -EINVAL; - return 0; -} - static long fixed_pll_clk_round_rate(struct clk *c, unsigned long rate) { return c->rate; @@ -132,7 +125,6 @@ struct clk_ops clk_ops_pll_vote = { .disable = pll_vote_clk_disable, .is_enabled = pll_vote_clk_is_enabled, .round_rate = fixed_pll_clk_round_rate, - .set_rate = fixed_pll_clk_set_rate, .handoff = pll_vote_clk_handoff, .list_registers = pll_vote_clk_list_registers, }; @@ -520,7 +512,6 @@ struct clk_ops clk_ops_pll_acpu_vote = { .enable = pll_acpu_vote_clk_enable, .disable = pll_acpu_vote_clk_disable, .round_rate = fixed_pll_clk_round_rate, - .set_rate = fixed_pll_clk_set_rate, .is_enabled = pll_vote_clk_is_enabled, .handoff = pll_acpu_vote_clk_handoff, .list_registers = pll_vote_clk_list_registers, diff --git a/arch/arm/mach-msm/clock-rpm.c b/drivers/clk/qcom/clock-rpm.c index 4d51b130f3d..5f830d6c7e9 100644 --- a/arch/arm/mach-msm/clock-rpm.c +++ b/drivers/clk/qcom/clock-rpm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,8 +14,7 @@ #include <linux/err.h> #include <linux/mutex.h> #include <linux/clk/msm-clk-provider.h> - -#include "clock-rpm.h" +#include <soc/qcom/clock-rpm.h> #define __clk_rpmrs_set_rate(r, value, ctx) \ ((r)->rpmrs_data->set_rate_fn((r), (value), (ctx))) diff --git a/arch/arm/mach-msm/clock-voter.c b/drivers/clk/qcom/clock-voter.c index 5c7a1c64d30..c6066091292 100644 --- a/arch/arm/mach-msm/clock-voter.c +++ b/drivers/clk/qcom/clock-voter.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,7 +14,7 @@ #include <linux/mutex.h> #include <linux/clk.h> #include <linux/clk/msm-clk-provider.h> -#include "clock-voter.h" +#include <soc/qcom/clock-voter.h> static DEFINE_MUTEX(voter_clk_lock); diff --git a/drivers/clk/qcom/clock.c b/drivers/clk/qcom/clock.c index e69f0cbdd65..1f5092e1ffe 100644 --- a/drivers/clk/qcom/clock.c +++ b/drivers/clk/qcom/clock.c @@ -1,7 +1,7 @@ /* arch/arm/mach-msm/clock.c * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2007-2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -488,9 +488,6 @@ int clk_set_rate(struct clk *clk, unsigned long rate) if (IS_ERR_OR_NULL(clk)) return -EINVAL; - if (!clk->ops->set_rate) - return -ENOSYS; - if (!is_rate_valid(clk, rate)) return -EINVAL; @@ -500,6 +497,11 @@ int clk_set_rate(struct clk *clk, unsigned long rate) if (clk->rate == rate && !(clk->flags & CLKFLAG_NO_RATE_CACHE)) goto out; + if (!clk->ops->set_rate) { + rc = -ENOSYS; + goto out; + } + trace_clock_set_rate(name, rate, raw_smp_processor_id()); start_rate = clk->rate; diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index 99aeab501ae..b1e03134273 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -83,8 +83,8 @@ static int gdsc_enable(struct regulator_dev *rdev) ret = readl_tight_poll_timeout(sc->gdscr, regval, regval & PWR_ON_MASK, TIMEOUT_US); if (ret) { - dev_err(&rdev->dev, "%s enable timed out\n", - sc->rdesc.name); + dev_err(&rdev->dev, "%s enable timed out: 0x%x\n", + sc->rdesc.name, regval); return ret; } } else { @@ -139,8 +139,8 @@ static int gdsc_disable(struct regulator_dev *rdev) !(regval & PWR_ON_MASK), TIMEOUT_US); if (ret) - dev_err(&rdev->dev, "%s disable timed out\n", - sc->rdesc.name); + dev_err(&rdev->dev, "%s disable timed out: 0x%x\n", + sc->rdesc.name, regval); } else { for (i = sc->clock_count-1; i >= 0; i--) clk_reset(sc->clocks[i], CLK_RESET_ASSERT); @@ -212,8 +212,8 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode) ret = readl_tight_poll_timeout(sc->gdscr, regval, regval & PWR_ON_MASK, TIMEOUT_US); if (ret) { - dev_err(&rdev->dev, "%s set_mode timed out\n", - sc->rdesc.name); + dev_err(&rdev->dev, "%s set_mode timed out: 0x%x\n", + sc->rdesc.name, regval); return ret; } break; @@ -334,8 +334,8 @@ static int gdsc_probe(struct platform_device *pdev) ret = readl_tight_poll_timeout(sc->gdscr, regval, regval & PWR_ON_MASK, TIMEOUT_US); if (ret) { - dev_err(&pdev->dev, "%s enable timed out\n", - sc->rdesc.name); + dev_err(&pdev->dev, "%s enable timed out: 0x%x\n", + sc->rdesc.name, regval); return ret; } } diff --git a/drivers/coresight/coresight-audio-etm.c b/drivers/coresight/coresight-audio-etm.c index cdf44bfa66f..be270058b66 100644 --- a/drivers/coresight/coresight-audio-etm.c +++ b/drivers/coresight/coresight-audio-etm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -19,30 +19,110 @@ #include <linux/io.h> #include <linux/err.h> #include <linux/sysfs.h> +#include <linux/mutex.h> #include <linux/of_coresight.h> #include <linux/coresight.h> +#include "coresight-qmi.h" struct audio_etm_drvdata { struct device *dev; struct coresight_device *csdev; + struct mutex mutex; + struct workqueue_struct *wq; + struct qmi_handle *handle; + struct work_struct work_svc_arrive; + struct work_struct work_svc_exit; + struct work_struct work_rcv_msg; + struct notifier_block nb; }; static int audio_etm_enable(struct coresight_device *csdev) { struct audio_etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct coresight_set_etm_req_msg_v01 req; + struct coresight_set_etm_resp_msg_v01 resp = { { 0, 0 } }; + struct msg_desc req_desc, resp_desc; + int ret; + + mutex_lock(&drvdata->mutex); + + req.state = CORESIGHT_ETM_STATE_ENABLED_V01; + + req_desc.msg_id = CORESIGHT_QMI_SET_ETM_REQ_V01; + req_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_REQ_MAX_LEN; + req_desc.ei_array = coresight_set_etm_req_msg_v01_ei; + + resp_desc.msg_id = CORESIGHT_QMI_SET_ETM_RESP_V01; + resp_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_RESP_MAX_LEN; + resp_desc.ei_array = coresight_set_etm_resp_msg_v01_ei; + + ret = qmi_send_req_wait(drvdata->handle, &req_desc, &req, sizeof(req), + &resp_desc, &resp, sizeof(resp), TIMEOUT_MS); + + if (ret < 0) { + dev_err(drvdata->dev, "%s: QMI send req failed %d\n", __func__, + ret); + goto err; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + dev_err(drvdata->dev, "%s: QMI request failed %d %d\n", + __func__, resp.resp.result, resp.resp.error); + ret = -EREMOTEIO; + goto err; + } + + mutex_unlock(&drvdata->mutex); dev_info(drvdata->dev, "Audio ETM tracing enabled\n"); return 0; +err: + mutex_unlock(&drvdata->mutex); + return ret; } - static void audio_etm_disable(struct coresight_device *csdev) { struct audio_etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct coresight_set_etm_req_msg_v01 req; + struct coresight_set_etm_resp_msg_v01 resp = { { 0, 0 } }; + struct msg_desc req_desc, resp_desc; + int ret; + + mutex_lock(&drvdata->mutex); + + req.state = CORESIGHT_ETM_STATE_DISABLED_V01; + + req_desc.msg_id = CORESIGHT_QMI_SET_ETM_REQ_V01; + req_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_REQ_MAX_LEN; + req_desc.ei_array = coresight_set_etm_req_msg_v01_ei; + + resp_desc.msg_id = CORESIGHT_QMI_SET_ETM_RESP_V01; + resp_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_RESP_MAX_LEN; + resp_desc.ei_array = coresight_set_etm_resp_msg_v01_ei; + + ret = qmi_send_req_wait(drvdata->handle, &req_desc, &req, sizeof(req), + &resp_desc, &resp, sizeof(resp), TIMEOUT_MS); + if (ret < 0) { + dev_err(drvdata->dev, "%s: QMI send req failed %d\n", __func__, + ret); + goto err; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + dev_err(drvdata->dev, "%s: QMI request failed %d %d\n", + __func__, resp.resp.result, resp.resp.error); + goto err; + } + + mutex_unlock(&drvdata->mutex); dev_info(drvdata->dev, "Audio ETM tracing disabled\n"); + return; +err: + mutex_unlock(&drvdata->mutex); } static const struct coresight_ops_source audio_etm_source_ops = { @@ -54,12 +134,89 @@ static const struct coresight_ops audio_cs_ops = { .source_ops = &audio_etm_source_ops, }; +static void audio_etm_rcv_msg(struct work_struct *work) +{ + struct audio_etm_drvdata *drvdata = container_of(work, + struct audio_etm_drvdata, + work_rcv_msg); + + if (qmi_recv_msg(drvdata->handle) < 0) + pr_err("%s: Error receiving QMI message\n", __func__); +} + +static void audio_etm_notify(struct qmi_handle *handle, + enum qmi_event_type event, void *notify_priv) +{ + struct audio_etm_drvdata *drvdata = + (struct audio_etm_drvdata *)notify_priv; + switch (event) { + case QMI_RECV_MSG: + queue_work(drvdata->wq, &drvdata->work_rcv_msg); + break; + default: + break; + } +} + +static void audio_etm_svc_arrive(struct work_struct *work) +{ + struct audio_etm_drvdata *drvdata = container_of(work, + struct audio_etm_drvdata, + work_svc_arrive); + + drvdata->handle = qmi_handle_create(audio_etm_notify, drvdata); + if (!drvdata->handle) { + pr_err("%s: QMI client handle alloc failed\n", __func__); + return; + } + + if (qmi_connect_to_service(drvdata->handle, CORESIGHT_QMI_SVC_ID, + CORESIGHT_QMI_VERSION, + CORESIGHT_SVC_INST_ID_AUDIO_V01) < 0) { + pr_err("%s: Could not connect handle to service\n", __func__); + qmi_handle_destroy(drvdata->handle); + drvdata->handle = NULL; + } +} + +static void audio_etm_svc_exit(struct work_struct *work) +{ + struct audio_etm_drvdata *drvdata = container_of(work, + struct audio_etm_drvdata, + work_svc_exit); + + qmi_handle_destroy(drvdata->handle); + drvdata->handle = NULL; +} + +static int audio_etm_svc_event_notify(struct notifier_block *this, + unsigned long event, + void *data) +{ + struct audio_etm_drvdata *drvdata = container_of(this, + struct audio_etm_drvdata, + nb); + + switch (event) { + case QMI_SERVER_ARRIVE: + queue_work(drvdata->wq, &drvdata->work_svc_arrive); + break; + case QMI_SERVER_EXIT: + queue_work(drvdata->wq, &drvdata->work_svc_exit); + break; + default: + break; + } + return 0; +} + static int audio_etm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct coresight_platform_data *pdata; struct audio_etm_drvdata *drvdata; struct coresight_desc *desc; + int ret; if (pdev->dev.of_node) { pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node); @@ -79,6 +236,23 @@ static int audio_etm_probe(struct platform_device *pdev) if (!desc) return -ENOMEM; + mutex_init(&drvdata->mutex); + + drvdata->nb.notifier_call = audio_etm_svc_event_notify; + + drvdata->wq = create_singlethread_workqueue("audio-etm"); + if (!drvdata->wq) + return -EFAULT; + INIT_WORK(&drvdata->work_svc_arrive, audio_etm_svc_arrive); + INIT_WORK(&drvdata->work_svc_exit, audio_etm_svc_exit); + INIT_WORK(&drvdata->work_rcv_msg, audio_etm_rcv_msg); + ret = qmi_svc_event_notifier_register(CORESIGHT_QMI_SVC_ID, + CORESIGHT_QMI_VERSION, + CORESIGHT_SVC_INST_ID_AUDIO_V01, + &drvdata->nb); + if (ret < 0) + goto err0; + desc->type = CORESIGHT_DEV_TYPE_SOURCE; desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC; desc->ops = &audio_cs_ops; @@ -86,11 +260,20 @@ static int audio_etm_probe(struct platform_device *pdev) desc->dev = &pdev->dev; desc->owner = THIS_MODULE; drvdata->csdev = coresight_register(desc); - if (IS_ERR(drvdata->csdev)) - return PTR_ERR(drvdata->csdev); - + if (IS_ERR(drvdata->csdev)) { + ret = PTR_ERR(drvdata->csdev); + goto err1; + } dev_info(dev, "Audio ETM initialized\n"); return 0; +err1: + qmi_svc_event_notifier_unregister(CORESIGHT_QMI_SVC_ID, + CORESIGHT_QMI_VERSION, + CORESIGHT_SVC_INST_ID_AUDIO_V01, + &drvdata->nb); +err0: + destroy_workqueue(drvdata->wq); + return ret; } static int audio_etm_remove(struct platform_device *pdev) diff --git a/drivers/coresight/coresight-modem-etm.c b/drivers/coresight/coresight-modem-etm.c index 4c8075c2996..b2ad8ff4f1d 100644 --- a/drivers/coresight/coresight-modem-etm.c +++ b/drivers/coresight/coresight-modem-etm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -19,21 +19,67 @@ #include <linux/io.h> #include <linux/err.h> #include <linux/sysfs.h> +#include <linux/mutex.h> #include <linux/of_coresight.h> #include <linux/coresight.h> +#include "coresight-qmi.h" struct modem_etm_drvdata { struct device *dev; struct coresight_device *csdev; + struct mutex mutex; + struct workqueue_struct *wq; + struct qmi_handle *handle; + struct work_struct work_svc_arrive; + struct work_struct work_svc_exit; + struct work_struct work_rcv_msg; + struct notifier_block nb; }; static int modem_etm_enable(struct coresight_device *csdev) { struct modem_etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct coresight_set_etm_req_msg_v01 req; + struct coresight_set_etm_resp_msg_v01 resp = { { 0, 0 } }; + struct msg_desc req_desc, resp_desc; + int ret; + + mutex_lock(&drvdata->mutex); + + req.state = CORESIGHT_ETM_STATE_ENABLED_V01; + + req_desc.msg_id = CORESIGHT_QMI_SET_ETM_REQ_V01; + req_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_REQ_MAX_LEN; + req_desc.ei_array = coresight_set_etm_req_msg_v01_ei; + + resp_desc.msg_id = CORESIGHT_QMI_SET_ETM_RESP_V01; + resp_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_RESP_MAX_LEN; + resp_desc.ei_array = coresight_set_etm_resp_msg_v01_ei; + + ret = qmi_send_req_wait(drvdata->handle, &req_desc, &req, sizeof(req), + &resp_desc, &resp, sizeof(resp), TIMEOUT_MS); + + if (ret < 0) { + dev_err(drvdata->dev, "%s: QMI send req failed %d\n", __func__, + ret); + goto err; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + dev_err(drvdata->dev, "%s: QMI request failed %d %d\n", + __func__, resp.resp.result, resp.resp.error); + ret = -EREMOTEIO; + goto err; + } + + mutex_unlock(&drvdata->mutex); dev_info(drvdata->dev, "Modem ETM tracing enabled\n"); return 0; +err: + mutex_unlock(&drvdata->mutex); + return ret; } @@ -41,8 +87,43 @@ static void modem_etm_disable(struct coresight_device *csdev) { struct modem_etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct coresight_set_etm_req_msg_v01 req; + struct coresight_set_etm_resp_msg_v01 resp = { { 0, 0 } }; + struct msg_desc req_desc, resp_desc; + int ret; + + mutex_lock(&drvdata->mutex); + + req.state = CORESIGHT_ETM_STATE_DISABLED_V01; + + req_desc.msg_id = CORESIGHT_QMI_SET_ETM_REQ_V01; + req_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_REQ_MAX_LEN; + req_desc.ei_array = coresight_set_etm_req_msg_v01_ei; + + resp_desc.msg_id = CORESIGHT_QMI_SET_ETM_RESP_V01; + resp_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_RESP_MAX_LEN; + resp_desc.ei_array = coresight_set_etm_resp_msg_v01_ei; + + ret = qmi_send_req_wait(drvdata->handle, &req_desc, &req, sizeof(req), + &resp_desc, &resp, sizeof(resp), TIMEOUT_MS); + if (ret < 0) { + dev_err(drvdata->dev, "%s: QMI send req failed %d\n", __func__, + ret); + goto err; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + dev_err(drvdata->dev, "%s: QMI request failed %d %d\n", + __func__, resp.resp.result, resp.resp.error); + goto err; + } + + mutex_unlock(&drvdata->mutex); dev_info(drvdata->dev, "Modem ETM tracing disabled\n"); + return; +err: + mutex_unlock(&drvdata->mutex); } static const struct coresight_ops_source modem_etm_source_ops = { @@ -54,12 +135,89 @@ static const struct coresight_ops modem_cs_ops = { .source_ops = &modem_etm_source_ops, }; +static void modem_etm_rcv_msg(struct work_struct *work) +{ + struct modem_etm_drvdata *drvdata = container_of(work, + struct modem_etm_drvdata, + work_rcv_msg); + + if (qmi_recv_msg(drvdata->handle) < 0) + pr_err("%s: Error receiving QMI message\n", __func__); +} + +static void modem_etm_notify(struct qmi_handle *handle, + enum qmi_event_type event, void *notify_priv) +{ + struct modem_etm_drvdata *drvdata = + (struct modem_etm_drvdata *)notify_priv; + switch (event) { + case QMI_RECV_MSG: + queue_work(drvdata->wq, &drvdata->work_rcv_msg); + break; + default: + break; + } +} + +static void modem_etm_svc_arrive(struct work_struct *work) +{ + struct modem_etm_drvdata *drvdata = container_of(work, + struct modem_etm_drvdata, + work_svc_arrive); + + drvdata->handle = qmi_handle_create(modem_etm_notify, drvdata); + if (!drvdata->handle) { + pr_err("%s: QMI client handle alloc failed\n", __func__); + return; + } + + if (qmi_connect_to_service(drvdata->handle, CORESIGHT_QMI_SVC_ID, + CORESIGHT_QMI_VERSION, + CORESIGHT_SVC_INST_ID_MODEM_V01) < 0) { + pr_err("%s: Could not connect handle to service\n", __func__); + qmi_handle_destroy(drvdata->handle); + drvdata->handle = NULL; + } +} + +static void modem_etm_svc_exit(struct work_struct *work) +{ + struct modem_etm_drvdata *drvdata = container_of(work, + struct modem_etm_drvdata, + work_svc_exit); + + qmi_handle_destroy(drvdata->handle); + drvdata->handle = NULL; +} + +static int modem_etm_svc_event_notify(struct notifier_block *this, + unsigned long event, + void *data) +{ + struct modem_etm_drvdata *drvdata = container_of(this, + struct modem_etm_drvdata, + nb); + + switch (event) { + case QMI_SERVER_ARRIVE: + queue_work(drvdata->wq, &drvdata->work_svc_arrive); + break; + case QMI_SERVER_EXIT: + queue_work(drvdata->wq, &drvdata->work_svc_exit); + break; + default: + break; + } + return 0; +} + static int modem_etm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct coresight_platform_data *pdata; struct modem_etm_drvdata *drvdata; struct coresight_desc *desc; + int ret; if (pdev->dev.of_node) { pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node); @@ -79,6 +237,23 @@ static int modem_etm_probe(struct platform_device *pdev) if (!desc) return -ENOMEM; + mutex_init(&drvdata->mutex); + + drvdata->nb.notifier_call = modem_etm_svc_event_notify; + + drvdata->wq = create_singlethread_workqueue("modem-etm"); + if (!drvdata->wq) + return -EFAULT; + INIT_WORK(&drvdata->work_svc_arrive, modem_etm_svc_arrive); + INIT_WORK(&drvdata->work_svc_exit, modem_etm_svc_exit); + INIT_WORK(&drvdata->work_rcv_msg, modem_etm_rcv_msg); + ret = qmi_svc_event_notifier_register(CORESIGHT_QMI_SVC_ID, + CORESIGHT_QMI_VERSION, + CORESIGHT_SVC_INST_ID_MODEM_V01, + &drvdata->nb); + if (ret < 0) + goto err0; + desc->type = CORESIGHT_DEV_TYPE_SOURCE; desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC; desc->ops = &modem_cs_ops; @@ -86,11 +261,20 @@ static int modem_etm_probe(struct platform_device *pdev) desc->dev = &pdev->dev; desc->owner = THIS_MODULE; drvdata->csdev = coresight_register(desc); - if (IS_ERR(drvdata->csdev)) - return PTR_ERR(drvdata->csdev); - + if (IS_ERR(drvdata->csdev)) { + ret = PTR_ERR(drvdata->csdev); + goto err1; + } dev_info(dev, "Modem ETM initialized\n"); return 0; +err1: + qmi_svc_event_notifier_unregister(CORESIGHT_QMI_SVC_ID, + CORESIGHT_QMI_VERSION, + CORESIGHT_SVC_INST_ID_MODEM_V01, + &drvdata->nb); +err0: + destroy_workqueue(drvdata->wq); + return ret; } static int modem_etm_remove(struct platform_device *pdev) diff --git a/drivers/coresight/coresight-qmi.h b/drivers/coresight/coresight-qmi.h new file mode 100644 index 00000000000..0154efdcd15 --- /dev/null +++ b/drivers/coresight/coresight-qmi.h @@ -0,0 +1,132 @@ +/* Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CORESIGHT_QMI_H +#define _CORESIGHT_QMI_H + +#include <soc/qcom/msm_qmi_interface.h> + +#define CORESIGHT_QMI_SVC_ID (0x33) +#define CORESIGHT_QMI_VERSION (1) + +#define CORESIGHT_QMI_GET_ETM_REQ_V01 (0x002B) +#define CORESIGHT_QMI_GET_ETM_RESP_V01 (0x002B) +#define CORESIGHT_QMI_SET_ETM_REQ_V01 (0x002C) +#define CORESIGHT_QMI_SET_ETM_RESP_V01 (0x002C) + +#define CORESIGHT_QMI_GET_ETM_REQ_MAX_LEN (0) +#define CORESIGHT_QMI_GET_ETM_RESP_MAX_LEN (14) +#define CORESIGHT_QMI_SET_ETM_REQ_MAX_LEN (7) +#define CORESIGHT_QMI_SET_ETM_RESP_MAX_LEN (7) + +#define TIMEOUT_MS (5000) + +enum coresight_svc_instance_id { + /* To force a 32 bit signed enum. Do not change or use */ + CORESIGHT_SVC_INST_ID_ENUM_TYPE_MIN_ENUM_VAL_V01 = INT_MIN, + CORESIGHT_SVC_INST_ID_UNKNOWN_V01 = 0, + CORESIGHT_SVC_INST_ID_APPS_V01 = 1, + CORESIGHT_SVC_INST_ID_MODEM_V01 = 2, + CORESIGHT_SVC_INST_ID_WCN_V01 = 3, + CORESIGHT_SVC_INST_ID_RPM_V01 = 4, + CORESIGHT_SVC_INST_ID_AUDIO_V01 = 5, + CORESIGHT_SVC_INST_ID_VIDEO_V01 = 6, + CORESIGHT_SVC_INST_ID_GNSS_V01 = 7, + CORESIGHT_SVC_INST_ID_SENSOR_V01 = 8, + CORESIGHT_SVC_INST_ID_VPU_V01 = 10, + CORESIGHT_SVC_INST_ID_ENUM_TYPE_MAX_ENUM_VAL_V01 = INT_MAX, +}; + +enum coresight_etm_state_enum_type_v01 { + /* To force a 32 bit signed enum. Do not change or use */ + CORESIGHT_ETM_STATE_ENUM_TYPE_MIN_ENUM_VAL_V01 = INT_MIN, + CORESIGHT_ETM_STATE_DISABLED_V01 = 0, + CORESIGHT_ETM_STATE_ENABLED_V01 = 1, + CORESIGHT_ETM_STATE_ENUM_TYPE_MAX_ENUM_VAL_01 = INT_MAX, +}; + +struct coresight_get_etm_req_msg_v01 { + /* + * This element is a placeholder to prevent declaration of + * empty struct. Do not change. + */ + char __placeholder; +}; + +struct coresight_get_etm_resp_msg_v01 { + /* Mandatory */ + /* QMI result Code */ + struct qmi_response_type_v01 resp; + + /* Optional */ + /* ETM output state, must be set to true if state is being passed */ + uint8_t state_valid; + /* Present when result code is QMI_RESULT_SUCCESS */ + enum coresight_etm_state_enum_type_v01 state; +}; + +struct coresight_set_etm_req_msg_v01 { + /* Mandatory */ + /* ETM output state */ + enum coresight_etm_state_enum_type_v01 state; +}; + +struct coresight_set_etm_resp_msg_v01 { + /* Mandatory */ + struct qmi_response_type_v01 resp; +}; + +static struct elem_info coresight_set_etm_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(enum coresight_etm_state_enum_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct coresight_set_etm_req_msg_v01, + state), + .ei_array = NULL, + }, + { + .data_type = QMI_EOTI, + .elem_len = 0, + .elem_size = 0, + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = 0, + .ei_array = NULL, + }, +}; + +static struct elem_info coresight_set_etm_resp_msg_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 coresight_set_etm_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .elem_len = 0, + .elem_size = 0, + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = 0, + .ei_array = NULL, + }, +}; + +#endif diff --git a/drivers/coresight/coresight-rpm-etm.c b/drivers/coresight/coresight-rpm-etm.c index e752e4f57e2..93efd65a6d3 100644 --- a/drivers/coresight/coresight-rpm-etm.c +++ b/drivers/coresight/coresight-rpm-etm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -19,21 +19,67 @@ #include <linux/io.h> #include <linux/err.h> #include <linux/sysfs.h> +#include <linux/mutex.h> #include <linux/of_coresight.h> #include <linux/coresight.h> +#include "coresight-qmi.h" struct rpm_etm_drvdata { struct device *dev; struct coresight_device *csdev; + struct mutex mutex; + struct workqueue_struct *wq; + struct qmi_handle *handle; + struct work_struct work_svc_arrive; + struct work_struct work_svc_exit; + struct work_struct work_rcv_msg; + struct notifier_block nb; }; static int rpm_etm_enable(struct coresight_device *csdev) { struct rpm_etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct coresight_set_etm_req_msg_v01 req; + struct coresight_set_etm_resp_msg_v01 resp = { { 0, 0 } }; + struct msg_desc req_desc, resp_desc; + int ret; + + mutex_lock(&drvdata->mutex); + + req.state = CORESIGHT_ETM_STATE_ENABLED_V01; + + req_desc.msg_id = CORESIGHT_QMI_SET_ETM_REQ_V01; + req_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_REQ_MAX_LEN; + req_desc.ei_array = coresight_set_etm_req_msg_v01_ei; + + resp_desc.msg_id = CORESIGHT_QMI_SET_ETM_RESP_V01; + resp_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_RESP_MAX_LEN; + resp_desc.ei_array = coresight_set_etm_resp_msg_v01_ei; + + ret = qmi_send_req_wait(drvdata->handle, &req_desc, &req, sizeof(req), + &resp_desc, &resp, sizeof(resp), TIMEOUT_MS); + + if (ret < 0) { + dev_err(drvdata->dev, "%s: QMI send req failed %d\n", __func__, + ret); + goto err; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + dev_err(drvdata->dev, "%s: QMI request failed %d %d\n", + __func__, resp.resp.result, resp.resp.error); + ret = -EREMOTEIO; + goto err; + } + + mutex_unlock(&drvdata->mutex); dev_info(drvdata->dev, "RPM ETM tracing enabled\n"); return 0; +err: + mutex_unlock(&drvdata->mutex); + return ret; } @@ -41,8 +87,43 @@ static void rpm_etm_disable(struct coresight_device *csdev) { struct rpm_etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct coresight_set_etm_req_msg_v01 req; + struct coresight_set_etm_resp_msg_v01 resp = { { 0, 0 } }; + struct msg_desc req_desc, resp_desc; + int ret; + + mutex_lock(&drvdata->mutex); + + req.state = CORESIGHT_ETM_STATE_DISABLED_V01; + + req_desc.msg_id = CORESIGHT_QMI_SET_ETM_REQ_V01; + req_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_REQ_MAX_LEN; + req_desc.ei_array = coresight_set_etm_req_msg_v01_ei; + + resp_desc.msg_id = CORESIGHT_QMI_SET_ETM_RESP_V01; + resp_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_RESP_MAX_LEN; + resp_desc.ei_array = coresight_set_etm_resp_msg_v01_ei; + + ret = qmi_send_req_wait(drvdata->handle, &req_desc, &req, sizeof(req), + &resp_desc, &resp, sizeof(resp), TIMEOUT_MS); + if (ret < 0) { + dev_err(drvdata->dev, "%s: QMI send req failed %d\n", __func__, + ret); + goto err; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + dev_err(drvdata->dev, "%s: QMI request failed %d %d\n", + __func__, resp.resp.result, resp.resp.error); + goto err; + } + + mutex_unlock(&drvdata->mutex); dev_info(drvdata->dev, "RPM ETM tracing disabled\n"); + return; +err: + mutex_unlock(&drvdata->mutex); } static const struct coresight_ops_source rpm_etm_source_ops = { @@ -54,12 +135,89 @@ static const struct coresight_ops rpm_cs_ops = { .source_ops = &rpm_etm_source_ops, }; +static void rpm_etm_rcv_msg(struct work_struct *work) +{ + struct rpm_etm_drvdata *drvdata = container_of(work, + struct rpm_etm_drvdata, + work_rcv_msg); + + if (qmi_recv_msg(drvdata->handle) < 0) + pr_err("%s: Error receiving QMI message\n", __func__); +} + +static void rpm_etm_notify(struct qmi_handle *handle, + enum qmi_event_type event, void *notify_priv) +{ + struct rpm_etm_drvdata *drvdata = + (struct rpm_etm_drvdata *)notify_priv; + switch (event) { + case QMI_RECV_MSG: + queue_work(drvdata->wq, &drvdata->work_rcv_msg); + break; + default: + break; + } +} + +static void rpm_etm_svc_arrive(struct work_struct *work) +{ + struct rpm_etm_drvdata *drvdata = container_of(work, + struct rpm_etm_drvdata, + work_svc_arrive); + + drvdata->handle = qmi_handle_create(rpm_etm_notify, drvdata); + if (!drvdata->handle) { + pr_err("%s: QMI client handle alloc failed\n", __func__); + return; + } + + if (qmi_connect_to_service(drvdata->handle, CORESIGHT_QMI_SVC_ID, + CORESIGHT_QMI_VERSION, + CORESIGHT_SVC_INST_ID_RPM_V01) < 0) { + pr_err("%s: Could not connect handle to service\n", __func__); + qmi_handle_destroy(drvdata->handle); + drvdata->handle = NULL; + } +} + +static void rpm_etm_svc_exit(struct work_struct *work) +{ + struct rpm_etm_drvdata *drvdata = container_of(work, + struct rpm_etm_drvdata, + work_svc_exit); + + qmi_handle_destroy(drvdata->handle); + drvdata->handle = NULL; +} + +static int rpm_etm_svc_event_notify(struct notifier_block *this, + unsigned long event, + void *data) +{ + struct rpm_etm_drvdata *drvdata = container_of(this, + struct rpm_etm_drvdata, + nb); + + switch (event) { + case QMI_SERVER_ARRIVE: + queue_work(drvdata->wq, &drvdata->work_svc_arrive); + break; + case QMI_SERVER_EXIT: + queue_work(drvdata->wq, &drvdata->work_svc_exit); + break; + default: + break; + } + return 0; +} + static int rpm_etm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct coresight_platform_data *pdata; struct rpm_etm_drvdata *drvdata; struct coresight_desc *desc; + int ret; if (pdev->dev.of_node) { pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node); @@ -79,6 +237,23 @@ static int rpm_etm_probe(struct platform_device *pdev) if (!desc) return -ENOMEM; + mutex_init(&drvdata->mutex); + + drvdata->nb.notifier_call = rpm_etm_svc_event_notify; + + drvdata->wq = create_singlethread_workqueue("rpm-etm"); + if (!drvdata->wq) + return -EFAULT; + INIT_WORK(&drvdata->work_svc_arrive, rpm_etm_svc_arrive); + INIT_WORK(&drvdata->work_svc_exit, rpm_etm_svc_exit); + INIT_WORK(&drvdata->work_rcv_msg, rpm_etm_rcv_msg); + ret = qmi_svc_event_notifier_register(CORESIGHT_QMI_SVC_ID, + CORESIGHT_QMI_VERSION, + CORESIGHT_SVC_INST_ID_RPM_V01, + &drvdata->nb); + if (ret < 0) + goto err0; + desc->type = CORESIGHT_DEV_TYPE_SOURCE; desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC; desc->ops = &rpm_cs_ops; @@ -86,11 +261,21 @@ static int rpm_etm_probe(struct platform_device *pdev) desc->dev = &pdev->dev; desc->owner = THIS_MODULE; drvdata->csdev = coresight_register(desc); - if (IS_ERR(drvdata->csdev)) - return PTR_ERR(drvdata->csdev); - + if (IS_ERR(drvdata->csdev)) { + ret = PTR_ERR(drvdata->csdev); + goto err1; + } dev_info(dev, "RPM ETM initialized\n"); return 0; +err1: + qmi_svc_event_notifier_unregister(CORESIGHT_QMI_SVC_ID, + CORESIGHT_QMI_VERSION, + CORESIGHT_SVC_INST_ID_RPM_V01, + &drvdata->nb); +err0: + destroy_workqueue(drvdata->wq); + return ret; + } static int rpm_etm_remove(struct platform_device *pdev) diff --git a/drivers/coresight/coresight-wcn-etm.c b/drivers/coresight/coresight-wcn-etm.c index 44852fb8209..b09e035d92d 100644 --- a/drivers/coresight/coresight-wcn-etm.c +++ b/drivers/coresight/coresight-wcn-etm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -19,21 +19,67 @@ #include <linux/io.h> #include <linux/err.h> #include <linux/sysfs.h> +#include <linux/mutex.h> #include <linux/of_coresight.h> #include <linux/coresight.h> +#include "coresight-qmi.h" struct wcn_etm_drvdata { struct device *dev; struct coresight_device *csdev; + struct mutex mutex; + struct workqueue_struct *wq; + struct qmi_handle *handle; + struct work_struct work_svc_arrive; + struct work_struct work_svc_exit; + struct work_struct work_rcv_msg; + struct notifier_block nb; }; static int wcn_etm_enable(struct coresight_device *csdev) { struct wcn_etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct coresight_set_etm_req_msg_v01 req; + struct coresight_set_etm_resp_msg_v01 resp = { { 0, 0 } }; + struct msg_desc req_desc, resp_desc; + int ret; + + mutex_lock(&drvdata->mutex); + + req.state = CORESIGHT_ETM_STATE_ENABLED_V01; + + req_desc.msg_id = CORESIGHT_QMI_SET_ETM_REQ_V01; + req_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_REQ_MAX_LEN; + req_desc.ei_array = coresight_set_etm_req_msg_v01_ei; + + resp_desc.msg_id = CORESIGHT_QMI_SET_ETM_RESP_V01; + resp_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_RESP_MAX_LEN; + resp_desc.ei_array = coresight_set_etm_resp_msg_v01_ei; + + ret = qmi_send_req_wait(drvdata->handle, &req_desc, &req, sizeof(req), + &resp_desc, &resp, sizeof(resp), TIMEOUT_MS); + + if (ret < 0) { + dev_err(drvdata->dev, "%s: QMI send req failed %d\n", __func__, + ret); + goto err; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + dev_err(drvdata->dev, "%s: QMI request failed %d %d\n", + __func__, resp.resp.result, resp.resp.error); + ret = -EREMOTEIO; + goto err; + } + + mutex_unlock(&drvdata->mutex); dev_info(drvdata->dev, "Wireless ETM tracing enabled\n"); return 0; +err: + mutex_unlock(&drvdata->mutex); + return ret; } @@ -41,8 +87,43 @@ static void wcn_etm_disable(struct coresight_device *csdev) { struct wcn_etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct coresight_set_etm_req_msg_v01 req; + struct coresight_set_etm_resp_msg_v01 resp = { { 0, 0 } }; + struct msg_desc req_desc, resp_desc; + int ret; + + mutex_lock(&drvdata->mutex); + + req.state = CORESIGHT_ETM_STATE_DISABLED_V01; + + req_desc.msg_id = CORESIGHT_QMI_SET_ETM_REQ_V01; + req_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_REQ_MAX_LEN; + req_desc.ei_array = coresight_set_etm_req_msg_v01_ei; + + resp_desc.msg_id = CORESIGHT_QMI_SET_ETM_RESP_V01; + resp_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_RESP_MAX_LEN; + resp_desc.ei_array = coresight_set_etm_resp_msg_v01_ei; + + ret = qmi_send_req_wait(drvdata->handle, &req_desc, &req, sizeof(req), + &resp_desc, &resp, sizeof(resp), TIMEOUT_MS); + if (ret < 0) { + dev_err(drvdata->dev, "%s: QMI send req failed %d\n", __func__, + ret); + goto err; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + dev_err(drvdata->dev, "%s: QMI request failed %d %d\n", + __func__, resp.resp.result, resp.resp.error); + goto err; + } + + mutex_unlock(&drvdata->mutex); dev_info(drvdata->dev, "Wireless ETM tracing disabled\n"); + return; +err: + mutex_unlock(&drvdata->mutex); } static const struct coresight_ops_source wcn_etm_source_ops = { @@ -54,12 +135,89 @@ static const struct coresight_ops wcn_cs_ops = { .source_ops = &wcn_etm_source_ops, }; +static void wcn_etm_rcv_msg(struct work_struct *work) +{ + struct wcn_etm_drvdata *drvdata = container_of(work, + struct wcn_etm_drvdata, + work_rcv_msg); + + if (qmi_recv_msg(drvdata->handle) < 0) + pr_err("%s: Error receiving QMI message\n", __func__); +} + +static void wcn_etm_notify(struct qmi_handle *handle, + enum qmi_event_type event, void *notify_priv) +{ + struct wcn_etm_drvdata *drvdata = + (struct wcn_etm_drvdata *)notify_priv; + switch (event) { + case QMI_RECV_MSG: + queue_work(drvdata->wq, &drvdata->work_rcv_msg); + break; + default: + break; + } +} + +static void wcn_etm_svc_arrive(struct work_struct *work) +{ + struct wcn_etm_drvdata *drvdata = container_of(work, + struct wcn_etm_drvdata, + work_svc_arrive); + + drvdata->handle = qmi_handle_create(wcn_etm_notify, drvdata); + if (!drvdata->handle) { + pr_err("%s: QMI client handle alloc failed\n", __func__); + return; + } + + if (qmi_connect_to_service(drvdata->handle, CORESIGHT_QMI_SVC_ID, + CORESIGHT_QMI_VERSION, + CORESIGHT_SVC_INST_ID_WCN_V01) < 0) { + pr_err("%s: Could not connect handle to service\n", __func__); + qmi_handle_destroy(drvdata->handle); + drvdata->handle = NULL; + } +} + +static void wcn_etm_svc_exit(struct work_struct *work) +{ + struct wcn_etm_drvdata *drvdata = container_of(work, + struct wcn_etm_drvdata, + work_svc_exit); + + qmi_handle_destroy(drvdata->handle); + drvdata->handle = NULL; +} + +static int wcn_etm_svc_event_notify(struct notifier_block *this, + unsigned long event, + void *data) +{ + struct wcn_etm_drvdata *drvdata = container_of(this, + struct wcn_etm_drvdata, + nb); + + switch (event) { + case QMI_SERVER_ARRIVE: + queue_work(drvdata->wq, &drvdata->work_svc_arrive); + break; + case QMI_SERVER_EXIT: + queue_work(drvdata->wq, &drvdata->work_svc_exit); + break; + default: + break; + } + return 0; +} + static int wcn_etm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct coresight_platform_data *pdata; struct wcn_etm_drvdata *drvdata; struct coresight_desc *desc; + int ret; if (pdev->dev.of_node) { pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node); @@ -79,6 +237,23 @@ static int wcn_etm_probe(struct platform_device *pdev) if (!desc) return -ENOMEM; + mutex_init(&drvdata->mutex); + + drvdata->nb.notifier_call = wcn_etm_svc_event_notify; + + drvdata->wq = create_singlethread_workqueue("wcn-etm"); + if (!drvdata->wq) + return -EFAULT; + INIT_WORK(&drvdata->work_svc_arrive, wcn_etm_svc_arrive); + INIT_WORK(&drvdata->work_svc_exit, wcn_etm_svc_exit); + INIT_WORK(&drvdata->work_rcv_msg, wcn_etm_rcv_msg); + ret = qmi_svc_event_notifier_register(CORESIGHT_QMI_SVC_ID, + CORESIGHT_QMI_VERSION, + CORESIGHT_SVC_INST_ID_WCN_V01, + &drvdata->nb); + if (ret < 0) + goto err0; + desc->type = CORESIGHT_DEV_TYPE_SOURCE; desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC; desc->ops = &wcn_cs_ops; @@ -86,11 +261,22 @@ static int wcn_etm_probe(struct platform_device *pdev) desc->dev = &pdev->dev; desc->owner = THIS_MODULE; drvdata->csdev = coresight_register(desc); - if (IS_ERR(drvdata->csdev)) - return PTR_ERR(drvdata->csdev); + if (IS_ERR(drvdata->csdev)) { + ret = PTR_ERR(drvdata->csdev); + goto err1; + } dev_info(dev, "Wireless ETM initialized\n"); return 0; +err1: + qmi_svc_event_notifier_unregister(CORESIGHT_QMI_SVC_ID, + CORESIGHT_QMI_VERSION, + CORESIGHT_SVC_INST_ID_WCN_V01, + &drvdata->nb); +err0: + destroy_workqueue(drvdata->wq); + return ret; + } static int wcn_etm_remove(struct platform_device *pdev) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3b64f9bd58b..84eaca9bfa7 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1252,6 +1252,7 @@ static int __cpufreq_remove_dev_finish(struct device *dev, read_lock_irqsave(&cpufreq_driver_lock, flags); policy = per_cpu(cpufreq_cpu_data, cpu); + per_cpu(cpufreq_cpu_data, cpu) = NULL; read_unlock_irqrestore(&cpufreq_driver_lock, flags); if (!policy) { @@ -1321,7 +1322,6 @@ static int __cpufreq_remove_dev_finish(struct device *dev, } } - per_cpu(cpufreq_cpu_data, cpu) = NULL; return 0; } diff --git a/drivers/crypto/msm/qce.h b/drivers/crypto/msm/qce.h index afd51417fbe..73438d0af15 100644 --- a/drivers/crypto/msm/qce.h +++ b/drivers/crypto/msm/qce.h @@ -1,6 +1,6 @@ /* Qualcomm Crypto Engine driver API * - * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -116,6 +116,13 @@ struct ce_hw_support { bool bam; bool is_shared; bool hw_key; + bool use_sw_aes_cbc_ecb_ctr_algo; + bool use_sw_aead_algo; + bool use_sw_aes_xts_algo; + bool use_sw_ahash_algo; + bool use_sw_hmac_algo; + bool use_sw_aes_ccm_algo; + bool clk_mgmt_sus_res; }; /* Sha operation parameters */ diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index 7295ddab2ac..92e6b28e10d 100644 --- a/drivers/crypto/msm/qce50.c +++ b/drivers/crypto/msm/qce50.c @@ -73,6 +73,7 @@ struct qce_device { int is_shared; /* CE HW is shared */ bool support_cmd_dscr; bool support_hw_key; + bool support_clk_mgmt_sus_res; void __iomem *iobase; /* Virtual io base of CE HW */ unsigned int phy_iobase; /* Physical io base of CE HW */ @@ -101,6 +102,13 @@ struct qce_device { dma_addr_t phy_ota_src; dma_addr_t phy_ota_dst; unsigned int ota_size; + + bool use_sw_aes_cbc_ecb_ctr_algo; + bool use_sw_aead_algo; + bool use_sw_aes_xts_algo; + bool use_sw_ahash_algo; + bool use_sw_hmac_algo; + bool use_sw_aes_ccm_algo; }; /* Standard initialization vector for SHA-1, source: FIPS 180-2 */ @@ -5060,6 +5068,28 @@ static int __qce_get_device_tree_data(struct platform_device *pdev, "qcom,ce-hw-shared"); pce_dev->support_hw_key = of_property_read_bool((&pdev->dev)->of_node, "qcom,ce-hw-key"); + + pce_dev->use_sw_aes_cbc_ecb_ctr_algo = + of_property_read_bool((&pdev->dev)->of_node, + "qcom,use-sw-aes-cbc-ecb-ctr-algo"); + pce_dev->use_sw_aead_algo = + of_property_read_bool((&pdev->dev)->of_node, + "qcom,use-sw-aead-algo"); + pce_dev->use_sw_aes_xts_algo = + of_property_read_bool((&pdev->dev)->of_node, + "qcom,use-sw-aes-xts-algo"); + pce_dev->use_sw_ahash_algo = + of_property_read_bool((&pdev->dev)->of_node, + "qcom,use-sw-ahash-algo"); + pce_dev->use_sw_hmac_algo = + of_property_read_bool((&pdev->dev)->of_node, + "qcom,use-sw-hmac-algo"); + pce_dev->use_sw_aes_ccm_algo = + of_property_read_bool((&pdev->dev)->of_node, + "qcom,use-sw-aes-ccm-algo"); + pce_dev->support_clk_mgmt_sus_res = of_property_read_bool( + (&pdev->dev)->of_node, "qcom,clk-mgmt-sus-res"); + if (of_property_read_u32((&pdev->dev)->of_node, "qcom,bam-pipe-pair", &pce_dev->ce_sps.pipe_pair_index)) { @@ -5387,10 +5417,24 @@ int qce_hw_support(void *handle, struct ce_hw_support *ce_support) ce_support->is_shared = (pce_dev->is_shared == 1) ? true : false; ce_support->hw_key = pce_dev->support_hw_key; ce_support->aes_ccm = true; + ce_support->clk_mgmt_sus_res = pce_dev->support_clk_mgmt_sus_res; if (pce_dev->ce_sps.minor_version) ce_support->aligned_only = false; else ce_support->aligned_only = true; + + ce_support->use_sw_aes_cbc_ecb_ctr_algo = + pce_dev->use_sw_aes_cbc_ecb_ctr_algo; + ce_support->use_sw_aead_algo = + pce_dev->use_sw_aead_algo; + ce_support->use_sw_aes_xts_algo = + pce_dev->use_sw_aes_xts_algo; + ce_support->use_sw_ahash_algo = + pce_dev->use_sw_ahash_algo; + ce_support->use_sw_hmac_algo = + pce_dev->use_sw_hmac_algo; + ce_support->use_sw_aes_ccm_algo = + pce_dev->use_sw_aes_ccm_algo; return 0; } EXPORT_SYMBOL(qce_hw_support); diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index 4845f11b3fc..72dbff3398a 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -12,6 +12,7 @@ * GNU General Public License for more details. */ #include <linux/mman.h> +#include <soc/qcom/scm.h> #include <linux/types.h> #include <linux/platform_device.h> @@ -30,7 +31,6 @@ #include <linux/crypto.h> #include <crypto/hash.h> #include <linux/platform_data/qcom_crypto_device.h> -#include <mach/scm.h> #include <mach/msm_bus.h> #include <linux/qcedev.h> #include "qce.h" diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c index cb07ca58c1e..da9a9f3d41b 100644 --- a/drivers/crypto/msm/qcrypto.c +++ b/drivers/crypto/msm/qcrypto.c @@ -1,6 +1,6 @@ /* Qualcomm Crypto driver * - * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,6 +28,7 @@ #include <linux/sched.h> #include <linux/init.h> #include <linux/cache.h> +#include <soc/qcom/scm.h> #include <crypto/ctr.h> #include <crypto/des.h> @@ -40,7 +41,6 @@ #include <crypto/scatterwalk.h> #include <crypto/internal/hash.h> -#include <mach/scm.h> #include <linux/platform_data/qcom_crypto_device.h> #include <mach/msm_bus.h> #include <mach/qcrypto.h> @@ -3237,6 +3237,16 @@ static int _sha256_hmac_digest(struct ahash_request *req) return _sha_digest(req); } +static int _qcrypto_prefix_alg_cra_name(char cra_name[], unsigned int size) +{ + char new_cra_name[CRYPTO_MAX_ALG_NAME] = "qcom-"; + if (CRYPTO_MAX_ALG_NAME < size + 5) + return -EINVAL; + strlcat(new_cra_name, cra_name, CRYPTO_MAX_ALG_NAME); + strlcpy(cra_name, new_cra_name, CRYPTO_MAX_ALG_NAME); + return 0; +} + int qcrypto_cipher_set_flag(struct ablkcipher_request *req, unsigned int flags) { struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); @@ -3868,6 +3878,17 @@ static int _qcrypto_probe(struct platform_device *pdev) rc = PTR_ERR(q_alg); goto err; } + if (cp->ce_support.use_sw_aes_cbc_ecb_ctr_algo) { + rc = _qcrypto_prefix_alg_cra_name( + q_alg->cipher_alg.cra_name, + strlen(q_alg->cipher_alg.cra_name)); + if (rc) { + dev_err(&pdev->dev, + "The algorithm name %s is too long.\n", + q_alg->cipher_alg.cra_name); + goto err; + } + } rc = crypto_register_alg(&q_alg->cipher_alg); if (rc) { dev_err(&pdev->dev, "%s alg registration failed\n", @@ -3890,6 +3911,17 @@ static int _qcrypto_probe(struct platform_device *pdev) rc = PTR_ERR(q_alg); goto err; } + if (cp->ce_support.use_sw_aes_xts_algo) { + rc = _qcrypto_prefix_alg_cra_name( + q_alg->cipher_alg.cra_name, + strlen(q_alg->cipher_alg.cra_name)); + if (rc) { + dev_err(&pdev->dev, + "The algorithm name %s is too long.\n", + q_alg->cipher_alg.cra_name); + goto err; + } + } rc = crypto_register_alg(&q_alg->cipher_alg); if (rc) { dev_err(&pdev->dev, "%s alg registration failed\n", @@ -3915,7 +3947,17 @@ static int _qcrypto_probe(struct platform_device *pdev) rc = PTR_ERR(q_alg); goto err; } - + if (cp->ce_support.use_sw_ahash_algo) { + rc = _qcrypto_prefix_alg_cra_name( + q_alg->sha_alg.halg.base.cra_name, + strlen(q_alg->sha_alg.halg.base.cra_name)); + if (rc) { + dev_err(&pdev->dev, + "The algorithm name %s is too long.\n", + q_alg->sha_alg.halg.base.cra_name); + goto err; + } + } rc = crypto_register_ahash(&q_alg->sha_alg); if (rc) { dev_err(&pdev->dev, "%s alg registration failed\n", @@ -3941,7 +3983,17 @@ static int _qcrypto_probe(struct platform_device *pdev) rc = PTR_ERR(q_alg); goto err; } - + if (cp->ce_support.use_sw_aead_algo) { + rc = _qcrypto_prefix_alg_cra_name( + q_alg->cipher_alg.cra_name, + strlen(q_alg->cipher_alg.cra_name)); + if (rc) { + dev_err(&pdev->dev, + "The algorithm name %s is too long.\n", + q_alg->cipher_alg.cra_name); + goto err; + } + } rc = crypto_register_alg(&q_alg->cipher_alg); if (rc) { dev_err(&pdev->dev, @@ -3968,7 +4020,18 @@ static int _qcrypto_probe(struct platform_device *pdev) rc = PTR_ERR(q_alg); goto err; } - + if (cp->ce_support.use_sw_hmac_algo) { + rc = _qcrypto_prefix_alg_cra_name( + q_alg->sha_alg.halg.base.cra_name, + strlen( + q_alg->sha_alg.halg.base.cra_name)); + if (rc) { + dev_err(&pdev->dev, + "The algorithm name %s is too long.\n", + q_alg->sha_alg.halg.base.cra_name); + goto err; + } + } rc = crypto_register_ahash(&q_alg->sha_alg); if (rc) { dev_err(&pdev->dev, @@ -3994,6 +4057,17 @@ static int _qcrypto_probe(struct platform_device *pdev) rc = PTR_ERR(q_alg); goto err; } + if (cp->ce_support.use_sw_aes_ccm_algo) { + rc = _qcrypto_prefix_alg_cra_name( + q_alg->cipher_alg.cra_name, + strlen(q_alg->cipher_alg.cra_name)); + if (rc) { + dev_err(&pdev->dev, + "The algorithm name %s is too long.\n", + q_alg->cipher_alg.cra_name); + goto err; + } + } rc = crypto_register_alg(&q_alg->cipher_alg); if (rc) { dev_err(&pdev->dev, "%s alg registration failed\n", @@ -4018,6 +4092,100 @@ err: }; +static int _qcrypto_suspend(struct platform_device *pdev, pm_message_t state) +{ + int ret = 0; + struct crypto_engine *pengine; + struct crypto_priv *cp; + + pengine = platform_get_drvdata(pdev); + if (!pengine) + return -EINVAL; + + /* + * Check if this platform supports clock management in suspend/resume + * If not, just simply return 0. + */ + cp = pengine->pcp; + if (!cp->ce_support.clk_mgmt_sus_res) + return 0; + + mutex_lock(&cp->engine_lock); + + if (pengine->high_bw_req) { + del_timer_sync(&(pengine->bw_scale_down_timer)); + ret = msm_bus_scale_client_update_request( + pengine->bus_scale_handle, 0); + if (ret) { + dev_err(&pdev->dev, "%s Unable to set to low bandwidth\n", + __func__); + mutex_unlock(&cp->engine_lock); + return ret; + } + ret = qce_disable_clk(pengine->qce); + if (ret) { + pr_err("%s Unable disable clk\n", __func__); + ret = msm_bus_scale_client_update_request( + pengine->bus_scale_handle, 1); + if (ret) + dev_err(&pdev->dev, + "%s Unable to set to high bandwidth\n", + __func__); + mutex_unlock(&cp->engine_lock); + return ret; + } + } + + mutex_unlock(&cp->engine_lock); + return 0; +} + +static int _qcrypto_resume(struct platform_device *pdev) +{ + int ret = 0; + struct crypto_engine *pengine; + struct crypto_priv *cp; + + pengine = platform_get_drvdata(pdev); + + if (!pengine) + return -EINVAL; + + cp = pengine->pcp; + if (!cp->ce_support.clk_mgmt_sus_res) + return 0; + + mutex_lock(&cp->engine_lock); + if (pengine->high_bw_req) { + ret = qce_enable_clk(pengine->qce); + if (ret) { + dev_err(&pdev->dev, "%s Unable to enable clk\n", + __func__); + mutex_unlock(&cp->engine_lock); + return ret; + } + ret = msm_bus_scale_client_update_request( + pengine->bus_scale_handle, 1); + if (ret) { + dev_err(&pdev->dev, + "%s Unable to set to high bandwidth\n", + __func__); + qce_disable_clk(pengine->qce); + mutex_unlock(&cp->engine_lock); + return ret; + } + pengine->bw_scale_down_timer.data = + (unsigned long)(pengine); + pengine->bw_scale_down_timer.expires = jiffies + + msecs_to_jiffies(QCRYPTO_HIGH_BANDWIDTH_TIMEOUT); + add_timer(&(pengine->bw_scale_down_timer)); + } + + mutex_unlock(&cp->engine_lock); + + return 0; +} + static struct of_device_id qcrypto_match[] = { { .compatible = "qcom,qcrypto", }, @@ -4027,6 +4195,8 @@ static struct of_device_id qcrypto_match[] = { static struct platform_driver _qualcomm_crypto = { .probe = _qcrypto_probe, .remove = _qcrypto_remove, + .suspend = _qcrypto_suspend, + .resume = _qcrypto_resume, .driver = { .owner = THIS_MODULE, .name = "qcrypto", diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c index a031bf88885..738056d4f7d 100644 --- a/drivers/devfreq/governor_msm_adreno_tz.c +++ b/drivers/devfreq/governor_msm_adreno_tz.c @@ -19,7 +19,7 @@ #include <linux/io.h> #include <linux/ftrace.h> #include <linux/msm_adreno_devfreq.h> -#include <mach/scm.h> +#include <soc/qcom/scm.h> #include "governor.h" static DEFINE_SPINLOCK(tz_lock); diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c index fe69160fff7..add77c2b0b4 100644 --- a/drivers/esoc/esoc-mdm-4x.c +++ b/drivers/esoc/esoc-mdm-4x.c @@ -18,8 +18,8 @@ #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/workqueue.h> +#include <soc/qcom/sysmon.h> #include <mach/gpiomux.h> -#include <mach/sysmon.h> #include "esoc.h" #define MDM_PBLRDY_CNT 20 @@ -465,6 +465,9 @@ static void mdm_notify(enum esoc_notify notify, struct esoc_clink *esoc) schedule_delayed_work(&mdm->mdm2ap_status_check_work, msecs_to_jiffies(MDM2AP_STATUS_TIMEOUT_MS)); break; + case ESOC_BOOT_DONE: + esoc_clink_evt_notify(ESOC_RUN_STATE, esoc); + break; case ESOC_IMG_XFER_RETRY: mdm->init = 1; mdm_toggle_soft_reset(mdm); @@ -547,7 +550,6 @@ static irqreturn_t mdm_status_change(int irq, void *dev_id) } else if (value == 1) { cancel_delayed_work(&mdm->mdm2ap_status_check_work); dev_dbg(dev, "status = 1: mdm is now ready\n"); - esoc_clink_evt_notify(ESOC_RUN_STATE, esoc); mdm->ready = true; queue_work(mdm->mdm_queue, &mdm->mdm_status_work); if (mdm->get_restart_reason) diff --git a/drivers/esoc/esoc.h b/drivers/esoc/esoc.h index 5eab16d5d3d..c4c951e1651 100644 --- a/drivers/esoc/esoc.h +++ b/drivers/esoc/esoc.h @@ -20,8 +20,8 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <mach/subsystem_notif.h> -#include <mach/subsystem_restart.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/subsystem_notif.h> #define ESOC_DEV_MAX 4 #define ESOC_NAME_LEN 20 diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile index 41cd73177e1..d025f5eb5db 100644 --- a/drivers/gpu/Makefile +++ b/drivers/gpu/Makefile @@ -1,3 +1,3 @@ -obj-y += drm/ vga/ ion/ +obj-y += drm/ vga/ obj-$(CONFIG_TEGRA_HOST1X) += host1x/ obj-$(CONFIG_MSM_KGSL) += msm/ diff --git a/drivers/gpu/ion/Kconfig b/drivers/gpu/ion/Kconfig deleted file mode 100644 index 5bb254b1655..00000000000 --- a/drivers/gpu/ion/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -menuconfig ION - tristate "Ion Memory Manager" - select GENERIC_ALLOCATOR - select DMA_SHARED_BUFFER - help - Chose this option to enable the ION Memory Manager. - -config ION_TEGRA - tristate "Ion for Tegra" - depends on ARCH_TEGRA && ION - help - Choose this option if you wish to use ion on an nVidia Tegra. - -config ION_MSM - tristate "Ion for MSM" - depends on ARCH_MSM && ION - help - Choose this option if you wish to use ion on an MSM target. diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c deleted file mode 100644 index 5dd15bf03c2..00000000000 --- a/drivers/gpu/ion/ion_cp_heap.c +++ /dev/null @@ -1,887 +0,0 @@ -/* - * drivers/gpu/ion/ion_cp_heap.c - * - * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include <linux/spinlock.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/genalloc.h> -#include <linux/io.h> -#include <linux/msm_ion.h> -#include <linux/mm.h> -#include <linux/scatterlist.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/seq_file.h> -#include <linux/iommu.h> -#include <linux/dma-mapping.h> -#include <trace/events/kmem.h> - -#include <mach/scm.h> - -#include "ion_priv.h" - -#include <asm/cacheflush.h> - -#include "msm/ion_cp_common.h" -/** - * struct ion_cp_heap - container for the heap and shared heap data - - * @heap: the heap information structure - * @pool: memory pool to allocate from. - * @base: the base address of the memory pool. - * @permission_type: Identifier for the memory used by SCM for protecting - * and unprotecting memory. - * @secure_base: Base address used when securing a heap that is shared. - * @secure_size: Size used when securing a heap that is shared. - * @lock: mutex to protect shared access. - * @heap_protected: Indicates whether heap has been protected or not. - * @allocated_bytes: the total number of allocated bytes from the pool. - * @total_size: the total size of the memory pool. - * @request_region: function pointer to call when first mapping of memory - * occurs. - * @release_region: function pointer to call when last mapping of memory - * unmapped. - * @bus_id: token used with request/release region. - * @kmap_cached_count: the total number of times this heap has been mapped in - * kernel space (cached). - * @kmap_uncached_count:the total number of times this heap has been mapped in - * kernel space (un-cached). - * @umap_count: the total number of times this heap has been mapped in - * user space. - * @has_outer_cache: set to 1 if outer cache is used, 0 otherwise. -*/ -struct ion_cp_heap { - struct ion_heap heap; - struct gen_pool *pool; - ion_phys_addr_t base; - unsigned int permission_type; - ion_phys_addr_t secure_base; - size_t secure_size; - struct mutex lock; - unsigned int heap_protected; - unsigned long allocated_bytes; - unsigned long total_size; - int (*heap_request_region)(void *); - int (*heap_release_region)(void *); - void *bus_id; - unsigned long kmap_cached_count; - unsigned long kmap_uncached_count; - unsigned long umap_count; - unsigned int has_outer_cache; - atomic_t protect_cnt; - void *cpu_addr; - size_t heap_size; - dma_addr_t handle; - int cma; - int allow_non_secure_allocation; -}; - -enum { - HEAP_NOT_PROTECTED = 0, - HEAP_PROTECTED = 1, -}; - -/* SCM related code for locking down memory for content protection */ - -#define SCM_CP_LOCK_CMD_ID 0x1 -#define SCM_CP_PROTECT 0x1 -#define SCM_CP_UNPROTECT 0x0 - -struct cp_lock_msg { - unsigned int start; - unsigned int end; - unsigned int permission_type; - unsigned char lock; -} __attribute__ ((__packed__)); - -#define DMA_ALLOC_TRIES 5 - -static int allocate_heap_memory(struct ion_heap *heap) -{ - struct device *dev = heap->priv; - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - int ret; - int tries = 0; - DEFINE_DMA_ATTRS(attrs); - dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); - - - if (cp_heap->cpu_addr) - return 0; - - while (!cp_heap->cpu_addr && (++tries < DMA_ALLOC_TRIES)) { - cp_heap->cpu_addr = dma_alloc_attrs(dev, - cp_heap->heap_size, - &(cp_heap->handle), - 0, - &attrs); - if (!cp_heap->cpu_addr) { - trace_ion_cp_alloc_retry(tries); - msleep(20); - } - } - - if (!cp_heap->cpu_addr) - goto out; - - cp_heap->base = cp_heap->handle; - - cp_heap->pool = gen_pool_create(12, -1); - if (!cp_heap->pool) - goto out_free; - - ret = gen_pool_add(cp_heap->pool, cp_heap->base, - cp_heap->heap_size, -1); - if (ret < 0) - goto out_pool; - - return 0; - -out_pool: - gen_pool_destroy(cp_heap->pool); -out_free: - dma_free_coherent(dev, cp_heap->heap_size, cp_heap->cpu_addr, - cp_heap->handle); -out: - return ION_CP_ALLOCATE_FAIL; -} - -static void free_heap_memory(struct ion_heap *heap) -{ - struct device *dev = heap->priv; - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - - /* release memory */ - dma_free_coherent(dev, cp_heap->heap_size, cp_heap->cpu_addr, - cp_heap->handle); - gen_pool_destroy(cp_heap->pool); - cp_heap->pool = NULL; - cp_heap->cpu_addr = 0; -} - - - -/** - * Get the total number of kernel mappings. - * Must be called with heap->lock locked. - */ -static unsigned long ion_cp_get_total_kmap_count( - const struct ion_cp_heap *cp_heap) -{ - return cp_heap->kmap_cached_count + cp_heap->kmap_uncached_count; -} - -static int ion_on_first_alloc(struct ion_heap *heap) -{ - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - int ret_value; - - if (cp_heap->cma) { - ret_value = allocate_heap_memory(heap); - if (ret_value) - return 1; - } - return 0; -} - -static void ion_on_last_free(struct ion_heap *heap) -{ - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - - if (cp_heap->cma) - free_heap_memory(heap); -} - -/** - * Protects memory if heap is unsecured heap. - * Must be called with heap->lock locked. - */ -static int ion_cp_protect(struct ion_heap *heap, int version, void *data) -{ - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - int ret_value = 0; - - if (atomic_inc_return(&cp_heap->protect_cnt) == 1) { - /* Make sure we are in C state when the heap is protected. */ - if (!cp_heap->allocated_bytes) - if (ion_on_first_alloc(heap)) - goto out; - - ret_value = ion_cp_protect_mem(cp_heap->secure_base, - cp_heap->secure_size, cp_heap->permission_type, - version, data); - if (ret_value) { - pr_err("Failed to protect memory for heap %s - " - "error code: %d\n", heap->name, ret_value); - - if (!cp_heap->allocated_bytes) - ion_on_last_free(heap); - - atomic_dec(&cp_heap->protect_cnt); - } else { - cp_heap->heap_protected = HEAP_PROTECTED; - pr_debug("Protected heap %s @ 0x%pa\n", - heap->name, &cp_heap->base); - } - } -out: - pr_debug("%s: protect count is %d\n", __func__, - atomic_read(&cp_heap->protect_cnt)); - BUG_ON(atomic_read(&cp_heap->protect_cnt) < 0); - return ret_value; -} - -/** - * Unprotects memory if heap is secure heap. - * Must be called with heap->lock locked. - */ -static void ion_cp_unprotect(struct ion_heap *heap, int version, void *data) -{ - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - - if (atomic_dec_and_test(&cp_heap->protect_cnt)) { - int error_code = ion_cp_unprotect_mem( - cp_heap->secure_base, cp_heap->secure_size, - cp_heap->permission_type, version, data); - if (error_code) { - pr_err("Failed to un-protect memory for heap %s - " - "error code: %d\n", heap->name, error_code); - } else { - cp_heap->heap_protected = HEAP_NOT_PROTECTED; - pr_debug("Un-protected heap %s @ 0x%x\n", heap->name, - (unsigned int) cp_heap->base); - - if (!cp_heap->allocated_bytes) - ion_on_last_free(heap); - } - } - pr_debug("%s: protect count is %d\n", __func__, - atomic_read(&cp_heap->protect_cnt)); - BUG_ON(atomic_read(&cp_heap->protect_cnt) < 0); -} - -ion_phys_addr_t ion_cp_allocate(struct ion_heap *heap, - unsigned long size, - unsigned long align, - unsigned long flags) -{ - unsigned long offset; - unsigned long secure_allocation = flags & ION_FLAG_SECURE; - unsigned long force_contig = flags & ION_FLAG_FORCE_CONTIGUOUS; - - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - - mutex_lock(&cp_heap->lock); - if (!secure_allocation && cp_heap->heap_protected == HEAP_PROTECTED) { - mutex_unlock(&cp_heap->lock); - pr_err("ION cannot allocate un-secure memory from protected" - " heap %s\n", heap->name); - return ION_CP_ALLOCATE_FAIL; - } - - if (!force_contig && !secure_allocation && - !cp_heap->allow_non_secure_allocation) { - mutex_unlock(&cp_heap->lock); - pr_debug("%s: non-secure allocation disallowed from this heap\n", - __func__); - return ION_CP_ALLOCATE_FAIL; - } - - /* - * The check above already checked for non-secure allocations when the - * heap is protected. HEAP_PROTECTED implies that this must be a secure - * allocation. If the heap is protected and there are userspace or - * cached kernel mappings, something has gone wrong in the security - * model. - */ - if (cp_heap->heap_protected == HEAP_PROTECTED) { - BUG_ON(cp_heap->umap_count != 0); - BUG_ON(cp_heap->kmap_cached_count != 0); - } - - /* - * if this is the first reusable allocation, transition - * the heap - */ - if (!cp_heap->allocated_bytes) - if (ion_on_first_alloc(heap)) { - mutex_unlock(&cp_heap->lock); - return ION_RESERVED_ALLOCATE_FAIL; - } - - cp_heap->allocated_bytes += size; - mutex_unlock(&cp_heap->lock); - - offset = gen_pool_alloc_aligned(cp_heap->pool, - size, ilog2(align)); - - if (!offset) { - mutex_lock(&cp_heap->lock); - cp_heap->allocated_bytes -= size; - if ((cp_heap->total_size - - cp_heap->allocated_bytes) >= size) - pr_debug("%s: heap %s has enough memory (%lx) but" - " the allocation of size %lx still failed." - " Memory is probably fragmented.\n", - __func__, heap->name, - cp_heap->total_size - - cp_heap->allocated_bytes, size); - if (!cp_heap->allocated_bytes && - cp_heap->heap_protected == HEAP_NOT_PROTECTED) - ion_on_last_free(heap); - mutex_unlock(&cp_heap->lock); - - return ION_CP_ALLOCATE_FAIL; - } - - return offset; -} - -void ion_cp_free(struct ion_heap *heap, ion_phys_addr_t addr, - unsigned long size) -{ - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - - if (addr == ION_CP_ALLOCATE_FAIL) - return; - gen_pool_free(cp_heap->pool, addr, size); - - mutex_lock(&cp_heap->lock); - cp_heap->allocated_bytes -= size; - - if (!cp_heap->allocated_bytes && - cp_heap->heap_protected == HEAP_NOT_PROTECTED) - ion_on_last_free(heap); - - mutex_unlock(&cp_heap->lock); -} - -static int ion_cp_heap_phys(struct ion_heap *heap, - struct ion_buffer *buffer, - ion_phys_addr_t *addr, size_t *len) -{ - struct ion_cp_buffer *buf = buffer->priv_virt; - - *addr = buf->buffer; - *len = buffer->size; - return 0; -} - -static int ion_cp_heap_allocate(struct ion_heap *heap, - struct ion_buffer *buffer, - unsigned long size, unsigned long align, - unsigned long flags) -{ - struct ion_cp_buffer *buf; - phys_addr_t addr; - - /* - * we never want Ion to fault pages in for us with this - * heap. We want to set up the mappings ourselves in .map_user - */ - flags |= ION_FLAG_CACHED_NEEDS_SYNC; - - buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (!buf) - return ION_CP_ALLOCATE_FAIL; - - addr = ion_cp_allocate(heap, size, align, flags); - if (addr == ION_CP_ALLOCATE_FAIL) - return -ENOMEM; - - buf->buffer = addr; - buf->want_delayed_unsecure = 0; - atomic_set(&buf->secure_cnt, 0); - mutex_init(&buf->lock); - buf->is_secure = flags & ION_FLAG_SECURE ? 1 : 0; - buffer->priv_virt = buf; - - return 0; -} - -static void ion_cp_heap_free(struct ion_buffer *buffer) -{ - struct ion_heap *heap = buffer->heap; - struct ion_cp_buffer *buf = buffer->priv_virt; - - ion_cp_free(heap, buf->buffer, buffer->size); - WARN_ON(atomic_read(&buf->secure_cnt)); - WARN_ON(atomic_read(&buf->map_cnt)); - kfree(buf); - - buffer->priv_virt = NULL; -} - -struct sg_table *ion_cp_heap_create_sg_table(struct ion_buffer *buffer) -{ - size_t chunk_size = buffer->size; - struct ion_cp_buffer *buf = buffer->priv_virt; - - if (ION_IS_CACHED(buffer->flags)) - chunk_size = PAGE_SIZE; - else if (buf->is_secure && IS_ALIGNED(buffer->size, SZ_1M)) - chunk_size = SZ_1M; - - return ion_create_chunked_sg_table(buf->buffer, chunk_size, - buffer->size); -} - -struct sg_table *ion_cp_heap_map_dma(struct ion_heap *heap, - struct ion_buffer *buffer) -{ - return ion_cp_heap_create_sg_table(buffer); -} - -void ion_cp_heap_unmap_dma(struct ion_heap *heap, - struct ion_buffer *buffer) -{ - if (buffer->sg_table) - sg_free_table(buffer->sg_table); - kfree(buffer->sg_table); - buffer->sg_table = 0; -} - -/** - * Call request region for SMI memory of this is the first mapping. - */ -static int ion_cp_request_region(struct ion_cp_heap *cp_heap) -{ - int ret_value = 0; - if ((cp_heap->umap_count + ion_cp_get_total_kmap_count(cp_heap)) == 0) - if (cp_heap->heap_request_region) - ret_value = cp_heap->heap_request_region( - cp_heap->bus_id); - return ret_value; -} - -/** - * Call release region for SMI memory of this is the last un-mapping. - */ -static int ion_cp_release_region(struct ion_cp_heap *cp_heap) -{ - int ret_value = 0; - if ((cp_heap->umap_count + ion_cp_get_total_kmap_count(cp_heap)) == 0) - if (cp_heap->heap_release_region) - ret_value = cp_heap->heap_release_region( - cp_heap->bus_id); - return ret_value; -} - -void *ion_cp_heap_map_kernel(struct ion_heap *heap, struct ion_buffer *buffer) -{ - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - void *ret_value = NULL; - struct ion_cp_buffer *buf = buffer->priv_virt; - - mutex_lock(&cp_heap->lock); - if ((cp_heap->heap_protected == HEAP_NOT_PROTECTED) || - ((cp_heap->heap_protected == HEAP_PROTECTED) && - !ION_IS_CACHED(buffer->flags))) { - - if (ion_cp_request_region(cp_heap)) { - mutex_unlock(&cp_heap->lock); - return NULL; - } - - if (cp_heap->cma) { - int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; - struct page **pages = vmalloc( - sizeof(struct page *) * npages); - int i; - pgprot_t pgprot; - - if (!pages) { - mutex_unlock(&cp_heap->lock); - return ERR_PTR(-ENOMEM); - } - - if (ION_IS_CACHED(buffer->flags)) - pgprot = PAGE_KERNEL; - else - pgprot = pgprot_writecombine(PAGE_KERNEL); - - for (i = 0; i < npages; i++) { - pages[i] = phys_to_page(buf->buffer + - i * PAGE_SIZE); - } - ret_value = vmap(pages, npages, VM_IOREMAP, pgprot); - vfree(pages); - } else { - if (ION_IS_CACHED(buffer->flags)) - ret_value = ioremap_cached(buf->buffer, - buffer->size); - else - ret_value = ioremap(buf->buffer, - buffer->size); - } - - if (!ret_value) { - ion_cp_release_region(cp_heap); - } else { - if (ION_IS_CACHED(buffer->flags)) - ++cp_heap->kmap_cached_count; - else - ++cp_heap->kmap_uncached_count; - atomic_inc(&buf->map_cnt); - } - } - mutex_unlock(&cp_heap->lock); - return ret_value; -} - -void ion_cp_heap_unmap_kernel(struct ion_heap *heap, - struct ion_buffer *buffer) -{ - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - struct ion_cp_buffer *buf = buffer->priv_virt; - - if (cp_heap->cma) - vunmap(buffer->vaddr); - else - iounmap(buffer->vaddr); - - buffer->vaddr = NULL; - - mutex_lock(&cp_heap->lock); - if (ION_IS_CACHED(buffer->flags)) - --cp_heap->kmap_cached_count; - else - --cp_heap->kmap_uncached_count; - - atomic_dec(&buf->map_cnt); - ion_cp_release_region(cp_heap); - mutex_unlock(&cp_heap->lock); - - return; -} - -int ion_cp_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, - struct vm_area_struct *vma) -{ - int ret_value = -EAGAIN; - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - struct ion_cp_buffer *buf = buffer->priv_virt; - - mutex_lock(&cp_heap->lock); - if (cp_heap->heap_protected == HEAP_NOT_PROTECTED && !buf->is_secure) { - if (ion_cp_request_region(cp_heap)) { - mutex_unlock(&cp_heap->lock); - return -EINVAL; - } - - if (!ION_IS_CACHED(buffer->flags)) - vma->vm_page_prot = pgprot_writecombine( - vma->vm_page_prot); - - ret_value = remap_pfn_range(vma, vma->vm_start, - __phys_to_pfn(buf->buffer) + vma->vm_pgoff, - vma->vm_end - vma->vm_start, - vma->vm_page_prot); - - if (ret_value) { - ion_cp_release_region(cp_heap); - } else { - atomic_inc(&buf->map_cnt); - ++cp_heap->umap_count; - } - - } - mutex_unlock(&cp_heap->lock); - return ret_value; -} - -void ion_cp_heap_unmap_user(struct ion_heap *heap, - struct ion_buffer *buffer) -{ - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - struct ion_cp_buffer *buf = buffer->priv_virt; - - mutex_lock(&cp_heap->lock); - --cp_heap->umap_count; - atomic_dec(&buf->map_cnt); - ion_cp_release_region(cp_heap); - mutex_unlock(&cp_heap->lock); -} - -static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s, - const struct list_head *mem_map) -{ - unsigned long total_alloc; - unsigned long total_size; - unsigned long umap_count; - unsigned long kmap_count; - unsigned long heap_protected; - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - - mutex_lock(&cp_heap->lock); - total_alloc = cp_heap->allocated_bytes; - total_size = cp_heap->total_size; - umap_count = cp_heap->umap_count; - kmap_count = ion_cp_get_total_kmap_count(cp_heap); - heap_protected = cp_heap->heap_protected == HEAP_PROTECTED; - mutex_unlock(&cp_heap->lock); - - seq_printf(s, "total bytes currently allocated: %lx\n", total_alloc); - seq_printf(s, "total heap size: %lx\n", total_size); - seq_printf(s, "umapping count: %lx\n", umap_count); - seq_printf(s, "kmapping count: %lx\n", kmap_count); - seq_printf(s, "heap protected: %s\n", heap_protected ? "Yes" : "No"); - - if (mem_map) { - unsigned long base = cp_heap->base; - unsigned long size = cp_heap->total_size; - unsigned long end = base+size; - unsigned long last_end = base; - struct mem_map_data *data; - - seq_printf(s, "\nMemory Map\n"); - seq_printf(s, "%16.s %14.s %14.s %14.s\n", - "client", "start address", "end address", - "size (hex)"); - - list_for_each_entry(data, mem_map, node) { - const char *client_name = "(null)"; - - if (last_end < data->addr) { - phys_addr_t da; - - da = data->addr-1; - seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n", - "FREE", &last_end, &da, - (unsigned long)data->addr-last_end, - (unsigned long)data->addr-last_end); - } - - if (data->client_name) - client_name = data->client_name; - - seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n", - client_name, &data->addr, - &data->addr_end, - data->size, data->size); - last_end = data->addr_end+1; - } - if (last_end < end) { - seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n", "FREE", - last_end, end-1, end-last_end, end-last_end); - } - } - - return 0; -} - -int ion_cp_secure_heap(struct ion_heap *heap, int version, void *data) -{ - int ret_value; - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - mutex_lock(&cp_heap->lock); - if (cp_heap->umap_count == 0 && cp_heap->kmap_cached_count == 0) { - ret_value = ion_cp_protect(heap, version, data); - } else { - pr_err("ION cannot secure heap with outstanding mappings: " - "User space: %lu, kernel space (cached): %lu\n", - cp_heap->umap_count, cp_heap->kmap_cached_count); - ret_value = -EINVAL; - } - - mutex_unlock(&cp_heap->lock); - return ret_value; -} - -int ion_cp_unsecure_heap(struct ion_heap *heap, int version, void *data) -{ - int ret_value = 0; - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - mutex_lock(&cp_heap->lock); - ion_cp_unprotect(heap, version, data); - mutex_unlock(&cp_heap->lock); - return ret_value; -} - -static struct ion_heap_ops cp_heap_ops = { - .allocate = ion_cp_heap_allocate, - .free = ion_cp_heap_free, - .phys = ion_cp_heap_phys, - .map_user = ion_cp_heap_map_user, - .unmap_user = ion_cp_heap_unmap_user, - .map_kernel = ion_cp_heap_map_kernel, - .unmap_kernel = ion_cp_heap_unmap_kernel, - .map_dma = ion_cp_heap_map_dma, - .unmap_dma = ion_cp_heap_unmap_dma, - .print_debug = ion_cp_print_debug, - .secure_heap = ion_cp_secure_heap, - .unsecure_heap = ion_cp_unsecure_heap, -}; - -struct ion_heap *ion_cp_heap_create(struct ion_platform_heap *heap_data) -{ - struct ion_cp_heap *cp_heap; - int ret; - - cp_heap = kzalloc(sizeof(*cp_heap), GFP_KERNEL); - if (!cp_heap) - return ERR_PTR(-ENOMEM); - - mutex_init(&cp_heap->lock); - - - cp_heap->allocated_bytes = 0; - cp_heap->umap_count = 0; - cp_heap->kmap_cached_count = 0; - cp_heap->kmap_uncached_count = 0; - cp_heap->total_size = heap_data->size; - cp_heap->heap.ops = &cp_heap_ops; - cp_heap->heap.type = (enum ion_heap_type) ION_HEAP_TYPE_CP; - cp_heap->heap_protected = HEAP_NOT_PROTECTED; - cp_heap->secure_base = heap_data->base; - cp_heap->secure_size = heap_data->size; - cp_heap->has_outer_cache = heap_data->has_outer_cache; - cp_heap->heap_size = heap_data->size; - - atomic_set(&cp_heap->protect_cnt, 0); - if (heap_data->extra_data) { - struct ion_cp_heap_pdata *extra_data = - heap_data->extra_data; - cp_heap->permission_type = extra_data->permission_type; - if (extra_data->secure_size) { - cp_heap->secure_base = extra_data->secure_base; - cp_heap->secure_size = extra_data->secure_size; - } - if (extra_data->setup_region) - cp_heap->bus_id = extra_data->setup_region(); - if (extra_data->request_region) - cp_heap->heap_request_region = - extra_data->request_region; - if (extra_data->release_region) - cp_heap->heap_release_region = - extra_data->release_region; - cp_heap->cma = extra_data->is_cma; - cp_heap->allow_non_secure_allocation = - extra_data->allow_nonsecure_alloc; - - } - - if (cp_heap->cma) { - cp_heap->pool = NULL; - cp_heap->cpu_addr = 0; - cp_heap->heap.priv = heap_data->priv; - } else { - cp_heap->pool = gen_pool_create(12, -1); - if (!cp_heap->pool) - goto free_heap; - - cp_heap->base = heap_data->base; - ret = gen_pool_add(cp_heap->pool, cp_heap->base, - heap_data->size, -1); - if (ret < 0) - goto destroy_pool; - - } - return &cp_heap->heap; - -destroy_pool: - gen_pool_destroy(cp_heap->pool); - -free_heap: - kfree(cp_heap); - - return ERR_PTR(-ENOMEM); -} - -void ion_cp_heap_destroy(struct ion_heap *heap) -{ - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - - gen_pool_destroy(cp_heap->pool); - kfree(cp_heap); - cp_heap = NULL; -} - -void ion_cp_heap_get_base(struct ion_heap *heap, unsigned long *base, - unsigned long *size) \ -{ - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - *base = cp_heap->base; - *size = cp_heap->total_size; -} - -static int ion_cp_protect_mem_v1(unsigned int phy_base, unsigned int size, - unsigned int permission_type) -{ - struct cp_lock_msg cmd; - cmd.start = phy_base; - cmd.end = phy_base + size; - cmd.permission_type = permission_type; - cmd.lock = SCM_CP_PROTECT; - - return scm_call(SCM_SVC_MP, SCM_CP_LOCK_CMD_ID, - &cmd, sizeof(cmd), NULL, 0); -} - -static int ion_cp_unprotect_mem_v1(unsigned int phy_base, unsigned int size, - unsigned int permission_type) -{ - struct cp_lock_msg cmd; - cmd.start = phy_base; - cmd.end = phy_base + size; - cmd.permission_type = permission_type; - cmd.lock = SCM_CP_UNPROTECT; - - return scm_call(SCM_SVC_MP, SCM_CP_LOCK_CMD_ID, - &cmd, sizeof(cmd), NULL, 0); -} - -int ion_cp_protect_mem(unsigned int phy_base, unsigned int size, - unsigned int permission_type, int version, - void *data) -{ - switch (version) { - case ION_CP_V1: - return ion_cp_protect_mem_v1(phy_base, size, permission_type); - default: - return -EINVAL; - } -} - -int ion_cp_unprotect_mem(unsigned int phy_base, unsigned int size, - unsigned int permission_type, int version, - void *data) -{ - switch (version) { - case ION_CP_V1: - return ion_cp_unprotect_mem_v1(phy_base, size, permission_type); - default: - return -EINVAL; - } -} - diff --git a/drivers/gpu/ion/ion_system_mapper.c b/drivers/gpu/ion/ion_system_mapper.c deleted file mode 100644 index 692458e07b5..00000000000 --- a/drivers/gpu/ion/ion_system_mapper.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * drivers/gpu/ion/ion_system_mapper.c - * - * Copyright (C) 2011 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. - * - */ - -#include <linux/err.h> -#include <linux/ion.h> -#include <linux/memory.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include "ion_priv.h" -/* - * This mapper is valid for any heap that allocates memory that already has - * a kernel mapping, this includes vmalloc'd memory, kmalloc'd memory, - * pages obtained via io_remap, etc. - */ -static void *ion_kernel_mapper_map(struct ion_mapper *mapper, - struct ion_buffer *buffer, - struct ion_mapping **mapping) -{ - if (!((1 << buffer->heap->type) & mapper->heap_mask)) { - pr_err("%s: attempting to map an unsupported heap\n", __func__); - return ERR_PTR(-EINVAL); - } - /* XXX REVISIT ME!!! */ - *((unsigned long *)mapping) = (unsigned long)buffer->priv; - return buffer->priv; -} - -static void ion_kernel_mapper_unmap(struct ion_mapper *mapper, - struct ion_buffer *buffer, - struct ion_mapping *mapping) -{ - if (!((1 << buffer->heap->type) & mapper->heap_mask)) - pr_err("%s: attempting to unmap an unsupported heap\n", - __func__); -} - -static void *ion_kernel_mapper_map_kernel(struct ion_mapper *mapper, - struct ion_buffer *buffer, - struct ion_mapping *mapping) -{ - if (!((1 << buffer->heap->type) & mapper->heap_mask)) { - pr_err("%s: attempting to unmap an unsupported heap\n", - __func__); - return ERR_PTR(-EINVAL); - } - return buffer->priv; -} - -static int ion_kernel_mapper_map_user(struct ion_mapper *mapper, - struct ion_buffer *buffer, - struct vm_area_struct *vma, - struct ion_mapping *mapping) -{ - int ret; - - switch (buffer->heap->type) { - case ION_HEAP_KMALLOC: - { - unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv)); - ret = remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff, - vma->vm_end - vma->vm_start, - vma->vm_page_prot); - break; - } - case ION_HEAP_VMALLOC: - ret = remap_vmalloc_range(vma, buffer->priv, vma->vm_pgoff); - break; - default: - pr_err("%s: attempting to map unsupported heap to userspace\n", - __func__); - return -EINVAL; - } - - return ret; -} - -static struct ion_mapper_ops ops = { - .map = ion_kernel_mapper_map, - .map_kernel = ion_kernel_mapper_map_kernel, - .map_user = ion_kernel_mapper_map_user, - .unmap = ion_kernel_mapper_unmap, -}; - -struct ion_mapper *ion_system_mapper_create(void) -{ - struct ion_mapper *mapper; - mapper = kzalloc(sizeof(struct ion_mapper), GFP_KERNEL); - if (!mapper) - return ERR_PTR(-ENOMEM); - mapper->type = ION_SYSTEM_MAPPER; - mapper->ops = &ops; - mapper->heap_mask = (1 << ION_HEAP_VMALLOC) | (1 << ION_HEAP_KMALLOC); - return mapper; -} - -void ion_system_mapper_destroy(struct ion_mapper *mapper) -{ - kfree(mapper); -} - diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 46ac589c78b..35ab19c634c 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1162,9 +1162,11 @@ static int adreno_iommu_setstate(struct kgsl_device *device, * after the command has been retired */ if (result) - kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false); + kgsl_mmu_disable_clk(&device->mmu, + KGSL_IOMMU_CONTEXT_USER); else - kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts, true); + kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts, + KGSL_IOMMU_CONTEXT_USER); done: kgsl_context_put(context); @@ -1449,6 +1451,12 @@ static int adreno_of_get_pdata(struct platform_device *pdev) if (ret) goto err; + /* get pm_qos from target, set it to default if not found */ + if (adreno_of_read_property(pdev->dev.of_node, "qcom,pm_qos_latency", + &pdata->pm_qos_latency)) + pdata->pm_qos_latency = 501; + + if (adreno_of_read_property(pdev->dev.of_node, "qcom,idle-timeout", &pdata->idle_timeout)) pdata->idle_timeout = HZ/12; diff --git a/drivers/gpu/msm/adreno_a4xx_snapshot.c b/drivers/gpu/msm/adreno_a4xx_snapshot.c index 3655325305f..cc6a37b8c1e 100644 --- a/drivers/gpu/msm/adreno_a4xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a4xx_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -326,6 +326,7 @@ void *a4xx_snapshot(struct adreno_device *adreno_dev, void *snapshot, goto skip_regs; } if (kgsl_mmu_enable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_PRIV)) { + kgsl_mmu_disable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_USER); KGSL_CORE_ERR("Failed to turn on iommu priv context clocks\n"); goto skip_regs; } @@ -333,6 +334,9 @@ void *a4xx_snapshot(struct adreno_device *adreno_dev, void *snapshot, snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain, kgsl_snapshot_dump_regs, &list); + + kgsl_mmu_disable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_USER); + kgsl_mmu_disable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_PRIV); skip_regs: snapshot = kgsl_snapshot_indexed_registers(device, snapshot, remain, @@ -399,7 +403,5 @@ skip_regs: kgsl_regwrite(device, A4XX_RBBM_CLOCK_CTL2, clock_ctl2); - /* This will only disable the clock if no one else turned on */ - kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, 0); return snapshot; } diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 68d766ae716..aac609f3a06 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -652,7 +652,8 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, total_sizedwords += (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) ? 2 : 0; /* Add two dwords for the CP_INTERRUPT */ - total_sizedwords += drawctxt ? 2 : 0; + total_sizedwords += + (drawctxt || (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) ? 2 : 0; /* context rollover */ if (adreno_is_a3xx(adreno_dev)) diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index a791d67c8e0..5454498f6db 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -457,7 +457,7 @@ done: * Disables iommu clocks * Return - void */ -static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu) +static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu, int ctx_id) { struct kgsl_iommu *iommu = mmu->priv; struct msm_iommu_drvdata *iommu_drvdata; @@ -466,8 +466,15 @@ static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu) for (i = 0; i < iommu->unit_count; i++) { struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i]; for (j = 0; j < iommu_unit->dev_count; j++) { - if (!iommu_unit->dev[j].clk_enabled) + if (ctx_id != iommu_unit->dev[j].ctx_id) continue; + atomic_dec(&iommu_unit->dev[j].clk_enable_count); + BUG_ON( + atomic_read(&iommu_unit->dev[j].clk_enable_count) < 0); + /* + * the clock calls have a refcount so call them on every + * enable/disable call + */ iommu_drvdata = dev_get_drvdata( iommu_unit->dev[j].dev->parent); if (iommu_drvdata->aclk) @@ -475,7 +482,6 @@ static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu) if (iommu_drvdata->clk) clk_disable_unprepare(iommu_drvdata->clk); clk_disable_unprepare(iommu_drvdata->pclk); - iommu_unit->dev[j].clk_enabled = false; } } } @@ -496,32 +502,14 @@ static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data, unsigned int id, unsigned int ts, u32 type) { - struct kgsl_mmu *mmu = data; - struct kgsl_iommu *iommu = mmu->priv; - - if (!iommu->clk_event_queued) { - if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) - KGSL_DRV_ERR(device, - "IOMMU disable clock event being cancelled, " - "iommu_last_cmd_ts: %x, retired ts: %x\n", - iommu->iommu_last_cmd_ts, ts); - return; - } + struct kgsl_iommu_disable_clk_param *param = data; - if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) { - kgsl_iommu_disable_clk(mmu); - iommu->clk_event_queued = false; - } else { - /* add new event to fire when ts is reached, this can happen - * if we queued an event and someone requested the clocks to - * be disbaled on a later timestamp */ - if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts, - kgsl_iommu_clk_disable_event, mmu, mmu)) { - KGSL_DRV_ERR(device, - "Failed to add IOMMU disable clk event\n"); - iommu->clk_event_queued = false; - } - } + if ((0 <= timestamp_cmp(ts, param->ts)) || + (KGSL_EVENT_CANCELLED == type)) + kgsl_iommu_disable_clk(param->mmu, param->ctx_id); + else + /* something went wrong with the event handling mechanism */ + BUG_ON(1); } /* @@ -531,6 +519,8 @@ static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data, * @ts_valid - Indicates whether ts parameter is valid, if this parameter * is false then it means that the calling function wants to disable the * IOMMU clocks immediately without waiting for any timestamp + * @ctx_id: Context id of the IOMMU context for which clocks are to be + * turned off * * Creates an event to disable the IOMMU clocks on timestamp and if event * already exists then updates the timestamp of disabling the IOMMU clocks @@ -539,28 +529,25 @@ static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data, * Return - void */ static void -kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, unsigned int ts, - bool ts_valid) +kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, + unsigned int ts, int ctx_id) { - struct kgsl_iommu *iommu = mmu->priv; + struct kgsl_iommu_disable_clk_param *param; - if (iommu->clk_event_queued) { - if (ts_valid && (0 < - timestamp_cmp(ts, iommu->iommu_last_cmd_ts))) - iommu->iommu_last_cmd_ts = ts; - } else { - if (ts_valid) { - iommu->iommu_last_cmd_ts = ts; - iommu->clk_event_queued = true; - if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL, - ts, kgsl_iommu_clk_disable_event, mmu, mmu)) { - KGSL_DRV_ERR(mmu->device, - "Failed to add IOMMU disable clk event\n"); - iommu->clk_event_queued = false; - } - } else { - kgsl_iommu_disable_clk(mmu); - } + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + KGSL_CORE_ERR("kzalloc(%d) failed\n", sizeof(*param)); + return; + } + param->mmu = mmu; + param->ctx_id = ctx_id; + param->ts = ts; + + if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL, + ts, kgsl_iommu_clk_disable_event, param, mmu)) { + KGSL_DRV_ERR(mmu->device, + "Failed to add IOMMU disable clk event\n"); + kfree(param); } } @@ -583,8 +570,7 @@ static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu, for (i = 0; i < iommu->unit_count; i++) { struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i]; for (j = 0; j < iommu_unit->dev_count; j++) { - if (iommu_unit->dev[j].clk_enabled || - ctx_id != iommu_unit->dev[j].ctx_id) + if (ctx_id != iommu_unit->dev[j].ctx_id) continue; iommu_drvdata = dev_get_drvdata(iommu_unit->dev[j].dev->parent); @@ -610,12 +596,25 @@ static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu, goto done; } } - iommu_unit->dev[j].clk_enabled = true; + atomic_inc(&iommu_unit->dev[j].clk_enable_count); } } done: - if (ret) - kgsl_iommu_disable_clk(mmu); + if (ret) { + struct kgsl_iommu_unit *iommu_unit; + if (iommu->unit_count == i) + i--; + iommu_unit = &iommu->iommu_units[i]; + do { + for (j--; j >= 0; j--) + kgsl_iommu_disable_clk(mmu, ctx_id); + i--; + if (i >= 0) { + iommu_unit = &iommu->iommu_units[i]; + j = iommu_unit->dev_count; + } + } while (i >= 0); + } return ret; } @@ -842,6 +841,9 @@ static int _get_iommu_ctxs(struct kgsl_mmu *mmu, ret = -EINVAL; goto done; } + atomic_set( + &(iommu_unit->dev[iommu_unit->dev_count].clk_enable_count), + 0); iommu_unit->dev[iommu_unit->dev_count].dev = msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name); @@ -1625,6 +1627,7 @@ static int kgsl_iommu_start(struct kgsl_mmu *mmu) } status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV); if (status) { + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); KGSL_CORE_ERR("clk enable failed\n"); goto done; } @@ -1670,14 +1673,11 @@ static int kgsl_iommu_start(struct kgsl_mmu *mmu) KGSL_IOMMU_SETSTATE_NOP_OFFSET, cp_nop_packet(1), sizeof(unsigned int)); - kgsl_iommu_disable_clk_on_ts(mmu, 0, false); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV); mmu->flags |= KGSL_FLAGS_STARTED; done: - if (status) { - kgsl_iommu_disable_clk_on_ts(mmu, 0, false); - kgsl_detach_pagetable_iommu_domain(mmu); - } return status; } @@ -1800,6 +1800,7 @@ static void kgsl_iommu_pagefault_resume(struct kgsl_mmu *mmu) iommu_unit, iommu_unit->dev[j].ctx_id, FSR, 0); + kgsl_iommu_disable_clk(mmu, j); _iommu_unlock(iommu); iommu_unit->dev[j].fault = 0; } @@ -1812,7 +1813,6 @@ static void kgsl_iommu_pagefault_resume(struct kgsl_mmu *mmu) static void kgsl_iommu_stop(struct kgsl_mmu *mmu) { - struct kgsl_iommu *iommu = mmu->priv; /* * stop device mmu * @@ -1828,9 +1828,7 @@ static void kgsl_iommu_stop(struct kgsl_mmu *mmu) kgsl_iommu_pagefault_resume(mmu); } /* switch off MMU clocks and cancel any events it has queued */ - iommu->clk_event_queued = false; kgsl_cancel_events(mmu->device, mmu); - kgsl_iommu_disable_clk(mmu); } static int kgsl_iommu_close(struct kgsl_mmu *mmu) @@ -1883,7 +1881,7 @@ kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu) pt_base = KGSL_IOMMU_GET_CTX_REG_TTBR0(iommu, (&iommu->iommu_units[0]), KGSL_IOMMU_CONTEXT_USER); - kgsl_iommu_disable_clk_on_ts(mmu, 0, false); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); return pt_base & KGSL_IOMMU_CTX_TTBR0_ADDR_MASK; } @@ -1911,7 +1909,6 @@ static int kgsl_iommu_default_setstate(struct kgsl_mmu *mmu, phys_addr_t pt_val; ret = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); - if (ret) { KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n"); return ret; @@ -1992,7 +1989,7 @@ unlock: _iommu_unlock(iommu); /* Disable smmu clock */ - kgsl_iommu_disable_clk_on_ts(mmu, 0, false); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); return ret; } @@ -2072,13 +2069,14 @@ static int kgsl_iommu_set_pf_policy(struct kgsl_mmu *mmu, if (ret) { KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n"); - kgsl_iommu_disable_clk_on_ts(mmu, 0, false); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); return ret; } /* Need to idle device before changing options */ ret = mmu->device->ftbl->idle(mmu->device); if (ret) { - kgsl_iommu_disable_clk_on_ts(mmu, 0, false); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV); return ret; } @@ -2101,7 +2099,8 @@ static int kgsl_iommu_set_pf_policy(struct kgsl_mmu *mmu, SCTLR, sctlr_val); } } - kgsl_iommu_disable_clk_on_ts(mmu, 0, false); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER); + kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV); return ret; } diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h index 3b900dea663..85ab7dbee94 100644 --- a/drivers/gpu/msm/kgsl_iommu.h +++ b/drivers/gpu/msm/kgsl_iommu.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -155,6 +155,7 @@ struct kgsl_iommu_register_list { * are on, else the clocks are off * fault: Flag when set indicates that this iommu device has caused a page * fault + * @clk_enable_count: The ref count of clock enable calls */ struct kgsl_iommu_device { struct device *dev; @@ -164,6 +165,7 @@ struct kgsl_iommu_device { bool clk_enabled; struct kgsl_device *kgsldev; int fault; + atomic_t clk_enable_count; }; /* @@ -194,10 +196,6 @@ struct kgsl_iommu_unit { * iommu contexts owned by graphics cores * @unit_count: Number of IOMMU units that are available for this * instance of the IOMMU driver - * @iommu_last_cmd_ts: The timestamp of last command submitted that - * aceeses iommu registers - * @clk_event_queued: Indicates whether an event to disable clocks - * is already queued or not * @device: Pointer to kgsl device * @ctx_offset: The context offset to be added to base address when * accessing IOMMU registers @@ -213,8 +211,6 @@ struct kgsl_iommu_unit { struct kgsl_iommu { struct kgsl_iommu_unit iommu_units[KGSL_IOMMU_MAX_UNITS]; unsigned int unit_count; - unsigned int iommu_last_cmd_ts; - bool clk_event_queued; struct kgsl_device *device; unsigned int ctx_offset; struct kgsl_iommu_register_list *iommu_reg_list; @@ -234,4 +230,18 @@ struct kgsl_iommu_pt { struct kgsl_iommu *iommu; }; +/* + * struct kgsl_iommu_disable_clk_param - Parameter struct for disble clk event + * @mmu: The mmu pointer + * @rb_level: the rb level in which the timestamp of the event belongs to + * @ctx_id: The IOMMU context whose clock is to be turned off + * @ts: Timestamp on which clock is to be disabled + */ +struct kgsl_iommu_disable_clk_param { + struct kgsl_mmu *mmu; + int rb_level; + int ctx_id; + unsigned int ts; +}; + #endif diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 0d5f46454c1..8fb3a23e33f 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -99,11 +99,12 @@ struct kgsl_mmu_ops { void (*mmu_pagefault_resume) (struct kgsl_mmu *mmu); void (*mmu_disable_clk_on_ts) - (struct kgsl_mmu *mmu, uint32_t ts, bool ts_valid); + (struct kgsl_mmu *mmu, + uint32_t ts, int ctx_id); int (*mmu_enable_clk) (struct kgsl_mmu *mmu, int ctx_id); void (*mmu_disable_clk) - (struct kgsl_mmu *mmu); + (struct kgsl_mmu *mmu, int ctx_id); phys_addr_t (*mmu_get_default_ttbr0)(struct kgsl_mmu *mmu, unsigned int unit_id, enum kgsl_iommu_context_id ctx_id); @@ -275,17 +276,18 @@ static inline int kgsl_mmu_enable_clk(struct kgsl_mmu *mmu, return 0; } -static inline void kgsl_mmu_disable_clk(struct kgsl_mmu *mmu) +static inline void kgsl_mmu_disable_clk(struct kgsl_mmu *mmu, int ctx_id) { if (mmu->mmu_ops && mmu->mmu_ops->mmu_disable_clk) - mmu->mmu_ops->mmu_disable_clk(mmu); + mmu->mmu_ops->mmu_disable_clk(mmu, ctx_id); } static inline void kgsl_mmu_disable_clk_on_ts(struct kgsl_mmu *mmu, - unsigned int ts, bool ts_valid) + unsigned int ts, + int ctx_id) { if (mmu->mmu_ops && mmu->mmu_ops->mmu_disable_clk_on_ts) - mmu->mmu_ops->mmu_disable_clk_on_ts(mmu, ts, ts_valid); + mmu->mmu_ops->mmu_disable_clk_on_ts(mmu, ts, ctx_id); } static inline unsigned int kgsl_mmu_get_reg_gpuaddr(struct kgsl_mmu *mmu, diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 44c0a331430..7271e402e74 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1085,8 +1085,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) pwr->interval_timeout = pdata->idle_timeout; pwr->strtstp_sleepwake = pdata->strtstp_sleepwake; - /* Set the CPU latency to 501usec to allow low latency PC modes */ - pwr->pm_qos_latency = 501; + pwr->pm_qos_latency = pdata->pm_qos_latency; pm_runtime_enable(device->parentdev); @@ -1366,8 +1365,6 @@ _sleep(struct kgsl_device *device) break; } - kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false); - return 0; } diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h index 0085e8c6857..eb6a6d64931 100644 --- a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h +++ b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h @@ -20,7 +20,7 @@ #define MC_SMC_FASTCALL /*--------------- Implementation -------------- */ -#include <mach/scm.h> +#include <soc/qcom/scm.h> /* from following file */ #define SCM_SVC_MOBICORE 250 #define SCM_CMD_MOBICORE 1 diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c index d819d23c56c..55e792dd43d 100644 --- a/drivers/input/touchscreen/gt9xx/gt9xx.c +++ b/drivers/input/touchscreen/gt9xx/gt9xx.c @@ -1,6 +1,6 @@ /* drivers/input/touchscreen/gt9xx.c * - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * * Linux Foundation chooses to take subject only to the GPLv2 license * terms, and distributes only under these terms. @@ -121,6 +121,8 @@ struct i2c_client *i2c_connect_client; #define GTP_DEBUGFS_DIR "ts_debug" #define GTP_DEBUGFS_FILE_SUSPEND "suspend" +#define GTP_DEBUGFS_FILE_DATA "data" +#define GTP_DEBUGFS_FILE_ADDR "addr" /******************************************************* Function: @@ -1529,12 +1531,105 @@ static ssize_t gtp_fw_name_store(struct device *dev, return size; } +static ssize_t gtp_fw_upgrade_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + return snprintf(buf, 2, "%d\n", ts->fw_loading); +} + +static ssize_t gtp_fw_upgrade_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + unsigned int val; + int ret; + + if (size > 2) + return -EINVAL; + + if (sscanf(buf, "%u", &val) != 1) + return -EINVAL; + + if (ts->gtp_is_suspend) { + dev_err(&ts->client->dev, + "Can't start fw upgrade. Device is in suspend state."); + return -EBUSY; + } + + mutex_lock(&ts->input_dev->mutex); + if (!ts->fw_loading && val) { + disable_irq(ts->client->irq); + ts->fw_loading = true; + if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) { + ret = gup_update_proc(NULL); + if (ret == FAIL) + dev_err(&ts->client->dev, + "Fail to update GTP firmware.\n"); + } + ts->fw_loading = false; + enable_irq(ts->client->irq); + } + mutex_unlock(&ts->input_dev->mutex); + + return size; +} + +static ssize_t gtp_force_fw_upgrade_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + unsigned int val; + int ret; + + if (size > 2) + return -EINVAL; + + if (sscanf(buf, "%u", &val) != 1) + return -EINVAL; + + if (ts->gtp_is_suspend) { + dev_err(&ts->client->dev, + "Can't start fw upgrade. Device is in suspend state."); + return -EBUSY; + } + + mutex_lock(&ts->input_dev->mutex); + if (!ts->fw_loading && val) { + disable_irq(ts->client->irq); + ts->fw_loading = true; + ts->force_update = true; + if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) { + ret = gup_update_proc(NULL); + if (ret == FAIL) + dev_err(&ts->client->dev, + "Fail to force update GTP firmware.\n"); + } + ts->force_update = false; + ts->fw_loading = false; + enable_irq(ts->client->irq); + } + mutex_unlock(&ts->input_dev->mutex); + + return size; +} + static DEVICE_ATTR(fw_name, (S_IRUGO | S_IWUSR | S_IWGRP), gtp_fw_name_show, gtp_fw_name_store); +static DEVICE_ATTR(fw_upgrade, (S_IRUGO | S_IWUSR | S_IWGRP), + gtp_fw_upgrade_show, + gtp_fw_upgrade_store); +static DEVICE_ATTR(force_fw_upgrade, (S_IRUGO | S_IWUSR | S_IWGRP), + gtp_fw_upgrade_show, + gtp_force_fw_upgrade_store); static struct attribute *gtp_attrs[] = { &dev_attr_fw_name.attr, + &dev_attr_fw_upgrade.attr, + &dev_attr_force_fw_upgrade.attr, NULL }; @@ -1542,6 +1637,84 @@ static const struct attribute_group gtp_attr_grp = { .attrs = gtp_attrs, }; +static int gtp_debug_addr_is_valid(u16 addr) +{ + if (addr < GTP_VALID_ADDR_START || addr > GTP_VALID_ADDR_END) { + pr_err("GTP reg address is invalid: 0x%x\n", addr); + return false; + } + + return true; +} + +static int gtp_debug_data_set(void *_data, u64 val) +{ + struct goodix_ts_data *ts = _data; + + mutex_lock(&ts->input_dev->mutex); + if (gtp_debug_addr_is_valid(ts->addr)) + dev_err(&ts->client->dev, + "Writing to GTP registers not supported.\n"); + mutex_unlock(&ts->input_dev->mutex); + + return 0; +} + +static int gtp_debug_data_get(void *_data, u64 *val) +{ + struct goodix_ts_data *ts = _data; + int ret; + u8 buf[3] = {0}; + + mutex_lock(&ts->input_dev->mutex); + buf[0] = ts->addr >> 8; + buf[1] = ts->addr & 0x00ff; + + if (gtp_debug_addr_is_valid(ts->addr)) { + ret = gtp_i2c_read(ts->client, buf, 3); + if (ret < 0) + dev_err(&ts->client->dev, + "GTP read register 0x%x failed (%d)\n", + ts->addr, ret); + else + *val = buf[2]; + } + mutex_unlock(&ts->input_dev->mutex); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(debug_data_fops, gtp_debug_data_get, + gtp_debug_data_set, "%llx\n"); + +static int gtp_debug_addr_set(void *_data, u64 val) +{ + struct goodix_ts_data *ts = _data; + + if (gtp_debug_addr_is_valid(val)) { + mutex_lock(&ts->input_dev->mutex); + ts->addr = val; + mutex_unlock(&ts->input_dev->mutex); + } + + return 0; +} + +static int gtp_debug_addr_get(void *_data, u64 *val) +{ + struct goodix_ts_data *ts = _data; + + mutex_lock(&ts->input_dev->mutex); + if (gtp_debug_addr_is_valid(ts->addr)) + *val = ts->addr; + mutex_unlock(&ts->input_dev->mutex); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(debug_addr_fops, gtp_debug_addr_get, + gtp_debug_addr_set, "%llx\n"); + static int gtp_debug_suspend_set(void *_data, u64 val) { struct goodix_ts_data *ts = _data; @@ -1575,7 +1748,7 @@ static int gtp_debugfs_init(struct goodix_ts_data *data) data->debug_base = debugfs_create_dir(GTP_DEBUGFS_DIR, NULL); if (IS_ERR_OR_NULL(data->debug_base)) { - pr_err("Failed to create debugfs dir.\n"); + dev_err(&data->client->dev, "Failed to create debugfs dir.\n"); return -EINVAL; } @@ -1584,7 +1757,27 @@ static int gtp_debugfs_init(struct goodix_ts_data *data) data->debug_base, data, &debug_suspend_fops)))) { - pr_err("Failed to create suspend file.\n"); + dev_err(&data->client->dev, "Failed to create suspend file.\n"); + debugfs_remove_recursive(data->debug_base); + return -EINVAL; + } + + if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_DATA, + S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, + data->debug_base, + data, + &debug_data_fops)))) { + dev_err(&data->client->dev, "Failed to create data file.\n"); + debugfs_remove_recursive(data->debug_base); + return -EINVAL; + } + + if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_ADDR, + S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, + data->debug_base, + data, + &debug_addr_fops)))) { + dev_err(&data->client->dev, "Failed to create addr file.\n"); debugfs_remove_recursive(data->debug_base); return -EINVAL; } @@ -1653,8 +1846,8 @@ static int goodix_parse_dt(struct device *dev, pdata->i2c_pull_up = of_property_read_bool(np, "goodix,i2c-pull-up"); - pdata->no_force_update = of_property_read_bool(np, - "goodix,no-force-update"); + pdata->force_update = of_property_read_bool(np, + "goodix,force-update"); pdata->enable_power_off = of_property_read_bool(np, "goodix,enable-power-off"); @@ -1772,9 +1965,7 @@ static int goodix_ts_probe(struct i2c_client *client, return -EINVAL; } -#if GTP_ESD_PROTECT i2c_connect_client = client; -#endif if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "GTP I2C not supported\n"); @@ -1824,19 +2015,21 @@ static int goodix_ts_probe(struct i2c_client *client, goto exit_power_off; } + if (pdata->force_update) + ts->force_update = true; + if (pdata->fw_name) strlcpy(ts->fw_name, pdata->fw_name, strlen(pdata->fw_name) + 1); -#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE - ret = gup_init_update_proc(ts); - if (ret < 0) { - dev_err(&client->dev, - "GTP Create firmware update thread error.\n"); - goto exit_power_off; + if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) { + ret = gup_init_update_proc(ts); + if (ret < 0) { + dev_err(&client->dev, + "GTP Create firmware update thread error.\n"); + goto exit_power_off; + } } -#endif - ret = gtp_init_panel(ts); if (ret < 0) { dev_err(&client->dev, "GTP init panel failed.\n"); @@ -2033,6 +2226,14 @@ static int goodix_ts_suspend(struct device *dev) } mutex_lock(&ts->lock); + + if (ts->fw_loading) { + dev_info(&ts->client->dev, + "Fw upgrade in progress, can't go to suspend."); + mutex_unlock(&ts->lock); + return 0; + } + #if GTP_ESD_PROTECT gtp_esd_switch(ts->client, SWITCH_OFF); #endif diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h index 4d656ddc605..0ba6895e5e7 100644 --- a/drivers/input/touchscreen/gt9xx/gt9xx.h +++ b/drivers/input/touchscreen/gt9xx/gt9xx.h @@ -1,6 +1,6 @@ /* drivers/input/touchscreen/gt9xx.h * - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * * Linux Foundation chooses to take subject only to the GPLv2 license * terms, and distributes only under these terms. @@ -56,7 +56,7 @@ struct goodix_ts_platform_data { u32 panel_miny; u32 panel_maxx; u32 panel_maxy; - bool no_force_update; + bool force_update; bool i2c_pull_up; bool enable_power_off; size_t config_data_len[GOODIX_MAX_CFG_GROUP]; @@ -78,6 +78,7 @@ struct goodix_ts_data { s32 use_irq; u16 abs_x_max; u16 abs_y_max; + u16 addr; u8 max_touch_num; u8 int_trigger_type; u8 green_wake_mode; @@ -92,6 +93,8 @@ struct goodix_ts_data { u8 fw_error; bool power_on; struct mutex lock; + bool fw_loading; + bool force_update; struct regulator *avdd; struct regulator *vdd; struct regulator *vcc_i2c; @@ -175,6 +178,8 @@ extern u16 total_len; /* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */ #define GTP_I2C_ADDRESS_HIGH 0x14 #define GTP_I2C_ADDRESS_LOW 0x5D +#define GTP_VALID_ADDR_START 0x8040 +#define GTP_VALID_ADDR_END 0x8177 #define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0])) @@ -215,11 +220,9 @@ s32 init_wr_node(struct i2c_client *client); void uninit_wr_node(void); #endif -#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE -extern u8 gup_init_update_proc(struct goodix_ts_data *ts); +u8 gup_init_update_proc(struct goodix_ts_data *ts); s32 gup_enter_update_mode(struct i2c_client *client); void gup_leave_update_mode(struct i2c_client *client); s32 gup_update_proc(void *dir); extern struct i2c_client *i2c_connect_client; -#endif #endif /* _GOODIX_GT9XX_H_ */ diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_update.c b/drivers/input/touchscreen/gt9xx/gt9xx_update.c index 71e8a55a72f..af80eefbc9d 100644 --- a/drivers/input/touchscreen/gt9xx/gt9xx_update.c +++ b/drivers/input/touchscreen/gt9xx/gt9xx_update.c @@ -1,7 +1,7 @@ /* drivers/input/touchscreen/gt9xx_update.c * * 2010 - 2012 Goodix Technology. - * Copyright (c) 2013, 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 as published by @@ -1432,10 +1432,15 @@ s32 gup_update_proc(void *dir) goto file_fail; } - ret = gup_enter_update_judge(ts->client, &fw_head); - if (ret == FAIL) { - pr_err("Check *.bin file fail."); - goto file_fail; + if (ts->force_update) { + dev_dbg(&ts->client->dev, "Enter force update."); + } else { + ret = gup_enter_update_judge(ts->client, &fw_head); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "Check *.bin file fail."); + goto file_fail; + } } ts->enter_update = 1; diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c index 3cb903cad5b..5076ea88e85 100644 --- a/drivers/iommu/msm_iommu_sec.c +++ b/drivers/iommu/msm_iommu_sec.c @@ -26,6 +26,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/kmemleak.h> +#include <soc/qcom/scm.h> #include <asm/sizes.h> @@ -33,7 +34,6 @@ #include <mach/iommu_hw-v1.h> #include <mach/msm_iommu_priv.h> #include <mach/iommu.h> -#include <mach/scm.h> #include <mach/memory.h> /* bitmap of the page sizes currently supported */ @@ -61,6 +61,12 @@ static struct iommu_access_ops *iommu_access_ops; +static const struct of_device_id msm_smmu_list[] = { + { .compatible = "qcom,msm-smmu-v1", }, + { .compatible = "qcom,msm-smmu-v2", }, + { } +}; + struct msm_scm_paddr_list { unsigned int list; unsigned int list_size; @@ -296,8 +302,9 @@ static int msm_iommu_sec_ptbl_init(void) int ret, ptbl_ret = 0; int version; - for_each_compatible_node(np, NULL, "qcom,msm-smmu-v1") - if (of_find_property(np, "qcom,iommu-secure-id", NULL)) + for_each_matching_node(np, msm_smmu_list) + if (of_find_property(np, "qcom,iommu-secure-id", NULL) && + of_device_is_available(np)) break; if (!np) diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c index 7e63430b480..09a1c6b307c 100644 --- a/drivers/leds/leds-qpnp.c +++ b/drivers/leds/leds-qpnp.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -146,11 +146,11 @@ #define FLASH_WATCHDOG_MASK 0x1F #define FLASH_RAMP_STEP_27US 0xBF -#define FLASH_STROBE_SW 0xC0 -#define FLASH_STROBE_HW 0x04 +#define FLASH_HW_SW_STROBE_SEL_MASK 0x04 #define FLASH_STROBE_MASK 0xC7 #define FLASH_LED_0_OUTPUT 0x80 #define FLASH_LED_1_OUTPUT 0x40 +#define FLASH_TORCH_OUTPUT 0xC0 #define FLASH_CURRENT_PRGM_MIN 1 #define FLASH_CURRENT_PRGM_SHIFT 1 @@ -1172,6 +1172,13 @@ static int qpnp_flash_set(struct qpnp_led_data *led) goto error_reg_write; } + if (!led->flash_cfg->strobe_type) + led->flash_cfg->trigger_flash &= + ~FLASH_HW_SW_STROBE_SEL_MASK; + else + led->flash_cfg->trigger_flash |= + FLASH_HW_SW_STROBE_SEL_MASK; + rc = qpnp_led_masked_write(led, FLASH_LED_STROBE_CTRL(led->base), led->flash_cfg->trigger_flash, @@ -1262,30 +1269,22 @@ static int qpnp_flash_set(struct qpnp_led_data *led) */ usleep(FLASH_RAMP_UP_DELAY_US); - if (!led->flash_cfg->strobe_type) { - rc = qpnp_led_masked_write(led, - FLASH_LED_STROBE_CTRL(led->base), - led->flash_cfg->trigger_flash, - led->flash_cfg->trigger_flash); - if (rc) { - dev_err(&led->spmi_dev->dev, - "LED %d strobe reg write failed(%d)\n", - led->id, rc); - goto error_flash_set; - } - } else { - rc = qpnp_led_masked_write(led, - FLASH_LED_STROBE_CTRL(led->base), - (led->flash_cfg->trigger_flash | - FLASH_STROBE_HW), - (led->flash_cfg->trigger_flash | - FLASH_STROBE_HW)); - if (rc) { - dev_err(&led->spmi_dev->dev, - "LED %d strobe reg write failed(%d)\n", - led->id, rc); - goto error_flash_set; - } + if (!led->flash_cfg->strobe_type) + led->flash_cfg->trigger_flash &= + ~FLASH_HW_SW_STROBE_SEL_MASK; + else + led->flash_cfg->trigger_flash |= + FLASH_HW_SW_STROBE_SEL_MASK; + + rc = qpnp_led_masked_write(led, + FLASH_LED_STROBE_CTRL(led->base), + led->flash_cfg->trigger_flash, + led->flash_cfg->trigger_flash); + if (rc) { + dev_err(&led->spmi_dev->dev, + "LED %d strobe reg write failed(%d)\n", + led->id, rc); + goto error_flash_set; } } } else { @@ -2916,7 +2915,7 @@ static int qpnp_get_config_flash(struct qpnp_led_data *led, led->flash_cfg->enable_module = FLASH_ENABLE_MODULE; } else led->flash_cfg->enable_module = FLASH_ENABLE_ALL; - led->flash_cfg->trigger_flash = FLASH_STROBE_SW; + led->flash_cfg->trigger_flash = FLASH_TORCH_OUTPUT; rc = of_property_read_u32(node, "qcom,duration", &val); if (!rc) diff --git a/drivers/media/platform/msm/broadcast/ensigma_uccp330.c b/drivers/media/platform/msm/broadcast/ensigma_uccp330.c index 9b47dd27aac..5c2b9fd682d 100644 --- a/drivers/media/platform/msm/broadcast/ensigma_uccp330.c +++ b/drivers/media/platform/msm/broadcast/ensigma_uccp330.c @@ -35,13 +35,11 @@ #include <linux/platform_device.h> #include <linux/errno.h> #include <linux/regulator/consumer.h> -#include <mach/subsystem_restart.h> -#include <mach/subsystem_notif.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/subsystem_notif.h> #include <mach/msm_bus_board.h> #include <mach/msm_bus.h> #include <linux/clk/msm-clk.h> -#include <mach/subsystem_restart.h> -#include <mach/subsystem_notif.h> #include <linux/iommu.h> #include <mach/iommu.h> #include <mach/iommu_domains.h> @@ -492,15 +490,14 @@ static long demod_ioctl(struct file *filp, break; case DEMOD_IOCTL_RESET: /* Reset DEMOD core. Block VBIF access at Top BCSS */ - clk_reset(drv->clks[0], CLK_RESET_ASSERT); writel_relaxed(1, drv->top_bcss + BCSS_VBIF); + clk_reset(drv->clks[1], CLK_RESET_ASSERT); udelay(10); - clk_reset(drv->clks[0], CLK_RESET_DEASSERT); + clk_reset(drv->clks[1], CLK_RESET_DEASSERT); writel_relaxed(0, drv->top_bcss + BCSS_VBIF); break; default: return 0; - } return 0; } diff --git a/drivers/media/platform/msm/broadcast/tspp2.c b/drivers/media/platform/msm/broadcast/tspp2.c index 62728e599c8..355cba0d993 100644 --- a/drivers/media/platform/msm/broadcast/tspp2.c +++ b/drivers/media/platform/msm/broadcast/tspp2.c @@ -200,7 +200,7 @@ enum tspp2_operation_opcode { /* Bits for TSPP2_FILTER_ENTRY1 register */ #define FILTER_ENTRY1_CONTEXT_OFFS 0 -/* Filter counter register definitions: n = 0..127 */ +/* Filter context-based counter register definitions: n = 0..127 */ #define TSPP2_FILTER_TSP_SYNC_ERROR(n) (0x4000 + ((n) << 2)) #define TSPP2_FILTER_ERRED_TSP(n) (0x4200 + ((n) << 2)) #define TSPP2_FILTER_DISCONTINUITIES(n) (0x4400 + ((n) << 2)) @@ -246,9 +246,6 @@ enum tspp2_operation_opcode { /* Bits for TSPP2_GLOBAL_IRQ_CLEAR register */ #define GLOBAL_IRQ_CLEAR_RESERVED_OFFS 4 -/* Bits for TSPP2_GLOBAL_IRQ_ENABLE register */ -#define GLOBAL_IRQ_ENABLE_READ_FAIL_OFFS 16 - /* Bits for TSPP2_VERSION register */ #define VERSION_MAJOR_OFFS 28 #define VERSION_MINOR_OFFS 16 @@ -733,12 +730,12 @@ struct tspp2_pipe_irq_stats { }; /** - * struct tspp2_filter_irq_stats - Filter interrupt statistics counters + * struct tspp2_filter_context_irq_stats - Filter interrupt statistics counters * * @sc_go_high: Scrambling bits change from clear to encrypted. * @sc_go_low: Scrambling bits change from encrypted to clear. */ -struct tspp2_filter_irq_stats { +struct tspp2_filter_context_irq_stats { u32 sc_go_high; u32 sc_go_low; }; @@ -750,14 +747,14 @@ struct tspp2_filter_irq_stats { * @src: Memory source interrupt statistics counters * @kt: Key table interrupt statistics counters * @pipe: Pipe interrupt statistics counters - * @filter: Filter interrupt statistics counters + * @ctx: Filter context interrupt statistics counters */ struct tspp2_irq_stats { struct tspp2_global_irq_stats global; struct tspp2_src_irq_stats src[TSPP2_NUM_MEM_INPUTS]; struct tspp2_keytable_irq_stats kt[TSPP2_NUM_KEYTABLES]; struct tspp2_pipe_irq_stats pipe[TSPP2_NUM_PIPES]; - struct tspp2_filter_irq_stats filter[TSPP2_NUM_HW_FILTERS]; + struct tspp2_filter_context_irq_stats ctx[TSPP2_NUM_CONTEXTS]; }; /** @@ -1226,6 +1223,45 @@ static int filter_debugfs_print(struct seq_file *s, void *p) seq_printf(s, "raw_op_set: %d\n", filter->raw_op_set); seq_printf(s, "pes_tx_op_set: %d\n", filter->pes_tx_op_set); seq_printf(s, "Status: %s\n", filter->enabled ? "enabled" : "disabled"); + + if (filter->enabled) { + seq_printf(s, "Filter context-based counters, context %d\n", + filter->context); + seq_printf(s, "filter_tsp_sync_err = 0x%08X\n", + readl_relaxed(filter->device->base + + TSPP2_FILTER_TSP_SYNC_ERROR(filter->context))); + seq_printf(s, "filter_erred_tsp = 0x%08X\n", + readl_relaxed(filter->device->base + + TSPP2_FILTER_ERRED_TSP(filter->context))); + seq_printf(s, "filter_discontinuities = 0x%08X\n", + readl_relaxed(filter->device->base + + TSPP2_FILTER_DISCONTINUITIES(filter->context))); + seq_printf(s, "filter_sc_bits_discard = 0x%08X\n", + readl_relaxed(filter->device->base + + TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(filter->context))); + seq_printf(s, "filter_tsp_total_num = 0x%08X\n", + readl_relaxed(filter->device->base + + TSPP2_FILTER_TSP_TOTAL_NUM(filter->context))); + seq_printf(s, "filter_discont_indicator = 0x%08X\n", + readl_relaxed(filter->device->base + + TSPP2_FILTER_DISCONT_INDICATOR(filter->context))); + seq_printf(s, "filter_tsp_no_payload = 0x%08X\n", + readl_relaxed(filter->device->base + + TSPP2_FILTER_TSP_NO_PAYLOAD(filter->context))); + seq_printf(s, "filter_tsp_duplicate = 0x%08X\n", + readl_relaxed(filter->device->base + + TSPP2_FILTER_TSP_DUPLICATE(filter->context))); + seq_printf(s, "filter_key_fetch_fail = 0x%08X\n", + readl_relaxed(filter->device->base + + TSPP2_FILTER_KEY_FETCH_FAILURE(filter->context))); + seq_printf(s, "filter_dropped_pcr = 0x%08X\n", + readl_relaxed(filter->device->base + + TSPP2_FILTER_DROPPED_PCR(filter->context))); + seq_printf(s, "filter_pes_errors = 0x%08X\n", + readl_relaxed(filter->device->base + + TSPP2_FILTER_PES_ERRORS(filter->context))); + } + return 0; } @@ -1369,35 +1405,11 @@ static void tspp2_debugfs_init(struct tspp2_device *device) &device->irq_stats.global.encrypt_level_err); } - dir = debugfs_create_dir("filters", device->debugfs_entry); - for (i = 0; i < TSPP2_NUM_HW_FILTERS; i++) { - snprintf(name, 80, "filter%03i", i); + dir = debugfs_create_dir("counters", device->debugfs_entry); + for (i = 0; i < TSPP2_NUM_CONTEXTS; i++) { + snprintf(name, 80, "context%03i", i); dentry = debugfs_create_dir(name, dir); if (dentry) { - debugfs_create_u32( - "stat_sc_go_high", - S_IRUGO | S_IWUSR | S_IWGRP, - dentry, - &device->irq_stats.filter[i].sc_go_high); - - debugfs_create_u32( - "stat_sc_go_low", - S_IRUGO | S_IWUSR | S_IWGRP, - dentry, - &device->irq_stats.filter[i].sc_go_low); - - debugfs_create_file("filter_entry0", - TSPP2_S_RW, - dentry, - base + TSPP2_FILTER_ENTRY0(i), - &fops_iomem_x32); - - debugfs_create_file("filter_entry1", - TSPP2_S_RW, - dentry, - base + TSPP2_FILTER_ENTRY1(i), - &fops_iomem_x32); - debugfs_create_file("filter_tsp_sync_err", TSPP2_S_RW, dentry, @@ -1464,6 +1476,37 @@ static void tspp2_debugfs_init(struct tspp2_device *device) base + TSPP2_FILTER_PES_ERRORS(i), &fops_iomem_x32); + debugfs_create_u32( + "stat_sc_go_high", + S_IRUGO | S_IWUSR | S_IWGRP, + dentry, + &device->irq_stats.ctx[i].sc_go_high); + + debugfs_create_u32( + "stat_sc_go_low", + S_IRUGO | S_IWUSR | S_IWGRP, + dentry, + &device->irq_stats.ctx[i].sc_go_low); + } + } + + dir = debugfs_create_dir("filters", device->debugfs_entry); + for (i = 0; i < TSPP2_NUM_HW_FILTERS; i++) { + snprintf(name, 80, "filter%03i", i); + dentry = debugfs_create_dir(name, dir); + if (dentry) { + debugfs_create_file("filter_entry0", + TSPP2_S_RW, + dentry, + base + TSPP2_FILTER_ENTRY0(i), + &fops_iomem_x32); + + debugfs_create_file("filter_entry1", + TSPP2_S_RW, + dentry, + base + TSPP2_FILTER_ENTRY1(i), + &fops_iomem_x32); + for (j = 0; j < TSPP2_MAX_OPS_PER_FILTER; j++) { snprintf(name, 80, "opcode%02i", j); debugfs_create_file(name, @@ -1948,27 +1991,24 @@ static void tspp2_clock_stop(struct tspp2_device *device) * tspp2_filter_counters_reset() - Reset a filter's HW counters. * * @device: TSPP2 device. - * @hw_index: Filter HW index. + * @index: Filter context index. Note counters are based on the context + * index and not on the filter HW index. */ -static void tspp2_filter_counters_reset(struct tspp2_device *device, - u32 hw_index) +static void tspp2_filter_counters_reset(struct tspp2_device *device, u32 index) { /* Reset filter counters */ - writel_relaxed(0, device->base + TSPP2_FILTER_TSP_SYNC_ERROR(hw_index)); - writel_relaxed(0, device->base + TSPP2_FILTER_ERRED_TSP(hw_index)); - writel_relaxed(0, - device->base + TSPP2_FILTER_DISCONTINUITIES(hw_index)); - writel_relaxed(0, - device->base + TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(hw_index)); - writel_relaxed(0, device->base + TSPP2_FILTER_TSP_TOTAL_NUM(hw_index)); - writel_relaxed(0, - device->base + TSPP2_FILTER_DISCONT_INDICATOR(hw_index)); - writel_relaxed(0, device->base + TSPP2_FILTER_TSP_NO_PAYLOAD(hw_index)); - writel_relaxed(0, device->base + TSPP2_FILTER_TSP_DUPLICATE(hw_index)); + writel_relaxed(0, device->base + TSPP2_FILTER_TSP_SYNC_ERROR(index)); + writel_relaxed(0, device->base + TSPP2_FILTER_ERRED_TSP(index)); + writel_relaxed(0, device->base + TSPP2_FILTER_DISCONTINUITIES(index)); writel_relaxed(0, - device->base + TSPP2_FILTER_KEY_FETCH_FAILURE(hw_index)); - writel_relaxed(0, device->base + TSPP2_FILTER_DROPPED_PCR(hw_index)); - writel_relaxed(0, device->base + TSPP2_FILTER_PES_ERRORS(hw_index)); + device->base + TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(index)); + writel_relaxed(0, device->base + TSPP2_FILTER_TSP_TOTAL_NUM(index)); + writel_relaxed(0, device->base + TSPP2_FILTER_DISCONT_INDICATOR(index)); + writel_relaxed(0, device->base + TSPP2_FILTER_TSP_NO_PAYLOAD(index)); + writel_relaxed(0, device->base + TSPP2_FILTER_TSP_DUPLICATE(index)); + writel_relaxed(0, device->base + TSPP2_FILTER_KEY_FETCH_FAILURE(index)); + writel_relaxed(0, device->base + TSPP2_FILTER_DROPPED_PCR(index)); + writel_relaxed(0, device->base + TSPP2_FILTER_PES_ERRORS(index)); } /** @@ -2075,7 +2115,10 @@ static int tspp2_global_hw_reset(struct tspp2_device *device, /* Disable all HW filters */ writel_relaxed(0, device->base + TSPP2_FILTER_ENTRY0(i)); writel_relaxed(0, device->base + TSPP2_FILTER_ENTRY1(i)); - /* Reset filter counters */ + } + + for (i = 0; i < TSPP2_NUM_CONTEXTS; i++) { + /* Reset filter context-based counters */ tspp2_filter_counters_reset(device, i); } @@ -5062,8 +5105,8 @@ int tspp2_src_filters_clear(u32 src_handle) TSPP2_FILTER_ENTRY0(filter->hw_index)); /* Clear filter operations in HW as well as related SW fields */ tspp2_filter_ops_clear(filter); - /* Reset filter counters */ - tspp2_filter_counters_reset(filter->device, filter->hw_index); + /* Reset filter context-based counters */ + tspp2_filter_counters_reset(filter->device, filter->context); /* Reset filter context and release it back to the device */ tspp2_filter_context_reset(filter); /* Reset filter SW fields */ @@ -5229,6 +5272,7 @@ int tspp2_filter_open(u32 src_handle, u16 pid, u16 mask, u32 *filter_handle) if (i == TSPP2_NUM_BATCHES) { pr_err("%s: No available filters\n", __func__); src->device->contexts[filter->context] = 0; + filter->context = 0; mutex_unlock(&src->device->mutex); pm_runtime_mark_last_busy(src->device->dev); pm_runtime_put_autosuspend(src->device->dev); @@ -5265,8 +5309,8 @@ int tspp2_filter_open(u32 src_handle, u16 pid, u16 mask, u32 *filter_handle) list_add_tail(&filter->link, &src->filters_list); src->num_associated_filters++; - /* Reset filter counters */ - tspp2_filter_counters_reset(filter->device, filter->hw_index); + /* Reset filter context-based counters */ + tspp2_filter_counters_reset(filter->device, filter->context); /* Reset this filter's context */ writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)), @@ -5378,8 +5422,8 @@ int tspp2_filter_close(u32 filter_handle) /* Clear filter operations in HW as well as related SW fields */ tspp2_filter_ops_clear(filter); - /* Reset filter counters */ - tspp2_filter_counters_reset(device, filter->hw_index); + /* Reset filter context-based counters */ + tspp2_filter_counters_reset(device, filter->context); /* Reset filter context and release it back to the device */ tspp2_filter_context_reset(filter); @@ -6315,9 +6359,6 @@ static int tspp2_filter_ops_update(struct tspp2_filter *filter, return -EINVAL; } - /* Reset new filter HW counters */ - tspp2_filter_counters_reset(filter->device, tmp_filter->hw_index); - /* Set the same context of the old filter to the new HW filter */ writel_relaxed((filter->context << FILTER_ENTRY1_CONTEXT_OFFS), filter->device->base + @@ -6329,6 +6370,10 @@ static int tspp2_filter_ops_update(struct tspp2_filter *filter, * that uses a context where before there was no operation that used it, * we reset that context. We need to do this before we start using the * new operation, so before we enable the new filter. + * Note: there is no need to reset most of the filter's context-based + * counters, because the filter keeps using the same context. The + * exception is the PES error counters that we may want to reset when + * resetting the entire PES context. */ if (!filter->pes_tx_op_set && tmp_filter->pes_tx_op_set) { /* PES Tx operation added */ @@ -6336,6 +6381,8 @@ static int tspp2_filter_ops_update(struct tspp2_filter *filter, (0x1 << TSPP2_MODULUS_OP(filter->context, 32)), filter->device->base + TSPP2_PES_CONTEXT_RESET(filter->context >> 5)); + writel_relaxed(0, filter->device->base + + TSPP2_FILTER_PES_ERRORS(filter->context)); } if (!filter->indexing_op_set && tmp_filter->indexing_op_set) { @@ -6379,9 +6426,6 @@ static int tspp2_filter_ops_update(struct tspp2_filter *filter, /* The new HW filter may be in a new batch, so we need to update */ filter->batch = batch; - /* Reset old filter HW counters */ - tspp2_filter_counters_reset(filter->device, filter->hw_index); - /* * Update source's reserved filter HW index, and also update the * new HW index in the filter object. @@ -7227,10 +7271,10 @@ int tspp2_src_event_notification_register(u32 src_handle, reg = readl_relaxed(src->device->base + TSPP2_GLOBAL_IRQ_ENABLE); if (callback && (src_event_bitmask & TSPP2_SRC_EVENT_FLOW_CTRL_STALL)) { reg |= ((0x1 << src->hw_index) << - GLOBAL_IRQ_ENABLE_READ_FAIL_OFFS); + GLOBAL_IRQ_FC_STALL_OFFS); } else { reg &= ~((0x1 << src->hw_index) << - GLOBAL_IRQ_ENABLE_READ_FAIL_OFFS); + GLOBAL_IRQ_FC_STALL_OFFS); } writel_relaxed(reg, src->device->base + TSPP2_GLOBAL_IRQ_ENABLE); @@ -7318,14 +7362,14 @@ int tspp2_filter_event_notification_register(u32 filter_handle, spin_unlock_irqrestore(&filter->device->spinlock, flags); /* Enable/disable SC high/low interrupts per filter as requested */ - idx = (filter->hw_index >> 5); + idx = (filter->context >> 5); reg = readl_relaxed(filter->device->base + TSPP2_SC_GO_HIGH_ENABLE(idx)); if (callback && (filter_event_bitmask & TSPP2_FILTER_EVENT_SCRAMBLING_HIGH)) { - reg |= (0x1 << TSPP2_MODULUS_OP(filter->hw_index, 32)); + reg |= (0x1 << TSPP2_MODULUS_OP(filter->context, 32)); } else { - reg &= ~(0x1 << TSPP2_MODULUS_OP(filter->hw_index, 32)); + reg &= ~(0x1 << TSPP2_MODULUS_OP(filter->context, 32)); } writel_relaxed(reg, filter->device->base + TSPP2_SC_GO_HIGH_ENABLE(idx)); @@ -7334,9 +7378,9 @@ int tspp2_filter_event_notification_register(u32 filter_handle, TSPP2_SC_GO_LOW_ENABLE(idx)); if (callback && (filter_event_bitmask & TSPP2_FILTER_EVENT_SCRAMBLING_LOW)) { - reg |= (0x1 << TSPP2_MODULUS_OP(filter->hw_index, 32)); + reg |= (0x1 << TSPP2_MODULUS_OP(filter->context, 32)); } else { - reg &= ~(0x1 << TSPP2_MODULUS_OP(filter->hw_index, 32)); + reg &= ~(0x1 << TSPP2_MODULUS_OP(filter->context, 32)); } writel_relaxed(reg, filter->device->base + TSPP2_SC_GO_LOW_ENABLE(idx)); @@ -7444,43 +7488,6 @@ msm_tspp2_dt_to_pdata(struct platform_device *pdev) return NULL; } - /* Get clocks information */ - rc = of_property_read_string(node, "qcom,tspp2-ahb-clk", - &data->tspp2_ahb_clk); - if (rc) { - pr_err("%s: Could not find tspp2-ahb-clk property, err = %d\n", - __func__, rc); - return NULL; - } - rc = of_property_read_string(node, "qcom,tspp2-core-clk", - &data->tspp2_core_clk); - if (rc) { - pr_err("%s: Could not find tspp2-core-clk property, err = %d\n", - __func__, rc); - return NULL; - } - rc = of_property_read_string(node, "qcom,tspp2-vbif-clk", - &data->tspp2_vbif_clk); - if (rc) { - pr_err("%s: Could not find tspp2-vbif-clk property, err = %d\n", - __func__, rc); - return NULL; - } - rc = of_property_read_string(node, "qcom,tspp2-klm-ahb-clk", - &data->tspp2_klm_ahb_clk); - if (rc) { - pr_err("%s: Could not find tspp2-klm-ahb-clk property, err = %d\n", - __func__, rc); - return NULL; - } - rc = of_property_read_string(node, "qcom,tsif-ref-clk", - &data->tsif_ref_clk); - if (rc) { - pr_err("%s: Could not find tsif-ref-clk property, err = %d\n", - __func__, rc); - return NULL; - } - /* Get IOMMU information */ rc = of_property_read_string(node, "qcom,iommu-hlos-group", &data->hlos_group); @@ -7658,8 +7665,6 @@ static int msm_tspp2_clocks_setup(struct platform_device *pdev, unsigned long rate_in_hz = 0; struct clk *tspp2_core_clk_src = NULL; - struct msm_tspp2_platform_data *data = pdev->dev.platform_data; - /* Get power regulator (GDSC) */ device->gdsc = devm_regulator_get(&pdev->dev, "vdd"); if (IS_ERR(device->gdsc)) { @@ -7677,40 +7682,28 @@ static int msm_tspp2_clocks_setup(struct platform_device *pdev, device->tspp2_klm_ahb_clk = NULL; device->tsif_ref_clk = NULL; - if (data->tspp2_ahb_clk) { - device->tspp2_ahb_clk = - clk_get(&pdev->dev, data->tspp2_ahb_clk); - if (IS_ERR(device->tspp2_ahb_clk)) { - pr_err("%s: Failed to get %s", - __func__, data->tspp2_ahb_clk); - ret = PTR_ERR(device->tspp2_ahb_clk); - device->tspp2_ahb_clk = NULL; - goto err_clocks; - } + device->tspp2_ahb_clk = clk_get(&pdev->dev, "bcc_tspp2_ahb_clk"); + if (IS_ERR(device->tspp2_ahb_clk)) { + pr_err("%s: Failed to get %s", __func__, "bcc_tspp2_ahb_clk"); + ret = PTR_ERR(device->tspp2_ahb_clk); + device->tspp2_ahb_clk = NULL; + goto err_clocks; } - if (data->tspp2_core_clk) { - device->tspp2_core_clk = - clk_get(&pdev->dev, data->tspp2_core_clk); - if (IS_ERR(device->tspp2_core_clk)) { - pr_err("%s: Failed to get %s", - __func__, data->tspp2_core_clk); - ret = PTR_ERR(device->tspp2_core_clk); - device->tspp2_core_clk = NULL; - goto err_clocks; - } + device->tspp2_core_clk = clk_get(&pdev->dev, "bcc_tspp2_core_clk"); + if (IS_ERR(device->tspp2_core_clk)) { + pr_err("%s: Failed to get %s", __func__, "bcc_tspp2_core_clk"); + ret = PTR_ERR(device->tspp2_core_clk); + device->tspp2_core_clk = NULL; + goto err_clocks; } - if (data->tspp2_vbif_clk) { - device->tspp2_vbif_clk = - clk_get(&pdev->dev, data->tspp2_vbif_clk); - if (IS_ERR(device->tspp2_vbif_clk)) { - pr_err("%s: Failed to get %s", - __func__, data->tspp2_vbif_clk); - ret = PTR_ERR(device->tspp2_vbif_clk); - device->tspp2_vbif_clk = NULL; - goto err_clocks; - } + device->tspp2_vbif_clk = clk_get(&pdev->dev, "bcc_vbif_tspp2_clk"); + if (IS_ERR(device->tspp2_vbif_clk)) { + pr_err("%s: Failed to get %s", __func__, "bcc_vbif_tspp2_clk"); + ret = PTR_ERR(device->tspp2_vbif_clk); + device->tspp2_vbif_clk = NULL; + goto err_clocks; } device->vbif_ahb_clk = clk_get(&pdev->dev, "iface_vbif_clk"); @@ -7729,34 +7722,27 @@ static int msm_tspp2_clocks_setup(struct platform_device *pdev, goto err_clocks; } - if (data->tspp2_klm_ahb_clk) { - device->tspp2_klm_ahb_clk = - clk_get(&pdev->dev, data->tspp2_klm_ahb_clk); - if (IS_ERR(device->tspp2_klm_ahb_clk)) { - pr_err("%s: Failed to get %s", - __func__, data->tspp2_klm_ahb_clk); - ret = PTR_ERR(device->tspp2_klm_ahb_clk); - device->tspp2_klm_ahb_clk = NULL; - goto err_clocks; - } + device->tspp2_klm_ahb_clk = clk_get(&pdev->dev, "bcc_klm_ahb_clk"); + if (IS_ERR(device->tspp2_klm_ahb_clk)) { + pr_err("%s: Failed to get %s", __func__, "bcc_klm_ahb_clk"); + ret = PTR_ERR(device->tspp2_klm_ahb_clk); + device->tspp2_klm_ahb_clk = NULL; + goto err_clocks; } - if (data->tsif_ref_clk) { - device->tsif_ref_clk = clk_get(&pdev->dev, data->tsif_ref_clk); - if (IS_ERR(device->tsif_ref_clk)) { - pr_err("%s: Failed to get %s", - __func__, data->tsif_ref_clk); - ret = PTR_ERR(device->tsif_ref_clk); - device->tsif_ref_clk = NULL; - goto err_clocks; - } + device->tsif_ref_clk = clk_get(&pdev->dev, "gcc_tsif_ref_clk"); + if (IS_ERR(device->tsif_ref_clk)) { + pr_err("%s: Failed to get %s", __func__, "gcc_tsif_ref_clk"); + ret = PTR_ERR(device->tsif_ref_clk); + device->tsif_ref_clk = NULL; + goto err_clocks; } /* Set relevant clock rates */ rate_in_hz = clk_round_rate(device->tsif_ref_clk, 1); if (clk_set_rate(device->tsif_ref_clk, rate_in_hz)) { pr_err("%s: Failed to set rate %lu to %s\n", __func__, - rate_in_hz, data->tsif_ref_clk); + rate_in_hz, "gcc_tsif_ref_clk"); goto err_clocks; } @@ -7926,7 +7912,7 @@ static irqreturn_t tspp2_isr(int irq, void *dev) u32 i = 0, j = 0; u32 global_bitmask = 0; u32 src_bitmask[TSPP2_NUM_MEM_INPUTS] = {0}; - u32 filter_bitmask[TSPP2_NUM_HW_FILTERS] = {0}; + u32 filter_bitmask[TSPP2_NUM_CONTEXTS] = {0}; u32 reg = 0; reg = readl_relaxed(device->base + TSPP2_GLOBAL_IRQ_STATUS); @@ -7993,7 +7979,7 @@ static irqreturn_t tspp2_isr(int irq, void *dev) for_each_set_bit(i, &ext_reg, 32) { filter_bitmask[j*32 + i] |= TSPP2_FILTER_EVENT_SCRAMBLING_HIGH; - device->irq_stats.filter[j*32 + i].sc_go_high++; + device->irq_stats.ctx[j*32 + i].sc_go_high++; } writel_relaxed(ext_reg, device->base + TSPP2_SC_GO_HIGH_CLEAR(j)); @@ -8007,7 +7993,7 @@ static irqreturn_t tspp2_isr(int irq, void *dev) for_each_set_bit(i, &ext_reg, 32) { filter_bitmask[j*32 + i] |= TSPP2_FILTER_EVENT_SCRAMBLING_LOW; - device->irq_stats.filter[j*32 + i].sc_go_low++; + device->irq_stats.ctx[j*32 + i].sc_go_low++; } writel_relaxed(ext_reg, device->base + TSPP2_SC_GO_LOW_CLEAR(j)); @@ -8056,12 +8042,12 @@ static irqreturn_t tspp2_isr(int irq, void *dev) for (i = 0; i < TSPP2_NUM_HW_FILTERS; i++) { f = &device->filters[i]; if (f->event_callback && - (f->event_bitmask & filter_bitmask[f->hw_index])) + (f->event_bitmask & filter_bitmask[f->context])) tspp2_event_work_prepare(device, f->event_callback, f->event_cookie, (f->event_bitmask & - filter_bitmask[f->hw_index])); + filter_bitmask[f->context])); } spin_unlock_irqrestore(&device->spinlock, flags); 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 9daeaa65c53..acd36f5b89b 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -340,7 +340,7 @@ struct msm_vfe_axi_shared_data { struct msm_vfe_stats_hardware_info { uint32_t stats_capability_mask; - uint32_t stats_ping_pong_offset; + uint8_t *stats_ping_pong_offset; uint8_t num_stats_type; uint8_t num_stats_comp_mask; }; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c index 2164982de6b..a296a72bb78 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c @@ -33,12 +33,14 @@ #define VFE32_PING_PONG_BASE(wm, ping_pong) \ (VFE32_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1))) +static uint8_t stats_pingpong_offset_map[] = { + 7, 8, 9, 10, 11, 12, 13}; + #define VFE32_NUM_STATS_TYPE 7 -#define VFE32_STATS_PING_PONG_OFFSET 7 #define VFE32_STATS_BASE(idx) (0xF4 + 0xC * idx) #define VFE32_STATS_PING_PONG_BASE(idx, ping_pong) \ (VFE32_STATS_BASE(idx) + 0x4 * \ - (~(ping_pong >> (idx + VFE32_STATS_PING_PONG_OFFSET)) & 0x1)) + (~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1)) #define VFE32_CLK_IDX 0 static struct msm_cam_clk_info msm_vfe32_1_clk_info[] = { @@ -1080,7 +1082,7 @@ static struct msm_vfe_stats_hardware_info msm_vfe32_stats_hw_info = { 1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST | 1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS | 1 << MSM_ISP_STATS_SKIN | 1 << MSM_ISP_STATS_BHIST, - .stats_ping_pong_offset = VFE32_STATS_PING_PONG_OFFSET, + .stats_ping_pong_offset = stats_pingpong_offset_map, .num_stats_type = VFE32_NUM_STATS_TYPE, .num_stats_comp_mask = 0, }; 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 eb4149c934f..9566974f65b 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -47,12 +47,14 @@ #define VFE40_PING_PONG_BASE(wm, ping_pong) \ (VFE40_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1))) +static uint8_t stats_pingpong_offset_map[] = { + 8, 9, 10, 11, 12, 13, 14, 15}; + #define VFE40_NUM_STATS_TYPE 8 -#define VFE40_STATS_PING_PONG_OFFSET 8 #define VFE40_STATS_BASE(idx) (0x168 + 0x18 * idx) #define VFE40_STATS_PING_PONG_BASE(idx, ping_pong) \ (VFE40_STATS_BASE(idx) + 0x4 * \ - (~(ping_pong >> (idx + VFE40_STATS_PING_PONG_OFFSET)) & 0x1)) + (~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1)) #define VFE40_VBIF_CLKON 0x4 #define VFE40_VBIF_IN_RD_LIM_CONF0 0xB0 @@ -1397,7 +1399,7 @@ static struct msm_vfe_stats_hardware_info msm_vfe40_stats_hw_info = { 1 << MSM_ISP_STATS_BG | 1 << MSM_ISP_STATS_BHIST | 1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST | 1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS, - .stats_ping_pong_offset = VFE40_STATS_PING_PONG_OFFSET, + .stats_ping_pong_offset = stats_pingpong_offset_map, .num_stats_type = VFE40_NUM_STATS_TYPE, .num_stats_comp_mask = 2, }; 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 94ad05f16b2..6dbc4ee6fd3 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c @@ -53,13 +53,15 @@ #define VFE44_PING_PONG_BASE(wm, ping_pong) \ (VFE44_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1))) +static uint8_t stats_pingpong_offset_map[] = { + 7, 8, 9, 10, 11, 12, 13, 14, 15}; + #define VFE44_NUM_STATS_TYPE 9 -#define VFE44_STATS_PING_PONG_OFFSET 7 #define VFE44_STATS_BASE(idx) \ ((idx) == STATS_IDX_BF_SCALE ? 0xA0C : (0x168 + 0x18 * (idx-1))) #define VFE44_STATS_PING_PONG_BASE(idx, ping_pong) \ (VFE44_STATS_BASE(idx) + 0x4 * \ - (~(ping_pong >> (idx + VFE44_STATS_PING_PONG_OFFSET)) & 0x1)) + (~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1)) #define VFE44_VBIF_CLKON 0x4 #define VFE44_VBIF_IN_RD_LIM_CONF0 0xB0 @@ -1285,7 +1287,7 @@ static struct msm_vfe_stats_hardware_info msm_vfe44_stats_hw_info = { 1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST | 1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS | 1 << MSM_ISP_STATS_BF_SCALE, - .stats_ping_pong_offset = VFE44_STATS_PING_PONG_OFFSET, + .stats_ping_pong_offset = stats_pingpong_offset_map, .num_stats_type = VFE44_NUM_STATS_TYPE, .num_stats_comp_mask = 2, }; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c index 433037953ae..f8474cce2a9 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -32,8 +32,9 @@ static int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev, return -EINVAL; } - stats_pingpong_offset = STATS_IDX(stream_info->stream_handle) + - vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset; + stats_pingpong_offset = + vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[ + STATS_IDX(stream_info->stream_handle)]; pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1); rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, 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 e830021171d..f7e506cc231 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 @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -855,7 +855,10 @@ static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin) /*Start firmware loading*/ msm_cpp_write(MSM_CPP_CMD_FW_LOAD, cpp_dev->base); - msm_cpp_write(fw->size, cpp_dev->base); + if (fw) + msm_cpp_write(fw->size, cpp_dev->base); + else + msm_cpp_write(MSM_CPP_END_ADDRESS, cpp_dev->base); msm_cpp_write(MSM_CPP_START_ADDRESS, cpp_dev->base); if (ptr_bin) { @@ -1541,6 +1544,7 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, CPP_DBG("VIDIOC_MSM_CPP_FLUSH_QUEUE\n"); rc = msm_cpp_flush_frames(cpp_dev); break; + case VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO: case VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO: { struct msm_cpp_stream_buff_info_t *u_stream_buff_info; struct msm_cpp_stream_buff_info_t k_stream_buff_info; @@ -1608,10 +1612,11 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, mutex_unlock(&cpp_dev->mutex); return -EINVAL; } - - rc = msm_cpp_add_buff_queue_entry(cpp_dev, - ((k_stream_buff_info.identity >> 16) & 0xFFFF), - (k_stream_buff_info.identity & 0xFFFF)); + if (cmd != VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO) { + rc = msm_cpp_add_buff_queue_entry(cpp_dev, + ((k_stream_buff_info.identity >> 16) & 0xFFFF), + (k_stream_buff_info.identity & 0xFFFF)); + } if (!rc) rc = msm_cpp_enqueue_buff_info_list(cpp_dev, &k_stream_buff_info); @@ -1628,8 +1633,11 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, return -EINVAL; } } - cpp_dev->stream_cnt++; - pr_err("stream_cnt:%d\n", cpp_dev->stream_cnt); + + if (cmd != VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO) { + cpp_dev->stream_cnt++; + pr_err("stream_cnt:%d\n", cpp_dev->stream_cnt); + } break; } case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO: { @@ -2091,6 +2099,13 @@ static int cpp_probe(struct platform_device *pdev) cpp_dev->timer_wq = create_workqueue("msm_cpp_workqueue"); cpp_dev->work = kmalloc(sizeof(struct msm_cpp_work_t), GFP_KERNEL); + + if (!cpp_dev->work) { + pr_err("no enough memory\n"); + rc = -ENOMEM; + goto CPP_PROBE_INIT_ERROR; + } + INIT_WORK((struct work_struct *)cpp_dev->work, msm_cpp_do_timeout_work); cpp_dev->cpp_open_cnt = 0; cpp_dev->is_firmware_loaded = 0; 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 3ff3d80a368..2090ce8757a 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 @@ -464,6 +464,45 @@ static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl) return rc; } +static int32_t msm_actuator_set_position( + struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_set_position_t *set_pos) +{ + int32_t rc = 0; + int32_t index; + uint16_t next_lens_position; + uint16_t delay; + uint32_t hw_params = 0; + struct msm_camera_i2c_reg_setting reg_setting; + CDBG("%s Enter %d\n", __func__, __LINE__); + if (set_pos->number_of_steps == 0) + return rc; + + a_ctrl->i2c_tbl_index = 0; + for (index = 0; index < set_pos->number_of_steps; index++) { + next_lens_position = set_pos->pos[index]; + delay = set_pos->delay[index]; + a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, + next_lens_position, hw_params, delay); + + reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; + reg_setting.size = a_ctrl->i2c_tbl_index; + reg_setting.data_type = a_ctrl->i2c_data_type; + + rc = a_ctrl->i2c_client.i2c_func_tbl-> + i2c_write_table_w_microdelay( + &a_ctrl->i2c_client, ®_setting); + if (rc < 0) { + pr_err("%s Failed I2C write Line %d\n", + __func__, __LINE__); + return rc; + } + a_ctrl->i2c_tbl_index = 0; + } + CDBG("%s exit %d\n", __func__, __LINE__); + return rc; +} + static int32_t msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl, struct msm_actuator_set_info_t *set_info) { struct reg_settings_t *init_settings = NULL; @@ -631,6 +670,13 @@ static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, if (rc < 0) pr_err("msm_actuator_power_down failed %d\n", rc); break; + + case CFG_SET_POSITION: + rc = a_ctrl->func_tbl->actuator_set_position(a_ctrl, + &cdata->cfg.setpos); + if (rc < 0) + pr_err("actuator_set_position failed %d\n", rc); + break; default: break; } @@ -752,7 +798,7 @@ static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl) int rc = 0; CDBG("%s called\n", __func__); - CDBG("vcm info: %x %x\n", a_ctrl->vcm_pwd, + CDBG("vcm info: %d %d\n", a_ctrl->vcm_pwd, a_ctrl->vcm_enable); if (a_ctrl->vcm_enable) { rc = gpio_request(a_ctrl->vcm_pwd, "msm_actuator"); @@ -990,6 +1036,7 @@ static struct msm_actuator msm_vcm_actuator_table = { .actuator_set_default_focus = msm_actuator_set_default_focus, .actuator_init_focus = msm_actuator_init_focus, .actuator_parse_i2c_params = msm_actuator_parse_i2c_params, + .actuator_set_position = msm_actuator_set_position, }, }; diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h index 29d2c41c4b5..ec607433c17 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h @@ -48,6 +48,8 @@ struct msm_actuator_func_tbl { struct damping_params_t *, int8_t, int16_t); + int32_t (*actuator_set_position)(struct msm_actuator_ctrl_t *, + struct msm_actuator_set_position_t *); }; struct msm_actuator { 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 08148362882..e527ed82530 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 @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -292,7 +292,7 @@ static int32_t msm_cci_write_i2c_queue(struct cci_device *cci_dev, pr_err("%s: failed %d", __func__, __LINE__); return rc; } - CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val %x:%x\n", + CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x\n", __func__, CCI_I2C_M0_Q0_LOAD_DATA_ADDR + reg_offset, val); msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + @@ -398,7 +398,7 @@ static int32_t msm_cci_i2c_read(struct v4l2_subdev *sd, val = msm_camera_io_r(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + master * 0x200 + queue * 0x100); - CDBG("%s cur word cnt %x\n", __func__, val); + CDBG("%s cur word cnt 0x%x\n", __func__, val); msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + master * 0x200 + queue * 0x100); @@ -438,16 +438,16 @@ static int32_t msm_cci_i2c_read(struct v4l2_subdev *sd, do { val = msm_camera_io_r(cci_dev->base + CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); - CDBG("%s read val %x\n", __func__, val); + CDBG("%s read val 0x%x\n", __func__, val); for (i = 0; (i < 4) && (index < read_cfg->num_byte); i++) { CDBG("%s i %d index %d\n", __func__, i, index); if (!first_byte) { - CDBG("%s sid %x\n", __func__, val & 0xFF); + CDBG("%s sid 0x%x\n", __func__, val & 0xFF); first_byte++; } else { read_cfg->data[index] = (val >> (i * 8)) & 0xFF; - CDBG("%s data[%d] %x\n", __func__, index, + CDBG("%s data[%d] 0x%x\n", __func__, index, read_cfg->data[index]); index++; } @@ -847,13 +847,13 @@ static irqreturn_t msm_cci_irq(int irq_num, void *data) cci_dev->base + CCI_RESET_CMD_ADDR); } if (irq & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { - pr_err("%s:%d MASTER_0 error %x\n", __func__, __LINE__, irq); + pr_err("%s:%d MASTER_0 error 0x%x\n", __func__, __LINE__, irq); cci_dev->cci_master_info[MASTER_0].status = -EINVAL; msm_camera_io_w(CCI_M0_HALT_REQ_RMSK, cci_dev->base + CCI_HALT_REQ_ADDR); } if (irq & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { - pr_err("%s:%d MASTER_1 error %x\n", __func__, __LINE__, irq); + pr_err("%s:%d MASTER_1 error 0x%x\n", __func__, __LINE__, irq); cci_dev->cci_master_info[MASTER_1].status = -EINVAL; msm_camera_io_w(CCI_M1_HALT_REQ_RMSK, cci_dev->base + CCI_HALT_REQ_ADDR); diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c index 4841370f12c..ce5b3f3fe4c 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -51,10 +51,11 @@ static int msm_csid_cid_lut( return -EINVAL; } for (i = 0; i < csid_lut_params->num_cid && i < 16; i++) { - CDBG("%s lut params num_cid = %d, cid = %d, dt = %x, df = %d\n", + CDBG("%s lut params num_cid = %d, cid = %d\n", __func__, csid_lut_params->num_cid, - csid_lut_params->vc_cfg[i]->cid, + csid_lut_params->vc_cfg[i]->cid); + CDBG("%s lut params dt = 0x%x, df = %d\n", __func__, csid_lut_params->vc_cfg[i]->dt, csid_lut_params->vc_cfg[i]->decode_format); if (csid_lut_params->vc_cfg[i]->dt < 0x12 || @@ -113,10 +114,11 @@ static int msm_csid_config(struct csid_device *csid_dev, return -EINVAL; } - CDBG("%s csid_params, lane_cnt = %d, lane_assign = %x, phy sel = %d\n", + CDBG("%s csid_params, lane_cnt = %d, lane_assign = 0x%x\n", __func__, csid_params->lane_cnt, - csid_params->lane_assign, + csid_params->lane_assign); + CDBG("%s csid_params phy_sel = %d\n", __func__, csid_params->phy_sel); msm_csid_reset(csid_dev); @@ -240,7 +242,7 @@ static int msm_csid_init(struct csid_device *csid_dev, uint32_t *csid_version) CDBG("%s:%d called\n", __func__, __LINE__); csid_dev->hw_version = msm_camera_io_r(csid_dev->base + CSID_HW_VERSION_ADDR); - CDBG("%s:%d called csid_dev->hw_version %x\n", __func__, __LINE__, + CDBG("%s:%d called csid_dev->hw_version 0x%x\n", __func__, __LINE__, csid_dev->hw_version); *csid_version = csid_dev->hw_version; @@ -276,7 +278,7 @@ static int msm_csid_release(struct csid_device *csid_dev) return -EINVAL; } - CDBG("%s:%d, hw_version = %x\n", __func__, __LINE__, + CDBG("%s:%d, hw_version = 0x%x\n", __func__, __LINE__, csid_dev->hw_version); irq = msm_camera_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR); @@ -316,7 +318,7 @@ static long msm_csid_cmd(struct csid_device *csid_dev, void *arg) switch (cdata->cfgtype) { case CSID_INIT: rc = msm_csid_init(csid_dev, &cdata->cfg.csid_version); - CDBG("%s csid version %x\n", __func__, + CDBG("%s csid version 0x%x\n", __func__, cdata->cfg.csid_version); break; case CSID_CFG: { 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 aa2c534aaef..2b88cd0d893 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 @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -60,11 +60,12 @@ static int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev, return rc; } - CDBG("%s csiphy_params, mask = %x cnt = %d settle cnt = %x csid %d\n", + CDBG("%s csiphy_params, mask = 0x%x cnt = %d\n", __func__, csiphy_params->lane_mask, - csiphy_params->lane_cnt, - csiphy_params->settle_cnt, + csiphy_params->lane_cnt); + CDBG("%s csiphy_params, settle cnt = 0x%x csid %d\n", + __func__, csiphy_params->settle_cnt, csiphy_params->csid_core); if (csiphy_dev->hw_version >= CSIPHY_VERSION_V30) { @@ -263,7 +264,7 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) else csiphy_dev->hw_version = CSIPHY_VERSION; - CDBG("%s:%d called csiphy_dev->hw_version %x\n", __func__, __LINE__, + CDBG("%s:%d called csiphy_dev->hw_version 0x%x\n", __func__, __LINE__, csiphy_dev->hw_version); csiphy_dev->csiphy_state = CSIPHY_POWER_UP; return 0; @@ -359,7 +360,7 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) else csiphy_dev->hw_version = CSIPHY_VERSION; - CDBG("%s:%d called csiphy_dev->hw_version %x\n", __func__, __LINE__, + CDBG("%s:%d called csiphy_dev->hw_version 0x%x\n", __func__, __LINE__, csiphy_dev->hw_version); csiphy_dev->csiphy_state = CSIPHY_POWER_UP; return 0; @@ -398,7 +399,7 @@ static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) } csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F); - CDBG("%s csiphy_params, lane assign %x mask = %x\n", + CDBG("%s csiphy_params, lane assign 0x%x mask = 0x%x\n", __func__, csi_lane_params->csi_lane_assign, csi_lane_params->csi_lane_mask); @@ -481,7 +482,7 @@ static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) } csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F); - CDBG("%s csiphy_params, lane assign %x mask = %x\n", + CDBG("%s csiphy_params, lane assign 0x%x mask = 0x%x\n", __func__, csi_lane_params->csi_lane_assign, csi_lane_params->csi_lane_mask); diff --git a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c index e8286a62959..961f67de287 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c +++ b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -407,6 +407,10 @@ int32_t gc0339_config(struct msm_sensor_ctrl_t *s_ctrl, for (i = 0; i < SUB_MODULE_MAX; i++) cdata->cfg.sensor_info.subdev_id[i] = s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; CDBG("%s:%d sensor name %s\n", __func__, __LINE__, cdata->cfg.sensor_info.sensor_name); CDBG("%s:%d session id %d\n", __func__, __LINE__, @@ -474,13 +478,13 @@ int32_t gc0339_config(struct msm_sensor_ctrl_t *s_ctrl, rc = -EFAULT; break; } - CDBG("%s sensor id %x\n", __func__, + CDBG("%s sensor id 0x%x\n", __func__, sensor_slave_info.slave_addr); CDBG("%s sensor addr type %d\n", __func__, sensor_slave_info.addr_type); - CDBG("%s sensor reg %x\n", __func__, + CDBG("%s sensor reg 0x%x\n", __func__, sensor_slave_info.sensor_id_info.sensor_id_reg_addr); - CDBG("%s sensor id %x\n", __func__, + CDBG("%s sensor id 0x%x\n", __func__, sensor_slave_info.sensor_id_info.sensor_id); for (slave_index = 0; slave_index < power_setting_array->size; slave_index++) { diff --git a/drivers/media/platform/msm/camera_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_v2/sensor/hi256.c index 9c1e4522373..e4f3bdfd975 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/hi256.c +++ b/drivers/media/platform/msm/camera_v2/sensor/hi256.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -1593,7 +1593,7 @@ static int32_t hi256_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl) return rc; } - CDBG("%s: read id: %x expected id %x:\n", __func__, chipid, + CDBG("%s: read id: 0x%x expected id 0x%x:\n", __func__, chipid, s_ctrl->sensordata->slave_info->sensor_id); if (chipid != s_ctrl->sensordata->slave_info->sensor_id) { pr_err("msm_sensor_match_id chip id doesnot match\n"); @@ -1768,6 +1768,10 @@ int32_t hi256_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, for (i = 0; i < SUB_MODULE_MAX; i++) cdata->cfg.sensor_info.subdev_id[i] = s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; CDBG("%s:%d sensor name %s\n", __func__, __LINE__, cdata->cfg.sensor_info.sensor_name); CDBG("%s:%d session id %d\n", __func__, __LINE__, @@ -1869,13 +1873,13 @@ int32_t hi256_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, rc = -EFAULT; break; } - CDBG("%s sensor id %x\n", __func__, + CDBG("%s sensor id 0x%x\n", __func__, sensor_slave_info.slave_addr); CDBG("%s sensor addr type %d\n", __func__, sensor_slave_info.addr_type); - CDBG("%s sensor reg %x\n", __func__, + CDBG("%s sensor reg 0x%x\n", __func__, sensor_slave_info.sensor_id_info.sensor_id_reg_addr); - CDBG("%s sensor id %x\n", __func__, + CDBG("%s sensor id 0x%x\n", __func__, sensor_slave_info.sensor_id_info.sensor_id); for (slave_index = 0; slave_index < power_setting_array->size; slave_index++) { 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 cc301ae8351..43a1fd383ef 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 @@ -324,7 +324,7 @@ int msm_sensor_get_dt_csi_data(struct device_node *of_node, *csi_lane_params = clp; rc = of_property_read_u32(of_node, "qcom,csi-lane-assign", &val); - CDBG("%s qcom,csi-lane-assign %x, rc %d\n", __func__, val, rc); + CDBG("%s qcom,csi-lane-assign 0x%x, rc %d\n", __func__, val, rc); if (rc < 0) { pr_err("%s failed %d\n", __func__, __LINE__); goto ERROR; @@ -332,7 +332,7 @@ int msm_sensor_get_dt_csi_data(struct device_node *of_node, clp->csi_lane_assign = val; rc = of_property_read_u32(of_node, "qcom,csi-lane-mask", &val); - CDBG("%s qcom,csi-lane-mask %x, rc %d\n", __func__, val, rc); + CDBG("%s qcom,csi-lane-mask 0x%x, rc %d\n", __func__, val, rc); if (rc < 0) { pr_err("%s failed %d\n", __func__, __LINE__); goto ERROR; diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c index d5b89b7c4d1..489206ab299 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, 2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011, 2013-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -248,7 +248,7 @@ int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client, client->addr_type = write_setting->addr_type; for (i = 0; i < write_setting->size; i++) { - CDBG("%s addr %x data %x\n", __func__, + CDBG("%s addr 0x%x data 0x%x\n", __func__, reg_setting->reg_addr, reg_setting->reg_data); rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr, 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 395248de2d6..4d82363d6b2 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c @@ -283,7 +283,8 @@ static int32_t msm_sensor_get_dt_data(struct device_node *of_node, sensordata->slave_info->sensor_slave_addr = id_info[0]; sensordata->slave_info->sensor_id_reg_addr = id_info[1]; sensordata->slave_info->sensor_id = id_info[2]; - CDBG("%s:%d slave addr %x sensor reg %x id %x\n", __func__, __LINE__, + CDBG("%s:%d slave addr 0x%x sensor reg 0x%x id 0x%x\n", + __func__, __LINE__, sensordata->slave_info->sensor_slave_addr, sensordata->slave_info->sensor_id_reg_addr, sensordata->slave_info->sensor_id); @@ -498,7 +499,7 @@ int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl) return rc; } - CDBG("%s: read id: %x expected id %x:\n", __func__, chipid, + CDBG("%s: read id: 0x%x expected id 0x%x:\n", __func__, chipid, slave_info->sensor_id); if (chipid != slave_info->sensor_id) { pr_err("msm_sensor_match_id chip id doesnot match\n"); @@ -655,13 +656,13 @@ int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp) rc = -EFAULT; break; } - CDBG("%s sensor id %x\n", __func__, + CDBG("%s sensor id 0x%x\n", __func__, sensor_slave_info.slave_addr); CDBG("%s sensor addr type %d\n", __func__, sensor_slave_info.addr_type); - CDBG("%s sensor reg %x\n", __func__, + CDBG("%s sensor reg 0x%x\n", __func__, sensor_slave_info.sensor_id_info.sensor_id_reg_addr); - CDBG("%s sensor id %x\n", __func__, + CDBG("%s sensor id 0x%x\n", __func__, sensor_slave_info.sensor_id_info.sensor_id); for (s_index = 0; s_index < p_ctrl->power_setting_size; s_index++) { 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 bc24e2d2f86..3551d77e4e9 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 @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -296,11 +296,11 @@ int32_t msm_sensor_driver_probe(void *setting) /* Print slave info */ CDBG("camera id %d", slave_info->camera_id); - CDBG("slave_addr %x", slave_info->slave_addr); + CDBG("slave_addr 0x%x", slave_info->slave_addr); CDBG("addr_type %d", slave_info->addr_type); - CDBG("sensor_id_reg_addr %x", + CDBG("sensor_id_reg_addr 0x%x", slave_info->sensor_id_info.sensor_id_reg_addr); - CDBG("sensor_id %x", slave_info->sensor_id_info.sensor_id); + CDBG("sensor_id 0x%x", slave_info->sensor_id_info.sensor_id); CDBG("size %d", slave_info->power_setting_array.size); CDBG("size down %d", slave_info->power_setting_array.size_down); @@ -456,7 +456,7 @@ int32_t msm_sensor_driver_probe(void *setting) cci_client->retries = 3; cci_client->id_map = 0; - /* Parse and fill vreg params */ + /* Parse and fill vreg params for powerup settings */ rc = msm_camera_fill_vreg_params( power_info->cam_vreg, power_info->num_vreg, @@ -468,6 +468,18 @@ int32_t msm_sensor_driver_probe(void *setting) goto FREE_CAMERA_INFO; } + /* Parse and fill vreg params for powerdown settings*/ + rc = msm_camera_fill_vreg_params( + power_info->cam_vreg, + power_info->num_vreg, + power_info->power_down_setting, + power_info->power_down_setting_size); + if (rc < 0) { + pr_err("failed: msm_camera_fill_vreg_params for PDOWN rc %d", + rc); + goto FREE_CAMERA_INFO; + } + /* Update sensor, actuator and eeprom name in * sensor control structure */ s_ctrl->sensordata->sensor_name = slave_info->sensor_name; diff --git a/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c b/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c index 23439422f47..26e35c62437 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c +++ b/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -1295,7 +1295,7 @@ int32_t mt9m114_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, rc = -EFAULT; break; } - CDBG("%s sensor id %x\n", __func__, + CDBG("%s sensor id 0x%x\n", __func__, sensor_slave_info.slave_addr); CDBG("%s sensor addr type %d\n", __func__, sensor_slave_info.addr_type); diff --git a/drivers/media/platform/msm/camera_v2/sensor/sp1628.c b/drivers/media/platform/msm/camera_v2/sensor/sp1628.c index 1ca5d6b3739..70d03414398 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/sp1628.c +++ b/drivers/media/platform/msm/camera_v2/sensor/sp1628.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -938,7 +938,7 @@ int32_t sp1628_match_id(struct msm_sensor_ctrl_t *s_ctrl) return rc; } - CDBG("%s: read id: %x expected id 0x16:\n", __func__, chipid); + CDBG("%s: read id: 0x%x expected id 0x16:\n", __func__, chipid); if (chipid != 0x16) { pr_err("msm_sensor_match_id chip id doesnot match\n"); return -ENODEV; @@ -955,7 +955,7 @@ int32_t sp1628_match_id(struct msm_sensor_ctrl_t *s_ctrl) return rc; } - CDBG("%s: read id: %x expected id 0x28:\n", __func__, chipid); + CDBG("%s: read id: 0x%x expected id 0x28:\n", __func__, chipid); if (chipid != 0x28) { pr_err("msm_sensor_match_id chip id doesnot match\n"); return -ENODEV; diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 34a2d79ff78..6610b258d6d 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -12,7 +12,7 @@ */ #include <linux/slab.h> -#include <mach/scm.h> +#include <soc/qcom/scm.h> #include "msm_vidc_internal.h" #include "msm_vidc_common.h" #include "vidc_hfi_api.h" diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 7a2d18a3c1c..d8e8d768365 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -544,7 +544,7 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) if ((i == 0) && is_dynamic_output_buffer_mode(b, inst)) { rc = buf_ref_get(inst, binfo); if (rc < 0) - return rc; + goto exit; } dprintk(VIDC_DBG, "%s: [MAP] binfo = %p, handle[%d] = %p, device_addr = 0x%x, fd = %d, offset = %d, mapped = %d\n", @@ -961,6 +961,13 @@ int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b) } } + if (!buffer_info) { + dprintk(VIDC_ERR, + "%s: error - no buffer info found in registered list\n", + __func__); + return -EINVAL; + } + if (is_dynamic_output_buffer_mode(b, inst)) { mutex_lock(&inst->lock); buffer_info->dequeued = true; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 7b9c71d9508..5b1dca2ad55 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -15,8 +15,8 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/kernel.h> +#include <soc/qcom/subsystem_restart.h> #include <asm/div64.h> -#include <mach/subsystem_restart.h> #include "msm_vidc_common.h" #include "vidc_hfi_api.h" #include "msm_vidc_debug.h" diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c index 7f029c69674..b223474c9e6 100644 --- a/drivers/media/platform/msm/vidc/q6_hfi.c +++ b/drivers/media/platform/msm/vidc/q6_hfi.c @@ -15,7 +15,7 @@ #include <linux/iommu.h> #include <linux/msm_iommu_domains.h> #include <linux/qdsp6v2/apr.h> -#include <mach/subsystem_restart.h> +#include <soc/qcom/subsystem_restart.h> #include "hfi_packetization.h" #include "msm_vidc_debug.h" #include "q6_hfi.h" diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 9f8e78d3171..6af34303853 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -18,11 +18,11 @@ #include <linux/delay.h> #include <linux/of.h> #include <linux/iommu.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/scm.h> #include <mach/iommu.h> #include <linux/msm_iommu_domains.h> #include <mach/ocmem.h> -#include <mach/scm.h> -#include <mach/subsystem_restart.h> #include <soc/qcom/smem.h> #include <asm/memory.h> #include <linux/iopoll.h> @@ -3606,9 +3606,15 @@ int venus_hfi_get_core_capabilities(void) smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE, &smem_block_size, 0, SMEM_ANY_HOST_FLAG); if (smem_table_ptr && - ((smem_image_index_venus + 128) <= smem_block_size)) + ((smem_image_index_venus + 128) <= smem_block_size)) { memcpy(version_info, smem_table_ptr + smem_image_index_venus, 128); + } else { + dprintk(VIDC_ERR, + "%s: failed to read version info from smem table\n", + __func__); + return -EINVAL; + } while (version_info[i++] != 'V' && i < 128) ; diff --git a/drivers/media/platform/msm/vpu/vpu_channel.c b/drivers/media/platform/msm/vpu/vpu_channel.c index 7cfdd7dc410..c8784c29da4 100644 --- a/drivers/media/platform/msm/vpu/vpu_channel.c +++ b/drivers/media/platform/msm/vpu/vpu_channel.c @@ -26,7 +26,7 @@ #include <linux/slab.h> #include <linux/gfp.h> #include <linux/regulator/consumer.h> -#include <mach/scm.h> +#include <soc/qcom/scm.h> #include <mach/rpm-smd.h> #include <uapi/media/msm_vpu.h> diff --git a/drivers/media/platform/msm/vpu/vpu_hfi.c b/drivers/media/platform/msm/vpu/vpu_hfi.c index 7b9b49c7a86..10bbb6c5512 100644 --- a/drivers/media/platform/msm/vpu/vpu_hfi.c +++ b/drivers/media/platform/msm/vpu/vpu_hfi.c @@ -22,8 +22,8 @@ #include <linux/mutex.h> #include <linux/spinlock.h> #include <linux/compiler.h> -#include <mach/scm.h> -#include <mach/subsystem_restart.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/scm.h> #include "vpu_hfi.h" #include "vpu_hfi_intf.h" diff --git a/drivers/media/platform/msm/wfd/vsg-subdev.c b/drivers/media/platform/msm/wfd/vsg-subdev.c index 1f827bb0acc..433468ef4bb 100644 --- a/drivers/media/platform/msm/wfd/vsg-subdev.c +++ b/drivers/media/platform/msm/wfd/vsg-subdev.c @@ -26,12 +26,6 @@ #define TICKS_PER_TIMEOUT 2 -static void vsg_reset_timer(struct hrtimer *timer, ktime_t time) -{ - hrtimer_forward_now(timer, time); - hrtimer_restart(timer); -} - static int vsg_release_input_buffer(struct vsg_context *context, struct vsg_buf_info *buf) { @@ -467,7 +461,7 @@ static long vsg_queue_buffer(struct v4l2_subdev *sd, void *arg) * otherwise, diff between two consecutive frames might * be less than max_frame_interval (for just one sample) */ - vsg_reset_timer(&context->threshold_timer, + hrtimer_forward_now(&context->threshold_timer, ns_to_ktime(context->max_frame_interval)); } } diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 302fe8029c7..d6480c64a18 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -34,11 +34,11 @@ #include <linux/firmware.h> #include <linux/freezer.h> #include <linux/scatterlist.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/scm.h> #include <mach/board.h> #include <mach/msm_bus.h> #include <mach/msm_bus_board.h> -#include <mach/scm.h> -#include <mach/subsystem_restart.h> #include <mach/socinfo.h> #include <mach/qseecomi.h> #include <asm/cacheflush.h> diff --git a/drivers/misc/smsc_hub.c b/drivers/misc/smsc_hub.c index bb814068078..ded36ed5676 100644 --- a/drivers/misc/smsc_hub.c +++ b/drivers/misc/smsc_hub.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -266,7 +266,7 @@ static int msm_hsic_hub_init_gpio(struct hsic_hub *hub, int init) } /* Enable LDO if required for external pull-up */ - smsc_hub->int_pad_reg = devm_regulator_get(hub->dev, "hub_int"); + smsc_hub->int_pad_reg = devm_regulator_get(hub->dev, "hub-int"); if (IS_ERR(smsc_hub->int_pad_reg)) { dev_dbg(hub->dev, "unable to get ext hub_int reg\n"); } else { @@ -298,6 +298,9 @@ static int msm_hsic_hub_init_vdd(struct hsic_hub *hub, int init) { int ret; + if (!of_get_property(hub->dev->of_node, "ext-hub-vddio-supply", NULL)) + return 0; + if (!init) { if (!IS_ERR(smsc_hub->hsic_hub_reg)) { regulator_disable(smsc_hub->hsic_hub_reg); @@ -308,7 +311,7 @@ static int msm_hsic_hub_init_vdd(struct hsic_hub *hub, int init) return 0; } - smsc_hub->hsic_hub_reg = devm_regulator_get(hub->dev, "EXT_HUB_VDDIO"); + smsc_hub->hsic_hub_reg = devm_regulator_get(hub->dev, "ext-hub-vddio"); if (IS_ERR(smsc_hub->hsic_hub_reg)) { dev_dbg(hub->dev, "unable to get ext hub vddcx\n"); } else { @@ -416,11 +419,14 @@ static int smsc_hub_probe(struct platform_device *pdev) smsc_hub->dev = &pdev->dev; smsc_hub->pdata = pdata; - smsc_hub->hub_vbus_reg = devm_regulator_get(&pdev->dev, "hub_vbus"); - ret = PTR_ERR(smsc_hub->hub_vbus_reg); - if (ret == -EPROBE_DEFER) { - dev_dbg(&pdev->dev, "failed to get hub_vbus\n"); - return ret; + if (of_get_property(pdev->dev.of_node, "hub-vbus-supply", NULL)) { + smsc_hub->hub_vbus_reg = devm_regulator_get(&pdev->dev, + "hub-vbus"); + ret = PTR_ERR(smsc_hub->hub_vbus_reg); + if (ret == -EPROBE_DEFER) { + dev_dbg(&pdev->dev, "failed to get hub_vbus\n"); + return ret; + } } ret = msm_hsic_hub_init_vdd(smsc_hub, 1); @@ -447,7 +453,7 @@ static int smsc_hub_probe(struct platform_device *pdev) udelay(5); gpio_direction_output(pdata->hub_reset, 1); - if (!IS_ERR(smsc_hub->hub_vbus_reg)) { + if (!IS_ERR_OR_NULL(smsc_hub->hub_vbus_reg)) { ret = regulator_enable(smsc_hub->hub_vbus_reg); if (ret) { dev_err(&pdev->dev, "unable to enable hub_vbus\n"); @@ -532,7 +538,7 @@ static int smsc_hub_remove(struct platform_device *pdev) } pm_runtime_disable(&pdev->dev); - if (!IS_ERR(smsc_hub->hub_vbus_reg)) + if (!IS_ERR_OR_NULL(smsc_hub->hub_vbus_reg)) regulator_disable(smsc_hub->hub_vbus_reg); msm_hsic_hub_init_gpio(smsc_hub, 0); msm_hsic_hub_init_clock(smsc_hub, 0); diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c index 9f062580308..7ec317a0d3e 100644 --- a/drivers/net/ethernet/msm/msm_rmnet_bam.c +++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -341,6 +341,8 @@ static int _rmnet_xmit(struct sk_buff *skb, struct net_device *dev) if (bam_ret != 0 && bam_ret != -EAGAIN && bam_ret != -EFAULT) { pr_err("[%s] %s: write returned error %d", dev->name, __func__, bam_ret); + if (RMNET_IS_MODE_QOS(opmode)) + skb_pull(skb, sizeof(struct QMI_QOS_HDR_S)); return -EPERM; } diff --git a/drivers/net/usb/rmnet_usb.h b/drivers/net/usb/rmnet_usb.h index 2e7db04351f..ccf59012440 100644 --- a/drivers/net/usb/rmnet_usb.h +++ b/drivers/net/usb/rmnet_usb.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -53,18 +53,16 @@ struct mux_hdr { __u16 pkt_len_w_padding; } __packed; -struct rmnet_ctrl_dev { +struct rmnet_ctrl_udev { - /*for debugging purpose*/ - char name[CTRL_DEV_MAX_LEN]; - - struct cdev cdev; - struct device *devicep; - unsigned ch_id; - - /*to identify the usb device*/ - unsigned id; + /* + * In case of non-mux ctrl channel there is a one to one mapping + * between rmnet_ctrl_dev and rmnet_ctrl_udev. Save the claimed + * device id. + */ + unsigned int ctrldev_id; + unsigned int rdev_num; struct usb_interface *intf; unsigned int int_pipe; struct urb *rcvurb; @@ -75,15 +73,38 @@ struct rmnet_ctrl_dev { void *intbuf; struct usb_ctrlrequest *in_ctlreq; + struct workqueue_struct *wq; + struct work_struct get_encap_work; + + unsigned long status; + + /*counters*/ + unsigned int snd_encap_cmd_cnt; + unsigned int get_encap_resp_cnt; + unsigned int resp_avail_cnt; + unsigned int get_encap_failure_cnt; + unsigned int set_ctrl_line_state_cnt; + unsigned int tx_ctrl_err_cnt; + unsigned int zlp_cnt; + unsigned int invalid_mux_id_cnt; +}; + +struct rmnet_ctrl_dev { + + /*for debugging purpose*/ + char name[CTRL_DEV_MAX_LEN]; + + struct cdev cdev; + struct device *devicep; + unsigned ch_id; + + struct rmnet_ctrl_udev *cudev; + spinlock_t rx_lock; struct mutex dev_lock; struct list_head rx_list; wait_queue_head_t read_wait_queue; wait_queue_head_t open_wait_queue; - - struct workqueue_struct *wq; - struct work_struct get_encap_work; - unsigned long status; bool claimed; @@ -94,27 +115,20 @@ struct rmnet_ctrl_dev { unsigned int cbits_tolocal; /*output control lines (DTR, RTS)*/ unsigned int cbits_tomdm; - - /*counters*/ - unsigned int snd_encap_cmd_cnt; - unsigned int get_encap_resp_cnt; - unsigned int resp_avail_cnt; - unsigned int get_encap_failure_cnt; - unsigned int set_ctrl_line_state_cnt; - unsigned int tx_ctrl_err_cnt; - unsigned int zlp_cnt; }; extern struct workqueue_struct *usbnet_wq; -extern int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *); -extern int rmnet_usb_ctrl_suspend(struct rmnet_ctrl_dev *dev); -extern int rmnet_usb_ctrl_init(int num_devs, int insts_per_dev); -extern void rmnet_usb_ctrl_exit(int num_devs, int insts_per_dev); +extern int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_udev *); +extern int rmnet_usb_ctrl_suspend(struct rmnet_ctrl_udev *dev); +extern int rmnet_usb_ctrl_init(int num_devs, int insts_per_dev, + unsigned long mux_info); +extern void rmnet_usb_ctrl_exit(int num_devs, int insts_per_dev, + unsigned long mux_info); extern int rmnet_usb_ctrl_probe(struct usb_interface *intf, struct usb_host_endpoint *int_in, unsigned long rmnet_devnum, unsigned long *data); -extern void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_dev *); +extern void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_udev *); #endif /* __RMNET_USB_H*/ diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c index 21325a24fc1..946031dadd1 100644 --- a/drivers/net/usb/rmnet_usb_ctrl.c +++ b/drivers/net/usb/rmnet_usb_ctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -38,10 +38,6 @@ module_param_array(rmnet_dev_names, charp, NULL, S_IRUGO | S_IWUSR); #define ACM_CTRL_RI BIT(2) #define ACM_CTRL_CD BIT(3) -/* polling interval for Interrupt ep */ -#define HS_INTERVAL 7 -#define FS_LS_INTERVAL 3 - /*echo modem_wait > /sys/class/hsicctl/hsicctlx/modem_wait*/ static ssize_t modem_wait_store(struct device *d, struct device_attribute *attr, const char *buf, size_t n) @@ -172,8 +168,8 @@ static void rmnet_usb_ctrl_mux(unsigned int id, struct ctrl_pkt *cpkt) static void get_encap_work(struct work_struct *w) { struct usb_device *udev; - struct rmnet_ctrl_dev *dev = - container_of(w, struct rmnet_ctrl_dev, get_encap_work); + struct rmnet_ctrl_udev *dev = + container_of(w, struct rmnet_ctrl_udev, get_encap_work); int status; if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) @@ -202,8 +198,7 @@ static void get_encap_work(struct work_struct *w) usb_unanchor_urb(dev->rcvurb); usb_autopm_put_interface(dev->intf); if (status != -ENODEV) - dev_err(dev->devicep, - "%s: Error submitting Read URB %d\n", + pr_err("%s: Error submitting Read URB %d\n", __func__, status); goto resubmit_int_urb; } @@ -218,8 +213,7 @@ resubmit_int_urb: if (status) { usb_unanchor_urb(dev->inturb); if (status != -ENODEV) - dev_err(dev->devicep, - "%s: Error re-submitting Int URB %d\n", + pr_err("%s: Error re-submitting Int URB %d\n", __func__, status); } } @@ -230,7 +224,12 @@ static void notification_available_cb(struct urb *urb) int status; struct usb_cdc_notification *ctrl; struct usb_device *udev; - struct rmnet_ctrl_dev *dev = urb->context; + struct rmnet_ctrl_udev *dev = urb->context; + struct rmnet_ctrl_dev *cdev; + + /*usb device disconnect*/ + if (urb->dev->state == USB_STATE_NOTATTACHED) + return; udev = interface_to_usbdev(dev->intf); @@ -268,13 +267,14 @@ static void notification_available_cb(struct urb *urb) switch (ctrl->bNotificationType) { case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: dev->resp_avail_cnt++; - /* If MUX is not enabled, wakeup up the open process * upon first notify response available. */ if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) { set_bit(RMNET_CTRL_DEV_READY, &dev->status); - wake_up(&dev->open_wait_queue); + + cdev = &ctrl_devs[dev->rdev_num][dev->ctrldev_id]; + wake_up(&cdev->open_wait_queue); } usb_mark_last_busy(udev); @@ -282,7 +282,7 @@ static void notification_available_cb(struct urb *urb) return; default: - dev_err(dev->devicep, + dev_err(&dev->intf->dev, "%s:Command not implemented\n", __func__); } @@ -292,8 +292,7 @@ resubmit_int_urb: if (status) { usb_unanchor_urb(urb); if (status != -ENODEV) - dev_err(dev->devicep, - "%s: Error re-submitting Int URB %d\n", + pr_err("%s: Error re-submitting Int URB %d\n", __func__, status); } @@ -304,11 +303,17 @@ static void resp_avail_cb(struct urb *urb) { struct usb_device *udev; struct ctrl_pkt_list_elem *list_elem = NULL; - struct rmnet_ctrl_dev *rx_dev, *dev = urb->context; + struct rmnet_ctrl_udev *dev = urb->context; + struct rmnet_ctrl_dev *rx_dev; void *cpkt; - int ch_id, status = 0; + int status = 0; + int ch_id = -EINVAL; size_t cpkt_size = 0; + /*usb device disconnect*/ + if (urb->dev->state == USB_STATE_NOTATTACHED) + return; + udev = interface_to_usbdev(dev->intf); usb_autopm_put_interface_async(dev->intf); @@ -334,26 +339,24 @@ static void resp_avail_cb(struct urb *urb) goto resubmit_int_urb; } - dev_dbg(dev->devicep, "Read %d bytes for %s\n", - urb->actual_length, dev->name); - cpkt = urb->transfer_buffer; cpkt_size = urb->actual_length; if (!cpkt_size) { dev->zlp_cnt++; - dev_dbg(dev->devicep, "%s: zero length pkt received\n", + dev_dbg(&dev->intf->dev, "%s: zero length pkt received\n", __func__); goto resubmit_int_urb; } list_elem = kmalloc(sizeof(struct ctrl_pkt_list_elem), GFP_ATOMIC); if (!list_elem) { - dev_err(dev->devicep, "%s: list_elem alloc failed\n", __func__); + dev_err(&dev->intf->dev, "%s: list_elem alloc failed\n", + __func__); return; } list_elem->cpkt.data = kmalloc(cpkt_size, GFP_ATOMIC); if (!list_elem->cpkt.data) { - dev_err(dev->devicep, "%s: list_elem->data alloc failed\n", + dev_err(&dev->intf->dev, "%s: list_elem->data alloc failed\n", __func__); kfree(list_elem); return; @@ -361,20 +364,23 @@ static void resp_avail_cb(struct urb *urb) memcpy(list_elem->cpkt.data, cpkt, cpkt_size); list_elem->cpkt.data_size = cpkt_size; - rx_dev = dev; + ch_id = dev->ctrldev_id; if (test_bit(RMNET_CTRL_DEV_MUX_EN, &dev->status)) { ch_id = rmnet_usb_ctrl_dmux(list_elem); if (ch_id < 0) { + dev->invalid_mux_id_cnt++; kfree(list_elem->cpkt.data); kfree(list_elem); goto resubmit_int_urb; } - - rx_dev = &ctrl_devs[dev->id][ch_id]; } - rx_dev->get_encap_resp_cnt++; + rx_dev = &ctrl_devs[dev->rdev_num][ch_id]; + + dev->get_encap_resp_cnt++; + dev_dbg(&dev->intf->dev, "Read %d bytes for %s\n", + urb->actual_length, rx_dev->name); spin_lock(&rx_dev->rx_lock); list_add_tail(&list_elem->list, &rx_dev->rx_list); @@ -391,14 +397,13 @@ resubmit_int_urb: if (status) { usb_unanchor_urb(dev->inturb); if (status != -ENODEV) - dev_err(dev->devicep, - "%s: Error re-submitting Int URB %d\n", + pr_err("%s: Error re-submitting Int URB %d\n", __func__, status); } } } -int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *dev) +int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_udev *dev) { int retval = 0; @@ -407,14 +412,13 @@ int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *dev) if (retval < 0) { usb_unanchor_urb(dev->inturb); if (retval != -ENODEV) - dev_err(dev->devicep, - "%s Intr submit %d\n", __func__, retval); + pr_err("%s Intr submit %d\n", __func__, retval); } return retval; } -static int rmnet_usb_ctrl_alloc_rx(struct rmnet_ctrl_dev *dev) +static int rmnet_usb_ctrl_alloc_rx(struct rmnet_ctrl_udev *dev) { dev->rcvurb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->rcvurb) { @@ -444,118 +448,43 @@ nomem: return -ENOMEM; } -static int rmnet_usb_ctrl_write_cmd(struct rmnet_ctrl_dev *dev) +static int rmnet_usb_ctrl_write_cmd(struct rmnet_ctrl_udev *dev, u8 req, + u16 val, void *data, u16 size) { struct usb_device *udev; + int ret; if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) - return -ENODEV; + return -ENETRESET; + + ret = usb_autopm_get_interface(dev->intf); + if (ret < 0) { + pr_debug("%s: Unable to resume interface: %d\n", + __func__, ret); + return ret; + } udev = interface_to_usbdev(dev->intf); - dev->set_ctrl_line_state_cnt++; - return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - USB_CDC_REQ_SET_CONTROL_LINE_STATE, + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + req, (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE), - dev->cbits_tomdm, + val, dev->intf->cur_altsetting->desc.bInterfaceNumber, - NULL, 0, USB_CTRL_SET_TIMEOUT); -} - -static void ctrl_write_callback(struct urb *urb) -{ - struct ctrl_pkt *cpkt = urb->context; - struct rmnet_ctrl_dev *dev = cpkt->ctxt; - - if (urb->status) { + data, size, USB_CTRL_SET_TIMEOUT); + if (ret < 0) dev->tx_ctrl_err_cnt++; - pr_debug_ratelimited("Write status/size %d/%d\n", - urb->status, urb->actual_length); - } - - kfree(urb->setup_packet); - kfree(urb->transfer_buffer); - usb_free_urb(urb); - kfree(cpkt); - usb_autopm_put_interface_async(dev->intf); -} - -static int rmnet_usb_ctrl_write(struct rmnet_ctrl_dev *dev, - struct ctrl_pkt *cpkt, size_t size) -{ - int result; - struct urb *sndurb; - struct usb_ctrlrequest *out_ctlreq; - struct usb_device *udev; - - if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) - return -ENETRESET; - - udev = interface_to_usbdev(dev->intf); - - sndurb = usb_alloc_urb(0, GFP_KERNEL); - if (!sndurb) { - dev_err(dev->devicep, "Error allocating read urb\n"); - return -ENOMEM; - } - - out_ctlreq = kmalloc(sizeof(*out_ctlreq), GFP_KERNEL); - if (!out_ctlreq) { - usb_free_urb(sndurb); - dev_err(dev->devicep, "Error allocating setup packet buffer\n"); - return -ENOMEM; - } - /* CDC Send Encapsulated Request packet */ - out_ctlreq->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS | - USB_RECIP_INTERFACE); - out_ctlreq->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; - out_ctlreq->wValue = 0; - out_ctlreq->wIndex = dev->intf->cur_altsetting->desc.bInterfaceNumber; - out_ctlreq->wLength = cpu_to_le16(cpkt->data_size); - - usb_fill_control_urb(sndurb, udev, - usb_sndctrlpipe(udev, 0), - (unsigned char *)out_ctlreq, (void *)cpkt->data, - cpkt->data_size, ctrl_write_callback, cpkt); - - result = usb_autopm_get_interface(dev->intf); - if (result < 0) { - dev_dbg(dev->devicep, "%s: Unable to resume interface: %d\n", - __func__, result); - - /* - * Revisit: if (result == -EPERM) - * rmnet_usb_suspend(dev->intf, PMSG_SUSPEND); - */ - - usb_free_urb(sndurb); - kfree(out_ctlreq); - return result; - } - - usb_anchor_urb(sndurb, &dev->tx_submitted); - dev->snd_encap_cmd_cnt++; - result = usb_submit_urb(sndurb, GFP_KERNEL); - if (result < 0) { - if (result != -ENODEV) - dev_err(dev->devicep, - "%s: Submit URB error %d\n", - __func__, result); - dev->snd_encap_cmd_cnt--; - usb_autopm_put_interface(dev->intf); - usb_unanchor_urb(sndurb); - usb_free_urb(sndurb); - kfree(out_ctlreq); - return result; - } + usb_autopm_put_interface(dev->intf); - return size; + return ret; } static int rmnet_ctl_open(struct inode *inode, struct file *file) { - int retval = 0; - struct rmnet_ctrl_dev *dev = + struct ctrl_pkt_list_elem *list_elem = NULL; + unsigned long flag; + int retval = 0; + struct rmnet_ctrl_dev *dev = container_of(inode->i_cdev, struct rmnet_ctrl_dev, cdev); if (!dev) @@ -565,10 +494,11 @@ static int rmnet_ctl_open(struct inode *inode, struct file *file) goto already_opened; if (dev->mdm_wait_timeout && - !test_bit(RMNET_CTRL_DEV_READY, &dev->status)) { + !test_bit(RMNET_CTRL_DEV_READY, &dev->cudev->status)) { retval = wait_event_interruptible_timeout( dev->open_wait_queue, - test_bit(RMNET_CTRL_DEV_READY, &dev->status), + test_bit(RMNET_CTRL_DEV_READY, + &dev->cudev->status), msecs_to_jiffies(dev->mdm_wait_timeout * 1000)); if (retval == 0) { dev_err(dev->devicep, "%s: Timeout opening %s\n", @@ -581,12 +511,25 @@ static int rmnet_ctl_open(struct inode *inode, struct file *file) } } - if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) { + if (!test_bit(RMNET_CTRL_DEV_READY, &dev->cudev->status)) { dev_dbg(dev->devicep, "%s: Connection timedout opening %s\n", __func__, dev->name); return -ETIMEDOUT; } + /* clear stale data if device close called but channel was ready */ + spin_lock_irqsave(&dev->rx_lock, flag); + while (!list_empty(&dev->rx_list)) { + list_elem = list_first_entry( + &dev->rx_list, + struct ctrl_pkt_list_elem, + list); + list_del(&list_elem->list); + kfree(list_elem->cpkt.data); + kfree(list_elem); + } + spin_unlock_irqrestore(&dev->rx_lock, flag); + set_bit(RMNET_CTRL_DEV_OPEN, &dev->status); file->private_data = dev; @@ -602,7 +545,6 @@ static int rmnet_ctl_release(struct inode *inode, struct file *file) struct ctrl_pkt_list_elem *list_elem = NULL; struct rmnet_ctrl_dev *dev; unsigned long flag; - int time; dev = file->private_data; if (!dev) @@ -624,11 +566,6 @@ static int rmnet_ctl_release(struct inode *inode, struct file *file) clear_bit(RMNET_CTRL_DEV_OPEN, &dev->status); - time = usb_wait_anchor_empty_timeout(&dev->tx_submitted, - UNLINK_TIMEOUT_MS); - if (!time) - usb_kill_anchored_urbs(&dev->tx_submitted); - file->private_data = NULL; return 0; @@ -644,7 +581,7 @@ static unsigned int rmnet_ctl_poll(struct file *file, poll_table *wait) return POLLERR; poll_wait(file, &dev->read_wait_queue, wait); - if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) { + if (!test_bit(RMNET_CTRL_DEV_READY, &dev->cudev->status)) { dev_dbg(dev->devicep, "%s: Device not connected\n", __func__); return POLLERR; @@ -673,7 +610,7 @@ static ssize_t rmnet_ctl_read(struct file *file, char __user *buf, size_t count, DBG("%s: Read from %s\n", __func__, dev->name); ctrl_read: - if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) { + if (!test_bit(RMNET_CTRL_DEV_READY, &dev->cudev->status)) { dev_dbg(dev->devicep, "%s: Device not connected\n", __func__); return -ENETRESET; @@ -684,7 +621,8 @@ ctrl_read: retval = wait_event_interruptible(dev->read_wait_queue, !list_empty(&dev->rx_list) || - !test_bit(RMNET_CTRL_DEV_READY, &dev->status)); + !test_bit(RMNET_CTRL_DEV_READY, + &dev->cudev->status)); if (retval < 0) return retval; @@ -740,7 +678,7 @@ static ssize_t rmnet_ctl_write(struct file *file, const char __user * buf, if (size <= 0) return -EINVAL; - if (!test_bit(RMNET_CTRL_DEV_READY, &dev->status)) + if (!test_bit(RMNET_CTRL_DEV_READY, &dev->cudev->status)) return -ENETRESET; DBG("%s: Writing %i bytes on %s\n", __func__, size, dev->name); @@ -779,9 +717,14 @@ static ssize_t rmnet_ctl_write(struct file *file, const char __user * buf, } DUMP_BUFFER("Write: ", size, buf); - status = rmnet_usb_ctrl_write(dev, cpkt, size); - if (status == size) - return size; + status = rmnet_usb_ctrl_write_cmd(dev->cudev, + USB_CDC_SEND_ENCAPSULATED_COMMAND, 0, cpkt->data, + cpkt->data_size); + if (status > 0) + dev->cudev->snd_encap_cmd_cnt++; + + kfree(cpkt->data); + kfree(cpkt); return status; } @@ -810,16 +753,11 @@ static int rmnet_ctrl_tiocmset(struct rmnet_ctrl_dev *dev, unsigned int set, mutex_unlock(&dev->dev_lock); - retval = usb_autopm_get_interface(dev->intf); - if (retval < 0) { - dev_dbg(dev->devicep, "%s: Unable to resume interface: %d\n", - __func__, retval); - return retval; - } - - retval = rmnet_usb_ctrl_write_cmd(dev); + retval = rmnet_usb_ctrl_write_cmd(dev->cudev, + USB_CDC_REQ_SET_CONTROL_LINE_STATE, 0, NULL, 0); + if (!retval) + dev->cudev->set_ctrl_line_state_cnt++; - usb_autopm_put_interface(dev->intf); return retval; } @@ -884,6 +822,7 @@ int rmnet_usb_ctrl_probe(struct usb_interface *intf, unsigned long rmnet_devnum, unsigned long *data) { + struct rmnet_ctrl_udev *cudev; struct rmnet_ctrl_dev *dev = NULL; u16 wMaxPacketSize; struct usb_endpoint_descriptor *ep; @@ -904,91 +843,99 @@ int rmnet_usb_ctrl_probe(struct usb_interface *intf, return -ENODEV; } - dev->int_pipe = usb_rcvintpipe(udev, - int_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - - dev->intf = intf; + cudev = dev->cudev; - dev->id = rmnet_devnum; + cudev->int_pipe = usb_rcvintpipe(udev, + int_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - dev->snd_encap_cmd_cnt = 0; - dev->get_encap_resp_cnt = 0; - dev->resp_avail_cnt = 0; - dev->tx_ctrl_err_cnt = 0; - dev->set_ctrl_line_state_cnt = 0; + cudev->intf = intf; - dev->inturb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->inturb) { - dev_err(dev->devicep, "Error allocating int urb\n"); + cudev->inturb = usb_alloc_urb(0, GFP_KERNEL); + if (!cudev->inturb) { + dev_err(&intf->dev, "Error allocating int urb\n"); + kfree(cudev); return -ENOMEM; } /*use max pkt size from ep desc*/ - ep = &dev->intf->cur_altsetting->endpoint[0].desc; + ep = &cudev->intf->cur_altsetting->endpoint[0].desc; wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize); - dev->intbuf = kmalloc(wMaxPacketSize, GFP_KERNEL); - if (!dev->intbuf) { - usb_free_urb(dev->inturb); - dev_err(dev->devicep, "Error allocating int buffer\n"); + cudev->intbuf = kmalloc(wMaxPacketSize, GFP_KERNEL); + if (!cudev->intbuf) { + usb_free_urb(cudev->inturb); + kfree(cudev); + dev_err(&intf->dev, "Error allocating int buffer\n"); return -ENOMEM; } - dev->in_ctlreq->bRequestType = + cudev->in_ctlreq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); - dev->in_ctlreq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; - dev->in_ctlreq->wValue = 0; - dev->in_ctlreq->wIndex = - dev->intf->cur_altsetting->desc.bInterfaceNumber; - dev->in_ctlreq->wLength = cpu_to_le16(DEFAULT_READ_URB_LENGTH); + cudev->in_ctlreq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; + cudev->in_ctlreq->wValue = 0; + cudev->in_ctlreq->wIndex = + cudev->intf->cur_altsetting->desc.bInterfaceNumber; + cudev->in_ctlreq->wLength = cpu_to_le16(DEFAULT_READ_URB_LENGTH); - interval = max((int)int_in->desc.bInterval, - (udev->speed == USB_SPEED_HIGH) ? HS_INTERVAL - : FS_LS_INTERVAL); + interval = int_in->desc.bInterval; - usb_fill_int_urb(dev->inturb, udev, - dev->int_pipe, - dev->intbuf, wMaxPacketSize, - notification_available_cb, dev, interval); + usb_fill_int_urb(cudev->inturb, udev, + cudev->int_pipe, + cudev->intbuf, wMaxPacketSize, + notification_available_cb, cudev, interval); usb_mark_last_busy(udev); - ret = rmnet_usb_ctrl_start_rx(dev); + ret = rmnet_usb_ctrl_start_rx(cudev); if (ret) { - usb_free_urb(dev->inturb); - kfree(dev->intbuf); + usb_free_urb(cudev->inturb); + kfree(cudev->intbuf); + kfree(cudev); return ret; } - dev->claimed = true; - - /*mux info is passed to data parameter*/ - if (*data) - set_bit(RMNET_CTRL_DEV_MUX_EN, &dev->status); + *data = (unsigned long)cudev; - *data = (unsigned long)dev; /* If MUX is enabled, wakeup the open process here */ - if (test_bit(RMNET_CTRL_DEV_MUX_EN, &dev->status)) { - set_bit(RMNET_CTRL_DEV_READY, &dev->status); - wake_up(&dev->open_wait_queue); + if (test_bit(RMNET_CTRL_DEV_MUX_EN, &cudev->status)) { + set_bit(RMNET_CTRL_DEV_READY, &cudev->status); + for (n = 0; n < insts_per_dev; n++) { + dev = &ctrl_devs[rmnet_devnum][n]; + wake_up(&dev->open_wait_queue); + } + } else { + cudev->ctrldev_id = n; + dev->claimed = true; } return 0; } -void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_dev *dev) +void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_udev *dev) { - dev->claimed = false; + struct rmnet_ctrl_dev *cdev; + int n; clear_bit(RMNET_CTRL_DEV_READY, &dev->status); - mutex_lock(&dev->dev_lock); - /*TBD: for now just update CD status*/ - dev->cbits_tolocal = ~ACM_CTRL_CD; - dev->cbits_tomdm = ~ACM_CTRL_DTR; - mutex_unlock(&dev->dev_lock); - - wake_up(&dev->read_wait_queue); + if (test_bit(RMNET_CTRL_DEV_MUX_EN, &dev->status)) { + for (n = 0; n < insts_per_dev; n++) { + cdev = &ctrl_devs[dev->rdev_num][n]; + wake_up(&cdev->read_wait_queue); + mutex_lock(&cdev->dev_lock); + cdev->cbits_tolocal = ~ACM_CTRL_CD; + cdev->cbits_tomdm = ~ACM_CTRL_DTR; + mutex_unlock(&cdev->dev_lock); + } + } else { + cdev = &ctrl_devs[dev->rdev_num][dev->ctrldev_id]; + cdev->claimed = false; + wake_up(&cdev->read_wait_queue); + mutex_lock(&cdev->dev_lock); + cdev->cbits_tolocal = ~ACM_CTRL_CD; + cdev->cbits_tomdm = ~ACM_CTRL_DTR; + mutex_unlock(&cdev->dev_lock); + } cancel_work_sync(&dev->get_encap_work); @@ -1007,7 +954,8 @@ void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_dev *dev) static ssize_t rmnet_usb_ctrl_read_stats(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { - struct rmnet_ctrl_dev *dev; + struct rmnet_ctrl_udev *dev; + struct rmnet_ctrl_dev *cdev; char *buf; int ret; int i, n; @@ -1019,7 +967,8 @@ static ssize_t rmnet_usb_ctrl_read_stats(struct file *file, char __user *ubuf, for (i = 0; i < num_devs; i++) { for (n = 0; n < insts_per_dev; n++) { - dev = &ctrl_devs[i][n]; + cdev = &ctrl_devs[i][n]; + dev = cdev->cudev; temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp, "\n#ctrl_dev: %p Name: %s#\n" "snd encap cmd cnt %u\n" @@ -1032,20 +981,22 @@ static ssize_t rmnet_usb_ctrl_read_stats(struct file *file, char __user *ubuf, "mdm_wait_timeout: %u\n" "zlp_cnt: %u\n" "get_encap_failure_cnt %u\n" + "invalid mux id cnt %u\n" "RMNET_CTRL_DEV_MUX_EN: %d\n" "RMNET_CTRL_DEV_OPEN: %d\n" "RMNET_CTRL_DEV_READY: %d\n", - dev, dev->name, + cdev, cdev->name, dev->snd_encap_cmd_cnt, dev->resp_avail_cnt, dev->get_encap_resp_cnt, dev->set_ctrl_line_state_cnt, dev->tx_ctrl_err_cnt, - dev->cbits_tolocal, - dev->cbits_tomdm, - dev->mdm_wait_timeout, + cdev->cbits_tolocal, + cdev->cbits_tomdm, + cdev->mdm_wait_timeout, dev->zlp_cnt, dev->get_encap_failure_cnt, + dev->invalid_mux_id_cnt, test_bit(RMNET_CTRL_DEV_MUX_EN, &dev->status), test_bit(RMNET_CTRL_DEV_OPEN, @@ -1063,12 +1014,14 @@ static ssize_t rmnet_usb_ctrl_read_stats(struct file *file, char __user *ubuf, static ssize_t rmnet_usb_ctrl_reset_stats(struct file *file, const char __user * buf, size_t count, loff_t *ppos) { - struct rmnet_ctrl_dev *dev; + struct rmnet_ctrl_udev *dev; + struct rmnet_ctrl_dev *cdev; int i, n; for (i = 0; i < num_devs; i++) { for (n = 0; n < insts_per_dev; n++) { - dev = &ctrl_devs[i][n]; + cdev = &ctrl_devs[i][n]; + dev = cdev->cudev; dev->snd_encap_cmd_cnt = 0; dev->resp_avail_cnt = 0; @@ -1076,6 +1029,7 @@ static ssize_t rmnet_usb_ctrl_reset_stats(struct file *file, const char __user * dev->set_ctrl_line_state_cnt = 0; dev->tx_ctrl_err_cnt = 0; dev->zlp_cnt = 0; + dev->invalid_mux_id_cnt = 0; } } return count; @@ -1111,11 +1065,14 @@ static void rmnet_usb_ctrl_debugfs_init(void) { } static void rmnet_usb_ctrl_debugfs_exit(void) { } #endif -int rmnet_usb_ctrl_init(int no_rmnet_devs, int no_rmnet_insts_per_dev) +int rmnet_usb_ctrl_init(int no_rmnet_devs, int no_rmnet_insts_per_dev, + unsigned long mux_info) { struct rmnet_ctrl_dev *dev; + struct rmnet_ctrl_udev *cudev; int i, n; int status; + int cmux_enabled; num_devs = no_rmnet_devs; insts_per_dev = no_rmnet_insts_per_dev; @@ -1153,13 +1110,6 @@ int rmnet_usb_ctrl_init(int no_rmnet_devs, int no_rmnet_insts_per_dev) snprintf(dev->name, CTRL_DEV_MAX_LEN, "%s%d", rmnet_dev_names[i], n); - dev->wq = create_singlethread_workqueue(dev->name); - if (!dev->wq) { - pr_err("unable to allocate workqueue"); - kfree(dev); - return -ENOMEM; - } - dev->ch_id = n; mutex_init(&dev->dev_lock); @@ -1167,9 +1117,6 @@ int rmnet_usb_ctrl_init(int no_rmnet_devs, int no_rmnet_insts_per_dev) init_waitqueue_head(&dev->read_wait_queue); init_waitqueue_head(&dev->open_wait_queue); INIT_LIST_HEAD(&dev->rx_list); - init_usb_anchor(&dev->tx_submitted); - init_usb_anchor(&dev->rx_submitted); - INIT_WORK(&dev->get_encap_work, get_encap_work); cdev_init(&dev->cdev, &ctrldev_fops); dev->cdev.owner = THIS_MODULE; @@ -1178,7 +1125,6 @@ int rmnet_usb_ctrl_init(int no_rmnet_devs, int no_rmnet_insts_per_dev) if (status) { pr_err("%s: cdev_add() ret %i\n", __func__, status); - destroy_workqueue(dev->wq); kfree(dev); return status; } @@ -1191,7 +1137,6 @@ int rmnet_usb_ctrl_init(int no_rmnet_devs, int no_rmnet_insts_per_dev) pr_err("%s: device_create() returned %ld\n", __func__, PTR_ERR(dev->devicep)); cdev_del(&dev->cdev); - destroy_workqueue(dev->wq); kfree(dev); return PTR_ERR(dev->devicep); } @@ -1203,23 +1148,65 @@ int rmnet_usb_ctrl_init(int no_rmnet_devs, int no_rmnet_insts_per_dev) device_destroy(dev->devicep->class, dev->devicep->devt); cdev_del(&dev->cdev); - destroy_workqueue(dev->wq); kfree(dev); return status; } dev_set_drvdata(dev->devicep, dev); - status = rmnet_usb_ctrl_alloc_rx(dev); + cmux_enabled = test_bit(i, &mux_info); + if (n && cmux_enabled) { + dev->cudev = cudev; + set_bit(RMNET_CTRL_DEV_MUX_EN, &dev->status); + continue; + } + cudev = kzalloc(sizeof(*cudev), GFP_KERNEL); + if (!cudev) { + pr_err("Error allocating rmnet usb ctrl dev\n"); + device_remove_file(dev->devicep, + &dev_attr_modem_wait); + device_destroy(dev->devicep->class, + dev->devicep->devt); + cdev_del(&dev->cdev); + kfree(dev); + return -ENOMEM; + } + + cudev->rdev_num = i; + cudev->wq = create_singlethread_workqueue(dev->name); + if (!cudev->wq) { + pr_err("unable to allocate workqueue"); + kfree(cudev); + device_remove_file(dev->devicep, + &dev_attr_modem_wait); + device_destroy(dev->devicep->class, + dev->devicep->devt); + cdev_del(&dev->cdev); + kfree(dev); + return -ENOMEM; + } + + init_usb_anchor(&cudev->tx_submitted); + init_usb_anchor(&cudev->rx_submitted); + INIT_WORK(&cudev->get_encap_work, get_encap_work); + + status = rmnet_usb_ctrl_alloc_rx(cudev); if (status) { + destroy_workqueue(cudev->wq); + kfree(cudev); device_remove_file(dev->devicep, &dev_attr_modem_wait); device_destroy(dev->devicep->class, dev->devicep->devt); cdev_del(&dev->cdev); - destroy_workqueue(dev->wq); kfree(dev); return status; } + + dev->cudev = cudev; + if (cmux_enabled) { + set_bit(RMNET_CTRL_DEV_MUX_EN, &dev->status); + set_bit(RMNET_CTRL_DEV_MUX_EN, &cudev->status); + } } } @@ -1230,25 +1217,35 @@ int rmnet_usb_ctrl_init(int no_rmnet_devs, int no_rmnet_insts_per_dev) static void free_rmnet_ctrl_dev(struct rmnet_ctrl_dev *dev) { - kfree(dev->in_ctlreq); - kfree(dev->rcvbuf); - kfree(dev->intbuf); - usb_free_urb(dev->rcvurb); - usb_free_urb(dev->inturb); device_remove_file(dev->devicep, &dev_attr_modem_wait); cdev_del(&dev->cdev); - destroy_workqueue(dev->wq); device_destroy(dev->devicep->class, dev->devicep->devt); } -void rmnet_usb_ctrl_exit(int no_rmnet_devs, int no_rmnet_insts_per_dev) +static void free_rmnet_ctrl_udev(struct rmnet_ctrl_udev *cudev) +{ + kfree(cudev->in_ctlreq); + kfree(cudev->rcvbuf); + kfree(cudev->intbuf); + usb_free_urb(cudev->rcvurb); + usb_free_urb(cudev->inturb); + destroy_workqueue(cudev->wq); + kfree(cudev); +} + +void rmnet_usb_ctrl_exit(int no_rmnet_devs, int no_rmnet_insts_per_dev, + unsigned long mux_info) { int i, n; for (i = 0; i < no_rmnet_devs; i++) { - for (n = 0; n < no_rmnet_insts_per_dev; n++) + for (n = 0; n < no_rmnet_insts_per_dev; n++) { free_rmnet_ctrl_dev(&ctrl_devs[i][n]); + if (n && test_bit(i, &mux_info)) + continue; + free_rmnet_ctrl_udev((&ctrl_devs[i][n])->cudev); + } kfree(ctrl_devs[i]); diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c index e2514537163..7a17525560b 100644 --- a/drivers/net/usb/rmnet_usb_data.c +++ b/drivers/net/usb/rmnet_usb_data.c @@ -24,13 +24,7 @@ #include "rmnet_usb.h" #define RMNET_DATA_LEN 2000 -#define RMNET_HEADROOM_W_MUX (sizeof(struct mux_hdr) + \ - sizeof(struct QMI_QOS_HDR_S)) #define RMNET_HEADROOM sizeof(struct QMI_QOS_HDR_S) -#define RMNET_TAILROOM MAX_PAD_BYTES(4); - -static unsigned int override_data_muxing = 1; -module_param(override_data_muxing, uint, S_IRUGO | S_IWUSR); static unsigned int no_rmnet_devs = 1; module_param(no_rmnet_devs, uint, S_IRUGO | S_IWUSR); @@ -46,9 +40,6 @@ module_param(no_rmnet_insts_per_dev, uint, S_IRUGO | S_IWUSR); static unsigned long mux_enabled; module_param(mux_enabled, ulong, S_IRUGO | S_IWUSR); -static unsigned int no_fwd_rmnet_links; -module_param(no_fwd_rmnet_links, uint, S_IRUGO | S_IWUSR); - struct usbnet *unet_list[TOTAL_RMNET_DEV_COUNT]; /* net device name prefixes, indexed by driver_info->data */ @@ -57,11 +48,6 @@ static const char * const rmnet_names[] = { "rmnet2_usb%d", }; -/* net device reverse link name prefixes, indexed by driver_info->data */ -static const char * const rev_rmnet_names[] = { - "rev_rmnet_usb%d", - "rev_rmnet2_usb%d", -}; static int data_msg_dbg_mask; enum { @@ -145,93 +131,40 @@ static struct kernel_param_ops rmnet_init_ops = { module_param_cb(rmnet_data_init, &rmnet_init_ops, &rmnet_data_init, S_IRUGO | S_IWUSR); -static void rmnet_usb_setup(struct net_device *, int mux_enabled); +static void rmnet_usb_setup(struct net_device *); static int rmnet_ioctl(struct net_device *, struct ifreq *, int); static int rmnet_usb_suspend(struct usb_interface *iface, pm_message_t message) { struct usbnet *unet = usb_get_intfdata(iface); - struct rmnet_ctrl_dev *dev; - int i, n, rdev_cnt, unet_id; - int retval = 0; - - rdev_cnt = unet->data[4] ? no_rmnet_insts_per_dev : 1; - - for (n = 0; n < rdev_cnt; n++) { - unet_id = n + unet->driver_info->data * no_rmnet_insts_per_dev; - unet = - unet->data[4] ? unet_list[unet_id] : usb_get_intfdata(iface); - - dev = (struct rmnet_ctrl_dev *)unet->data[1]; - spin_lock_irq(&unet->txq.lock); - if (work_busy(&dev->get_encap_work) || unet->txq.qlen) { - spin_unlock_irq(&unet->txq.lock); - retval = -EBUSY; - goto abort_suspend; - } + struct rmnet_ctrl_udev *dev; - set_bit(EVENT_DEV_ASLEEP, &unet->flags); - spin_unlock_irq(&unet->txq.lock); + dev = (struct rmnet_ctrl_udev *)unet->data[1]; + if (work_busy(&dev->get_encap_work)) + return -EBUSY; - usb_kill_anchored_urbs(&dev->rx_submitted); - if (work_busy(&dev->get_encap_work)) { - spin_lock_irq(&unet->txq.lock); - clear_bit(EVENT_DEV_ASLEEP, &unet->flags); - spin_unlock_irq(&unet->txq.lock); - retval = -EBUSY; - goto abort_suspend; - } - } + usb_kill_anchored_urbs(&dev->rx_submitted); + if (work_busy(&dev->get_encap_work)) + return -EBUSY; - for (n = 0; n < rdev_cnt; n++) { - unet_id = n + unet->driver_info->data * no_rmnet_insts_per_dev; - unet = - unet->data[4] ? unet_list[unet_id] : usb_get_intfdata(iface); - - dev = (struct rmnet_ctrl_dev *)unet->data[1]; - netif_device_detach(unet->net); - usbnet_terminate_urbs(unet); - netif_device_attach(unet->net); + if (usbnet_suspend(iface, message)) { + rmnet_usb_ctrl_start_rx(dev); + return -EBUSY; } return 0; - -abort_suspend: - for (i = 0; i < n; i++) { - unet_id = i + unet->driver_info->data * no_rmnet_insts_per_dev; - unet = - unet->data[4] ? unet_list[unet_id] : usb_get_intfdata(iface); - - dev = (struct rmnet_ctrl_dev *)unet->data[1]; - rmnet_usb_ctrl_start_rx(dev); - spin_lock_irq(&unet->txq.lock); - clear_bit(EVENT_DEV_ASLEEP, &unet->flags); - spin_unlock_irq(&unet->txq.lock); - } - return retval; } static int rmnet_usb_resume(struct usb_interface *iface) { struct usbnet *unet = usb_get_intfdata(iface); - struct rmnet_ctrl_dev *dev; - int n, rdev_cnt, unet_id; - - rdev_cnt = unet->data[4] ? no_rmnet_insts_per_dev : 1; + struct rmnet_ctrl_udev *dev; - for (n = 0; n < rdev_cnt; n++) { - unet_id = n + unet->driver_info->data * no_rmnet_insts_per_dev; - unet = - unet->data[4] ? unet_list[unet_id] : usb_get_intfdata(iface); + dev = (struct rmnet_ctrl_udev *)unet->data[1]; - dev = (struct rmnet_ctrl_dev *)unet->data[1]; - rmnet_usb_ctrl_start_rx(dev); - usb_set_intfdata(iface, unet); - unet->suspend_count = 1; - usbnet_resume(iface); - } + usbnet_resume(iface); - return 0; + return rmnet_usb_ctrl_start_rx(dev); } static int rmnet_usb_bind(struct usbnet *usbnet, struct usb_interface *iface) @@ -244,9 +177,6 @@ static int rmnet_usb_bind(struct usbnet *usbnet, struct usb_interface *iface) int status = 0; int i; int numends; - bool mux; - - mux = test_bit(info->data, &mux_enabled); numends = iface->cur_altsetting->desc.bNumEndpoints; for (i = 0; i < numends; i++) { @@ -276,87 +206,13 @@ static int rmnet_usb_bind(struct usbnet *usbnet, struct usb_interface *iface) bulk_out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); usbnet->status = int_in; - /*change name of net device to rmnet_usbx here*/ - if (mux && (info->in > no_fwd_rmnet_links)) - strlcpy(usbnet->net->name, rev_rmnet_names[info->data], - IFNAMSIZ); - else - strlcpy(usbnet->net->name, rmnet_names[info->data], - IFNAMSIZ); - - if (mux) - usbnet->rx_urb_size = usbnet->hard_mtu + sizeof(struct mux_hdr) - + MAX_PAD_BYTES(4); + strlcpy(usbnet->net->name, rmnet_names[info->data], + IFNAMSIZ); + out: return status; } -static int rmnet_usb_data_dmux(struct sk_buff *skb, struct urb *rx_urb) -{ - struct mux_hdr *hdr; - size_t pad_len; - size_t total_len; - unsigned int mux_id; - - hdr = (struct mux_hdr *)skb->data; - mux_id = hdr->mux_id; - if (!mux_id || mux_id > no_rmnet_insts_per_dev) { - pr_err_ratelimited("%s: Invalid data channel id %u.\n", - __func__, mux_id); - return -EINVAL; - } - - pad_len = hdr->padding_info >> MUX_PAD_SHIFT; - if (pad_len > MAX_PAD_BYTES(4)) { - pr_err_ratelimited("%s: Invalid pad len %d\n", - __func__, pad_len); - return -EINVAL; - } - - total_len = le16_to_cpu(hdr->pkt_len_w_padding); - if (!total_len || !(total_len - pad_len)) { - pr_err_ratelimited("%s: Invalid pkt length %d\n", __func__, - total_len); - return -EINVAL; - } - - skb->data = (unsigned char *)(hdr + 1); - skb_reset_tail_pointer(skb); - rx_urb->actual_length = total_len - pad_len; - - return mux_id - 1; -} - -static struct sk_buff *rmnet_usb_data_mux(struct sk_buff *skb, unsigned int id) -{ - struct mux_hdr *hdr; - size_t len; - struct sk_buff *new_skb; - - if ((skb->len & 0x3) && (skb_tailroom(skb) < (4 - (skb->len & 0x3)))) { - new_skb = skb_copy_expand(skb, skb_headroom(skb), - 4 - (skb->len & 0x3), GFP_ATOMIC); - dev_kfree_skb_any(skb); - if (new_skb == NULL) { - pr_err("%s: cannot allocate skb\n", __func__); - return NULL; - } - skb = new_skb; - } - - hdr = (struct mux_hdr *)skb_push(skb, sizeof(struct mux_hdr)); - hdr->mux_id = id + 1; - len = skb->len - sizeof(struct mux_hdr); - - /*add padding if len is not 4 byte aligned*/ - skb_put(skb, ALIGN(len, 4) - len); - - hdr->pkt_len_w_padding = cpu_to_le16(skb->len - sizeof(struct mux_hdr)); - hdr->padding_info = (ALIGN(len, 4) - len) << MUX_PAD_SHIFT; - - return skb; -} - static struct sk_buff *rmnet_usb_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { @@ -370,9 +226,6 @@ static struct sk_buff *rmnet_usb_tx_fixup(struct usbnet *dev, qmih->flow_id = skb->mark; } - if (!override_data_muxing && dev->data[4]) - rmnet_usb_data_mux(skb, dev->data[3]); - if (skb) DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n", dev->net->name, dev->net->stats.tx_packets, @@ -403,32 +256,6 @@ static __be16 rmnet_ip_type_trans(struct sk_buff *skb) return protocol; } -static void rmnet_usb_rx_complete(struct urb *rx_urb) -{ - struct sk_buff *skb = (struct sk_buff *) rx_urb->context; - struct skb_data *entry = (struct skb_data *) skb->cb; - struct usbnet *dev = entry->dev; - unsigned int unet_offset; - unsigned int unet_id; - int mux_id; - - unet_offset = dev->driver_info->data * no_rmnet_insts_per_dev; - - if (!override_data_muxing && !rx_urb->status && dev->data[4]) { - mux_id = rmnet_usb_data_dmux(skb, rx_urb); - if (mux_id < 0) { - /*resubmit urb and free skb in rx_complete*/ - rx_urb->status = -EINVAL; - } else { - /*map urb to actual network iface based on mux id*/ - unet_id = unet_offset + mux_id; - skb->dev = unet_list[unet_id]->net; - } - } - - rx_complete(rx_urb); -} - static int rmnet_usb_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { if (test_bit(RMNET_MODE_LLP_IP, &dev->data[0])) @@ -642,7 +469,7 @@ static int rmnet_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return rc; } -static void rmnet_usb_setup(struct net_device *dev, int mux_enabled) +static void rmnet_usb_setup(struct net_device *dev) { /* Using Ethernet mode by default */ dev->netdev_ops = &rmnet_usb_ops_ether; @@ -650,14 +477,8 @@ static void rmnet_usb_setup(struct net_device *dev, int mux_enabled) /* set this after calling ether_setup */ dev->mtu = RMNET_DATA_LEN; - if (mux_enabled) { - dev->needed_headroom = RMNET_HEADROOM_W_MUX; - - /*max pad bytes for 4 byte alignment*/ - dev->needed_tailroom = RMNET_TAILROOM; - } else { - dev->needed_headroom = RMNET_HEADROOM; - } + /* for QOS header */ + dev->needed_headroom = RMNET_HEADROOM; random_ether_addr(dev->dev_addr); dev->watchdog_timeo = 1000; /* 10 seconds? */ @@ -755,75 +576,51 @@ static int rmnet_usb_probe(struct usb_interface *iface, struct driver_info *info = (struct driver_info *)prod->driver_info; struct usb_device *udev; int status = 0; - unsigned int i, unet_id, rdev_cnt, n = 0; - bool mux; - struct rmnet_ctrl_dev *dev; udev = interface_to_usbdev(iface); if (iface->num_altsetting != 1) { dev_err(&iface->dev, "%s invalid num_altsetting %u\n", __func__, iface->num_altsetting); - status = -EINVAL; - goto out; + return -EINVAL; } - mux = test_bit(info->data, &mux_enabled); - rdev_cnt = mux ? no_rmnet_insts_per_dev : 1; - info->in = 0; - - for (n = 0; n < rdev_cnt; n++) { - - /* Use this filed to increment device count this will be - * used by bind to determin the forward link and reverse - * link network interface names. - */ - info->in++; - status = usbnet_probe(iface, prod); - if (status < 0) { - dev_err(&iface->dev, "usbnet_probe failed %d\n", - status); - goto out; - } - - unet_id = n + info->data * no_rmnet_insts_per_dev; - - unet_list[unet_id] = unet = usb_get_intfdata(iface); - - /*store mux id for later access*/ - unet->data[3] = n; - - /*save mux info for control and usbnet devices*/ - unet->data[1] = unet->data[4] = mux; + status = usbnet_probe(iface, prod); + if (status < 0) { + dev_err(&iface->dev, "usbnet_probe failed %d\n", + status); + return status; + } - /*set rmnet operation mode to eth by default*/ - set_bit(RMNET_MODE_LLP_ETH, &unet->data[0]); + unet = usb_get_intfdata(iface); - /*update net device*/ - rmnet_usb_setup(unet->net, mux); + /*set rmnet operation mode to eth by default*/ + set_bit(RMNET_MODE_LLP_ETH, &unet->data[0]); - /*create /sys/class/net/rmnet_usbx/dbg_mask*/ - status = device_create_file(&unet->net->dev, - &dev_attr_dbg_mask); - if (status) { - usbnet_disconnect(iface); - goto out; - } + /*update net device*/ + rmnet_usb_setup(unet->net); - status = rmnet_usb_ctrl_probe(iface, unet->status, info->data, - &unet->data[1]); - if (status) { - device_remove_file(&unet->net->dev, &dev_attr_dbg_mask); - usbnet_disconnect(iface); - goto out; - } + /*create /sys/class/net/rmnet_usbx/dbg_mask*/ + status = device_create_file(&unet->net->dev, + &dev_attr_dbg_mask); + if (status) { + usbnet_disconnect(iface); + return status; + } - status = rmnet_usb_data_debugfs_init(unet); - if (status) - dev_dbg(&iface->dev, - "mode debugfs file is not available\n"); + status = rmnet_usb_ctrl_probe(iface, unet->status, info->data, + &unet->data[1]); + if (status) { + device_remove_file(&unet->net->dev, &dev_attr_dbg_mask); + usbnet_disconnect(iface); + return status; } + status = rmnet_usb_data_debugfs_init(unet); + if (status) + dev_dbg(&iface->dev, + "mode debugfs file is not available\n"); + usb_enable_autosuspend(udev); if (udev->parent && !udev->parent->parent) { @@ -833,51 +630,23 @@ static int rmnet_usb_probe(struct usb_interface *iface, } return 0; - -out: - for (i = 0; i < n; i++) { - /* This cleanup happens only for MUX case */ - unet_id = i + info->data * no_rmnet_insts_per_dev; - unet = unet_list[unet_id]; - dev = (struct rmnet_ctrl_dev *)unet->data[1]; - - rmnet_usb_data_debugfs_cleanup(unet); - rmnet_usb_ctrl_disconnect(dev); - device_remove_file(&unet->net->dev, &dev_attr_dbg_mask); - usb_set_intfdata(iface, unet_list[unet_id]); - usbnet_disconnect(iface); - unet_list[unet_id] = NULL; - } - - return status; } static void rmnet_usb_disconnect(struct usb_interface *intf) { struct usbnet *unet = usb_get_intfdata(intf); - struct rmnet_ctrl_dev *dev; - unsigned int n, rdev_cnt, unet_id; - struct driver_info *info = unet->driver_info; - bool mux = unet->data[4]; - - rdev_cnt = mux ? no_rmnet_insts_per_dev : 1; + struct rmnet_ctrl_udev *dev; device_set_wakeup_enable(&unet->udev->dev, 0); - for (n = 0; n < rdev_cnt; n++) { - unet_id = n + info->data * no_rmnet_insts_per_dev; - unet = mux ? unet_list[unet_id] : usb_get_intfdata(intf); - device_remove_file(&unet->net->dev, &dev_attr_dbg_mask); + device_remove_file(&unet->net->dev, &dev_attr_dbg_mask); - dev = (struct rmnet_ctrl_dev *)unet->data[1]; - rmnet_usb_ctrl_disconnect(dev); - unet->data[0] = 0; - unet->data[1] = 0; - rmnet_usb_data_debugfs_cleanup(unet); - usb_set_intfdata(intf, unet); - usbnet_disconnect(intf); - unet_list[unet_id] = NULL; - } + dev = (struct rmnet_ctrl_udev *)unet->data[1]; + rmnet_usb_ctrl_disconnect(dev); + unet->data[0] = 0; + unet->data[1] = 0; + rmnet_usb_data_debugfs_cleanup(unet); + usbnet_disconnect(intf); } static struct driver_info rmnet_info = { @@ -886,7 +655,6 @@ static struct driver_info rmnet_info = { .bind = rmnet_usb_bind, .tx_fixup = rmnet_usb_tx_fixup, .rx_fixup = rmnet_usb_rx_fixup, - .rx_complete = rmnet_usb_rx_complete, .manage_power = rmnet_usb_manage_power, .data = 0, }; @@ -897,7 +665,6 @@ static struct driver_info rmnet_usb_info = { .bind = rmnet_usb_bind, .tx_fixup = rmnet_usb_tx_fixup, .rx_fixup = rmnet_usb_rx_fixup, - .rx_complete = rmnet_usb_rx_complete, .manage_power = rmnet_usb_manage_power, .data = 1, }; @@ -984,7 +751,8 @@ static int rmnet_data_start(void) } /* initialize ctrl devices */ - retval = rmnet_usb_ctrl_init(no_rmnet_devs, no_rmnet_insts_per_dev); + retval = rmnet_usb_ctrl_init(no_rmnet_devs, no_rmnet_insts_per_dev, + mux_enabled); if (retval) { pr_err("rmnet_usb_cmux_init failed: %d", retval); return retval; @@ -1002,7 +770,7 @@ static int rmnet_data_start(void) static void __exit rmnet_usb_exit(void) { usb_deregister(&rmnet_usb); - rmnet_usb_ctrl_exit(no_rmnet_devs, no_rmnet_insts_per_dev); + rmnet_usb_ctrl_exit(no_rmnet_devs, no_rmnet_insts_per_dev, mux_enabled); } module_exit(rmnet_usb_exit); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 207a1259009..15ce89b77e7 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -440,11 +440,12 @@ EXPORT_SYMBOL_GPL(usbnet_defer_kevent); /*-------------------------------------------------------------------------*/ +static void rx_complete(struct urb *urb); + static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) { struct sk_buff *skb; struct skb_data *entry; - usb_complete_t complete_fn; int retval = 0; unsigned long lockflags; size_t size = dev->rx_urb_size; @@ -468,13 +469,8 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) entry->dev = dev; entry->length = 0; - if (dev->driver_info->rx_complete) - complete_fn = dev->driver_info->rx_complete; - else - complete_fn = rx_complete; - usb_fill_bulk_urb (urb, dev->udev, dev->in, - skb->data, size, complete_fn, skb); + skb->data, size, rx_complete, skb); spin_lock_irqsave (&dev->rxq.lock, lockflags); @@ -548,7 +544,7 @@ done: /*-------------------------------------------------------------------------*/ -void rx_complete(struct urb *urb) +static void rx_complete(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; struct skb_data *entry = (struct skb_data *) skb->cb; diff --git a/drivers/net/wireless/cnss/cnss.c b/drivers/net/wireless/cnss/cnss.c index f1e41dc41c4..eb30cdd634f 100644 --- a/drivers/net/wireless/cnss/cnss.c +++ b/drivers/net/wireless/cnss/cnss.c @@ -23,10 +23,12 @@ #include <linux/of_gpio.h> #include <linux/pm.h> #include <linux/pm_wakeup.h> +#include <linux/sched.h> +#include <linux/pm_qos.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/ramdump.h> #include <mach/gpiomux.h> #include <mach/msm_pcie.h> -#include <mach/subsystem_restart.h> -#include <mach/ramdump.h> #include <net/cnss.h> #define subsys_to_drv(d) container_of(d, struct cnss_data, subsys_desc) @@ -57,6 +59,7 @@ struct cnss_wlan_gpio_info { u32 num; bool state; bool init; + bool prop; }; struct cnss_wlan_vreg_info { @@ -83,6 +86,7 @@ static struct cnss_data { struct pci_saved_state *saved_state; u16 revision_id; struct cnss_fw_files fw_files; + struct pm_qos_request qos_request; } *penv; static int cnss_wlan_vreg_set(struct cnss_wlan_vreg_info *vreg_info, bool state) @@ -140,6 +144,9 @@ err_gpio_req: static void cnss_wlan_gpio_set(struct cnss_wlan_gpio_info *info, bool state) { + if (!info->prop) + return; + if (info->state == state) { pr_debug("Already %s gpio is %s\n", info->name, state ? "high" : "low"); @@ -178,6 +185,12 @@ static int cnss_wlan_get_resources(struct platform_device *pdev) } vreg_info->state = VREG_ON; + if (!of_find_property((&pdev->dev)->of_node, gpio_info->name, NULL)) { + gpio_info->prop = false; + goto end; + } + + gpio_info->prop = true; ret = of_get_named_gpio((&pdev->dev)->of_node, gpio_info->name, 0); @@ -200,6 +213,7 @@ static int cnss_wlan_get_resources(struct platform_device *pdev) goto err_gpio_init; } +end: return ret; err_gpio_init: @@ -223,6 +237,7 @@ static void cnss_wlan_release_resources(void) gpio_free(gpio_info->num); regulator_put(vreg_info->wlan_reg); gpio_info->state = WLAN_EN_LOW; + gpio_info->prop = false; vreg_info->state = VREG_OFF; } @@ -586,6 +601,20 @@ void cnss_pm_wake_lock_destroy(struct wakeup_source *ws) } EXPORT_SYMBOL(cnss_pm_wake_lock_destroy); +void cnss_flush_work(void *work) +{ + struct work_struct *cnss_work = work; + cancel_work_sync(cnss_work); +} +EXPORT_SYMBOL(cnss_flush_work); + +void cnss_flush_delayed_work(void *dwork) +{ + struct delayed_work *cnss_dwork = dwork; + cancel_delayed_work_sync(cnss_dwork); +} +EXPORT_SYMBOL(cnss_flush_delayed_work); + int cnss_get_ramdump_mem(unsigned long *address, unsigned long *size) { struct resource *res; @@ -614,6 +643,12 @@ void cnss_device_crashed(void) } EXPORT_SYMBOL(cnss_device_crashed); +int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu) +{ + return set_cpus_allowed_ptr(task, cpumask_of(cpu)); +} +EXPORT_SYMBOL(cnss_set_cpus_allowed_ptr); + static int cnss_shutdown(const struct subsys_desc *subsys, bool force_stop) { struct cnss_wlan_driver *wdrv; @@ -800,6 +835,7 @@ static int cnss_probe(struct platform_device *pdev) penv->gpio_info.num = 0; penv->gpio_info.state = WLAN_EN_LOW; penv->gpio_info.init = WLAN_EN_HIGH; + penv->gpio_info.prop = false; penv->vreg_info.wlan_reg = NULL; penv->vreg_info.state = VREG_OFF; @@ -873,6 +909,18 @@ static void __exit cnss_exit(void) platform_driver_unregister(&cnss_driver); } +void cnss_request_pm_qos(u32 qos_val) +{ + pm_qos_add_request(&penv->qos_request, PM_QOS_CPU_DMA_LATENCY, qos_val); +} +EXPORT_SYMBOL(cnss_request_pm_qos); + +void cnss_remove_pm_qos(void) +{ + pm_qos_remove_request(&penv->qos_request); +} +EXPORT_SYMBOL(cnss_remove_pm_qos); + module_init(cnss_initialize); module_exit(cnss_exit); diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 71a1e61a9bc..919b0dddede 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -35,11 +35,11 @@ #include <linux/rwsem.h> #include <linux/mfd/pm8xxx/misc.h> #include <linux/qpnp/qpnp-adc.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/subsystem_notif.h> #include <mach/msm_smd.h> #include <mach/msm_iomap.h> -#include <mach/subsystem_restart.h> -#include <mach/subsystem_notif.h> #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC #include "wcnss_prealloc.h" diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c index c766b9aead1..8db7175d69f 100644 --- a/drivers/nfc/nfc-nci.c +++ b/drivers/nfc/nfc-nci.c @@ -31,8 +31,10 @@ struct qca199x_platform_data { unsigned int irq_gpio; + unsigned int irq_gpio_clk_req; + unsigned int clk_req_irq_num; unsigned int dis_gpio; - unsigned int ven_gpio; + unsigned int clkreq_gpio; unsigned int reg; const char *clk_src_name; unsigned int clk_src_gpio; @@ -53,29 +55,44 @@ MODULE_DEVICE_TABLE(of, msm_match_table); #define MAX_PACKET_SIZE (PACKET_HEADER_SIZE_NCI + 255) #define MAX_QCA_REG (116) /* will timeout in approx. 100ms as 10us steps */ +#define NFC_RF_CLK_FREQ (19200000) #define NTF_TIMEOUT (10000) #define CORE_RESET_RSP_GID (0x60) #define CORE_RESET_OID (0x00) #define CORE_RST_NTF_LENGTH (0x02) +static void clk_req_update(struct work_struct *work); struct qca199x_dev { wait_queue_head_t read_wq; - struct mutex read_mutex; - struct i2c_client *client; - struct miscdevice qca199x_device; - unsigned int irq_gpio; - unsigned int dis_gpio; - unsigned int ven_gpio; - bool irq_enabled; - bool sent_first_nci_write; - spinlock_t irq_enabled_lock; - unsigned int count_irq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice qca199x_device; + /* NFC_IRQ new NCI data available */ + unsigned int irq_gpio; + /* CLK_REQ IRQ to signal the state has changed */ + unsigned int irq_gpio_clk_req; + /* Actual IRQ no. assigned to CLK_REQ */ + unsigned int clk_req_irq_num; + unsigned int dis_gpio; + unsigned int clkreq_gpio; + /* NFC_IRQ state */ + bool irq_enabled; + bool sent_first_nci_write; + spinlock_t irq_enabled_lock; + unsigned int count_irq; + /* CLK_REQ IRQ state */ + bool irq_enabled_clk_req; + spinlock_t irq_enabled_lock_clk_req; + unsigned int count_irq_clk_req; enum nfcc_state state; - unsigned int clk_src_gpio; - const char *clk_src_name; - struct clk *s_clk; - bool clk_run; + /* CLK control */ + unsigned int clk_src_gpio; + const char *clk_src_name; + struct clk *s_clk; + bool clk_run; + struct work_struct msm_clock_controll_work; + struct workqueue_struct *my_wq; }; static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len); @@ -93,9 +110,10 @@ static int logging_level; /* * FTM-RAW-I2C RD/WR MODE */ -static struct devicemode device_mode; -static int ftm_raw_write_mode; -static int ftm_werr_code; +static struct devicemode device_mode; +static int ftm_raw_write_mode; +static int ftm_werr_code; + unsigned int disable_ctrl; @@ -159,6 +177,95 @@ static unsigned int nfc_poll(struct file *filp, poll_table *wait) return mask; } +/* Handlers for CLK_REQ */ +static void qca199x_disable_irq_clk_req(struct qca199x_dev *qca199x_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&qca199x_dev->irq_enabled_lock_clk_req, flags); + if (qca199x_dev->irq_enabled_clk_req) { + disable_irq_nosync(qca199x_dev->clk_req_irq_num); + qca199x_dev->irq_enabled_clk_req = false; + } + spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock_clk_req, flags); +} + + +static void qca199x_enable_irq_clk_req(struct qca199x_dev *qca199x_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&qca199x_dev->irq_enabled_lock_clk_req, flags); + if (!qca199x_dev->irq_enabled_clk_req) { + qca199x_dev->irq_enabled_clk_req = true; + enable_irq(qca199x_dev->clk_req_irq_num); + } + spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock_clk_req, flags); +} + + +static irqreturn_t qca199x_dev_irq_handler_clk_req(int irq, void *dev_id) +{ + struct qca199x_dev *qca199x_dev = dev_id; + unsigned long flags; + + spin_lock_irqsave(&qca199x_dev->irq_enabled_lock_clk_req, flags); + qca199x_dev->count_irq_clk_req++; + spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock_clk_req, flags); + + queue_work(qca199x_dev->my_wq, &qca199x_dev->msm_clock_controll_work); + + return IRQ_HANDLED; +} + + +static struct gpiomux_setting nfc_clk_on = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, +}; +static struct gpiomux_setting nfc_clk_on_suspend = { + .func = GPIOMUX_FUNC_2, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; +static struct gpiomux_setting nfc_clk_off = { + .func = GPIOMUX_FUNC_GPIO, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_DOWN, +}; + +static void clk_req_update(struct work_struct *work) +{ + struct i2c_client *client; + struct qca199x_dev *qca199x_dev; + int gpio_clk_req_level = 0; + + qca199x_dev = container_of(work, struct qca199x_dev, + msm_clock_controll_work); + client = qca199x_dev->client; + + /* Read status level of CLK_REQ from NFC Controller, QCA199_x */ + gpio_clk_req_level = gpio_get_value(qca199x_dev->irq_gpio_clk_req); + if (gpio_clk_req_level == 1) { + if (qca199x_dev->clk_run == false) { + msm_gpiomux_write(qca199x_dev->clk_src_gpio, + GPIOMUX_ACTIVE, &nfc_clk_on, NULL); + msm_gpiomux_write(qca199x_dev->clk_src_gpio, + GPIOMUX_SUSPENDED, &nfc_clk_on_suspend, NULL); + qca199x_dev->clk_run = true; + } + } else{ + if (qca199x_dev->clk_run == true) { + msm_gpiomux_write(qca199x_dev->clk_src_gpio, + GPIOMUX_ACTIVE, &nfc_clk_off, NULL); + msm_gpiomux_write(qca199x_dev->clk_src_gpio, + GPIOMUX_SUSPENDED, &nfc_clk_off, NULL); + qca199x_dev->clk_run = false; + } + } +} + /* * ONLY for FTM-RAW-I2C Mode * Required to instigate a read, which comes from DT layer. This means we need @@ -399,7 +506,14 @@ static int nfc_open(struct inode *inode, struct file *filp) filp->private_data = qca199x_dev; qca199x_init_stat(qca199x_dev); + /* Enable interrupts from NFCC NFC_INT new NCI data available */ qca199x_enable_irq(qca199x_dev); + + if ((!strcmp(qca199x_dev->clk_src_name, "GPCLK")) || + (!strcmp(qca199x_dev->clk_src_name, "GPCLK2"))) { + /* Enable interrupts from NFCC CLK_REQ */ + qca199x_enable_irq_clk_req(qca199x_dev); + } dev_dbg(&qca199x_dev->client->dev, "%d,%d\n", imajor(inode), iminor(inode)); return ret; @@ -965,6 +1079,14 @@ static int qca199x_clock_select(struct qca199x_dev *qca199x_dev) goto err_invalid_dis_gpio; } if (qca199x_dev->clk_run == false) { + /* Set clock rate */ + if ((!strcmp(qca199x_dev->clk_src_name, "GPCLK")) || + (!strcmp(qca199x_dev->clk_src_name, "GPCLK2"))) { + r = clk_set_rate(qca199x_dev->s_clk, NFC_RF_CLK_FREQ); + if (r) + goto err_invalid_clk; + } + r = clk_prepare_enable(qca199x_dev->s_clk); if (r) goto err_invalid_clk; @@ -1006,10 +1128,6 @@ static int nfc_parse_dt(struct device *dev, struct qca199x_platform_data *pdata) if (r) return -EINVAL; - r = of_property_read_u32(np, "qcom,clk-gpio", &pdata->ven_gpio); - if (r) - return -EINVAL; - pdata->dis_gpio = of_get_named_gpio(np, "qcom,dis-gpio", 0); if ((!gpio_is_valid(pdata->dis_gpio))) return -EINVAL; @@ -1021,11 +1139,24 @@ static int nfc_parse_dt(struct device *dev, struct qca199x_platform_data *pdata) r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src_name); - if ((!strcmp(pdata->clk_src_name, "GPCLK")) || - (!strcmp(pdata->clk_src_name, "GPCLK2"))) - pdata->clk_src_gpio = of_get_named_gpio(np, - "qcom,clk-en-gpio", 0); + if (strcmp(pdata->clk_src_name, "GPCLK2")) { + r = of_property_read_u32(np, "qcom,clk-gpio", + &pdata->clkreq_gpio); + if (r) + return -EINVAL; + } + if ((!strcmp(pdata->clk_src_name, "GPCLK")) || + (!strcmp(pdata->clk_src_name, "GPCLK2"))) { + pdata->clk_src_gpio = of_get_named_gpio(np, + "qcom,clk-src-gpio", 0); + if ((!gpio_is_valid(pdata->clk_src_gpio))) + return -EINVAL; + pdata->irq_gpio_clk_req = of_get_named_gpio(np, + "qcom,clk-req-gpio", 0); + if ((!gpio_is_valid(pdata->irq_gpio_clk_req))) + return -EINVAL; + } if (r) return -EINVAL; return r; @@ -1089,7 +1220,6 @@ static int qca199x_probe(struct i2c_client *client, platform_data->irq_gpio); goto err_irq; } - gpio_to_irq(0); irqn = gpio_to_irq(platform_data->irq_gpio); if (irqn < 0) { r = irqn; @@ -1101,13 +1231,45 @@ static int qca199x_probe(struct i2c_client *client, dev_err(&client->dev, "irq gpio not provided\n"); goto err_free_dev; } + /* Interrupt from NFCC CLK_REQ to handle REF_CLK + o/p gating/selection */ + if ((!strcmp(platform_data->clk_src_name, "GPCLK")) || + (!strcmp(platform_data->clk_src_name, "GPCLK2"))) { + if (gpio_is_valid(platform_data->irq_gpio_clk_req)) { + r = gpio_request(platform_data->irq_gpio_clk_req, + "nfc_irq_gpio_clk_en"); + if (r) { + dev_err(&client->dev, "unable to request CLK_EN gpio [%d]\n", + platform_data->irq_gpio_clk_req); + goto err_irq; + } + r = gpio_direction_input( + platform_data->irq_gpio_clk_req); + if (r) { + dev_err(&client->dev, + "unable to set direction for CLK_EN gpio [%d]\n", + platform_data->irq_gpio_clk_req); + goto err_irq_clk; + } + gpio_to_irq(0); + irqn = gpio_to_irq(platform_data->irq_gpio_clk_req); + if (irqn < 0) { + r = irqn; + goto err_irq_clk; + } + platform_data->clk_req_irq_num = irqn; + } else { + dev_err(&client->dev, "irq CLK_EN gpio not provided\n"); + goto err_irq; + } + } if (gpio_is_valid(platform_data->dis_gpio)) { r = gpio_request(platform_data->dis_gpio, "nfc_reset_gpio"); if (r) { dev_err(&client->dev, "NFC: unable to request gpio [%d]\n", platform_data->dis_gpio); - goto err_irq; + goto err_irq_clk; } r = gpio_direction_output(platform_data->dis_gpio, 1); if (r) { @@ -1118,7 +1280,7 @@ static int qca199x_probe(struct i2c_client *client, } } else { dev_err(&client->dev, "dis gpio not provided\n"); - goto err_irq; + goto err_irq_clk; } /* Get the clock source name and gpio from from Device Tree */ qca199x_dev->clk_src_name = platform_data->clk_src_name; @@ -1131,35 +1293,47 @@ static int qca199x_probe(struct i2c_client *client, else goto err_dis_gpio; } - platform_data->ven_gpio = of_get_named_gpio(node, - "qcom,clk-gpio", 0); - if (gpio_is_valid(platform_data->ven_gpio)) { - r = gpio_request(platform_data->ven_gpio, "nfc_ven_gpio"); - if (r) { - dev_err(&client->dev, "unable to request gpio [%d]\n", - platform_data->ven_gpio); - goto err_ven_gpio; - } - r = gpio_direction_input(platform_data->ven_gpio); - if (r) { - dev_err(&client->dev, - "unable to set direction for gpio [%d]\n", - platform_data->ven_gpio); - goto err_ven_gpio; + if (strcmp(platform_data->clk_src_name, "GPCLK2")) { + platform_data->clkreq_gpio = + of_get_named_gpio(node, "qcom,clk-gpio", 0); + + if (gpio_is_valid(platform_data->clkreq_gpio)) { + r = gpio_request(platform_data->clkreq_gpio, + "nfc_clkreq_gpio"); + if (r) { + dev_err(&client->dev, "unable to request gpio [%d]\n", + platform_data->clkreq_gpio); + goto err_clkreq_gpio; + } + r = gpio_direction_input(platform_data->clkreq_gpio); + if (r) { + dev_err(&client->dev, + "unable to set direction for gpio [%d]\n", + platform_data->clkreq_gpio); + goto err_clkreq_gpio; + } + } else { + dev_err(&client->dev, "clkreq gpio not provided\n"); + goto err_clk; } - } else { - dev_err(&client->dev, "ven gpio not provided\n"); - goto err_clk; + qca199x_dev->clkreq_gpio = platform_data->clkreq_gpio; } qca199x_dev->dis_gpio = platform_data->dis_gpio; qca199x_dev->irq_gpio = platform_data->irq_gpio; - qca199x_dev->ven_gpio = platform_data->ven_gpio; + if ((!strcmp(platform_data->clk_src_name, "GPCLK")) || + (!strcmp(platform_data->clk_src_name, "GPCLK2"))) { + qca199x_dev->irq_gpio_clk_req = + platform_data->irq_gpio_clk_req; + qca199x_dev->clk_req_irq_num = + platform_data->clk_req_irq_num; + } /* init mutex and queues */ init_waitqueue_head(&qca199x_dev->read_wq); mutex_init(&qca199x_dev->read_mutex); spin_lock_init(&qca199x_dev->irq_enabled_lock); + spin_lock_init(&qca199x_dev->irq_enabled_lock_clk_req); qca199x_dev->qca199x_device.minor = MISC_DYNAMIC_MINOR; qca199x_dev->qca199x_device.name = "nfc-nci"; @@ -1189,6 +1363,7 @@ static int qca199x_probe(struct i2c_client *client, * for reading. It is cleared when all data has been read. */ device_mode.handle_flavour = UNSOLICITED_MODE; + /* NFC_INT IRQ */ qca199x_dev->irq_enabled = true; r = request_irq(client->irq, qca199x_dev_irq_handler, IRQF_TRIGGER_RISING, client->name, qca199x_dev); @@ -1197,6 +1372,31 @@ static int qca199x_probe(struct i2c_client *client, goto err_request_irq_failed; } qca199x_disable_irq(qca199x_dev); + /* CLK_REQ IRQ */ + if ((!strcmp(platform_data->clk_src_name, "GPCLK")) || + (!strcmp(platform_data->clk_src_name, "GPCLK2"))) { + r = request_irq(qca199x_dev->clk_req_irq_num, + qca199x_dev_irq_handler_clk_req, + (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING), + client->name, qca199x_dev); + if (r) { + dev_err(&client->dev, + "nfc-nci probe: request_irq failed. irq no = %d\n, main irq = %d", + qca199x_dev->clk_req_irq_num, client->irq); + goto err_request_irq_failed; + } + qca199x_dev->irq_enabled_clk_req = true; + qca199x_disable_irq_clk_req(qca199x_dev); + + + qca199x_dev->my_wq = + create_singlethread_workqueue("qca1990x_CLK_REQ_queue"); + if (!qca199x_dev->my_wq) + goto err_create_workq; + + INIT_WORK(&qca199x_dev->msm_clock_controll_work, + clk_req_update); + } i2c_set_clientdata(client, qca199x_dev); gpio_set_value(platform_data->dis_gpio, 1); dev_dbg(&client->dev, @@ -1204,12 +1404,18 @@ static int qca199x_probe(struct i2c_client *client, __func__); return 0; +err_create_workq: + dev_err(&client->dev, + "nfc-nci probe: %s, work_queue creation failure\n", + __func__); + free_irq(client->irq, qca199x_dev); err_request_irq_failed: misc_deregister(&qca199x_dev->qca199x_device); err_misc_register: mutex_destroy(&qca199x_dev->read_mutex); -err_ven_gpio: - gpio_free(platform_data->ven_gpio); +err_clkreq_gpio: + if (strcmp(platform_data->clk_src_name, "GPCLK2")) + gpio_free(platform_data->clkreq_gpio); err_clk: qca199x_clock_deselect(qca199x_dev); err_dis_gpio: @@ -1217,13 +1423,21 @@ err_dis_gpio: if (r) dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n"); if ((!strcmp(platform_data->clk_src_name, "GPCLK")) || - (!strcmp(platform_data->clk_src_name, "GPCLK2"))) { + (!strcmp(platform_data->clk_src_name, "GPCLK2"))) { r = gpio_direction_input(platform_data->clk_src_gpio); if (r) dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n"); gpio_free(platform_data->clk_src_gpio); } gpio_free(platform_data->dis_gpio); +err_irq_clk: + if ((!strcmp(platform_data->clk_src_name, "GPCLK")) || + (!strcmp(platform_data->clk_src_name, "GPCLK2"))) { + r = gpio_direction_input(platform_data->irq_gpio_clk_req); + if (r) + dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n"); + gpio_free(platform_data->irq_gpio_clk_req); + } err_irq: gpio_free(platform_data->irq_gpio); err_free_dev: @@ -1240,8 +1454,13 @@ static int qca199x_remove(struct i2c_client *client) misc_deregister(&qca199x_dev->qca199x_device); mutex_destroy(&qca199x_dev->read_mutex); gpio_free(qca199x_dev->irq_gpio); + if ((!strcmp(qca199x_dev->clk_src_name, "GPCLK")) || + (!strcmp(qca199x_dev->clk_src_name, "GPCLK2"))) { + gpio_free(qca199x_dev->irq_gpio_clk_req); + } gpio_free(qca199x_dev->dis_gpio); - gpio_free(qca199x_dev->ven_gpio); + if (strcmp(qca199x_dev->clk_src_name, "GPCLK2")) + gpio_free(qca199x_dev->clkreq_gpio); kfree(qca199x_dev); return 0; diff --git a/drivers/phy/phy-msm-sata.c b/drivers/phy/phy-msm-sata.c index 02a48001079..8de31902dce 100644 --- a/drivers/phy/phy-msm-sata.c +++ b/drivers/phy/phy-msm-sata.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -59,11 +59,11 @@ /* QSERDES RX registers */ #define QSERDES_RX_CDR_CONTROL 0x200 -#define QSERDES_RX_SIGDET_CNTRL 0x234 +#define QSERDES_RX_CDR_CONTROL2 0x210 +#define QSERDES_RX_RX_EQ_GAIN12 0x230 #define QSERDES_RX_PWM_CNTRL1 0x280 #define QSERDES_RX_PWM_CNTRL2 0x284 #define QSERDES_RX_CDR_CONTROL_QUARTER 0x29c -#define QSERDES_RX_RX_SIGDET_PWMDECSTATUS 0x2D8 /* SATA PHY registers */ #define SATA_PHY_SERDES_START 0x300 @@ -72,6 +72,7 @@ #define SATA_PHY_TX_PWR_CTRL 0x30c #define SATA_PHY_LANE_CTRL1 0x318 #define SATA_PHY_CDR_CTRL0 0x358 +#define SATA_PHY_CDR_CTRL1 0x35c #define SATA_PHY_TX_DRV_WAKEUP 0x360 #define SATA_PHY_CLK_BUF_SETTLING 0x364 #define SATA_PHY_SPDNEG_CFG0 0x370 @@ -80,7 +81,7 @@ #define SATA_PHY_ALIGNP 0x3a4 #define MAX_PROP_NAME 32 -#define VDDA_PHY_MIN_UV 1000000 +#define VDDA_PHY_MIN_UV 950000 #define VDDA_PHY_MAX_UV 1000000 #define VDDA_PLL_MIN_UV 1800000 #define VDDA_PLL_MAX_UV 1800000 @@ -418,13 +419,27 @@ static int msm_sata_phy_power_up(struct msm_sata_phy *phy) /* PI configurations- First Order threshold and Second order gain */ writel_relaxed(0xeb, phy->mmio + QSERDES_RX_CDR_CONTROL); - writel_relaxed(0x1a, phy->mmio + QSERDES_RX_CDR_CONTROL_QUARTER); + writel_relaxed(0x5a, phy->mmio + QSERDES_RX_CDR_CONTROL2); + /* Config required only on reference boards with shared PHY */ + if (phy->phy_sel) + writel_relaxed(0x1a, phy->mmio + + QSERDES_RX_CDR_CONTROL_QUARTER); /* TX configurations */ - writel_relaxed(0x1f, phy->mmio + QSERDES_TX_TX_DRV_LVL); + /* TX config differences between shared & dedicated PHY */ + if (phy->phy_sel) + writel_relaxed(0x1f, phy->mmio + QSERDES_TX_TX_DRV_LVL); + else + writel_relaxed(0x16, phy->mmio + QSERDES_TX_TX_DRV_LVL); writel_relaxed(0x00, phy->mmio + QSERDES_TX_BIST_MODE_LANENO); writel_relaxed(0x30, phy->mmio + QSERDES_TX_TX_EMP_POST1_LVL); + /* RX config differences between shared & dedicated PHY */ + if (!phy->phy_sel) { + writel_relaxed(0x44, phy->mmio + QSERDES_RX_RX_EQ_GAIN12); + writel_relaxed(0x01, phy->mmio + SATA_PHY_CDR_CTRL1); + } + /* SSC Configurations and Serdes start */ writel_relaxed(0x00, phy->mmio + QSERDES_COM_SSC_EN_CENTER); writel_relaxed(0x31, phy->mmio + QSERDES_COM_SSC_PER1); @@ -608,6 +623,7 @@ static int msm_sata_phy_probe(struct platform_device *pdev) if (IS_ERR(phy->phy_sel)) { err = PTR_ERR(phy->phy_sel); /* phy_sel resource is optional */ + phy->phy_sel = 0; dev_dbg(dev, "%s: phy select resource get failed %d\n", __func__, err); } diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c index fa8ef98fa6e..d20f03d646b 100644 --- a/drivers/platform/msm/ipa/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_client.c @@ -309,9 +309,6 @@ int ipa_connect(const struct ipa_connect_params *in, struct ipa_sps_params *sps, ep->connect.event_thresh = IPA_EVENT_THRESHOLD; ep->connect.options = SPS_O_AUTO_ENABLE; /* BAM-to-BAM */ - if (IPA_CLIENT_IS_CONS(in->client)) - ep->connect.options |= SPS_O_NO_DISABLE; - result = sps_connect(ep->ep_hdl, &ep->connect); if (result) { IPAERR("sps_connect fails.\n"); diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c index 7efca891ee9..4150ebc58af 100644 --- a/drivers/platform/msm/ipa/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_dp.c @@ -2076,7 +2076,7 @@ static int ipa_assign_policy(struct ipa_sys_connect_params *in, } else if (in->client == IPA_CLIENT_APPS_LAN_CONS) { sys->policy = IPA_POLICY_INTR_POLL_MODE; sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT | - SPS_O_ACK_TRANSFERS | SPS_O_NO_DISABLE); + SPS_O_ACK_TRANSFERS); sys->sps_callback = ipa_sps_irq_rx_notify; INIT_WORK(&sys->work, ipa_wq_handle_rx); INIT_DELAYED_WORK(&sys->switch_to_intr_work, @@ -2150,7 +2150,7 @@ static int ipa_assign_policy(struct ipa_sys_connect_params *in, sys->ep->status.status_en = false; sys->policy = IPA_POLICY_INTR_POLL_MODE; sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT - | SPS_O_ACK_TRANSFERS | SPS_O_NO_DISABLE); + | SPS_O_ACK_TRANSFERS); sys->sps_callback = ipa_sps_irq_rx_notify; INIT_WORK(&sys->work, ipa_wq_handle_rx); INIT_DELAYED_WORK(&sys->switch_to_intr_work, diff --git a/drivers/platform/msm/ipa/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_qmi_service.h index e1f0148242e..4681bec42df 100644 --- a/drivers/platform/msm/ipa/ipa_qmi_service.h +++ b/drivers/platform/msm/ipa/ipa_qmi_service.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -15,8 +15,8 @@ #include <mach/ipa.h> #include <linux/ipa_qmi_service_v01.h> -#include <mach/msm_qmi_interface.h> #include <uapi/linux/msm_rmnet.h> +#include <soc/qcom/msm_qmi_interface.h> #include "ipa_i.h" /** diff --git a/drivers/platform/msm/ipa/ipa_qmi_service_v01.c b/drivers/platform/msm/ipa/ipa_qmi_service_v01.c index b6696925313..d7f0953825f 100644 --- a/drivers/platform/msm/ipa/ipa_qmi_service_v01.c +++ b/drivers/platform/msm/ipa/ipa_qmi_service_v01.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -12,9 +12,10 @@ */ #include <linux/qmi_encdec.h> -#include <mach/msm_qmi_interface.h> #include <linux/ipa_qmi_service_v01.h> +#include <soc/qcom/msm_qmi_interface.h> + /* Type Definitions */ static struct elem_info ipa_hdr_tbl_info_type_data_v01_ei[] = { { diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c index 71aecbf9f1f..7b082e3ffe4 100644 --- a/drivers/platform/msm/sps/sps_bam.c +++ b/drivers/platform/msm/sps/sps_bam.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -169,6 +169,7 @@ static irqreturn_t bam_isr(int irq, void *ctxt) list_for_each_entry(pipe, &dev->pipes_q, list) { /* Check this pipe's bit in the source mask */ if (BAM_PIPE_IS_ASSIGNED(pipe) + && (!pipe->disconnecting) && (source & pipe->pipe_index_mask)) { /* This pipe has an interrupt pending */ pipe_handler(dev, pipe); @@ -585,6 +586,8 @@ static void pipe_clear(struct sps_pipe *pipe) pipe->mode = -1; pipe->num_descs = 0; pipe->desc_size = 0; + pipe->disconnecting = false; + pipe->late_eot = false; memset(&pipe->sys, 0, sizeof(pipe->sys)); INIT_LIST_HEAD(&pipe->sys.events_q); } @@ -1046,6 +1049,7 @@ int sps_bam_pipe_set_params(struct sps_bam *dev, u32 pipe_index, u32 options) ack_xfers = ((options & SPS_O_ACK_TRANSFERS)); pipe->hybrid = options & SPS_O_HYBRID; + pipe->late_eot = options & SPS_O_LATE_EOT; /* Create interrupt source mask */ mask = 0; @@ -1567,6 +1571,24 @@ static void pipe_handler_eot(struct sps_bam *dev, struct sps_pipe *pipe) /* Get offset of last descriptor completed by the pipe */ end_offset = bam_pipe_get_desc_read_offset(dev->base, pipe_index); + if (producer && pipe->late_eot) { + struct sps_iovec *desc_end; + if (end_offset == 0) + desc_end = (struct sps_iovec *)(pipe->sys.desc_buf + + pipe->desc_size - sizeof(struct sps_iovec)); + else + desc_end = (struct sps_iovec *) (pipe->sys.desc_buf + + end_offset - sizeof(struct sps_iovec)); + + if (!(desc_end->flags & SPS_IOVEC_FLAG_EOT)) { + if (end_offset == 0) + end_offset = pipe->desc_size + - sizeof(struct sps_iovec); + else + end_offset -= sizeof(struct sps_iovec); + } + } + /* If no queue, then do not generate any events */ if (pipe->sys.no_queue) { if (!pipe->sys.ack_xfers) { diff --git a/drivers/platform/msm/sps/sps_bam.h b/drivers/platform/msm/sps/sps_bam.h index da5dafd8941..8fae5cb0339 100644 --- a/drivers/platform/msm/sps/sps_bam.h +++ b/drivers/platform/msm/sps/sps_bam.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -176,6 +176,7 @@ struct sps_pipe { u32 irq_mask; int polled; int hybrid; + bool late_eot; u32 irq_gen_addr; enum sps_mode mode; u32 num_descs; /* Size (number of elements) of descriptor FIFO */ @@ -185,6 +186,7 @@ struct sps_pipe { /* System mode control */ struct sps_bam_sys_mode sys; + bool disconnecting; }; /* BAM device descriptor */ diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c index 7d7e1a6abdd..d8c7a4deb1b 100644 --- a/drivers/platform/msm/sps/sps_rm.c +++ b/drivers/platform/msm/sps/sps_rm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -556,11 +556,8 @@ static int sps_rm_free(struct sps_pipe *pipe) { struct sps_connection *map = (void *)pipe->map; struct sps_connect *cfg = &pipe->connect; - struct sps_bam *bam = pipe->bam; - unsigned long flags; mutex_lock(&sps_rm->lock); - spin_lock_irqsave(&bam->isr_lock, flags); /* Free this connection */ if (cfg->mode == SPS_MODE_SRC) @@ -574,7 +571,6 @@ static int sps_rm_free(struct sps_pipe *pipe) sps_rm_remove_ref(map); - spin_unlock_irqrestore(&bam->isr_lock, flags); mutex_unlock(&sps_rm->lock); return 0; @@ -800,8 +796,9 @@ int sps_rm_state_change(struct sps_pipe *pipe, u32 state) synchronize_irq(bam->props.irq); spin_lock_irqsave(&bam->isr_lock, flags); - result = sps_bam_pipe_disconnect(pipe->bam, pipe_index); + pipe->disconnecting = true; spin_unlock_irqrestore(&bam->isr_lock, flags); + result = sps_bam_pipe_disconnect(pipe->bam, pipe_index); if (result) { SPS_ERR("sps:Failed to disconnect BAM 0x%x pipe %d", pipe->bam->props.phys_addr, diff --git a/drivers/platform/msm/ssm.c b/drivers/platform/msm/ssm.c index ea59abf00e4..fe612a683a6 100644 --- a/drivers/platform/msm/ssm.c +++ b/drivers/platform/msm/ssm.c @@ -27,7 +27,7 @@ #include <linux/platform_device.h> #include <linux/msm_ion.h> #include <linux/platform_data/qcom_ssm.h> -#include <mach/scm.h> +#include <soc/qcom/scm.h> #include <mach/msm_smd.h> #include "qseecom_kernel.h" diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c index 28b9eec1449..c900daab9d5 100644 --- a/drivers/power/qpnp-bms.c +++ b/drivers/power/qpnp-bms.c @@ -4307,6 +4307,12 @@ static int qpnp_bms_probe(struct spmi_device *spmi) goto error_setup; } + rc = bms_request_irqs(chip); + if (rc) { + pr_err("error requesting bms irqs, rc = %d\n", rc); + goto error_setup; + } + battery_insertion_check(chip); batfet_status_check(chip); battery_status_check(chip); @@ -4340,12 +4346,6 @@ static int qpnp_bms_probe(struct spmi_device *spmi) goto unregister_dc; } - rc = bms_request_irqs(chip); - if (rc) { - pr_err("error requesting bms irqs, rc = %d\n", rc); - goto unregister_dc; - } - pr_info("probe success: soc =%d vbatt = %d ocv = %d r_sense_uohm = %u warm_reset = %d\n", get_prop_bms_capacity(chip), vbatt, chip->last_ocv_uv, chip->r_sense_uohm, warm_reset); diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c index 93f38fd141b..39ea2b3a66d 100644 --- a/drivers/power/qpnp-charger.c +++ b/drivers/power/qpnp-charger.c @@ -219,6 +219,7 @@ struct qpnp_chg_irq { int irq; unsigned long disabled; + unsigned long wake_enable; }; struct qpnp_chg_regulator { @@ -534,6 +535,24 @@ qpnp_chg_disable_irq(struct qpnp_chg_irq *irq) } } +static void +qpnp_chg_irq_wake_enable(struct qpnp_chg_irq *irq) +{ + if (!__test_and_set_bit(0, &irq->wake_enable)) { + pr_debug("number = %d\n", irq->irq); + enable_irq_wake(irq->irq); + } +} + +static void +qpnp_chg_irq_wake_disable(struct qpnp_chg_irq *irq) +{ + if (__test_and_clear_bit(0, &irq->wake_enable)) { + pr_debug("number = %d\n", irq->irq); + disable_irq_wake(irq->irq); + } +} + #define USB_OTG_EN_BIT BIT(0) static int qpnp_chg_is_otg_en_set(struct qpnp_chg_chip *chip) @@ -1733,6 +1752,7 @@ qpnp_chg_chgr_chg_fastchg_irq_handler(int irq, void *_chip) struct qpnp_chg_chip *chip = _chip; bool fastchg_on = false; + qpnp_chg_irq_wake_disable(&chip->chg_fastchg); fastchg_on = qpnp_chg_is_fastchg_on(chip); pr_debug("FAST_CHG IRQ triggered, fastchg_on: %d\n", fastchg_on); @@ -2208,6 +2228,7 @@ get_prop_capacity(struct qpnp_chg_chip *chip) && soc <= chip->soc_resume_limit) { pr_debug("resuming charging at %d%% soc\n", soc); chip->resuming_charging = true; + qpnp_chg_irq_wake_enable(&chip->chg_fastchg); qpnp_chg_set_appropriate_vbatdet(chip); qpnp_chg_charge_en(chip, !chip->charging_disabled); } @@ -3909,10 +3930,10 @@ qpnp_chg_request_irqs(struct qpnp_chg_chip *chip) return rc; } - enable_irq_wake(chip->chg_trklchg.irq); - enable_irq_wake(chip->chg_failed.irq); + qpnp_chg_irq_wake_enable(&chip->chg_trklchg); + qpnp_chg_irq_wake_enable(&chip->chg_failed); qpnp_chg_disable_irq(&chip->chg_vbatdet_lo); - enable_irq_wake(chip->chg_vbatdet_lo.irq); + qpnp_chg_irq_wake_enable(&chip->chg_vbatdet_lo); break; case SMBB_BAT_IF_SUBTYPE: @@ -3935,7 +3956,7 @@ qpnp_chg_request_irqs(struct qpnp_chg_chip *chip) return rc; } - enable_irq_wake(chip->batt_pres.irq); + qpnp_chg_irq_wake_enable(&chip->batt_pres); chip->batt_temp_ok.irq = spmi_get_irq_byname(spmi, spmi_resource, "bat-temp-ok"); @@ -3954,7 +3975,7 @@ qpnp_chg_request_irqs(struct qpnp_chg_chip *chip) } qpnp_chg_bat_if_batt_temp_irq_handler(0, chip); - enable_irq_wake(chip->batt_temp_ok.irq); + qpnp_chg_irq_wake_enable(&chip->batt_temp_ok); break; case SMBB_BUCK_SUBTYPE: @@ -4036,11 +4057,11 @@ qpnp_chg_request_irqs(struct qpnp_chg_chip *chip) return rc; } - enable_irq_wake(chip->usb_ocp.irq); + qpnp_chg_irq_wake_enable(&chip->usb_ocp); } - enable_irq_wake(chip->usbin_valid.irq); - enable_irq_wake(chip->chg_gone.irq); + qpnp_chg_irq_wake_enable(&chip->usbin_valid); + qpnp_chg_irq_wake_enable(&chip->chg_gone); break; case SMBB_DC_CHGPTH_SUBTYPE: chip->dcin_valid.irq = spmi_get_irq_byname(spmi, @@ -4059,7 +4080,7 @@ qpnp_chg_request_irqs(struct qpnp_chg_chip *chip) return rc; } - enable_irq_wake(chip->dcin_valid.irq); + qpnp_chg_irq_wake_enable(&chip->dcin_valid); break; } } diff --git a/drivers/power/smb135x-charger.c b/drivers/power/smb135x-charger.c index dd703f3fb60..2f4eeb3c47c 100644 --- a/drivers/power/smb135x-charger.c +++ b/drivers/power/smb135x-charger.c @@ -793,7 +793,11 @@ static int smb135x_set_usb_chg_current(struct smb135x_chg *chip, current_ma = CURRENT_500_MA; } - if (current_ma <= SUSPEND_CURRENT_MA) { + if (current_ma == 0) + /* choose the lowest available value of 100mA */ + current_ma = CURRENT_100_MA; + + if (current_ma == SUSPEND_CURRENT_MA) { /* force suspend bit */ rc = smb135x_path_suspend(chip, USB, CURRENT, true); goto out; @@ -869,6 +873,17 @@ static int smb135x_set_appropriate_current(struct smb135x_chg *chip, int (*func)(struct smb135x_chg *chip, int current_ma); int rc = 0; + /* + * If battery is absent do not modify the current at all, these + * would be some appropriate values set by the bootloader or default + * configuration and since it is the only source of power we should + * not change it + */ + if (!chip->batt_present) { + pr_debug("ignoring current request since battery is absent\n"); + return 0; + } + if (path == USB) { path_current = chip->usb_psy_ma; func = smb135x_set_usb_chg_current; @@ -900,7 +915,7 @@ static int smb135x_set_appropriate_current(struct smb135x_chg *chip, return rc; } -static int smb135x_charging(struct smb135x_chg *chip, int enable) +static int __smb135x_charging(struct smb135x_chg *chip, int enable) { int rc = 0; @@ -937,6 +952,27 @@ static int smb135x_charging(struct smb135x_chg *chip, int enable) return rc; } +static int smb135x_charging(struct smb135x_chg *chip, int enable) +{ + int rc = 0; + + pr_debug("charging enable = %d\n", enable); + + __smb135x_charging(chip, enable); + + if (chip->usb_psy) { + pr_debug("usb psy changed\n"); + power_supply_changed(chip->usb_psy); + } + if (chip->dc_psy_type != -EINVAL) { + pr_debug("dc psy changed\n"); + power_supply_changed(&chip->dc_psy); + } + pr_debug("charging %s\n", + enable ? "enabled" : "disabled running from batt"); + return rc; +} + static int smb135x_system_temp_level_set(struct smb135x_chg *chip, int lvl_sel) { @@ -1094,6 +1130,7 @@ static int smb135x_battery_get_property(struct power_supply *psy, } static enum power_supply_property smb135x_dc_properties[] = { + POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_HEALTH, }; @@ -1106,9 +1143,12 @@ static int smb135x_dc_get_property(struct power_supply *psy, struct smb135x_chg, dc_psy); switch (prop) { - case POWER_SUPPLY_PROP_ONLINE: + case POWER_SUPPLY_PROP_PRESENT: val->intval = chip->dc_present; break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = chip->chg_enabled ? chip->dc_present : 0; + break; case POWER_SUPPLY_PROP_HEALTH: val->intval = chip->dc_present; break; @@ -1123,21 +1163,13 @@ static void smb135x_external_power_changed(struct power_supply *psy) struct smb135x_chg *chip = container_of(psy, struct smb135x_chg, batt_psy); union power_supply_propval prop = {0,}; - int rc, current_limit = 0, online = 0; + int rc, current_limit = 0; if (chip->bms_psy_name) chip->bms_psy = power_supply_get_by_name((char *)chip->bms_psy_name); rc = chip->usb_psy->get_property(chip->usb_psy, - POWER_SUPPLY_PROP_ONLINE, &prop); - if (rc < 0) - dev_err(chip->dev, - "could not read USB online property, rc=%d\n", rc); - else - online = prop.intval; - - rc = chip->usb_psy->get_property(chip->usb_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &prop); if (rc < 0) dev_err(chip->dev, @@ -1145,17 +1177,35 @@ static void smb135x_external_power_changed(struct power_supply *psy) else current_limit = prop.intval / 1000; - pr_debug("online = %d, current_limit = %d\n", online, current_limit); + pr_debug("current_limit = %d\n", current_limit); - if (!online) - current_limit = CURRENT_100_MA; + if (chip->usb_psy_ma != current_limit) { + mutex_lock(&chip->current_change_lock); + chip->usb_psy_ma = current_limit; + rc = smb135x_set_appropriate_current(chip, USB); + mutex_unlock(&chip->current_change_lock); + if (rc < 0) + dev_err(chip->dev, "Couldn't set usb current rc = %d\n", + rc); + } - mutex_lock(&chip->current_change_lock); - chip->usb_psy_ma = current_limit; - rc = smb135x_set_appropriate_current(chip, USB); - mutex_unlock(&chip->current_change_lock); + rc = chip->usb_psy->get_property(chip->usb_psy, + POWER_SUPPLY_PROP_ONLINE, &prop); + if (rc < 0) + dev_err(chip->dev, + "could not read USB ONLINE property, rc=%d\n", rc); + + /* update online property */ + rc = 0; + if (chip->usb_present && chip->chg_enabled && chip->usb_psy_ma != 0) { + if (prop.intval == 0) + rc = power_supply_set_online(chip->usb_psy, true); + } else { + if (prop.intval == 1) + rc = power_supply_set_online(chip->usb_psy, false); + } if (rc < 0) - dev_err(chip->dev, "Couldn't set usb current rc = %d\n", rc); + dev_err(chip->dev, "could not set usb online, rc=%d\n", rc); } #define MIN_FLOAT_MV 3600 @@ -2415,7 +2465,7 @@ static int smb135x_hw_init(struct smb135x_chg *chip) return rc; } - smb135x_charging(chip, chip->chg_enabled); + __smb135x_charging(chip, chip->chg_enabled); /* interrupt enabling - active low */ if (chip->client->irq) { diff --git a/drivers/scsi/ufs/ufs-msm.c b/drivers/scsi/ufs/ufs-msm.c index 4cfe7bbef8a..ca05ead836d 100644 --- a/drivers/scsi/ufs/ufs-msm.c +++ b/drivers/scsi/ufs/ufs-msm.c @@ -44,7 +44,7 @@ #define UFS_MSM_LIMIT_HS_RATE PA_HS_MODE_B #define UFS_MSM_LIMIT_DESIRED_MODE FAST -static struct msm_ufs_phy_calibration phy_cal_table_rate_A[] = { +static struct msm_ufs_phy_calibration phy_cal_table_ctrl_1_1_0_rate_A[] = { { .cfg_value = 0x01, .reg_offset = UFS_PHY_POWER_DOWN_CONTROL, @@ -651,6 +651,621 @@ static struct msm_ufs_phy_calibration phy_cal_table_rate_A[] = { }, }; +static struct msm_ufs_phy_calibration phy_cal_table_ctrl_1_1_1_rate_A[] = { + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_POWER_DOWN_CONTROL, + }, + { + .cfg_value = 0x43, + .reg_offset = QSERDES_COM_PLL_CRCTRL, + }, + { + .cfg_value = 0x24, + .reg_offset = QSERDES_COM_PLL_CNTRL, + }, + { + .cfg_value = 0x08, + .reg_offset = QSERDES_COM_SYSCLK_EN_SEL, + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_COM_SYS_CLK_CTRL, + }, + { + .cfg_value = 0x03, + .reg_offset = QSERDES_COM_PLL_CLKEPDIV, + }, + { + .cfg_value = 0x82, + .reg_offset = QSERDES_COM_DEC_START1, + }, + { + .cfg_value = 0x03, + .reg_offset = QSERDES_COM_DEC_START2, + }, + { + .cfg_value = 0x80, + .reg_offset = QSERDES_COM_DIV_FRAC_START1, + }, + { + .cfg_value = 0x80, + .reg_offset = QSERDES_COM_DIV_FRAC_START2, + }, + { + .cfg_value = 0x10, + .reg_offset = QSERDES_COM_DIV_FRAC_START3, + }, + { + .cfg_value = 0xff, + .reg_offset = QSERDES_COM_PLLLOCK_CMP1, + }, + { + .cfg_value = 0x19, + .reg_offset = QSERDES_COM_PLLLOCK_CMP2, + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_COM_PLLLOCK_CMP3, + }, + { + .cfg_value = 0x03, + .reg_offset = QSERDES_COM_PLLLOCK_CMP_EN, + }, + { + .cfg_value = 0x10, + .reg_offset = QSERDES_COM_RESETSM_CNTRL, + }, + { + .cfg_value = 0x10, + .reg_offset = QSERDES_COM_PLL_RXTXEPCLK_EN, + }, + { + .cfg_value = 0x43, + .reg_offset = QSERDES_RX_PWM_CNTRL1(0), + }, + { + .cfg_value = 0x43, + .reg_offset = QSERDES_RX_PWM_CNTRL1(1), + }, + { + .cfg_value = 0x40, + .reg_offset = QSERDES_RX_CDR_CONTROL(0), + }, + { + .cfg_value = 0x0c, + .reg_offset = QSERDES_RX_CDR_CONTROL_HALF(0), + }, + { + .cfg_value = 0x12, + .reg_offset = QSERDES_RX_CDR_CONTROL_QUARTER(0), + }, + { + .cfg_value = 0x40, + .reg_offset = QSERDES_RX_CDR_CONTROL(1), + }, + { + .cfg_value = 0x0c, + .reg_offset = QSERDES_RX_CDR_CONTROL_HALF(1), + }, + { + .cfg_value = 0x12, + .reg_offset = QSERDES_RX_CDR_CONTROL_QUARTER(1), + }, + { + .cfg_value = 0xC0, + .reg_offset = QSERDES_RX_SIGDET_CNTRL(0), + }, + { + .cfg_value = 0xC0, + .reg_offset = QSERDES_RX_SIGDET_CNTRL(1), + }, + { + .cfg_value = 0x07, + .reg_offset = QSERDES_RX_SIGDET_CNTRL2(0), + }, + { + .cfg_value = 0x07, + .reg_offset = QSERDES_RX_SIGDET_CNTRL2(1), + }, + { + .cfg_value = 0x30, + .reg_offset = UFS_PHY_PWM_G1_CLK_DIVIDER, + }, + { + .cfg_value = 0x18, + .reg_offset = UFS_PHY_PWM_G2_CLK_DIVIDER, + }, + { + .cfg_value = 0x0c, + .reg_offset = UFS_PHY_PWM_G3_CLK_DIVIDER, + }, + { + .cfg_value = 0x06, + .reg_offset = UFS_PHY_PWM_G4_CLK_DIVIDER, + }, + { + .cfg_value = 0xa8, + .reg_offset = UFS_PHY_CORECLK_PWM_G1_CLK_DIVIDER, + }, + { + .cfg_value = 0x54, + .reg_offset = UFS_PHY_CORECLK_PWM_G2_CLK_DIVIDER, + }, + { + .cfg_value = 0x2a, + .reg_offset = UFS_PHY_CORECLK_PWM_G3_CLK_DIVIDER, + }, + { + .cfg_value = 0x15, + .reg_offset = UFS_PHY_CORECLK_PWM_G4_CLK_DIVIDER, + }, + { + .cfg_value = 0xff, + .reg_offset = UFS_PHY_OMC_STATUS_RDVAL, + }, + { + .cfg_value = 0x1f, + .reg_offset = UFS_PHY_LINE_RESET_TIME, + }, + { + .cfg_value = 0x00, + .reg_offset = UFS_PHY_LINE_RESET_GRANULARITY, + }, + { + .cfg_value = 0x03, + .reg_offset = UFS_PHY_TSYNC_RSYNC_CNTL, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_PLL_CNTL, + }, + { + .cfg_value = 0x0f, + .reg_offset = UFS_PHY_TX_LARGE_AMP_DRV_LVL, + }, + { + .cfg_value = 0x1a, + .reg_offset = UFS_PHY_TX_SMALL_AMP_DRV_LVL, + }, + { + .cfg_value = 0x00, + .reg_offset = UFS_PHY_TX_LARGE_AMP_POST_EMP_LVL, + }, + { + .cfg_value = 0x00, + .reg_offset = UFS_PHY_TX_SMALL_AMP_POST_EMP_LVL, + }, + { + .cfg_value = 0x09, + .reg_offset = UFS_PHY_CFG_CHANGE_CNT_VAL, + }, + { + .cfg_value = 0x30, + .reg_offset = UFS_PHY_RX_SYNC_WAIT_TIME, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_TX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY, + }, + { + .cfg_value = 0x08, + .reg_offset = UFS_PHY_RX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_TX_MIN_STALL_NOCONFIG_TIME_CAPABILITY, + }, + { + .cfg_value = 0x0f, + .reg_offset = UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAPABILITY, + }, + { + .cfg_value = 0x04, + .reg_offset = UFS_PHY_TX_MIN_SAVE_CONFIG_TIME_CAPABILITY, + }, + { + .cfg_value = 0xc8, + .reg_offset = UFS_PHY_RX_MIN_SAVE_CONFIG_TIME_CAPABILITY, + }, + { + .cfg_value = 0x10, + .reg_offset = UFS_PHY_RX_PWM_BURST_CLOSURE_LENGTH_CAPABILITY, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_RX_MIN_ACTIVATETIME_CAPABILITY, + }, + { + .cfg_value = 0x1f, + .reg_offset = QSERDES_RX_RX_EQ_GAIN1(0), + }, + { + .cfg_value = 0x17, + .reg_offset = QSERDES_RX_RX_EQ_GAIN2(0), + }, + { + .cfg_value = 0x1f, + .reg_offset = QSERDES_RX_RX_EQ_GAIN1(1), + }, + { + .cfg_value = 0x17, + .reg_offset = QSERDES_RX_RX_EQ_GAIN2(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_CDR_CONTROL3(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_CDR_CONTROL3(1), + }, + { + .cfg_value = 0x07, + .reg_offset = QSERDES_COM_PLL_IP_SETI, + }, + { + .cfg_value = 0x0f, + .reg_offset = QSERDES_COM_PLL_CP_SETI, + }, + { + .cfg_value = 0x07, + .reg_offset = QSERDES_COM_PLL_IP_SETP, + }, + { + .cfg_value = 0x01, + .reg_offset = QSERDES_COM_PLL_CP_SETP, + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_COM_RES_TRIM_OFFSET, + }, + { + .cfg_value = 0x0f, + .reg_offset = QSERDES_COM_BGTC, + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_COM_PLL_AMP_OS, + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_TX_DRV_LVL(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_TX_DRV_LVL(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_BIST_MODE_LANENO(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_BIST_MODE_LANENO(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_TX_EMP_POST1_LVL(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_TX_EMP_POST1_LVL(1), + }, + { + .cfg_value = 0x05, + .reg_offset = QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_EN(0), + }, + { + .cfg_value = 0x05, + .reg_offset = QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_EN(1), + }, + { + .cfg_value = 0x07, + .reg_offset = UFS_PHY_TIMER_100US_SYSCLK_STEPS_MSB, + }, + { + .cfg_value = 0x80, + .reg_offset = UFS_PHY_TIMER_100US_SYSCLK_STEPS_LSB, + }, + { + .cfg_value = 0x27, + .reg_offset = UFS_PHY_TIMER_20US_CORECLK_STEPS_MSB, + }, + { + .cfg_value = 0x00, + .reg_offset = UFS_PHY_TIMER_20US_CORECLK_STEPS_LSB, + }, + { + .cfg_value = 0x00, + .reg_offset = UFS_PHY_CONTROLSYM_ONE_HOT_DISABLE, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_RETIME_BUFFER_EN, + }, + { + .cfg_value = 0x03, + .reg_offset = UFS_PHY_TX_HSGEAR_CAPABILITY, + }, + { + .cfg_value = 0x04, + .reg_offset = UFS_PHY_TX_PWMGEAR_CAPABILITY, + }, + { + .cfg_value = 0x03, + .reg_offset = UFS_PHY_TX_AMPLITUDE_CAPABILITY, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_TX_EXTERNALSYNC_CAPABILITY, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_TX_HS_UNTERMINATED_LINE_DRIVE_CAPABILITY, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_TX_LS_TERMINATED_LINE_DRIVE_CAPABILITY, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_TX_REF_CLOCK_SHARED_CAPABILITY, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_TX_HIBERN8TIME_CAPABILITY, + }, + { + .cfg_value = 0x03, + .reg_offset = UFS_PHY_RX_HSGEAR_CAPABILITY, + }, + { + .cfg_value = 0x04, + .reg_offset = UFS_PHY_RX_PWMGEAR_CAPABILITY, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_RX_HS_UNTERMINATED_CAPABILITY, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_RX_LS_TERMINATED_CAPABILITY, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_RX_REF_CLOCK_SHARED_CAPABILITY, + }, + { + .cfg_value = 0x48, + .reg_offset = UFS_PHY_RX_HS_G1_SYNC_LENGTH_CAPABILITY, + }, + { + .cfg_value = 0x0f, + .reg_offset = UFS_PHY_RX_HS_G1_PREPARE_LENGTH_CAPABILITY, + }, + { + .cfg_value = 0x0a, + .reg_offset = UFS_PHY_RX_LS_PREPARE_LENGTH_CAPABILITY, + }, + { + .cfg_value = 0x01, + .reg_offset = UFS_PHY_RX_HIBERN8TIME_CAPABILITY, + }, + { + .cfg_value = 0x48, + .reg_offset = UFS_PHY_RX_HS_G2_SYNC_LENGTH_CAPABILITY, + }, + { + .cfg_value = 0x48, + .reg_offset = UFS_PHY_RX_HS_G3_SYNC_LENGTH_CAPABILITY, + }, + { + .cfg_value = 0x0f, + .reg_offset = UFS_PHY_RX_HS_G2_PREPARE_LENGTH_CAPABILITY, + }, + { + .cfg_value = 0x0f, + .reg_offset = UFS_PHY_RX_HS_G3_PREPARE_LENGTH_CAPABILITY, + }, + { + .cfg_value = 0x09, + .reg_offset = QSERDES_TX_CLKBUF_ENABLE(0), + }, + { + .cfg_value = 0x01, + .reg_offset = QSERDES_TX_RESET_TSYNC_EN(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_RES_CODE(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_SERDES_BYP_EN_OUT(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_REC_DETECT_LVL(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_TRAN_DRVR_EMP_EN(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_AUX_CONTROL(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_AUX_DATA_TCODE(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_RCLK_AUXDATA_SEL(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_EQ_CONTROL(0), + }, + { + .cfg_value = 0x51, + .reg_offset = QSERDES_RX_RX_IQ_RXDET_EN(0), + }, + { + .cfg_value = 0x05, + .reg_offset = QSERDES_RX_RX_TERM_HIGHZ_CM_AC_COUPLE(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_CDR_FREEZE_UP_DN(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_UFS_CNTRL(0), + }, + { + .cfg_value = 0x22, + .reg_offset = QSERDES_RX_CDR_CONTROL_EIGHTH(0), + }, + { + .cfg_value = 0x0a, + .reg_offset = QSERDES_RX_UCDR_FO_GAIN(0), + }, + { + .cfg_value = 0x06, + .reg_offset = QSERDES_RX_UCDR_SO_GAIN(0), + }, + { + .cfg_value = 0x35, + .reg_offset = QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE(0), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_UCDR_FO_TO_SO_DELAY(0), + }, + { + .cfg_value = 0x09, + .reg_offset = QSERDES_TX_CLKBUF_ENABLE(1), + }, + { + .cfg_value = 0x01, + .reg_offset = QSERDES_TX_RESET_TSYNC_EN(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_RES_CODE(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_SERDES_BYP_EN_OUT(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_REC_DETECT_LVL(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_TX_TRAN_DRVR_EMP_EN(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_AUX_CONTROL(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_AUX_DATA_TCODE(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_RCLK_AUXDATA_SEL(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_EQ_CONTROL(1), + }, + { + .cfg_value = 0x51, + .reg_offset = QSERDES_RX_RX_IQ_RXDET_EN(1), + }, + { + .cfg_value = 0x05, + .reg_offset = QSERDES_RX_RX_TERM_HIGHZ_CM_AC_COUPLE(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_CDR_FREEZE_UP_DN(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_UFS_CNTRL(1), + }, + { + .cfg_value = 0x22, + .reg_offset = QSERDES_RX_CDR_CONTROL_EIGHTH(1), + }, + { + .cfg_value = 0x0a, + .reg_offset = QSERDES_RX_UCDR_FO_GAIN(1), + }, + { + .cfg_value = 0x06, + .reg_offset = QSERDES_RX_UCDR_SO_GAIN(1), + }, + { + .cfg_value = 0x35, + .reg_offset = QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_RX_UCDR_FO_TO_SO_DELAY(1), + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_COM_CMN_MODE, + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_COM_IE_TRIM, + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_COM_IP_TRIM, + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_COM_CORE_CLK_IN_SYNC_SEL, + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_COM_BIAS_EN_CLKBUFLR_EN, + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_COM_PLL_TEST_UPDN_RESTRIMSTEP, + }, + { + .cfg_value = 0x00, + .reg_offset = QSERDES_COM_FAUX_EN, + }, + { + .cfg_value = 0x08, + .reg_offset = QSERDES_TX_LANE_MODE(0), + }, + { + .cfg_value = 0x08, + .reg_offset = QSERDES_TX_LANE_MODE(1), + }, +}; + static struct msm_ufs_phy_calibration phy_cal_table_rate_B[] = { { .cfg_value = 0x03, @@ -897,11 +1512,43 @@ out: return ret; } -static void msm_ufs_phy_calibrate(struct msm_ufs_phy *phy) +#define UFS_HW_VER_MAJOR_SHFT (28) +#define UFS_HW_VER_MAJOR_MASK (0x000F << UFS_HW_VER_MAJOR_SHFT) +#define UFS_HW_VER_MINOR_SHFT (16) +#define UFS_HW_VER_MINOR_MASK (0x0FFF << UFS_HW_VER_MINOR_SHFT) +#define UFS_HW_VER_STEP_SHFT (0) +#define UFS_HW_VER_STEP_MASK (0xFFFF << UFS_HW_VER_STEP_SHFT) + +static inline void +msm_ufs_get_controller_revision(struct ufs_hba *hba, + u8 *major, u16 *minor, u16 *step) { - struct msm_ufs_phy_calibration *tbl = phy_cal_table_rate_A; - int tbl_size = ARRAY_SIZE(phy_cal_table_rate_A); + u32 ver = ufshcd_readl(hba, REG_UFS_HW_VERSION); + + *major = (ver & UFS_HW_VER_MAJOR_MASK) >> UFS_HW_VER_MAJOR_SHFT; + *minor = (ver & UFS_HW_VER_MINOR_MASK) >> UFS_HW_VER_MINOR_SHFT; + *step = (ver & UFS_HW_VER_STEP_MASK) >> UFS_HW_VER_STEP_SHFT; +} + +static void msm_ufs_phy_calibrate(struct ufs_hba *hba) +{ + struct msm_ufs_host *host = hba->priv; + struct msm_ufs_phy *phy = host->phy; + struct msm_ufs_phy_calibration *tbl; + int tbl_size; int i; + u8 major; + u16 minor, step; + + msm_ufs_get_controller_revision(hba, &major, &minor, &step); + + if ((major == 0x1) && (minor == 0x001) && (step == 0x0000)) { + tbl_size = ARRAY_SIZE(phy_cal_table_ctrl_1_1_0_rate_A); + tbl = phy_cal_table_ctrl_1_1_0_rate_A; + } else if ((major == 0x1) && (minor == 0x001) && (step == 0x0001)) { + tbl_size = ARRAY_SIZE(phy_cal_table_ctrl_1_1_1_rate_A); + tbl = phy_cal_table_ctrl_1_1_1_rate_A; + } for (i = 0; i < tbl_size; i++) writel_relaxed(tbl[i].cfg_value, phy->mmio + tbl[i].reg_offset); @@ -1168,7 +1815,7 @@ static int msm_ufs_hce_enable_notify(struct ufs_hba *hba, bool status) /* provide 1ms delay to let the reset pulse propagate */ usleep_range(1000, 1100); - msm_ufs_phy_calibrate(phy); + msm_ufs_phy_calibrate(hba); /* De-assert PHY reset and start serdes */ msm_ufs_deassert_reset(hba); @@ -1631,13 +2278,6 @@ out: return ret; } -#define UFS_HW_VER_MAJOR_SHFT (28) -#define UFS_HW_VER_MAJOR_MASK (0x000F << UFS_HW_VER_MAJOR_SHFT) -#define UFS_HW_VER_MINOR_SHFT (16) -#define UFS_HW_VER_MINOR_MASK (0x0FFF << UFS_HW_VER_MINOR_SHFT) -#define UFS_HW_VER_STEP_SHFT (0) -#define UFS_HW_VER_STEP_MASK (0xFFFF << UFS_HW_VER_STEP_SHFT) - /** * msm_ufs_advertise_quirks - advertise the known MSM UFS controller quirks * @hba: host controller instance @@ -1649,13 +2289,10 @@ out: */ static void msm_ufs_advertise_quirks(struct ufs_hba *hba) { - u32 ver = ufshcd_readl(hba, REG_UFS_HW_VERSION); u8 major; u16 minor, step; - major = (ver & UFS_HW_VER_MAJOR_MASK) >> UFS_HW_VER_MAJOR_SHFT; - minor = (ver & UFS_HW_VER_MINOR_MASK) >> UFS_HW_VER_MINOR_SHFT; - step = (ver & UFS_HW_VER_STEP_MASK) >> UFS_HW_VER_STEP_SHFT; + msm_ufs_get_controller_revision(hba, &major, &minor, &step); /* * Interrupt aggregation and HIBERN8 on UFS HW controller revision 1.1.0 @@ -1668,12 +2305,14 @@ static void msm_ufs_advertise_quirks(struct ufs_hba *hba) | UFSHCD_QUIRK_BROKEN_CAP_64_BIT_0 | UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS | UFSHCD_QUIRK_BROKEN_2_TX_LANES - | UFSHCD_QUIRK_BROKEN_SUSPEND); + | UFSHCD_QUIRK_BROKEN_SUSPEND + | UFSHCD_BROKEN_LCC); else if ((major == 0x1) && (minor == 0x001) && (step == 0x0001)) hba->quirks |= (UFSHCD_QUIRK_BROKEN_HIBERN8 | UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS | UFSHCD_QUIRK_BROKEN_INTR_AGGR - | UFSHCD_QUIRK_BROKEN_SUSPEND); + | UFSHCD_QUIRK_BROKEN_SUSPEND + | UFSHCD_BROKEN_LCC); } static int msm_ufs_get_bus_vote(struct msm_ufs_host *host, @@ -1961,8 +2600,6 @@ static int msm_ufs_init(struct ufs_hba *hba) hba->spm_lvl = UFS_PM_LVL_3; } - hba->caps |= UFSHCD_CAP_CLK_GATING | - UFSHCD_CAP_HIBERN8_WITH_CLK_GATING; msm_ufs_setup_clocks(hba, true); goto out; diff --git a/drivers/scsi/ufs/ufs_test.c b/drivers/scsi/ufs/ufs_test.c index c764087aa34..339dbefc5c7 100644 --- a/drivers/scsi/ufs/ufs_test.c +++ b/drivers/scsi/ufs/ufs_test.c @@ -39,6 +39,7 @@ #define MAX_PARALLEL_QUERIES 33 #define RANDOM_REQUEST_THREADS 4 #define LUN_DEPTH_TEST_SIZE 9 +#define SECTOR_SIZE 512 /* the amount of requests that will be inserted */ #define LONG_SEQ_TEST_NUM_REQS 256 @@ -941,11 +942,7 @@ static int run_long_test(struct test_data *td) direction = WRITE; } - /* NUM_OF_BLOCK * (BLOCK_SIZE / SECTOR_SIZE) */ - seq_sector_delta = num_bios_per_request * (PAGE_SIZE / - td->req_q->limits.logical_block_size); - /* just for the first iteration */ - sector -= seq_sector_delta; + seq_sector_delta = num_bios_per_request * (TEST_BIO_SIZE / SECTOR_SIZE); seed = utd->random_test_seed ? utd->random_test_seed : MAGIC_SEED; @@ -969,7 +966,9 @@ static int run_long_test(struct test_data *td) case UFS_TEST_LONG_SEQUENTIAL_READ: case UFS_TEST_LONG_SEQUENTIAL_WRITE: case UFS_TEST_LONG_SEQUENTIAL_MIXED: - sector += seq_sector_delta; + /* don't need to increment on the first iteration */ + if (inserted_requests) + sector += seq_sector_delta; break; case UFS_TEST_LONG_RANDOM_READ: case UFS_TEST_LONG_RANDOM_WRITE: diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index e61c6c2b3c3..f48711a0073 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2872,14 +2872,40 @@ static int ufshcd_link_startup(struct ufs_hba *hba) goto out; } else if (hba->quirks & UFSHCD_BROKEN_LCC) { int hc_tx_lanes; + int device_tx_lanes; int i; + int err; + /* + * Disabling the TX_LCC_ENABLE in the Host and in the Device. + * As disabling operation is done for each lane, the number of + * TX Connected Lanes should be read seperately from host and + * from Device and then, apply the disable command on every + * lane, on both, Host and Device + */ ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), &hc_tx_lanes); - for (i = 0; i < hc_tx_lanes; ++i) - ufshcd_dme_set(hba, + ufshcd_dme_peer_get(hba, + UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), + &device_tx_lanes); + + for (i = 0; i < hc_tx_lanes; ++i) { + err = ufshcd_dme_set(hba, + UIC_ARG_MIB_SEL(TX_LCC_ENABLE, i), 0); + if (err) + dev_err(hba->dev, "%s: Disable TX_LCC_ENABLE (Host) failed, lane = %d, err = %d", + __func__, i, err); + } + + for (i = 0; i < device_tx_lanes; ++i) { + err = ufshcd_dme_peer_set(hba, UIC_ARG_MIB_SEL(TX_LCC_ENABLE, i), 0); + if (err) + dev_err(hba->dev, "%s: Disable TX_LCC_ENABLE (Device) failed, lane = %d, err = %d", + __func__, i, err); + } + } /* Include any host controller configuration via UIC commands */ @@ -3778,6 +3804,8 @@ static void ufshcd_check_errors(struct ufs_hba *hba) bool pr_prdt = !!(hba->saved_err & SYSTEM_BUS_FATAL_ERROR); + dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x", + __func__, hba->errors, hba->uic_error); ufshcd_print_host_regs(hba); ufshcd_print_pwr_info(hba); ufshcd_print_tmrs(hba, hba->outstanding_tasks); @@ -6012,6 +6040,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) /* Hold auto suspend until async scan completes */ pm_runtime_get_sync(dev); + /* + * The device-initialize-sequence hasn't been invoked yet. + * Set the device to power-off state + */ + ufshcd_set_ufs_dev_poweroff(hba); + async_schedule(ufshcd_async_scan, hba); UFSDBG_ADD_DEBUGFS(hba) diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c index 07f0cf8fd6c..c9b5b07dcb7 100644 --- a/drivers/slimbus/slim-msm-ngd.c +++ b/drivers/slimbus/slim-msm-ngd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -304,8 +304,28 @@ static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn) * Messages related to data channel management can't * wait since they are holding reconfiguration lock. * clk_pause in resume (which can change state back to - * MSM_CTRL_AWAKE), will need that lock + * MSM_CTRL_AWAKE), will need that lock. + * Port disconnection, channel removal calls should pass + * through since there is no activity on the bus and + * those calls are triggered by clients due to + * device_down callback in that situation. + * Returning 0 on the disconnections and + * removals will ensure consistent state of channels, + * ports with the HW + * Remote requests to remove channel/port will be + * returned from the path where they wait on + * acknowledgement from ADSP */ + if ((txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER) && + ((mc == SLIM_USR_MC_CHAN_CTRL || + mc == SLIM_USR_MC_DISCONNECT_PORT || + mc == SLIM_USR_MC_RECONFIG_NOW))) + return -EREMOTEIO; + if ((txn->mt == SLIM_MSG_MT_CORE) && + ((mc == SLIM_MSG_MC_DISCONNECT_PORT || + mc == SLIM_MSG_MC_NEXT_REMOVE_CHANNEL || + mc == SLIM_USR_MC_RECONFIG_NOW))) + return 0; if ((txn->mt == SLIM_MSG_MT_CORE) && ((mc >= SLIM_MSG_MC_CONNECT_SOURCE && mc <= SLIM_MSG_MC_CHANGE_CONTENT) || @@ -314,11 +334,11 @@ static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn) return -EREMOTEIO; if ((txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER) && ((mc >= SLIM_USR_MC_DEFINE_CHAN && - mc <= SLIM_USR_MC_DISCONNECT_PORT))) + mc < SLIM_USR_MC_DISCONNECT_PORT))) return -EREMOTEIO; timeout = wait_for_completion_timeout(&dev->ctrl_up, HZ); - if (!timeout) + if (!timeout && dev->state == MSM_CTRL_DOWN) return -ETIMEDOUT; } ret = msm_slim_get_ctrl(dev); @@ -537,8 +557,10 @@ static int ngd_xferandwait_ack(struct slim_controller *ctrl, else ret = txn->ec; } + if (ret) { - pr_err("master msg:0x%x,tid:%d ret:%d", txn->mc, + if (ret != -EREMOTEIO || txn->mc != SLIM_USR_MC_CHAN_CTRL) + pr_err("master msg:0x%x,tid:%d ret:%d", txn->mc, txn->tid, ret); mutex_lock(&ctrl->m_ctrl); ctrl->txnt[txn->tid] = NULL; @@ -664,7 +686,10 @@ static int ngd_allocbw(struct slim_device *sb, int *subfrmc, int *clkgear) txn.mc = SLIM_USR_MC_CHAN_CTRL; txn.rl = txn.len + 4; ret = ngd_xferandwait_ack(ctrl, &txn); - if (ret) + /* HW restarting, channel removal should succeed */ + if (ret == -EREMOTEIO) + return 0; + else if (ret) return ret; txn.mc = SLIM_USR_MC_RECONFIG_NOW; @@ -1046,11 +1071,13 @@ static void ngd_laddr_lookup(struct work_struct *work) container_of(work, struct msm_slim_ctrl, slave_notify); struct slim_controller *ctrl = &dev->ctrl; struct slim_device *sbdev; + struct list_head *pos, *next; int i; slim_framer_booted(ctrl); mutex_lock(&ctrl->m_ctrl); - list_for_each_entry(sbdev, &ctrl->devs, dev_list) { + list_for_each_safe(pos, next, &ctrl->devs) { int ret = 0; + sbdev = list_entry(pos, struct slim_device, dev_list); mutex_unlock(&ctrl->m_ctrl); for (i = 0; i < LADDR_RETRY; i++) { ret = slim_get_logical_addr(sbdev, sbdev->e_addr, diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h index 5ffa3009c70..c8dbb0c6b50 100644 --- a/drivers/slimbus/slim-msm.h +++ b/drivers/slimbus/slim-msm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -15,8 +15,8 @@ #include <linux/irq.h> #include <linux/kthread.h> -#include <mach/msm_qmi_interface.h> -#include <mach/subsystem_notif.h> +#include <soc/qcom/msm_qmi_interface.h> +#include <soc/qcom/subsystem_notif.h> /* Per spec.max 40 bytes per received message */ #define SLIM_MSGQ_BUF_LEN 40 diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c index afefde164de..4d10ce0ea65 100644 --- a/drivers/slimbus/slimbus.c +++ b/drivers/slimbus/slimbus.c @@ -288,37 +288,27 @@ static struct device_type slim_dev_type = { static void slim_report(struct work_struct *work) { - u8 laddr; - int ret, i; struct slim_driver *sbdrv; struct slim_device *sbdev = container_of(work, struct slim_device, wd); - struct slim_controller *ctrl = sbdev->ctrl; if (!sbdev->dev.driver) return; /* check if device-up or down needs to be called */ - mutex_lock(&ctrl->m_ctrl); - /* address no longer valid, means device reported absent */ - for (i = 0; i < ctrl->num_dev; i++) { - if (sbdev->laddr == ctrl->addrt[i].laddr && - ctrl->addrt[i].valid == false && - sbdev->notified) - break; - } - mutex_unlock(&ctrl->m_ctrl); + if ((!sbdev->reported && !sbdev->notified) || + (sbdev->reported && sbdev->notified)) + return; + sbdrv = to_slim_driver(sbdev->dev.driver); - if (i < ctrl->num_dev) { + /* + * address no longer valid, means device reported absent, whereas + * address valid, means device reported present + */ + if (sbdev->notified && !sbdev->reported) { sbdev->notified = false; if (sbdrv->device_down) sbdrv->device_down(sbdev); - return; - } - if (sbdev->notified) - return; - ret = slim_get_logical_addr(sbdev, sbdev->e_addr, 6, &laddr); - if (!ret) { - if (sbdrv) - sbdev->notified = true; + } else if (!sbdev->notified && sbdev->reported) { + sbdev->notified = true; if (sbdrv->device_up) sbdrv->device_up(sbdev); } @@ -633,6 +623,7 @@ void slim_report_absent(struct slim_device *sbdev) ctrl->addrt[i].valid = false; } mutex_unlock(&ctrl->m_ctrl); + sbdev->reported = false; queue_work(ctrl->wq, &sbdev->wd); } EXPORT_SYMBOL(slim_report_absent); @@ -791,6 +782,8 @@ int slim_assign_laddr(struct slim_controller *ctrl, const u8 *e_addr, u8 i = 0; bool exists = false; struct slim_device *sbdev; + struct list_head *pos, *next; + mutex_lock(&ctrl->m_ctrl); /* already assigned */ if (ctrl_getlogical_addr(ctrl, e_addr, e_len, &i) == 0) { @@ -840,10 +833,12 @@ ret_assigned_laddr: pr_info("slimbus:%d laddr:0x%x, EAPC:0x%x:0x%x", ctrl->nr, *laddr, e_addr[1], e_addr[2]); mutex_lock(&ctrl->m_ctrl); - list_for_each_entry(sbdev, &ctrl->devs, dev_list) { + list_for_each_safe(pos, next, &ctrl->devs) { + sbdev = list_entry(pos, struct slim_device, dev_list); if (memcmp(sbdev->e_addr, e_addr, 6) == 0) { struct slim_driver *sbdrv; sbdev->laddr = *laddr; + sbdev->reported = true; if (sbdev->dev.driver) { sbdrv = to_slim_driver(sbdev->dev.driver); if (sbdrv->device_up) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index d4e674ed840..896cf99554d 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -22,6 +22,16 @@ config MSM_IPC_ROUTER_HSIC_XPRT registers the transport with IPC Router and enable message exchange. +config MSM_QMI_INTERFACE + depends on IPC_ROUTER + depends on QMI_ENCDEC + bool "MSM QMI Interface Library" + help + Library to send and receive QMI messages over IPC Router. + This library provides interface functions to the kernel drivers + to perform QMI message marshaling and transport them over IPC + Router. + config MSM_SMEM depends on REMOTE_SPINLOCK_MSM bool "MSM Shared Memory (SMEM)" @@ -30,6 +40,15 @@ config MSM_SMEM processors in the System on a Chip (SoC) which allows basic inter-processor communication. +config MSM_SMEM_LOGGING + depends on MSM_SMEM + bool "MSM Shared Memory Logger" + help + Enable the shared memory logging to log the events between + the various processors in the system. This option exposes + the shared memory logger at /dev/smem_log and a debugfs node + named smem_log. + config MSM_QDSP6_APRV2 bool "Audio QDSP6 APRv2 support" depends on MSM_SMD diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 9db826144a4..bf0a81af7c9 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -1,8 +1,14 @@ # When adding new entries keep the list in alphabetical order +CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) obj-y += qdsp6v2/ obj-$(CONFIG_MSM_IPC_ROUTER_HSIC_XPRT) += ipc_router_hsic_xprt.o obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o +obj-$(CONFIG_MSM_QMI_INTERFACE) += qmi_interface.o + +obj-$(CONFIG_MSM_SCM) += scm.o + obj-$(CONFIG_MSM_SMEM) += smem.o smem_debug.o +obj-$(CONFIG_MSM_SMEM_LOGGING) += smem_log.o obj-$(CONFIG_MEM_SHARE_QMI_SERVICE) += memshare/ diff --git a/drivers/soc/qcom/ipc_router_hsic_xprt.c b/drivers/soc/qcom/ipc_router_hsic_xprt.c index 8d2c8ab7d55..7f07f1970a1 100644 --- a/drivers/soc/qcom/ipc_router_hsic_xprt.c +++ b/drivers/soc/qcom/ipc_router_hsic_xprt.c @@ -23,9 +23,9 @@ #include <linux/skbuff.h> #include <linux/delay.h> #include <linux/sched.h> +#include <soc/qcom/subsystem_restart.h> #include <mach/ipc_bridge.h> -#include <mach/subsystem_restart.h> static int msm_ipc_router_hsic_xprt_debug_mask; module_param_named(debug_mask, msm_ipc_router_hsic_xprt_debug_mask, diff --git a/drivers/soc/qcom/ipc_router_smd_xprt.c b/drivers/soc/qcom/ipc_router_smd_xprt.c index 39043452f63..1cbd49bd5a4 100644 --- a/drivers/soc/qcom/ipc_router_smd_xprt.c +++ b/drivers/soc/qcom/ipc_router_smd_xprt.c @@ -23,9 +23,9 @@ #include <linux/skbuff.h> #include <linux/delay.h> #include <linux/sched.h> +#include <soc/qcom/subsystem_restart.h> #include <mach/msm_smd.h> -#include <mach/subsystem_restart.h> #include <mach/msm_smsm.h> static int msm_ipc_router_smd_xprt_debug_mask; diff --git a/drivers/soc/qcom/memshare/heap_mem_ext_v01.c b/drivers/soc/qcom/memshare/heap_mem_ext_v01.c index 3f9fe995fc8..b4c88a2df43 100644 --- a/drivers/soc/qcom/memshare/heap_mem_ext_v01.c +++ b/drivers/soc/qcom/memshare/heap_mem_ext_v01.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -12,7 +12,7 @@ */ #include <linux/qmi_encdec.h> -#include <mach/msm_qmi_interface.h> +#include <soc/qcom/msm_qmi_interface.h> #include "heap_mem_ext_v01.h" struct elem_info mem_alloc_req_msg_data_v01_ei[] = { diff --git a/drivers/soc/qcom/memshare/heap_mem_ext_v01.h b/drivers/soc/qcom/memshare/heap_mem_ext_v01.h index bc2a8cd69b9..288679712d7 100644 --- a/drivers/soc/qcom/memshare/heap_mem_ext_v01.h +++ b/drivers/soc/qcom/memshare/heap_mem_ext_v01.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, 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 @@ -14,7 +14,7 @@ #ifndef HEAP_MEM_EXT_SERVICE_01_H #define HEAP_MEM_EXT_SERVICE_01_H -#include <mach/msm_qmi_interface.h> +#include <soc/qcom/msm_qmi_interface.h> #define MEM_ALLOC_REQ_MAX_MSG_LEN_V01 255 #define MEM_FREE_REQ_MAX_MSG_LEN_V01 255 diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c index dec928fa5e2..3fd320e0fe7 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.c +++ b/drivers/soc/qcom/memshare/msm_memshare.c @@ -15,8 +15,8 @@ #include <linux/module.h> #include <linux/dma-mapping.h> #include <linux/mutex.h> -#include <mach/scm.h> -#include <mach/msm_qmi_interface.h> +#include <soc/qcom/msm_qmi_interface.h> +#include <soc/qcom/scm.h> #include "msm_memshare.h" #include "heap_mem_ext_v01.h" #define MEM_SHARE_SERVICE_SVC_ID 0x00000034 diff --git a/drivers/soc/qcom/qdsp6v2/adsp-loader.c b/drivers/soc/qcom/qdsp6v2/adsp-loader.c index d2a46319435..1762508cdb7 100644 --- a/drivers/soc/qcom/qdsp6v2/adsp-loader.c +++ b/drivers/soc/qcom/qdsp6v2/adsp-loader.c @@ -17,10 +17,10 @@ #include <linux/err.h> #include <linux/delay.h> #include <linux/platform_device.h> -#include <mach/subsystem_restart.h> #include <linux/qdsp6v2/apr.h> #include <linux/of_device.h> #include <linux/sysfs.h> +#include <soc/qcom/subsystem_restart.h> #define Q6_PIL_GET_DELAY_MS 100 #define BOOT_CMD 1 diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c index c3dd3d36709..d7d9448b0c4 100644 --- a/drivers/soc/qcom/qdsp6v2/apr.c +++ b/drivers/soc/qcom/qdsp6v2/apr.c @@ -26,14 +26,13 @@ #include <linux/sysfs.h> #include <linux/device.h> #include <linux/slab.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/subsystem_notif.h> #include <sound/apr_audio-v2.h> -#include <mach/subsystem_restart.h> #include <mach/msm_smd.h> #include <linux/qdsp6v2/apr.h> #include <linux/qdsp6v2/apr_tal.h> #include <linux/qdsp6v2/dsp_debug.h> -#include <mach/subsystem_notif.h> -#include <mach/subsystem_restart.h> static struct apr_q6 q6; static struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX]; diff --git a/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c index c63cc62c0e2..c513b150d4d 100644 --- a/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c +++ b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c @@ -17,10 +17,10 @@ #include <linux/err.h> #include <linux/delay.h> #include <linux/platform_device.h> -#include <mach/subsystem_restart.h> #include <linux/qdsp6v2/apr.h> #include <linux/of_device.h> #include <linux/msm_audio_ion.h> +#include <soc/qcom/subsystem_restart.h> #include <linux/iommu.h> #include <linux/msm_iommu_domains.h> diff --git a/arch/arm/mach-msm/msm_qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index 180e0e8fba5..59e5299e212 100644 --- a/arch/arm/mach-msm/msm_qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -30,9 +30,9 @@ #include <linux/hashtable.h> #include <linux/ipc_router.h> -#include <mach/msm_qmi_interface.h> +#include <soc/qcom/msm_qmi_interface.h> -#include "msm_qmi_interface_priv.h" +#include "qmi_interface_priv.h" #define BUILD_INSTANCE_ID(vers, ins) (((vers) & 0xFF) | (((ins) & 0xFF) << 8)) #define LOOKUP_MASK 0xFFFFFFFF diff --git a/arch/arm/mach-msm/msm_qmi_interface_priv.h b/drivers/soc/qcom/qmi_interface_priv.h index 11c0a247c32..b7dd905e4c3 100644 --- a/arch/arm/mach-msm/msm_qmi_interface_priv.h +++ b/drivers/soc/qcom/qmi_interface_priv.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,8 +10,8 @@ * GNU General Public License for more details. */ -#ifndef _MSM_QMI_INTERFACE_PRIV_H_ -#define _MSM_QMI_INTERFACE_PRIV_H_ +#ifndef _QMI_INTERFACE_PRIV_H_ +#define _QMI_INTERFACE_PRIV_H_ #include <linux/types.h> #include <linux/errno.h> @@ -22,7 +22,7 @@ #include <linux/platform_device.h> #include <linux/qmi_encdec.h> -#include <mach/msm_qmi_interface.h> +#include <soc/qcom/msm_qmi_interface.h> enum txn_type { QMI_SYNC_TXN = 1, diff --git a/arch/arm/mach-msm/scm.c b/drivers/soc/qcom/scm.c index 601c42c96ca..45d15a075b2 100644 --- a/arch/arm/mach-msm/scm.c +++ b/drivers/soc/qcom/scm.c @@ -17,10 +17,10 @@ #include <linux/errno.h> #include <linux/err.h> #include <linux/init.h> +#include <soc/qcom/scm.h> #include <asm/cacheflush.h> -#include <mach/scm.h> #define SCM_ENOMEM -5 #define SCM_EOPNOTSUPP -4 diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 077421ef971..9e59252bd5f 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -23,11 +23,11 @@ #include <linux/printk.h> #include <linux/slab.h> #include <linux/stat.h> +#include <soc/qcom/subsystem_notif.h> +#include <soc/qcom/ramdump.h> #include <soc/qcom/smem.h> -#include <mach/ramdump.h> -#include <mach/subsystem_notif.h> #include "smem_private.h" @@ -92,6 +92,7 @@ static DEFINE_SPINLOCK(smem_init_check_lock); static int smem_module_inited; static RAW_NOTIFIER_HEAD(smem_module_init_notifier_list); static DEFINE_MUTEX(smem_module_init_notifier_lock); +static bool probe_done; /* smem security feature components */ #define SMEM_TOC_IDENTIFIER 0x434f5424 /* "$TOC" */ @@ -181,6 +182,19 @@ static struct restart_notifier_block restart_notifiers[] = { static int init_smem_remote_spinlock(void); /** + * is_probe_done() - Did the probe function successfully complete + * + * @return - true if probe successfully completed, false if otherwise + * + * Helper function for EPROBE_DEFER support. If this function returns false, + * the calling function should immediately return -EPROBE_DEFER. + */ +static bool is_probe_done(void) +{ + return probe_done; +} + +/** * smem_phys_to_virt() - Convert a physical base and offset to virtual address * * @base: physical base address to check @@ -255,7 +269,10 @@ static void *smem_phys_to_virt(phys_addr_t base, unsigned offset) * @returns: Physical address (or NULL if there is a failure) * * This function should only be used if an SMEM item needs to be handed - * off to a DMA engine. + * off to a DMA engine. This function will not return a version of EPROBE_DEFER + * if the driver is not ready since the caller should obtain @smem_address from + * one of the other public APIs and get EPROBE_DEFER at that time, if + * applicable. */ phys_addr_t smem_virt_to_phys(void *smem_address) { @@ -485,7 +502,8 @@ static void *__smem_find(unsigned id, unsigned size_in, bool skip_init_check) * @size_in: Size of the SMEM item * @to_proc: SMEM host that shares the item with apps * @flags: Item attribute flags - * @returns: Pointer to SMEM item or NULL if it doesn't exist + * @returns: Pointer to SMEM item, NULL if it doesn't exist, or -EPROBE_DEFER + * if the driver is not ready */ void *smem_find(unsigned id, unsigned size_in, unsigned to_proc, unsigned flags) { @@ -495,6 +513,9 @@ void *smem_find(unsigned id, unsigned size_in, unsigned to_proc, unsigned flags) SMEM_DBG("%s(%u, %u, %u, %u)\n", __func__, id, size_in, to_proc, flags); + if (!is_probe_done()) + return ERR_PTR(-EPROBE_DEFER); + ptr = smem_get_entry(id, &size, to_proc, flags); if (!ptr) return 0; @@ -668,7 +689,8 @@ static void *alloc_item_secure(unsigned id, unsigned size_in, unsigned to_proc, * @size_in: Size of the SMEM item * @to_proc: SMEM host that shares the item with apps * @flags: Item attribute flags - * @returns: Pointer to SMEM item or NULL if it couldn't be found/allocated + * @returns: Pointer to SMEM item, NULL if it couldn't be found/allocated, + * or -EPROBE_DEFER if the driver is not ready */ void *smem_alloc(unsigned id, unsigned size_in, unsigned to_proc, unsigned flags) @@ -682,6 +704,9 @@ void *smem_alloc(unsigned id, unsigned size_in, unsigned to_proc, SMEM_DBG("%s(%u, %u, %u, %u)\n", __func__, id, size_in, to_proc, flags); + if (!is_probe_done()) + return ERR_PTR(-EPROBE_DEFER); + if (!smem_initialized_check()) return NULL; @@ -748,13 +773,17 @@ EXPORT_SYMBOL(smem_alloc); * @size: Pointer to size variable for storing the result * @to_proc: SMEM host that shares the item with apps * @flags: Item attribute flags - * @returns: Pointer to SMEM item or NULL if it doesn't exist + * @returns: Pointer to SMEM item, NULL if it doesn't exist, or -EPROBE_DEFER + * if the driver isn't ready */ void *smem_get_entry(unsigned id, unsigned *size, unsigned to_proc, unsigned flags) { SMEM_DBG("%s(%u, %u, %u, %u)\n", __func__, id, *size, to_proc, flags); + if (!is_probe_done()) + return ERR_PTR(-EPROBE_DEFER); + return __smem_get_entry_secure(id, size, to_proc, flags, false, true); } EXPORT_SYMBOL(smem_get_entry); @@ -766,7 +795,8 @@ EXPORT_SYMBOL(smem_get_entry); * @size_out: Pointer to size variable for storing the result * @to_proc: SMEM host that shares the item with apps * @flags: Item attribute flags - * @returns: Pointer to SMEM item or NULL if it doesn't exist + * @returns: Pointer to SMEM item, NULL if it doesn't exist, or -EPROBE_DEFER + * if the driver isn't ready * * This function does not lock the remote spinlock and should only be used in * failure-recover cases such as retrieving the subsystem failure reason during @@ -775,6 +805,9 @@ EXPORT_SYMBOL(smem_get_entry); void *smem_get_entry_no_rlock(unsigned id, unsigned *size_out, unsigned to_proc, unsigned flags) { + if (!is_probe_done()) + return ERR_PTR(-EPROBE_DEFER); + return __smem_get_entry_secure(id, size_out, to_proc, flags, false, false); } @@ -1384,6 +1417,8 @@ smem_targ_info_done: smem_init_security(); } + probe_done = true; + ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); if (ret) LOG_ERR("%s: of_platform_populate failed %d\n", __func__, ret); @@ -1442,4 +1477,4 @@ int __init msm_smem_init(void) return 0; } -module_init(msm_smem_init); +arch_initcall(msm_smem_init); diff --git a/arch/arm/mach-msm/smem_log.c b/drivers/soc/qcom/smem_log.c index a62fb3265eb..95bf570e7c8 100644 --- a/arch/arm/mach-msm/smem_log.c +++ b/drivers/soc/qcom/smem_log.c @@ -30,13 +30,12 @@ #include <linux/wait.h> #include <linux/delay.h> -#include <mach/smem_log.h> - #include <soc/qcom/smem.h> +#include <soc/qcom/smem_log.h> #include <asm/arch_timer.h> -#include "../../../drivers/soc/qcom/smem_private.h" +#include "smem_private.h" #define DEBUG #undef DEBUG diff --git a/drivers/soc/qcom/smem_private.h b/drivers/soc/qcom/smem_private.h index 02e2f0e77c1..7aeca5eed8d 100644 --- a/drivers/soc/qcom/smem_private.h +++ b/drivers/soc/qcom/smem_private.h @@ -14,8 +14,8 @@ #define _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_ #include <linux/remote_spinlock.h> +#include <soc/qcom/ramdump.h> -#include <mach/ramdump.h> #define SMD_HEAP_SIZE 512 diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 2df23ea8f06..2013d65cf14 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -116,6 +116,8 @@ config SW_SYNC_USER *WARNING* improper use of this can result in deadlocking kernel drivers from userspace. +source "drivers/staging/android/ion/Kconfig" + endif # if ANDROID endmenu diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index c136299e05a..0a01e191490 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -1,5 +1,7 @@ ccflags-y += -I$(src) # needed for trace events +obj-y += ion/ + obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o obj-$(CONFIG_ASHMEM) += ashmem.o obj-$(CONFIG_ANDROID_LOGGER) += logger.o diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig new file mode 100644 index 00000000000..713c496e8c0 --- /dev/null +++ b/drivers/staging/android/ion/Kconfig @@ -0,0 +1,29 @@ +menuconfig ION + bool "Ion Memory Manager" + select GENERIC_ALLOCATOR + select DMA_SHARED_BUFFER + ---help--- + Chose this option to enable the ION Memory Manager, + used by Android to efficiently allocate buffers + from userspace that can be shared between drivers. + If you're not using Android its probably safe to + say N here. + +config ION_TEST + tristate "Ion Test Device" + depends on ION + help + Choose this option to create a device that can be used to test the + kernel and device side ION functions. + +config ION_TEGRA + tristate "Ion for Tegra" + depends on ARCH_TEGRA && ION + help + Choose this option if you wish to use ion on an nVidia Tegra. + +config ION_MSM + tristate "Ion for MSM" + depends on ARCH_MSM && ION + help + Choose this option if you wish to use ion on an MSM target. diff --git a/drivers/gpu/ion/Makefile b/drivers/staging/android/ion/Makefile index 108abe67b45..c3c2144d0d7 100644 --- a/drivers/gpu/ion/Makefile +++ b/drivers/staging/android/ion/Makefile @@ -1,5 +1,9 @@ obj-$(CONFIG_ION) += ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \ ion_carveout_heap.o ion_chunk_heap.o obj-$(CONFIG_CMA) += ion_cma_heap.o ion_cma_secure_heap.o +obj-$(CONFIG_ION_TEST) += ion_test.o +ifdef CONFIG_COMPAT +obj-$(CONFIG_ION) += compat_ion.o +endif obj-$(CONFIG_ION_TEGRA) += tegra/ -obj-$(CONFIG_ION_MSM) += ion_cp_heap.o ion_removed_heap.o msm/ +obj-$(CONFIG_ION_MSM) += ion_removed_heap.o msm/ diff --git a/drivers/staging/android/ion/compat_ion.c b/drivers/staging/android/ion/compat_ion.c new file mode 100644 index 00000000000..e9a8132cd56 --- /dev/null +++ b/drivers/staging/android/ion/compat_ion.c @@ -0,0 +1,177 @@ +/* + * drivers/gpu/ion/compat_ion.c + * + * Copyright (C) 2013 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. + * + */ + +#include <linux/compat.h> +#include <linux/fs.h> +#include <linux/uaccess.h> + +#include "ion.h" +#include "compat_ion.h" + +/* See drivers/staging/android/uapi/ion.h for the definition of these structs */ +struct compat_ion_allocation_data { + compat_size_t len; + compat_size_t align; + compat_uint_t heap_id_mask; + compat_uint_t flags; + compat_int_t handle; +}; + +struct compat_ion_custom_data { + compat_uint_t cmd; + compat_ulong_t arg; +}; + +#define COMPAT_ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ + struct compat_ion_allocation_data) +#define COMPAT_ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data) +#define COMPAT_ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, \ + struct compat_ion_custom_data) + +static int compat_get_ion_allocation_data( + struct compat_ion_allocation_data __user *data32, + struct ion_allocation_data __user *data) +{ + compat_size_t s; + compat_uint_t u; + compat_int_t i; + int err; + + err = get_user(s, &data32->len); + err |= put_user(s, &data->len); + err |= get_user(s, &data32->align); + err |= put_user(s, &data->align); + err |= get_user(u, &data32->heap_id_mask); + err |= put_user(u, &data->heap_id_mask); + err |= get_user(u, &data32->flags); + err |= put_user(u, &data->flags); + err |= get_user(i, &data32->handle); + err |= put_user(i, &data->handle); + + return err; +} + +static int compat_put_ion_allocation_data( + struct compat_ion_allocation_data __user *data32, + struct ion_allocation_data __user *data) +{ + compat_size_t s; + compat_uint_t u; + compat_int_t i; + int err; + + err = get_user(s, &data->len); + err |= put_user(s, &data32->len); + err |= get_user(s, &data->align); + err |= put_user(s, &data32->align); + err |= get_user(u, &data->heap_id_mask); + err |= put_user(u, &data32->heap_id_mask); + err |= get_user(u, &data->flags); + err |= put_user(u, &data32->flags); + err |= get_user(i, &data->handle); + err |= put_user(i, &data32->handle); + + return err; +} + +static int compat_get_ion_custom_data( + struct compat_ion_custom_data __user *data32, + struct ion_custom_data __user *data) +{ + compat_uint_t cmd; + compat_ulong_t arg; + int err; + + err = get_user(cmd, &data32->cmd); + err |= put_user(cmd, &data->cmd); + err |= get_user(arg, &data32->arg); + err |= put_user(arg, &data->arg); + + return err; +}; + +long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret; + + if (!filp->f_op || !filp->f_op->unlocked_ioctl) + return -ENOTTY; + + switch (cmd) { + case COMPAT_ION_IOC_ALLOC: + { + struct compat_ion_allocation_data __user *data32; + struct ion_allocation_data __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ion_allocation_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, ION_IOC_ALLOC, + (unsigned long)data); + err = compat_put_ion_allocation_data(data32, data); + return ret ? ret : err; + } + case COMPAT_ION_IOC_FREE: + { + struct compat_ion_allocation_data __user *data32; + struct ion_allocation_data __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ion_allocation_data(data32, data); + if (err) + return err; + + return filp->f_op->unlocked_ioctl(filp, ION_IOC_FREE, + (unsigned long)data); + } + case COMPAT_ION_IOC_CUSTOM: { + struct compat_ion_custom_data __user *data32; + struct ion_custom_data __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ion_custom_data(data32, data); + if (err) + return err; + + return filp->f_op->unlocked_ioctl(filp, ION_IOC_CUSTOM, + (unsigned long)data); + } + case ION_IOC_SHARE: + case ION_IOC_MAP: + case ION_IOC_IMPORT: + case ION_IOC_SYNC: + return filp->f_op->unlocked_ioctl(filp, cmd, + (unsigned long)compat_ptr(arg)); + default: + return -ENOIOCTLCMD; + } +} diff --git a/drivers/staging/android/ion/compat_ion.h b/drivers/staging/android/ion/compat_ion.h new file mode 100644 index 00000000000..3a9c8c08c24 --- /dev/null +++ b/drivers/staging/android/ion/compat_ion.h @@ -0,0 +1,30 @@ +/* + + * drivers/gpu/ion/compat_ion.h + * + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_COMPAT_ION_H +#define _LINUX_COMPAT_ION_H + +#if IS_ENABLED(CONFIG_COMPAT) + +long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#else + +#define compat_ion_ioctl NULL + +#endif /* CONFIG_COMPAT */ +#endif /* _LINUX_COMPAT_ION_H */ diff --git a/drivers/gpu/ion/ion.c b/drivers/staging/android/ion/ion.c index eab7d35a779..d5a7c073366 100644 --- a/drivers/gpu/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -3,7 +3,7 @@ * drivers/gpu/ion/ion.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -20,7 +20,6 @@ #include <linux/freezer.h> #include <linux/fs.h> #include <linux/anon_inodes.h> -#include <linux/ion.h> #include <linux/kthread.h> #include <linux/list.h> #include <linux/list_sort.h> @@ -33,6 +32,7 @@ #include <linux/slab.h> #include <linux/seq_file.h> #include <linux/uaccess.h> +#include <linux/vmalloc.h> #include <linux/debugfs.h> #include <linux/dma-buf.h> #include <linux/idr.h> @@ -40,7 +40,9 @@ #include <trace/events/kmem.h> +#include "ion.h" #include "ion_priv.h" +#include "compat_ion.h" /** * struct ion_device - the metadata of the ion device node @@ -114,13 +116,33 @@ struct ion_handle { bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer) { - return ((buffer->flags & ION_FLAG_CACHED) && - !(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC)); + return (buffer->flags & ION_FLAG_CACHED) && + !(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC); } bool ion_buffer_cached(struct ion_buffer *buffer) { - return !!(buffer->flags & ION_FLAG_CACHED); + return !!(buffer->flags & ION_FLAG_CACHED); +} + +static inline struct page *ion_buffer_page(struct page *page) +{ + return (struct page *)((unsigned long)page & ~(1UL)); +} + +static inline bool ion_buffer_page_is_dirty(struct page *page) +{ + return !!((unsigned long)page & 1UL); +} + +static inline void ion_buffer_page_dirty(struct page **page) +{ + *page = (struct page *)((unsigned long)(*page) | 1UL); +} + +static inline void ion_buffer_page_clean(struct page **page) +{ + *page = (struct page *)((unsigned long)(*page) & ~(1UL)); } /* this function should only be called while dev->lock is held */ @@ -149,8 +171,6 @@ static void ion_buffer_add(struct ion_device *dev, rb_insert_color(&buffer->node, &dev->buffers); } -static int ion_buffer_alloc_dirty(struct ion_buffer *buffer); - /* this function should only be called while dev->lock is held */ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, struct ion_device *dev, @@ -190,7 +210,8 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, INIT_LIST_HEAD(&buffer->vmas); table = heap->ops->map_dma(heap, buffer); - if (WARN_ONCE(table == NULL, "heap->ops->map_dma should return ERR_PTR on error")) + if (WARN_ONCE(table == NULL, + "heap->ops->map_dma should return ERR_PTR on error")) table = ERR_PTR(-EINVAL); if (IS_ERR(table)) { heap->ops->free(buffer); @@ -199,17 +220,23 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, } buffer->sg_table = table; if (ion_buffer_fault_user_mappings(buffer)) { - for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, - i) { - if (sg_dma_len(sg) == PAGE_SIZE) - continue; - pr_err("%s: cached mappings that will be faulted in " - "must have pagewise sg_lists\n", __func__); - ret = -EINVAL; - goto err; + int num_pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; + struct scatterlist *sg; + int i, j, k = 0; + + buffer->pages = vmalloc(sizeof(struct page *) * num_pages); + if (!buffer->pages) { + ret = -ENOMEM; + goto err1; + } + + for_each_sg(table->sgl, sg, table->nents, i) { + struct page *page = sg_page(sg); + + for (j = 0; j < sg->length / PAGE_SIZE; j++) + buffer->pages[k++] = page++; } - ret = ion_buffer_alloc_dirty(buffer); if (ret) goto err; } @@ -235,6 +262,9 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, err: heap->ops->unmap_dma(heap, buffer); heap->ops->free(buffer); +err1: + if (buffer->pages) + vfree(buffer->pages); err2: kfree(buffer); return ERR_PTR(ret); @@ -247,8 +277,8 @@ void ion_buffer_destroy(struct ion_buffer *buffer) buffer->heap->ops->unmap_dma(buffer->heap, buffer); buffer->heap->ops->free(buffer); - if (buffer->flags & ION_FLAG_CACHED) - kfree(buffer->dirty); + if (buffer->pages) + vfree(buffer->pages); kfree(buffer); } @@ -375,13 +405,16 @@ int ion_handle_put(struct ion_handle *handle) static struct ion_handle *ion_handle_lookup(struct ion_client *client, struct ion_buffer *buffer) { - struct rb_node *n; + struct rb_node *n = client->handles.rb_node; - for (n = rb_first(&client->handles); n; n = rb_next(n)) { - struct ion_handle *handle = rb_entry(n, struct ion_handle, - node); - if (handle->buffer == buffer) - return handle; + while (n) { + struct ion_handle *entry = rb_entry(n, struct ion_handle, node); + if (buffer < entry->buffer) + n = n->rb_left; + else if (buffer > entry->buffer) + n = n->rb_right; + else + return entry; } return ERR_PTR(-EINVAL); } @@ -400,7 +433,8 @@ struct ion_handle *ion_handle_get_by_id(struct ion_client *client, return handle ? handle : ERR_PTR(-EINVAL); } -static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle) +static bool ion_handle_validate(struct ion_client *client, + struct ion_handle *handle) { WARN_ON(!mutex_is_locked(&client->lock)); return (idr_find(&client->idr, handle->id) == handle); @@ -423,9 +457,9 @@ static int ion_handle_add(struct ion_client *client, struct ion_handle *handle) parent = *p; entry = rb_entry(parent, struct ion_handle, node); - if (handle < entry) + if (handle->buffer < entry->buffer) p = &(*p)->rb_left; - else if (handle > entry) + else if (handle->buffer > entry->buffer) p = &(*p)->rb_right; else WARN(1, "%s: buffer already found.", __func__); @@ -469,11 +503,11 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, * request of the caller allocate from it. Repeat until allocate has * succeeded or all heaps have been tried */ - if (WARN_ON(!len)) - return ERR_PTR(-EINVAL); - len = PAGE_ALIGN(len); + if (!len) + return ERR_PTR(-EINVAL); + down_read(&dev->lock); plist_for_each_entry(heap, &dev->heaps, node) { /* if the caller didn't specify this heap id */ @@ -603,7 +637,8 @@ static void *ion_buffer_kmap_get(struct ion_buffer *buffer) return buffer->vaddr; } vaddr = buffer->heap->ops->map_kernel(buffer->heap, buffer); - if (WARN_ONCE(vaddr == NULL, "heap->ops->map_kernel should return ERR_PTR on error")) + if (WARN_ONCE(vaddr == NULL, + "heap->ops->map_kernel should return ERR_PTR on error")) return ERR_PTR(-EINVAL); if (IS_ERR(vaddr)) return vaddr; @@ -982,15 +1017,20 @@ static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment, { } -static int ion_buffer_alloc_dirty(struct ion_buffer *buffer) +void ion_pages_sync_for_device(struct device *dev, struct page *page, + size_t size, enum dma_data_direction dir) { - unsigned long pages = buffer->sg_table->nents; - unsigned long length = (pages + BITS_PER_LONG - 1)/BITS_PER_LONG; + struct scatterlist sg; - buffer->dirty = kzalloc(length * sizeof(unsigned long), GFP_KERNEL); - if (!buffer->dirty) - return -ENOMEM; - return 0; + sg_init_table(&sg, 1); + sg_set_page(&sg, page, size, 0); + /* + * This is not correct - sg_dma_address needs a dma_addr_t that is valid + * for the the targeted device, but this works on the currently targeted + * hardware. + */ + sg_dma_address(&sg) = page_to_phys(page); + dma_sync_sg_for_device(dev, &sg, 1, dir); } struct ion_vma_list { @@ -1002,9 +1042,9 @@ static void ion_buffer_sync_for_device(struct ion_buffer *buffer, struct device *dev, enum dma_data_direction dir) { - struct scatterlist *sg; - int i; struct ion_vma_list *vma_list; + int pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; + int i; pr_debug("%s: syncing for device %s\n", __func__, dev ? dev_name(dev) : "null"); @@ -1013,11 +1053,14 @@ static void ion_buffer_sync_for_device(struct ion_buffer *buffer, return; mutex_lock(&buffer->lock); - for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) { - if (!test_bit(i, buffer->dirty)) - continue; - dma_sync_sg_for_device(dev, sg, 1, dir); - clear_bit(i, buffer->dirty); + for (i = 0; i < pages; i++) { + struct page *page = buffer->pages[i]; + + if (ion_buffer_page_is_dirty(page)) + ion_pages_sync_for_device(dev, ion_buffer_page(page), + PAGE_SIZE, dir); + + ion_buffer_page_clean(buffer->pages + i); } list_for_each_entry(vma_list, &buffer->vmas, list) { struct vm_area_struct *vma = vma_list->vma; @@ -1028,24 +1071,22 @@ static void ion_buffer_sync_for_device(struct ion_buffer *buffer, mutex_unlock(&buffer->lock); } -int ion_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +static int ion_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct ion_buffer *buffer = vma->vm_private_data; - struct scatterlist *sg; - int i; + unsigned long pfn; + int ret; mutex_lock(&buffer->lock); - set_bit(vmf->pgoff, buffer->dirty); + ion_buffer_page_dirty(buffer->pages + vmf->pgoff); + BUG_ON(!buffer->pages || !buffer->pages[vmf->pgoff]); - for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) { - if (i != vmf->pgoff) - continue; - dma_sync_sg_for_cpu(NULL, sg, 1, DMA_BIDIRECTIONAL); - vm_insert_page(vma, (unsigned long)vmf->virtual_address, - sg_page(sg)); - break; - } + pfn = page_to_pfn(ion_buffer_page(buffer->pages[vmf->pgoff])); + ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); mutex_unlock(&buffer->lock); + if (ret) + return VM_FAULT_ERROR; + return VM_FAULT_NOPAGE; } @@ -1085,7 +1126,7 @@ static void ion_vm_close(struct vm_area_struct *vma) buffer->heap->ops->unmap_user(buffer->heap, buffer); } -struct vm_operations_struct ion_vma_ops = { +static struct vm_operations_struct ion_vma_ops = { .open = ion_vm_open, .close = ion_vm_close, .fault = ion_vm_fault, @@ -1103,6 +1144,8 @@ static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) } if (ion_buffer_fault_user_mappings(buffer)) { + vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | + VM_DONTDUMP; vma->vm_private_data = buffer; vma->vm_ops = &ion_vma_ops; vma->vm_flags |= VM_MIXEDMAP; @@ -1175,7 +1218,7 @@ static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start, mutex_unlock(&buffer->lock); } -struct dma_buf_ops dma_buf_ops = { +static struct dma_buf_ops dma_buf_ops = { .map_dma_buf = ion_map_dma_buf, .unmap_dma_buf = ion_unmap_dma_buf, .mmap = ion_mmap, @@ -1304,41 +1347,65 @@ static int ion_sync_for_device(struct ion_client *client, int fd) return 0; } +/* fix up the cases where the ioctl direction bits are incorrect */ +static unsigned int ion_ioctl_dir(unsigned int cmd) +{ + switch (cmd) { + case ION_IOC_SYNC: + case ION_IOC_FREE: + case ION_IOC_CUSTOM: + return _IOC_WRITE; + default: + return _IOC_DIR(cmd); + } +} + static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct ion_client *client = filp->private_data; + struct ion_device *dev = client->dev; + struct ion_handle *cleanup_handle = NULL; + int ret = 0; + unsigned int dir; + + union { + struct ion_fd_data fd; + struct ion_allocation_data allocation; + struct ion_handle_data handle; + struct ion_custom_data custom; + } data; + + dir = ion_ioctl_dir(cmd); + + if (_IOC_SIZE(cmd) > sizeof(data)) + return -EINVAL; + + if (dir & _IOC_WRITE) + if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd))) + return -EFAULT; switch (cmd) { case ION_IOC_ALLOC: { - struct ion_allocation_data data; struct ion_handle *handle; - if (copy_from_user(&data, (void __user *)arg, sizeof(data))) - return -EFAULT; - handle = ion_alloc(client, data.len, data.align, - data.heap_mask, data.flags); - + handle = ion_alloc(client, data.allocation.len, + data.allocation.align, + data.allocation.heap_mask, + data.allocation.flags); if (IS_ERR(handle)) return PTR_ERR(handle); - data.handle = (ion_user_handle_t)handle->id; + data.allocation.handle = handle->id; - if (copy_to_user((void __user *)arg, &data, sizeof(data))) { - ion_free(client, handle); - return -EFAULT; - } + cleanup_handle = handle; break; } case ION_IOC_FREE: { - struct ion_handle_data data; struct ion_handle *handle; - if (copy_from_user(&data, (void __user *)arg, - sizeof(struct ion_handle_data))) - return -EFAULT; - handle = ion_handle_get_by_id(client, (int)data.handle); + handle = ion_handle_get_by_id(client, data.handle.handle); if (IS_ERR(handle)) return PTR_ERR(handle); ion_free(client, handle); @@ -1348,63 +1415,39 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case ION_IOC_SHARE: case ION_IOC_MAP: { - struct ion_fd_data data; struct ion_handle *handle; - if (copy_from_user(&data, (void __user *)arg, sizeof(data))) - return -EFAULT; - handle = ion_handle_get_by_id(client, (int)data.handle); + handle = ion_handle_get_by_id(client, data.handle.handle); if (IS_ERR(handle)) return PTR_ERR(handle); - data.fd = ion_share_dma_buf_fd(client, handle); + data.fd.fd = ion_share_dma_buf_fd(client, handle); ion_handle_put(handle); - if (copy_to_user((void __user *)arg, &data, sizeof(data))) - return -EFAULT; - if (data.fd < 0) - return data.fd; + if (data.fd.fd < 0) + ret = data.fd.fd; break; } case ION_IOC_IMPORT: { - struct ion_fd_data data; struct ion_handle *handle; - int ret = 0; - if (copy_from_user(&data, (void __user *)arg, - sizeof(struct ion_fd_data))) - return -EFAULT; - handle = ion_import_dma_buf(client, data.fd); + handle = ion_import_dma_buf(client, data.fd.fd); if (IS_ERR(handle)) ret = PTR_ERR(handle); else - data.handle = (ion_user_handle_t)handle->id; - - if (copy_to_user((void __user *)arg, &data, - sizeof(struct ion_fd_data))) - return -EFAULT; - if (ret < 0) - return ret; + data.handle.handle = handle->id; break; } case ION_IOC_SYNC: { - struct ion_fd_data data; - if (copy_from_user(&data, (void __user *)arg, - sizeof(struct ion_fd_data))) - return -EFAULT; - ion_sync_for_device(client, data.fd); + ret = ion_sync_for_device(client, data.fd.fd); break; } case ION_IOC_CUSTOM: { - struct ion_device *dev = client->dev; - struct ion_custom_data data; - if (!dev->custom_ioctl) return -ENOTTY; - if (copy_from_user(&data, (void __user *)arg, - sizeof(struct ion_custom_data))) - return -EFAULT; - return dev->custom_ioctl(client, data.cmd, data.arg); + ret = dev->custom_ioctl(client, data.custom.cmd, + data.custom.arg); + break; } case ION_IOC_CLEAN_CACHES: return client->dev->custom_ioctl(client, @@ -1418,7 +1461,15 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) default: return -ENOTTY; } - return 0; + + if (dir & _IOC_READ) { + if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) { + if (cleanup_handle) + ion_free(client, cleanup_handle); + return -EFAULT; + } + } + return ret; } static int ion_release(struct inode *inode, struct file *file) @@ -1452,6 +1503,7 @@ static const struct file_operations ion_fops = { .open = ion_open, .release = ion_release, .unlocked_ioctl = ion_ioctl, + .compat_ioctl = compat_ion_ioctl, }; static size_t ion_debug_heap_total(struct ion_client *client, @@ -1614,9 +1666,9 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) total_size += buffer->size; if (!buffer->handle_count) { seq_printf(s, "%16.s %16u %16zu %d %d\n", - buffer->task_comm, buffer->pid, buffer->size, - buffer->kmap_cnt, - atomic_read(&buffer->ref.refcount)); + buffer->task_comm, buffer->pid, + buffer->size, buffer->kmap_cnt, + atomic_read(&buffer->ref.refcount)); total_orphaned_size += buffer->size; } } @@ -1625,6 +1677,9 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) seq_printf(s, "%16.s %16zu\n", "total orphaned", total_orphaned_size); seq_printf(s, "%16.s %16zu\n", "total ", total_size); + if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) + seq_printf(s, "%16.s %16zu\n", "deferred free", + heap->free_list_size); seq_printf(s, "----------------------------------------------------\n"); if (heap->debug_show) @@ -1649,39 +1704,39 @@ static const struct file_operations debug_heap_fops = { #ifdef DEBUG_HEAP_SHRINKER static int debug_shrink_set(void *data, u64 val) { - struct ion_heap *heap = data; - struct shrink_control sc; - int objs; + struct ion_heap *heap = data; + struct shrink_control sc; + int objs; - sc.gfp_mask = -1; - sc.nr_to_scan = 0; + sc.gfp_mask = -1; + sc.nr_to_scan = 0; - if (!val) - return 0; + if (!val) + return 0; - objs = heap->shrinker.shrink(&heap->shrinker, &sc); - sc.nr_to_scan = objs; + objs = heap->shrinker.shrink(&heap->shrinker, &sc); + sc.nr_to_scan = objs; - heap->shrinker.shrink(&heap->shrinker, &sc); - return 0; + heap->shrinker.shrink(&heap->shrinker, &sc); + return 0; } static int debug_shrink_get(void *data, u64 *val) { - struct ion_heap *heap = data; - struct shrink_control sc; - int objs; + struct ion_heap *heap = data; + struct shrink_control sc; + int objs; - sc.gfp_mask = -1; - sc.nr_to_scan = 0; + sc.gfp_mask = -1; + sc.nr_to_scan = 0; - objs = heap->shrinker.shrink(&heap->shrinker, &sc); - *val = objs; - return 0; + objs = heap->shrinker.shrink(&heap->shrinker, &sc); + *val = objs; + return 0; } DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get, - debug_shrink_set, "%llu\n"); + debug_shrink_set, "%llu\n"); #endif void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) @@ -1732,33 +1787,6 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) up_write(&dev->lock); } -int ion_secure_heap(struct ion_device *dev, int heap_id, int version, - void *data) -{ - int ret_val = 0; - struct ion_heap *heap; - - /* - * traverse the list of heaps available in this system - * and find the heap that is specified. - */ - down_write(&dev->lock); - plist_for_each_entry(heap, &dev->heaps, node) { - if (!ion_heap_allow_heap_secure(heap->type)) - continue; - if (ION_HEAP(heap->id) != heap_id) - continue; - if (heap->ops->secure_heap) - ret_val = heap->ops->secure_heap(heap, version, data); - else - ret_val = -EINVAL; - break; - } - up_write(&dev->lock); - return ret_val; -} -EXPORT_SYMBOL(ion_secure_heap); - int ion_walk_heaps(struct ion_client *client, int heap_id, void *data, int (*f)(struct ion_heap *heap, void *data)) { @@ -1781,33 +1809,6 @@ int ion_walk_heaps(struct ion_client *client, int heap_id, void *data, } EXPORT_SYMBOL(ion_walk_heaps); -int ion_unsecure_heap(struct ion_device *dev, int heap_id, int version, - void *data) -{ - int ret_val = 0; - struct ion_heap *heap; - - /* - * traverse the list of heaps available in this system - * and find the heap that is specified. - */ - down_write(&dev->lock); - plist_for_each_entry(heap, &dev->heaps, node) { - if (!ion_heap_allow_heap_secure(heap->type)) - continue; - if (ION_HEAP(heap->id) != heap_id) - continue; - if (heap->ops->secure_heap) - ret_val = heap->ops->unsecure_heap(heap, version, data); - else - ret_val = -EINVAL; - break; - } - up_write(&dev->lock); - return ret_val; -} -EXPORT_SYMBOL(ion_unsecure_heap); - struct ion_device *ion_device_create(long (*custom_ioctl) (struct ion_client *client, unsigned int cmd, diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h new file mode 100644 index 00000000000..a53867ed3ed --- /dev/null +++ b/drivers/staging/android/ion/ion.h @@ -0,0 +1,277 @@ +/* + * drivers/staging/android/ion/ion.h + * + * Copyright (C) 2011 Google, Inc. + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_ION_H +#define _LINUX_ION_H + +#include <linux/err.h> +#include "../uapi/linux/ion.h" + +struct ion_handle; +struct ion_device; +struct ion_heap; +struct ion_mapper; +struct ion_client; +struct ion_buffer; + +/* This should be removed some day when phys_addr_t's are fully + plumbed in the kernel, and all instances of ion_phys_addr_t should + be converted to phys_addr_t. For the time being many kernel interfaces + do not accept phys_addr_t's that would have to */ +#define ion_phys_addr_t dma_addr_t + +/** + * struct ion_platform_heap - defines a heap in the given platform + * @type: type of the heap from ion_heap_type enum + * @id: unique identifier for heap. When allocating higher numbers + * will be allocated from first. At allocation these are passed + * as a bit mask and therefore can not exceed ION_NUM_HEAP_IDS. + * @name: used for debug purposes + * @base: base address of heap in physical memory if applicable + * @size: size of the heap in bytes if applicable + * @has_outer_cache: set to 1 if outer cache is used, 0 otherwise. + * @extra_data: Extra data specific to each heap type + * @priv: heap private data + * @align: required alignment in physical memory if applicable + * @priv: private info passed from the board file + * + * Provided by the board file. + */ +struct ion_platform_heap { + enum ion_heap_type type; + unsigned int id; + const char *name; + ion_phys_addr_t base; + size_t size; + unsigned int has_outer_cache; + void *extra_data; + ion_phys_addr_t align; + void *priv; +}; + +/** + * struct ion_platform_data - array of platform heaps passed from board file + * @has_outer_cache: set to 1 if outer cache is used, 0 otherwise. + * @nr: number of structures in the array + * @heaps: array of platform_heap structions + * + * Provided by the board file in the form of platform data to a platform device. + */ +struct ion_platform_data { + unsigned int has_outer_cache; + int nr; + struct ion_platform_heap *heaps; +}; + +#ifdef CONFIG_ION + +/** + * ion_reserve() - reserve memory for ion heaps if applicable + * @data: platform data specifying starting physical address and + * size + * + * Calls memblock reserve to set aside memory for heaps that are + * located at specific memory addresses or of specfic sizes not + * managed by the kernel + */ +void ion_reserve(struct ion_platform_data *data); + +/** + * ion_client_create() - allocate a client and returns it + * @dev: the global ion device + * @heap_type_mask: mask of heaps this client can allocate from + * @name: used for debugging + */ +struct ion_client *ion_client_create(struct ion_device *dev, + const char *name); + +/** + * ion_client_destroy() - free's a client and all it's handles + * @client: the client + * + * Free the provided client and all it's resources including + * any handles it is holding. + */ +void ion_client_destroy(struct ion_client *client); + +/** + * ion_alloc - allocate ion memory + * @client: the client + * @len: size of the allocation + * @align: requested allocation alignment, lots of hardware blocks + * have alignment requirements of some kind + * @heap_id_mask: mask of heaps to allocate from, if multiple bits are set + * heaps will be tried in order from highest to lowest + * id + * @flags: heap flags, the low 16 bits are consumed by ion, the + * high 16 bits are passed on to the respective heap and + * can be heap custom + * + * Allocate memory in one of the heaps provided in heap mask and return + * an opaque handle to it. + */ +struct ion_handle *ion_alloc(struct ion_client *client, size_t len, + size_t align, unsigned int heap_id_mask, + unsigned int flags); + +/** + * ion_free - free a handle + * @client: the client + * @handle: the handle to free + * + * Free the provided handle. + */ +void ion_free(struct ion_client *client, struct ion_handle *handle); + +/** + * ion_phys - returns the physical address and len of a handle + * @client: the client + * @handle: the handle + * @addr: a pointer to put the address in + * @len: a pointer to put the length in + * + * This function queries the heap for a particular handle to get the + * handle's physical address. It't output is only correct if + * a heap returns physically contiguous memory -- in other cases + * this api should not be implemented -- ion_sg_table should be used + * instead. Returns -EINVAL if the handle is invalid. This has + * no implications on the reference counting of the handle -- + * the returned value may not be valid if the caller is not + * holding a reference. + */ +int ion_phys(struct ion_client *client, struct ion_handle *handle, + ion_phys_addr_t *addr, size_t *len); + +/** + * ion_map_dma - return an sg_table describing a handle + * @client: the client + * @handle: the handle + * + * This function returns the sg_table describing + * a particular ion handle. + */ +struct sg_table *ion_sg_table(struct ion_client *client, + struct ion_handle *handle); + +/** + * ion_map_kernel - create mapping for the given handle + * @client: the client + * @handle: handle to map + * + * Map the given handle into the kernel and return a kernel address that + * can be used to access this address. + */ +void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle); + +/** + * ion_unmap_kernel() - destroy a kernel mapping for a handle + * @client: the client + * @handle: handle to unmap + */ +void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle); + +/** + * ion_share_dma_buf() - share buffer as dma-buf + * @client: the client + * @handle: the handle + */ +struct dma_buf *ion_share_dma_buf(struct ion_client *client, + struct ion_handle *handle); + +/** + * ion_share_dma_buf_fd() - given an ion client, create a dma-buf fd + * @client: the client + * @handle: the handle + */ +int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle); + +/** + * ion_import_dma_buf() - given an dma-buf fd from the ion exporter get handle + * @client: the client + * @fd: the dma-buf fd + * + * Given an dma-buf fd that was allocated through ion via ion_share_dma_buf, + * import that fd and return a handle representing it. If a dma-buf from + * another exporter is passed in this function will return ERR_PTR(-EINVAL) + */ +struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd); + +#else +static inline void ion_reserve(struct ion_platform_data *data) +{ + +} + +static inline struct ion_client *ion_client_create(struct ion_device *dev, + unsigned int heap_mask, const char *name) +{ + return ERR_PTR(-ENODEV); +} + +static inline void ion_client_destroy(struct ion_client *client) { } + +static inline struct ion_handle *ion_alloc(struct ion_client *client, + size_t len, size_t align, + unsigned int heap_mask, + unsigned int flags) +{ + return ERR_PTR(-ENODEV); +} + +static inline void ion_free(struct ion_client *client, + struct ion_handle *handle) { } + + +static inline int ion_phys(struct ion_client *client, + struct ion_handle *handle, ion_phys_addr_t *addr, size_t *len) +{ + return -ENODEV; +} + +static inline struct sg_table *ion_sg_table(struct ion_client *client, + struct ion_handle *handle) +{ + return ERR_PTR(-ENODEV); +} + +static inline void *ion_map_kernel(struct ion_client *client, + struct ion_handle *handle) +{ + return ERR_PTR(-ENODEV); +} + +static inline void ion_unmap_kernel(struct ion_client *client, + struct ion_handle *handle) { } + +static inline int ion_share_dma_buf(struct ion_client *client, struct ion_handle *handle) +{ + return -ENODEV; +} + +static inline struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd) +{ + return ERR_PTR(-ENODEV); +} + +static inline int ion_handle_get_flags(struct ion_client *client, + struct ion_handle *handle, unsigned long *flags) +{ + return -ENODEV; +} + +#endif /* CONFIG_ION */ +#endif /* _LINUX_ION_H */ diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c index 1f8997c9698..9a7f46331d6 100644 --- a/drivers/gpu/ion/ion_carveout_heap.c +++ b/drivers/staging/android/ion/ion_carveout_heap.c @@ -2,7 +2,7 @@ * drivers/gpu/ion/ion_carveout_heap.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -19,12 +19,12 @@ #include <linux/err.h> #include <linux/genalloc.h> #include <linux/io.h> -#include <linux/ion.h> #include <linux/mm.h> #include <linux/scatterlist.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/seq_file.h> +#include "ion.h" #include "ion_priv.h" #include <asm/cacheflush.h> @@ -102,8 +102,8 @@ static void ion_carveout_heap_free(struct ion_buffer *buffer) buffer->priv_phys = ION_CARVEOUT_ALLOCATE_FAIL; } -struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap, - struct ion_buffer *buffer) +static struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap, + struct ion_buffer *buffer) { size_t chunk_size = buffer->size; @@ -114,8 +114,8 @@ struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap, buffer->size); } -void ion_carveout_heap_unmap_dma(struct ion_heap *heap, - struct ion_buffer *buffer) +static void ion_carveout_heap_unmap_dma(struct ion_heap *heap, + struct ion_buffer *buffer) { if (buffer->sg_table) sg_free_table(buffer->sg_table); @@ -133,6 +133,9 @@ void *ion_carveout_heap_map_kernel(struct ion_heap *heap, else ret_value = ioremap(buffer->priv_phys, buffer->size); + if (ret_value == NULL) + return ERR_PTR(-ENOMEM); + return ret_value; } @@ -154,7 +157,7 @@ int ion_carveout_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ret_value = remap_pfn_range(vma, vma->vm_start, - __phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff, + PFN_DOWN(buffer->priv_phys) + vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot); diff --git a/drivers/gpu/ion/ion_chunk_heap.c b/drivers/staging/android/ion/ion_chunk_heap.c index b2021a1b456..4f9528e5db1 100644 --- a/drivers/gpu/ion/ion_chunk_heap.c +++ b/drivers/staging/android/ion/ion_chunk_heap.c @@ -13,16 +13,15 @@ * GNU General Public License for more details. * */ -//#include <linux/spinlock.h> #include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/genalloc.h> #include <linux/io.h> -#include <linux/ion.h> #include <linux/mm.h> #include <linux/scatterlist.h> #include <linux/slab.h> #include <linux/vmalloc.h> +#include "ion.h" #include "ion_priv.h" struct ion_chunk_heap { @@ -45,15 +44,15 @@ static int ion_chunk_heap_allocate(struct ion_heap *heap, struct scatterlist *sg; int ret, i; unsigned long num_chunks; + unsigned long allocated_size; - if (ion_buffer_fault_user_mappings(buffer)) - return -ENOMEM; + if (align > chunk_heap->chunk_size) + return -EINVAL; - num_chunks = ALIGN(size, chunk_heap->chunk_size) / - chunk_heap->chunk_size; - buffer->size = num_chunks * chunk_heap->chunk_size; + allocated_size = ALIGN(size, chunk_heap->chunk_size); + num_chunks = allocated_size / chunk_heap->chunk_size; - if (buffer->size > chunk_heap->size - chunk_heap->allocated) + if (allocated_size > chunk_heap->size - chunk_heap->allocated) return -ENOMEM; table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); @@ -71,18 +70,19 @@ static int ion_chunk_heap_allocate(struct ion_heap *heap, chunk_heap->chunk_size); if (!paddr) goto err; - sg_set_page(sg, phys_to_page(paddr), chunk_heap->chunk_size, 0); + sg_set_page(sg, pfn_to_page(PFN_DOWN(paddr)), + chunk_heap->chunk_size, 0); sg = sg_next(sg); } buffer->priv_virt = table; - chunk_heap->allocated += buffer->size; + chunk_heap->allocated += allocated_size; return 0; err: sg = table->sgl; for (i -= 1; i >= 0; i--) { gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)), - sg_dma_len(sg)); + sg->length); sg = sg_next(sg); } sg_free_table(table); @@ -98,28 +98,35 @@ static void ion_chunk_heap_free(struct ion_buffer *buffer) struct sg_table *table = buffer->priv_virt; struct scatterlist *sg; int i; + unsigned long allocated_size; + + allocated_size = ALIGN(buffer->size, chunk_heap->chunk_size); ion_heap_buffer_zero(buffer); + if (ion_buffer_cached(buffer)) + dma_sync_sg_for_device(NULL, table->sgl, table->nents, + DMA_BIDIRECTIONAL); + for_each_sg(table->sgl, sg, table->nents, i) { if (ion_buffer_cached(buffer)) dma_sync_sg_for_device(NULL, sg, 1, DMA_BIDIRECTIONAL); gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)), - sg_dma_len(sg)); + sg->length); } - chunk_heap->allocated -= buffer->size; + chunk_heap->allocated -= allocated_size; sg_free_table(table); kfree(table); } -struct sg_table *ion_chunk_heap_map_dma(struct ion_heap *heap, - struct ion_buffer *buffer) +static struct sg_table *ion_chunk_heap_map_dma(struct ion_heap *heap, + struct ion_buffer *buffer) { return buffer->priv_virt; } -void ion_chunk_heap_unmap_dma(struct ion_heap *heap, - struct ion_buffer *buffer) +static void ion_chunk_heap_unmap_dma(struct ion_heap *heap, + struct ion_buffer *buffer) { return; } @@ -137,7 +144,10 @@ static struct ion_heap_ops chunk_heap_ops = { struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data) { struct ion_chunk_heap *chunk_heap; - struct scatterlist sg; + struct vm_struct *vm_struct; + pgprot_t pgprot = pgprot_writecombine(PAGE_KERNEL); + int i, ret; + chunk_heap = kzalloc(sizeof(struct ion_chunk_heap), GFP_KERNEL); if (!chunk_heap) @@ -147,24 +157,49 @@ struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data) chunk_heap->pool = gen_pool_create(get_order(chunk_heap->chunk_size) + PAGE_SHIFT, -1); if (!chunk_heap->pool) { - kfree(chunk_heap); - return ERR_PTR(-ENOMEM); + ret = -ENOMEM; + goto error_gen_pool_create; } chunk_heap->base = heap_data->base; chunk_heap->size = heap_data->size; chunk_heap->allocated = 0; - sg_init_table(&sg, 1); - sg_set_page(&sg, phys_to_page(heap_data->base), heap_data->size, 0); - dma_sync_sg_for_device(NULL, &sg, 1, DMA_BIDIRECTIONAL); + vm_struct = get_vm_area(PAGE_SIZE, VM_ALLOC); + if (!vm_struct) { + ret = -ENOMEM; + goto error; + } + for (i = 0; i < chunk_heap->size; i += PAGE_SIZE) { + struct page *page = pfn_to_page(PFN_DOWN(chunk_heap->base + i)); + struct page **pages = &page; + + ret = map_vm_area(vm_struct, pgprot, &pages); + if (ret) + goto error_map_vm_area; + memset(vm_struct->addr, 0, PAGE_SIZE); + unmap_kernel_range((unsigned long)vm_struct->addr, PAGE_SIZE); + } + free_vm_area(vm_struct); + + ion_pages_sync_for_device(NULL, pfn_to_page(PFN_DOWN(heap_data->base)), + heap_data->size, DMA_BIDIRECTIONAL); + gen_pool_add(chunk_heap->pool, chunk_heap->base, heap_data->size, -1); chunk_heap->heap.ops = &chunk_heap_ops; chunk_heap->heap.type = ION_HEAP_TYPE_CHUNK; chunk_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; - pr_info("%s: base %pa size %zd align %pa\n", __func__, + pr_info("%s: base %pa size %zu align %pa\n", __func__, &chunk_heap->base, heap_data->size, &heap_data->align); return &chunk_heap->heap; + +error_map_vm_area: + free_vm_area(vm_struct); +error: + gen_pool_destroy(chunk_heap->pool); +error_gen_pool_create: + kfree(chunk_heap); + return ERR_PTR(ret); } void ion_chunk_heap_destroy(struct ion_heap *heap) diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index 7868610e2b6..4768df332a2 100644 --- a/drivers/gpu/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -16,7 +16,6 @@ */ #include <linux/device.h> -#include <linux/ion.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/err.h> @@ -25,7 +24,7 @@ #include <asm/cacheflush.h> -/* for ion_heap_ops structure */ +#include "ion.h" #include "ion_priv.h" #define ION_CMA_ALLOCATE_FAILED -1 @@ -43,10 +42,10 @@ static int cma_heap_has_outer_cache; * This function could be replace by dma_common_get_sgtable * as soon as it will avalaible. */ -int ion_cma_get_sgtable(struct device *dev, struct sg_table *sgt, - void *cpu_addr, dma_addr_t handle, size_t size) +static int ion_cma_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t handle, size_t size) { - struct page *page = phys_to_page(handle); + struct page *page = pfn_to_page(PFN_DOWN(handle)); int ret; ret = sg_alloc_table(sgt, 1, GFP_KERNEL); @@ -136,16 +135,16 @@ static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer, return 0; } -struct sg_table *ion_cma_heap_map_dma(struct ion_heap *heap, - struct ion_buffer *buffer) +static struct sg_table *ion_cma_heap_map_dma(struct ion_heap *heap, + struct ion_buffer *buffer) { struct ion_cma_buffer_info *info = buffer->priv_virt; return info->table; } -void ion_cma_heap_unmap_dma(struct ion_heap *heap, - struct ion_buffer *buffer) +static void ion_cma_heap_unmap_dma(struct ion_heap *heap, + struct ion_buffer *buffer) { return; } diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/staging/android/ion/ion_cma_secure_heap.c index 35b782acdd6..9bba7724e55 100644 --- a/drivers/gpu/ion/ion_cma_secure_heap.c +++ b/drivers/staging/android/ion/ion_cma_secure_heap.c @@ -100,7 +100,7 @@ static void ion_secure_pool_pages(struct work_struct *work); int ion_secure_cma_get_sgtable(struct device *dev, struct sg_table *sgt, dma_addr_t handle, size_t size) { - struct page *page = phys_to_page(handle); + struct page *page = pfn_to_page(PFN_DOWN(handle)); int ret; ret = sg_alloc_table(sgt, 1, GFP_KERNEL); diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index 7a2308cccf0..0f92c89c3e1 100644 --- a/drivers/gpu/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -2,7 +2,7 @@ * drivers/gpu/ion/ion_heap.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -17,7 +17,6 @@ #include <linux/err.h> #include <linux/freezer.h> -#include <linux/ion.h> #include <linux/kthread.h> #include <linux/mm.h> #include <linux/rtmutex.h> @@ -26,6 +25,7 @@ #include <linux/vmalloc.h> #include <linux/slab.h> #include <linux/highmem.h> +#include "ion.h" #include "ion_priv.h" void *ion_heap_map_kernel(struct ion_heap *heap, @@ -41,7 +41,7 @@ void *ion_heap_map_kernel(struct ion_heap *heap, struct page **tmp = pages; if (!pages) - return 0; + return NULL; if (buffer->flags & ION_FLAG_CACHED) pgprot = PAGE_KERNEL; @@ -49,16 +49,18 @@ void *ion_heap_map_kernel(struct ion_heap *heap, pgprot = pgprot_writecombine(PAGE_KERNEL); for_each_sg(table->sgl, sg, table->nents, i) { - int npages_this_entry = PAGE_ALIGN(sg_dma_len(sg)) / PAGE_SIZE; + int npages_this_entry = PAGE_ALIGN(sg->length) / PAGE_SIZE; struct page *page = sg_page(sg); BUG_ON(i >= npages); - for (j = 0; j < npages_this_entry; j++) { + for (j = 0; j < npages_this_entry; j++) *(tmp++) = page++; - } } vaddr = vmap(pages, npages, VM_MAP, pgprot); vfree(pages); + if (vaddr == NULL) + return ERR_PTR(-ENOMEM); + return vaddr; } @@ -76,23 +78,26 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, unsigned long offset = vma->vm_pgoff * PAGE_SIZE; struct scatterlist *sg; int i; + int ret; for_each_sg(table->sgl, sg, table->nents, i) { struct page *page = sg_page(sg); unsigned long remainder = vma->vm_end - addr; - unsigned long len = sg_dma_len(sg); + unsigned long len = sg->length; - if (offset >= sg_dma_len(sg)) { - offset -= sg_dma_len(sg); + if (offset >= sg->length) { + offset -= sg->length; continue; } else if (offset) { page += offset / PAGE_SIZE; - len = sg_dma_len(sg) - offset; + len = sg->length - offset; offset = 0; } len = min(len, remainder); - remap_pfn_range(vma, addr, page_to_pfn(page), len, + ret = remap_pfn_range(vma, addr, page_to_pfn(page), len, vma->vm_page_prot); + if (ret) + return ret; addr += len; if (addr >= vma->vm_end) return 0; @@ -240,57 +245,7 @@ int ion_heap_buffer_zero(struct ion_buffer *buffer) return ret; } -int ion_heap_buffer_zero_old(struct ion_buffer *buffer) -{ - struct sg_table *table = buffer->sg_table; - pgprot_t pgprot; - struct scatterlist *sg; - struct vm_struct *vm_struct; - int i, j, ret = 0; - - if (buffer->flags & ION_FLAG_CACHED) - pgprot = PAGE_KERNEL; - else - pgprot = pgprot_writecombine(PAGE_KERNEL); - - vm_struct = get_vm_area(PAGE_SIZE, VM_ALLOC); - if (!vm_struct) - return -ENOMEM; - - for_each_sg(table->sgl, sg, table->nents, i) { - struct page *page = sg_page(sg); - unsigned long len = sg_dma_len(sg); - - for (j = 0; j < len / PAGE_SIZE; j++) { - struct page *sub_page = page + j; - struct page **pages = &sub_page; - ret = map_vm_area(vm_struct, pgprot, &pages); - if (ret) - goto end; - memset(vm_struct->addr, 0, PAGE_SIZE); - unmap_kernel_range((unsigned long)vm_struct->addr, - PAGE_SIZE); - } - } -end: - free_vm_area(vm_struct); - return ret; -} - -void ion_heap_free_page(struct ion_buffer *buffer, struct page *page, - unsigned int order) -{ - int i; - - if (!ion_buffer_fault_user_mappings(buffer)) { - __free_pages(page, order); - return; - } - for (i = 0; i < (1 << order); i++) - __free_page(page + i); -} - -void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer * buffer) +void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer) { rt_mutex_lock(&heap->lock); list_add(&buffer->list, &heap->free_list); @@ -348,7 +303,7 @@ size_t ion_heap_freelist_drain_from_shrinker(struct ion_heap *heap, size_t size) return _ion_heap_freelist_drain(heap, size, true); } -int ion_heap_deferred_free(void *data) +static int ion_heap_deferred_free(void *data) { struct ion_heap *heap = data; diff --git a/drivers/gpu/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index cc2a36d1ee6..665a42b73a3 100644 --- a/drivers/gpu/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -32,7 +32,6 @@ struct ion_page_pool_item { static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool) { struct page *page; - struct scatterlist sg; page = alloc_pages(pool->gfp_mask & ~__GFP_ZERO, pool->order); @@ -43,10 +42,8 @@ static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool) if (ion_heap_high_order_page_zero(page, pool->order)) goto error_free_pages; - sg_init_table(&sg, 1); - sg_set_page(&sg, page, PAGE_SIZE << pool->order, 0); - sg_dma_address(&sg) = sg_phys(&sg); - dma_sync_sg_for_device(NULL, &sg, 1, DMA_BIDIRECTIONAL); + ion_pages_sync_for_device(NULL, page, PAGE_SIZE << pool->order, + DMA_BIDIRECTIONAL); return page; error_free_pages: @@ -123,7 +120,7 @@ void *ion_page_pool_alloc(struct ion_page_pool *pool) return page; } -void ion_page_pool_free(struct ion_page_pool *pool, struct page* page) +void ion_page_pool_free(struct ion_page_pool *pool, struct page *page) { int ret; @@ -149,7 +146,7 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, int i; bool high; - high = gfp_mask & __GFP_HIGHMEM; + high = !!(gfp_mask & __GFP_HIGHMEM); if (nr_to_scan == 0) return ion_page_pool_total(pool, high); @@ -158,10 +155,10 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, struct page *page; mutex_lock(&pool->mutex); - if (high && pool->high_count) { - page = ion_page_pool_remove(pool, true); - } else if (pool->low_count) { + 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); break; diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index dadd580d942..ea48eb013e0 100644 --- a/drivers/gpu/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -2,7 +2,7 @@ * drivers/gpu/ion/ion_priv.h * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -18,7 +18,8 @@ #ifndef _ION_PRIV_H #define _ION_PRIV_H -#include <linux/ion.h> +#include <linux/device.h> +#include <linux/dma-direction.h> #include <linux/kref.h> #include <linux/mm_types.h> #include <linux/mutex.h> @@ -30,6 +31,8 @@ #include <linux/shrinker.h> #include <linux/types.h> +#include "ion.h" + struct ion_buffer *ion_handle_buffer(struct ion_handle *handle); /** @@ -49,9 +52,8 @@ struct ion_buffer *ion_handle_buffer(struct ion_handle *handle); * @vaddr: the kenrel mapping if kmap_cnt is not zero * @dmap_cnt: number of times the buffer is mapped for dma * @sg_table: the sg table for the buffer if dmap_cnt is not zero - * @dirty: bitmask representing which pages of this buffer have - * been dirtied by the cpu and need cache maintenance - * before dma + * @pages: flat array of pages in the buffer -- used by fault + * handler and only valid for buffers that are faulted in * @vmas: list of vma's mapping this buffer * @handle_count: count of handles referencing this buffer * @task_comm: taskcomm of last client to reference this buffer in a @@ -78,7 +80,7 @@ struct ion_buffer { void *vaddr; int dmap_cnt; struct sg_table *sg_table; - unsigned long *dirty; + struct page **pages; struct list_head vmas; /* used to track orphaned buffers */ int handle_count; @@ -124,8 +126,6 @@ struct ion_heap_ops { void (*unmap_user) (struct ion_heap *mapper, struct ion_buffer *buffer); int (*print_debug)(struct ion_heap *heap, struct seq_file *s, const struct list_head *mem_map); - int (*secure_heap)(struct ion_heap *heap, int version, void *data); - int (*unsecure_heap)(struct ion_heap *heap, int version, void *data); }; /** @@ -251,7 +251,7 @@ int ion_heap_init_deferred_free(struct ion_heap *heap); /** * ion_heap_freelist_add - add a buffer to the deferred free list * @heap: the heap - * @buffer: the buffer + * @buffer: the buffer * * Adds an item to the deferred freelist. */ @@ -387,6 +387,17 @@ void ion_page_pool_free(struct ion_page_pool *, struct page *); int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, int nr_to_scan); +/** + * ion_pages_sync_for_device - cache flush pages for use with the specified + * device + * @dev: the device the pages will be used with + * @page: the first page to be flushed + * @size: size in bytes of region to be flushed + * @dir: direction of dma transfer + */ +void ion_pages_sync_for_device(struct device *dev, struct page *page, + size_t size, enum dma_data_direction dir); + int ion_walk_heaps(struct ion_client *client, int heap_id, void *data, int (*f)(struct ion_heap *heap, void *data)); diff --git a/drivers/gpu/ion/ion_removed_heap.c b/drivers/staging/android/ion/ion_removed_heap.c index 132a32c3514..5eb721448f6 100644 --- a/drivers/gpu/ion/ion_removed_heap.c +++ b/drivers/staging/android/ion/ion_removed_heap.c @@ -2,7 +2,7 @@ * drivers/gpu/ion/ion_removed_heap.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -37,8 +37,8 @@ struct ion_removed_heap { ion_phys_addr_t base; unsigned long allocated_bytes; unsigned long total_size; - int (*request_region)(void *); - int (*release_region)(void *); + int (*request_ion_region)(void *); + int (*release_ion_region)(void *); atomic_t map_count; void *bus_id; }; @@ -142,8 +142,8 @@ static int ion_removed_request_region(struct ion_removed_heap *removed_heap) { int ret_value = 0; if (atomic_inc_return(&removed_heap->map_count) == 1) { - if (removed_heap->request_region) { - ret_value = removed_heap->request_region( + if (removed_heap->request_ion_region) { + ret_value = removed_heap->request_ion_region( removed_heap->bus_id); if (ret_value) { pr_err("Unable to request SMI region"); @@ -158,8 +158,8 @@ static int ion_removed_release_region(struct ion_removed_heap *removed_heap) { int ret_value = 0; if (atomic_dec_and_test(&removed_heap->map_count)) { - if (removed_heap->release_region) { - ret_value = removed_heap->release_region( + if (removed_heap->release_ion_region) { + ret_value = removed_heap->release_ion_region( removed_heap->bus_id); if (ret_value) pr_err("Unable to release SMI region"); @@ -215,7 +215,7 @@ int ion_removed_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ret_value = remap_pfn_range(vma, vma->vm_start, - __phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff, + PFN_DOWN(buffer->priv_phys) + vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot); @@ -328,14 +328,14 @@ struct ion_heap *ion_removed_heap_create(struct ion_platform_heap *heap_data) struct ion_co_heap_pdata *extra_data = heap_data->extra_data; - if (extra_data->setup_region) - removed_heap->bus_id = extra_data->setup_region(); - if (extra_data->request_region) - removed_heap->request_region = - extra_data->request_region; - if (extra_data->release_region) - removed_heap->release_region = - extra_data->release_region; + if (extra_data->setup_ion_region) + removed_heap->bus_id = extra_data->setup_ion_region(); + if (extra_data->request_ion_region) + removed_heap->request_ion_region = + extra_data->request_ion_region; + if (extra_data->release_ion_region) + removed_heap->release_ion_region = + extra_data->release_ion_region; } return &removed_heap->heap; } diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 4d0af374b88..2512a48fd50 100644 --- a/drivers/gpu/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -2,7 +2,7 @@ * drivers/gpu/ion/ion_system_heap.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -19,21 +19,19 @@ #include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/highmem.h> -#include <linux/ion.h> #include <linux/mm.h> #include <linux/scatterlist.h> #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/vmalloc.h> +#include "ion.h" #include "ion_priv.h" #include <linux/dma-mapping.h> #include <trace/events/kmem.h> -static unsigned int high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | - __GFP_NOWARN | __GFP_NORETRY | - __GFP_NO_KSWAPD) & ~__GFP_WAIT; -static unsigned int low_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | - __GFP_NOWARN); +static gfp_t high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN | + __GFP_NORETRY) & ~__GFP_WAIT; +static gfp_t low_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN); static const unsigned int orders[] = {9, 8, 4, 0}; static const int num_orders = ARRAY_SIZE(orders); static int order_to_index(unsigned int order) @@ -68,7 +66,6 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap, unsigned long order) { bool cached = ion_buffer_cached(buffer); - bool split_pages = ion_buffer_fault_user_mappings(buffer); struct page *page; struct ion_page_pool *pool; @@ -80,8 +77,6 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap, if (!page) return 0; - if (split_pages) - split_page(page, order); return page; } @@ -90,23 +85,16 @@ static void free_buffer_page(struct ion_system_heap *heap, unsigned int order) { bool cached = ion_buffer_cached(buffer); - bool split_pages = ion_buffer_fault_user_mappings(buffer); - int i; - if ((buffer->flags & ION_FLAG_FREED_FROM_SHRINKER)) { - if (split_pages) { - for (i = 0; i < (1 << order); i++) - __free_page(page + i); - } else { - __free_pages(page, order); - } - } else { + if (!(buffer->flags & ION_FLAG_FREED_FROM_SHRINKER)) { struct ion_page_pool *pool; if (cached) pool = heap->cached_pools[order_to_index(order)]; else pool = heap->uncached_pools[order_to_index(order)]; ion_page_pool_free(pool, page); + } else { + __free_pages(page, order); } } @@ -156,11 +144,14 @@ static int ion_system_heap_allocate(struct ion_heap *heap, int i = 0; unsigned long size_remaining = PAGE_ALIGN(size); unsigned int max_order = orders[0]; - bool split_pages = ion_buffer_fault_user_mappings(buffer); + + if (align > PAGE_SIZE) + return -EINVAL; INIT_LIST_HEAD(&pages); while (size_remaining > 0) { - info = alloc_largest_available(sys_heap, buffer, size_remaining, max_order); + info = alloc_largest_available(sys_heap, buffer, size_remaining, + max_order); if (!info) goto err; list_add_tail(&info->list, &pages); @@ -168,33 +159,19 @@ static int ion_system_heap_allocate(struct ion_heap *heap, max_order = info->order; i++; } - - table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); + table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); if (!table) goto err; - if (split_pages) - ret = sg_alloc_table(table, PAGE_ALIGN(size) / PAGE_SIZE, - GFP_KERNEL); - else - ret = sg_alloc_table(table, i, GFP_KERNEL); - + ret = sg_alloc_table(table, i, GFP_KERNEL); if (ret) goto err1; sg = table->sgl; list_for_each_entry_safe(info, tmp_info, &pages, list) { struct page *page = info->page; - if (split_pages) { - for (i = 0; i < (1 << info->order); i++) { - sg_set_page(sg, page + i, PAGE_SIZE, 0); - sg = sg_next(sg); - } - } else { - sg_set_page(sg, page, (1 << info->order) * PAGE_SIZE, - 0); - sg = sg_next(sg); - } + sg_set_page(sg, page, (1 << info->order) * PAGE_SIZE, 0); + sg = sg_next(sg); list_del(&info->list); kfree(info); } @@ -227,7 +204,7 @@ void ion_system_heap_free(struct ion_buffer *buffer) for_each_sg(table->sgl, sg, table->nents, i) free_buffer_page(sys_heap, buffer, sg_page(sg), - get_order(sg_dma_len(sg))); + get_order(sg->length)); sg_free_table(table); kfree(table); } @@ -362,7 +339,7 @@ static int ion_system_heap_create_pools(struct ion_page_pool **pools) struct ion_page_pool *pool; gfp_t gfp_flags = low_order_gfp_flags; - if (orders[i] > 4) + if (orders[i]) gfp_flags = high_order_gfp_flags; pool = ion_page_pool_create(gfp_flags, orders[i]); if (!pool) @@ -432,74 +409,76 @@ void ion_system_heap_destroy(struct ion_heap *heap) kfree(sys_heap); } -struct kmalloc_buffer_info { - struct sg_table *table; - void *vaddr; -}; - static int ion_system_contig_heap_allocate(struct ion_heap *heap, struct ion_buffer *buffer, unsigned long len, unsigned long align, unsigned long flags) { + int order = get_order(len); + struct page *page; + struct sg_table *table; + unsigned long i; int ret; - struct kmalloc_buffer_info *info; - info = kmalloc(sizeof(struct kmalloc_buffer_info), GFP_KERNEL); - if (!info) { - ret = -ENOMEM; - goto out; - } + if (align > (PAGE_SIZE << order)) + return -EINVAL; - info->table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); - if (!info->table) { + page = alloc_pages(low_order_gfp_flags, order); + if (!page) + return -ENOMEM; + + split_page(page, order); + + len = PAGE_ALIGN(len); + for (i = len >> PAGE_SHIFT; i < (1 << order); i++) + __free_page(page + i); + + table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + if (!table) { ret = -ENOMEM; - goto kfree_info; + goto out; } - ret = sg_alloc_table(info->table, 1, GFP_KERNEL); + ret = sg_alloc_table(table, 1, GFP_KERNEL); if (ret) - goto kfree_table; + goto out; - info->vaddr = kzalloc(len, GFP_KERNEL); - if (!info->vaddr) { - ret = -ENOMEM; - goto sg_free_table; - } + sg_set_page(table->sgl, page, len, 0); - sg_set_page(info->table->sgl, virt_to_page(info->vaddr), len, - 0); - sg_dma_address(info->table->sgl) = virt_to_phys(info->vaddr); - dma_sync_sg_for_device(NULL, info->table->sgl, 1, DMA_BIDIRECTIONAL); + buffer->priv_virt = table; + + ion_pages_sync_for_device(NULL, page, len, DMA_BIDIRECTIONAL); - buffer->priv_virt = info; return 0; -sg_free_table: - sg_free_table(info->table); -kfree_table: - kfree(info->table); -kfree_info: - kfree(info); out: + for (i = 0; i < len >> PAGE_SHIFT; i++) + __free_page(page + i); + kfree(table); return ret; } void ion_system_contig_heap_free(struct ion_buffer *buffer) { - struct kmalloc_buffer_info *info = buffer->priv_virt; - sg_free_table(info->table); - kfree(info->table); - kfree(info->vaddr); + struct sg_table *table = buffer->priv_virt; + struct page *page = sg_page(table->sgl); + unsigned long pages = PAGE_ALIGN(buffer->size) >> PAGE_SHIFT; + unsigned long i; + + for (i = 0; i < pages; i++) + __free_page(page + i); + sg_free_table(table); + kfree(table); } static int ion_system_contig_heap_phys(struct ion_heap *heap, struct ion_buffer *buffer, ion_phys_addr_t *addr, size_t *len) { - struct kmalloc_buffer_info *info = buffer->priv_virt; - *addr = virt_to_phys(info->vaddr); + struct sg_table *table = buffer->priv_virt; + struct page *page = sg_page(table->sgl); + *addr = page_to_phys(page); *len = buffer->size; return 0; } @@ -507,8 +486,7 @@ static int ion_system_contig_heap_phys(struct ion_heap *heap, struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap, struct ion_buffer *buffer) { - struct kmalloc_buffer_info *info = buffer->priv_virt; - return info->table; + return buffer->priv_virt; } void ion_system_contig_heap_unmap_dma(struct ion_heap *heap, diff --git a/drivers/staging/android/ion/ion_test.c b/drivers/staging/android/ion/ion_test.c new file mode 100644 index 00000000000..3e20349baf7 --- /dev/null +++ b/drivers/staging/android/ion/ion_test.c @@ -0,0 +1,281 @@ +/* + * + * Copyright (C) 2013 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. + * + */ + +#define pr_fmt(fmt) "ion-test: " fmt + +#include <linux/dma-buf.h> +#include <linux/dma-direction.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/vmalloc.h> + +#include "ion.h" +#include "../uapi/ion_test.h" + +#define u64_to_uptr(x) ((void __user *)(unsigned long)(x)) + +struct ion_test_device { + struct miscdevice misc; +}; + +struct ion_test_data { + struct dma_buf *dma_buf; + struct device *dev; +}; + +static int ion_handle_test_dma(struct device *dev, struct dma_buf *dma_buf, + void __user *ptr, size_t offset, size_t size, bool write) +{ + int ret = 0; + struct dma_buf_attachment *attach; + struct sg_table *table; + pgprot_t pgprot = pgprot_writecombine(PAGE_KERNEL); + enum dma_data_direction dir = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + struct sg_page_iter sg_iter; + unsigned long offset_page; + + attach = dma_buf_attach(dma_buf, dev); + if (IS_ERR(attach)) + return PTR_ERR(attach); + + table = dma_buf_map_attachment(attach, dir); + if (IS_ERR(table)) + return PTR_ERR(table); + + offset_page = offset >> PAGE_SHIFT; + offset %= PAGE_SIZE; + + for_each_sg_page(table->sgl, &sg_iter, table->nents, offset_page) { + struct page *page = sg_page_iter_page(&sg_iter); + void *vaddr = vmap(&page, 1, VM_MAP, pgprot); + size_t to_copy = PAGE_SIZE - offset; + + to_copy = min(to_copy, size); + if (!vaddr) { + ret = -ENOMEM; + goto err; + } + + if (write) + ret = copy_from_user(vaddr + offset, ptr, to_copy); + else + ret = copy_to_user(ptr, vaddr + offset, to_copy); + + vunmap(vaddr); + if (ret) { + ret = -EFAULT; + goto err; + } + size -= to_copy; + if (!size) + break; + ptr += to_copy; + offset = 0; + } + +err: + dma_buf_unmap_attachment(attach, table, dir); + dma_buf_detach(dma_buf, attach); + return ret; +} + +static int ion_handle_test_kernel(struct dma_buf *dma_buf, void __user *ptr, + size_t offset, size_t size, bool write) +{ + int ret; + unsigned long page_offset = offset >> PAGE_SHIFT; + size_t copy_offset = offset % PAGE_SIZE; + size_t copy_size = size; + enum dma_data_direction dir = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + if (offset > dma_buf->size || size > dma_buf->size - offset) + return -EINVAL; + + ret = dma_buf_begin_cpu_access(dma_buf, offset, size, dir); + if (ret) + return ret; + + while (copy_size > 0) { + size_t to_copy; + void *vaddr = dma_buf_kmap(dma_buf, page_offset); + + if (!vaddr) + goto err; + + to_copy = min_t(size_t, PAGE_SIZE - copy_offset, copy_size); + + if (write) + ret = copy_from_user(vaddr + copy_offset, ptr, to_copy); + else + ret = copy_to_user(ptr, vaddr + copy_offset, to_copy); + + dma_buf_kunmap(dma_buf, page_offset, vaddr); + if (ret) { + ret = -EFAULT; + goto err; + } + + copy_size -= to_copy; + ptr += to_copy; + page_offset++; + copy_offset = 0; + } +err: + dma_buf_end_cpu_access(dma_buf, offset, size, dir); + return ret; +} + +static long ion_test_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct ion_test_data *test_data = filp->private_data; + int ret = 0; + + union { + struct ion_test_rw_data test_rw; + } data; + + if (_IOC_SIZE(cmd) > sizeof(data)) + return -EINVAL; + + if (_IOC_DIR(cmd) & _IOC_WRITE) + if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd))) + return -EFAULT; + + switch (cmd) { + case ION_IOC_TEST_SET_FD: + { + struct dma_buf *dma_buf = NULL; + int fd = arg; + + if (fd >= 0) { + dma_buf = dma_buf_get((int)arg); + if (IS_ERR(dma_buf)) + return PTR_ERR(dma_buf); + } + if (test_data->dma_buf) + dma_buf_put(test_data->dma_buf); + test_data->dma_buf = dma_buf; + break; + } + case ION_IOC_TEST_DMA_MAPPING: + { + ret = ion_handle_test_dma(test_data->dev, test_data->dma_buf, + u64_to_uptr(data.test_rw.ptr), + data.test_rw.offset, data.test_rw.size, + data.test_rw.write); + break; + } + case ION_IOC_TEST_KERNEL_MAPPING: + { + ret = ion_handle_test_kernel(test_data->dma_buf, + u64_to_uptr(data.test_rw.ptr), + data.test_rw.offset, data.test_rw.size, + data.test_rw.write); + break; + } + default: + return -ENOTTY; + } + + if (_IOC_DIR(cmd) & _IOC_READ) { + if (copy_to_user((void __user *)arg, &data, sizeof(data))) + return -EFAULT; + } + return ret; +} + +static int ion_test_open(struct inode *inode, struct file *file) +{ + struct ion_test_data *data; + struct miscdevice *miscdev = file->private_data; + + data = kzalloc(sizeof(struct ion_test_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = miscdev->parent; + + file->private_data = data; + + return 0; +} + +static int ion_test_release(struct inode *inode, struct file *file) +{ + struct ion_test_data *data = file->private_data; + + kfree(data); + + return 0; +} + +static const struct file_operations ion_test_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = ion_test_ioctl, + .open = ion_test_open, + .release = ion_test_release, +}; + +static int __init ion_test_probe(struct platform_device *pdev) +{ + int ret; + struct ion_test_device *testdev; + + testdev = devm_kzalloc(&pdev->dev, sizeof(struct ion_test_device), + GFP_KERNEL); + if (!testdev) + return -ENOMEM; + + testdev->misc.minor = MISC_DYNAMIC_MINOR; + testdev->misc.name = "ion-test"; + testdev->misc.fops = &ion_test_fops; + testdev->misc.parent = &pdev->dev; + ret = misc_register(&testdev->misc); + if (ret) { + pr_err("failed to register misc device.\n"); + return ret; + } + + platform_set_drvdata(pdev, testdev); + + return 0; +} + +static struct platform_driver ion_test_platform_driver = { + .driver = { + .name = "ion-test", + }, +}; + +static int __init ion_test_init(void) +{ + platform_device_register_simple("ion-test", -1, NULL, 0); + return platform_driver_probe(&ion_test_platform_driver, ion_test_probe); +} + +static void __exit ion_test_exit(void) +{ + platform_driver_unregister(&ion_test_platform_driver); +} + +module_init(ion_test_init); +module_exit(ion_test_exit); diff --git a/drivers/gpu/ion/msm/Makefile b/drivers/staging/android/ion/msm/Makefile index 25d515a5306..25d515a5306 100644 --- a/drivers/gpu/ion/msm/Makefile +++ b/drivers/staging/android/ion/msm/Makefile diff --git a/drivers/gpu/ion/msm/ion_cp_common.h b/drivers/staging/android/ion/msm/ion_cp_common.h index 249f58d0029..2e0247d032f 100644 --- a/drivers/gpu/ion/msm/ion_cp_common.h +++ b/drivers/staging/android/ion/msm/ion_cp_common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and diff --git a/drivers/gpu/ion/msm/ion_iommu_map.c b/drivers/staging/android/ion/msm/ion_iommu_map.c index 3e8dfbe3cdf..d7bb8a13932 100644 --- a/drivers/gpu/ion/msm/ion_iommu_map.c +++ b/drivers/staging/android/ion/msm/ion_iommu_map.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c index 5fa2514628a..4b7076d0200 100644 --- a/drivers/gpu/ion/msm/msm_ion.c +++ b/drivers/staging/android/ion/msm/msm_ion.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -123,30 +123,6 @@ struct ion_client *msm_ion_client_create(unsigned int heap_mask, } EXPORT_SYMBOL(msm_ion_client_create); -int msm_ion_secure_heap(int heap_id) -{ - return ion_secure_heap(idev, heap_id, ION_CP_V1, NULL); -} -EXPORT_SYMBOL(msm_ion_secure_heap); - -int msm_ion_unsecure_heap(int heap_id) -{ - return ion_unsecure_heap(idev, heap_id, ION_CP_V1, NULL); -} -EXPORT_SYMBOL(msm_ion_unsecure_heap); - -int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage) -{ - return ion_secure_heap(idev, heap_id, ION_CP_V2, (void *)usage); -} -EXPORT_SYMBOL(msm_ion_secure_heap_2_0); - -int msm_ion_unsecure_heap_2_0(int heap_id, enum cp_mem_usage usage) -{ - return ion_unsecure_heap(idev, heap_id, ION_CP_V2, (void *)usage); -} -EXPORT_SYMBOL(msm_ion_unsecure_heap_2_0); - int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, void *vaddr, unsigned long len, unsigned int cmd) { @@ -420,18 +396,6 @@ static int msm_init_extra_data(struct device_node *node, int ret = 0; switch ((int) heap->type) { - case ION_HEAP_TYPE_CP: - { - heap->extra_data = kzalloc(sizeof(struct ion_cp_heap_pdata), - GFP_KERNEL); - if (!heap->extra_data) { - ret = -ENOMEM; - } else { - struct ion_cp_heap_pdata *extra = heap->extra_data; - extra->permission_type = heap_desc->permission_type; - } - break; - } case ION_HEAP_TYPE_CARVEOUT: { heap->extra_data = kzalloc(sizeof(struct ion_co_heap_pdata), @@ -481,7 +445,6 @@ static struct heap_types_info { MAKE_HEAP_TYPE_MAPPING(CARVEOUT), MAKE_HEAP_TYPE_MAPPING(CHUNK), MAKE_HEAP_TYPE_MAPPING(DMA), - MAKE_HEAP_TYPE_MAPPING(CP), MAKE_HEAP_TYPE_MAPPING(SECURE_DMA), MAKE_HEAP_TYPE_MAPPING(REMOVED), }; @@ -548,13 +511,6 @@ static void msm_ion_get_heap_align(struct device_node *node, int ret = of_property_read_u32(node, "qcom,heap-align", &val); if (!ret) { switch ((int) heap->type) { - case ION_HEAP_TYPE_CP: - { - struct ion_cp_heap_pdata *extra = - heap->extra_data; - extra->align = val; - break; - } case ION_HEAP_TYPE_CARVEOUT: { struct ion_co_heap_pdata *extra = @@ -771,49 +727,73 @@ out: int ion_heap_allow_secure_allocation(enum ion_heap_type type) { - return type == ((enum ion_heap_type) ION_HEAP_TYPE_CP) || - type == ((enum ion_heap_type) ION_HEAP_TYPE_SECURE_DMA); + return type == ((enum ion_heap_type) ION_HEAP_TYPE_SECURE_DMA); } int ion_heap_allow_handle_secure(enum ion_heap_type type) { - return type == ((enum ion_heap_type) ION_HEAP_TYPE_CP) || - type == ((enum ion_heap_type) ION_HEAP_TYPE_SECURE_DMA); + return type == ((enum ion_heap_type) ION_HEAP_TYPE_SECURE_DMA); } int ion_heap_allow_heap_secure(enum ion_heap_type type) { - return type == ((enum ion_heap_type) ION_HEAP_TYPE_CP); + return false; +} + +/* fix up the cases where the ioctl direction bits are incorrect */ +static unsigned int msm_ion_ioctl_dir(unsigned int cmd) +{ + switch (cmd) { + case ION_IOC_CLEAN_CACHES: + case ION_IOC_INV_CACHES: + case ION_IOC_CLEAN_INV_CACHES: + case ION_IOC_PREFETCH: + case ION_IOC_DRAIN: + return _IOC_WRITE; + default: + return _IOC_DIR(cmd); + } } static long msm_ion_custom_ioctl(struct ion_client *client, unsigned int cmd, unsigned long arg) { + unsigned int dir; + union { + struct ion_flush_data flush_data; + struct ion_prefetch_data prefetch_data; + } data; + + dir = msm_ion_ioctl_dir(cmd); + + if (_IOC_SIZE(cmd) > sizeof(data)) + return -EINVAL; + + if (dir & _IOC_WRITE) + if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd))) + return -EFAULT; + switch (cmd) { case ION_IOC_CLEAN_CACHES: case ION_IOC_INV_CACHES: case ION_IOC_CLEAN_INV_CACHES: { - struct ion_flush_data data; unsigned long start, end; struct ion_handle *handle = NULL; int ret; struct mm_struct *mm = current->active_mm; - if (copy_from_user(&data, (void __user *)arg, - sizeof(struct ion_flush_data))) - return -EFAULT; - - if (data.handle > 0) { - handle = ion_handle_get_by_id(client, (int)data.handle); + if (data.flush_data.handle > 0) { + handle = ion_handle_get_by_id(client, + (int)data.flush_data.handle); if (IS_ERR(handle)) { pr_info("%s: Could not find handle: %d\n", - __func__, (int)data.handle); + __func__, (int)data.flush_data.handle); return PTR_ERR(handle); } } else { - handle = ion_import_dma_buf(client, data.fd); + handle = ion_import_dma_buf(client, data.flush_data.fd); if (IS_ERR(handle)) { pr_info("%s: Could not import handle: %p\n", __func__, handle); @@ -823,16 +803,19 @@ static long msm_ion_custom_ioctl(struct ion_client *client, down_read(&mm->mmap_sem); - start = (unsigned long) data.vaddr; - end = (unsigned long) data.vaddr + data.length; + start = (unsigned long) data.flush_data.vaddr; + end = (unsigned long) data.flush_data.vaddr + + data.flush_data.length; if (start && check_vaddr_bounds(start, end)) { pr_err("%s: virtual address %p is out of bounds\n", - __func__, data.vaddr); + __func__, data.flush_data.vaddr); ret = -EINVAL; } else { - ret = ion_do_cache_op(client, handle, data.vaddr, - data.offset, data.length, cmd); + ret = ion_do_cache_op( + client, handle, data.flush_data.vaddr, + data.flush_data.offset, + data.flush_data.length, cmd); } up_read(&mm->mmap_sem); @@ -844,26 +827,16 @@ static long msm_ion_custom_ioctl(struct ion_client *client, } case ION_IOC_PREFETCH: { - struct ion_prefetch_data data; - - if (copy_from_user(&data, (void __user *)arg, - sizeof(struct ion_prefetch_data))) - return -EFAULT; - - ion_walk_heaps(client, data.heap_id, (void *)data.len, - ion_secure_cma_prefetch); + ion_walk_heaps(client, data.prefetch_data.heap_id, + (void *)data.prefetch_data.len, + ion_secure_cma_prefetch); break; } case ION_IOC_DRAIN: { - struct ion_prefetch_data data; - - if (copy_from_user(&data, (void __user *)arg, - sizeof(struct ion_prefetch_data))) - return -EFAULT; - - ion_walk_heaps(client, data.heap_id, (void *)data.len, - ion_secure_cma_drain_pool); + ion_walk_heaps(client, data.prefetch_data.heap_id, + (void *)data.prefetch_data.len, + ion_secure_cma_drain_pool); break; } @@ -878,9 +851,6 @@ static struct ion_heap *msm_ion_heap_create(struct ion_platform_heap *heap_data) struct ion_heap *heap = NULL; switch ((int)heap_data->type) { - case ION_HEAP_TYPE_CP: - heap = ion_cp_heap_create(heap_data); - break; #ifdef CONFIG_CMA case ION_HEAP_TYPE_DMA: heap = ion_cma_heap_create(heap_data); @@ -917,9 +887,6 @@ static void msm_ion_heap_destroy(struct ion_heap *heap) return; switch ((int)heap->type) { - case ION_HEAP_TYPE_CP: - ion_cp_heap_destroy(heap); - break; #ifdef CONFIG_CMA case ION_HEAP_TYPE_DMA: ion_cma_heap_destroy(heap); diff --git a/drivers/staging/android/ion/msm/msm_ion.h b/drivers/staging/android/ion/msm/msm_ion.h new file mode 100644 index 00000000000..b7bde0dd6eb --- /dev/null +++ b/drivers/staging/android/ion/msm/msm_ion.h @@ -0,0 +1,267 @@ +#ifndef _MSM_MSM_ION_H +#define _MSM_MSM_ION_H + +#include "../ion.h" +#include "../../uapi/linux/msm_ion.h" + +enum ion_permission_type { + IPT_TYPE_MM_CARVEOUT = 0, + IPT_TYPE_MFC_SHAREDMEM = 1, + IPT_TYPE_MDP_WRITEBACK = 2, +}; + +/* + * This flag allows clients when mapping into the IOMMU to specify to + * defer un-mapping from the IOMMU until the buffer memory is freed. + */ +#define ION_IOMMU_UNMAP_DELAYED 1 + +/* + * This flag allows clients to defer unsecuring a buffer until the buffer + * is actually freed. + */ +#define ION_UNSECURE_DELAYED 1 + +/** + * struct ion_cp_heap_pdata - defines a content protection heap in the given + * platform + * @permission_type: Memory ID used to identify the memory to TZ + * @align: Alignment requirement for the memory + * @secure_base: Base address for securing the heap. + * Note: This might be different from actual base address + * of this heap in the case of a shared heap. + * @secure_size: Memory size for securing the heap. + * Note: This might be different from actual size + * of this heap in the case of a shared heap. + * @fixed_position If nonzero, position in the fixed area. + * @iommu_map_all: Indicates whether we should map whole heap into IOMMU. + * @iommu_2x_map_domain: Indicates the domain to use for overmapping. + * @request_ion_region: function to be called when the number of allocations + * goes from 0 -> 1 + * @release_ion_region: function to be called when the number of allocations + * goes from 1 -> 0 + * @setup_ion_region: function to be called upon ion registration + * @allow_nonsecure_alloc: allow non-secure allocations from this heap. For + * secure heaps, this flag must be set so allow non-secure + * allocations. For non-secure heaps, this flag is ignored. + * + */ +struct ion_cp_heap_pdata { + enum ion_permission_type permission_type; + unsigned int align; + ion_phys_addr_t secure_base; /* Base addr used when heap is shared */ + size_t secure_size; /* Size used for securing heap when heap is shared*/ + int is_cma; + enum ion_fixed_position fixed_position; + int iommu_map_all; + int iommu_2x_map_domain; + int (*request_ion_region)(void *); + int (*release_ion_region)(void *); + void *(*setup_ion_region)(void); + int allow_nonsecure_alloc; +}; + +/** + * struct ion_co_heap_pdata - defines a carveout heap in the given platform + * @adjacent_mem_id: Id of heap that this heap must be adjacent to. + * @align: Alignment requirement for the memory + * @fixed_position If nonzero, position in the fixed area. + * @request_ion_region: function to be called when the number of allocations + * goes from 0 -> 1 + * @release_ion_region: function to be called when the number of allocations + * goes from 1 -> 0 + * @setup_ion_region: function to be called upon ion registration + * @memory_type:Memory type used for the heap + * + */ +struct ion_co_heap_pdata { + int adjacent_mem_id; + unsigned int align; + enum ion_fixed_position fixed_position; + int (*request_ion_region)(void *); + int (*release_ion_region)(void *); + void *(*setup_ion_region)(void); +}; + +/** + * struct ion_cma_pdata - extra data for CMA regions + * @default_prefetch_size - default size to use for prefetching + */ +struct ion_cma_pdata { + unsigned long default_prefetch_size; +}; + +#ifdef CONFIG_ION +/** + * msm_ion_client_create - allocate a client using the ion_device specified in + * drivers/gpu/ion/msm/msm_ion.c + * + * heap_mask and name are the same as ion_client_create, return values + * are the same as ion_client_create. + */ + +struct ion_client *msm_ion_client_create(unsigned int heap_mask, + const char *name); + +/** + * ion_handle_get_flags - get the flags for a given handle + * + * @client - client who allocated the handle + * @handle - handle to get the flags + * @flags - pointer to store the flags + * + * Gets the current flags for a handle. These flags indicate various options + * of the buffer (caching, security, etc.) + */ +int ion_handle_get_flags(struct ion_client *client, struct ion_handle *handle, + unsigned long *flags); + + +/** + * ion_map_iommu - map the given handle into an iommu + * + * @client - client who allocated the handle + * @handle - handle to map + * @domain_num - domain number to map to + * @partition_num - partition number to allocate iova from + * @align - alignment for the iova + * @iova_length - length of iova to map. If the iova length is + * greater than the handle length, the remaining + * address space will be mapped to a dummy buffer. + * @iova - pointer to store the iova address + * @buffer_size - pointer to store the size of the buffer + * @flags - flags for options to map + * @iommu_flags - flags specific to the iommu. + * + * Maps the handle into the iova space specified via domain number. Iova + * will be allocated from the partition specified via partition_num. + * Returns 0 on success, negative value on error. + */ +int ion_map_iommu(struct ion_client *client, struct ion_handle *handle, + int domain_num, int partition_num, unsigned long align, + unsigned long iova_length, ion_phys_addr_t *iova, + unsigned long *buffer_size, + unsigned long flags, unsigned long iommu_flags); + + +/** + * ion_handle_get_size - get the allocated size of a given handle + * + * @client - client who allocated the handle + * @handle - handle to get the size + * @size - pointer to store the size + * + * gives the allocated size of a handle. returns 0 on success, negative + * value on error + * + * NOTE: This is intended to be used only to get a size to pass to map_iommu. + * You should *NOT* rely on this for any other usage. + */ + +int ion_handle_get_size(struct ion_client *client, struct ion_handle *handle, + unsigned long *size); + +/** + * ion_unmap_iommu - unmap the handle from an iommu + * + * @client - client who allocated the handle + * @handle - handle to unmap + * @domain_num - domain to unmap from + * @partition_num - partition to unmap from + * + * Decrement the reference count on the iommu mapping. If the count is + * 0, the mapping will be removed from the iommu. + */ +void ion_unmap_iommu(struct ion_client *client, struct ion_handle *handle, + int domain_num, int partition_num); + +/** + * msm_ion_do_cache_op - do cache operations. + * + * @client - pointer to ION client. + * @handle - pointer to buffer handle. + * @vaddr - virtual address to operate on. + * @len - Length of data to do cache operation on. + * @cmd - Cache operation to perform: + * ION_IOC_CLEAN_CACHES + * ION_IOC_INV_CACHES + * ION_IOC_CLEAN_INV_CACHES + * + * Returns 0 on success + */ +int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, + void *vaddr, unsigned long len, unsigned int cmd); + +/** + * msm_ion_secure_buffer - secure an individual buffer + * + * @client - client who has access to the buffer + * @handle - buffer to secure + * @usage - usage hint to TZ + * @flags - flags for the securing + */ +int msm_ion_secure_buffer(struct ion_client *client, struct ion_handle *handle, + enum cp_mem_usage usage, int flags); + +/** + * msm_ion_unsecure_buffer - unsecure an individual buffer + * + * @client - client who has access to the buffer + * @handle - buffer to secure + */ +int msm_ion_unsecure_buffer(struct ion_client *client, + struct ion_handle *handle); +#else +static inline struct ion_client *msm_ion_client_create(unsigned int heap_mask, + const char *name) +{ + return ERR_PTR(-ENODEV); +} + +static inline int ion_map_iommu(struct ion_client *client, + struct ion_handle *handle, int domain_num, + int partition_num, unsigned long align, + unsigned long iova_length, ion_phys_addr_t *iova, + unsigned long *buffer_size, + unsigned long flags, + unsigned long iommu_flags) +{ + return -ENODEV; +} + +static inline int ion_handle_get_size(struct ion_client *client, + struct ion_handle *handle, unsigned long *size) +{ + return -ENODEV; +} + +static inline void ion_unmap_iommu(struct ion_client *client, + struct ion_handle *handle, int domain_num, + int partition_num) +{ + return; +} + +static inline int msm_ion_do_cache_op(struct ion_client *client, + struct ion_handle *handle, void *vaddr, + unsigned long len, unsigned int cmd) +{ + return -ENODEV; +} + +static inline int msm_ion_secure_buffer(struct ion_client *client, + struct ion_handle *handle, + enum cp_mem_usage usage, + int flags) +{ + return -ENODEV; +} + +static inline int msm_ion_unsecure_buffer(struct ion_client *client, + struct ion_handle *handle) +{ + return -ENODEV; +} +#endif /* CONFIG_ION */ + +#endif diff --git a/drivers/gpu/ion/msm/secure_buffer.c b/drivers/staging/android/ion/msm/secure_buffer.c index c492ec3245e..7dc2032d6fd 100644 --- a/drivers/gpu/ion/msm/secure_buffer.c +++ b/drivers/staging/android/ion/msm/secure_buffer.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2011 Google, Inc - * Copyright (c) 2011-2013, 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 @@ -20,8 +20,8 @@ #include <linux/mutex.h> #include <linux/scatterlist.h> #include <linux/slab.h> +#include <soc/qcom/scm.h> -#include <mach/scm.h> static struct rb_root secure_root; DEFINE_MUTEX(secure_buffer_mutex); diff --git a/drivers/gpu/ion/msm_ion_priv.h b/drivers/staging/android/ion/msm_ion_priv.h index 3225f1a6506..9408e4ec138 100644 --- a/drivers/gpu/ion/msm_ion_priv.h +++ b/drivers/staging/android/ion/msm_ion_priv.h @@ -2,7 +2,7 @@ * drivers/gpu/ion/ion_priv.h * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and diff --git a/drivers/gpu/ion/tegra/Makefile b/drivers/staging/android/ion/tegra/Makefile index 11cd003fb08..11cd003fb08 100644 --- a/drivers/gpu/ion/tegra/Makefile +++ b/drivers/staging/android/ion/tegra/Makefile diff --git a/drivers/gpu/ion/tegra/tegra_ion.c b/drivers/staging/android/ion/tegra/tegra_ion.c index 7af6e168ff4..0849600bcc0 100644 --- a/drivers/gpu/ion/tegra/tegra_ion.c +++ b/drivers/staging/android/ion/tegra/tegra_ion.c @@ -15,9 +15,9 @@ */ #include <linux/err.h> -#include <linux/ion.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include "../ion.h" #include "../ion_priv.h" struct ion_device *idev; diff --git a/drivers/staging/android/uapi/Kbuild b/drivers/staging/android/uapi/Kbuild new file mode 100644 index 00000000000..c9a138f17b7 --- /dev/null +++ b/drivers/staging/android/uapi/Kbuild @@ -0,0 +1 @@ +header-y += linux/ diff --git a/drivers/staging/android/uapi/ion_test.h b/drivers/staging/android/uapi/ion_test.h new file mode 100644 index 00000000000..614d1e36f72 --- /dev/null +++ b/drivers/staging/android/uapi/ion_test.h @@ -0,0 +1,69 @@ +/* + * drivers/staging/android/uapi/ion.h + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _UAPI_LINUX_ION_TEST_H +#define _UAPI_LINUX_ION_TEST_H + +#include <linux/ioctl.h> +#include <linux/types.h> + +/** + * struct ion_test_rw_data - metadata passed to the kernel to read handle + * @ptr: a pointer to an area at least as large as size + * @offset: offset into the ion buffer to start reading + * @size: size to read or write + * @write: 1 to write, 0 to read + */ +struct ion_test_rw_data { + __u64 ptr; + __u64 offset; + __u64 size; + int write; +}; + +#define ION_IOC_MAGIC 'I' + +/** + * DOC: ION_IOC_TEST_SET_DMA_BUF - attach a dma buf to the test driver + * + * Attaches a dma buf fd to the test driver. Passing a second fd or -1 will + * release the first fd. + */ +#define ION_IOC_TEST_SET_FD \ + _IO(ION_IOC_MAGIC, 0xf0) + +/** + * DOC: ION_IOC_TEST_DMA_MAPPING - read or write memory from a handle as DMA + * + * Reads or writes the memory from a handle using an uncached mapping. Can be + * used by unit tests to emulate a DMA engine as close as possible. Only + * expected to be used for debugging and testing, may not always be available. + */ +#define ION_IOC_TEST_DMA_MAPPING \ + _IOW(ION_IOC_MAGIC, 0xf1, struct ion_test_rw_data) + +/** + * DOC: ION_IOC_TEST_KERNEL_MAPPING - read or write memory from a handle + * + * Reads or writes the memory from a handle using a kernel mapping. Can be + * used by unit tests to test heap map_kernel functions. Only expected to be + * used for debugging and testing, may not always be available. + */ +#define ION_IOC_TEST_KERNEL_MAPPING \ + _IOW(ION_IOC_MAGIC, 0xf2, struct ion_test_rw_data) + + +#endif /* _UAPI_LINUX_ION_H */ diff --git a/drivers/staging/android/uapi/linux/Kbuild b/drivers/staging/android/uapi/linux/Kbuild new file mode 100644 index 00000000000..67358c786f4 --- /dev/null +++ b/drivers/staging/android/uapi/linux/Kbuild @@ -0,0 +1,2 @@ +header-y += ion.h +header-y += msm_ion.h diff --git a/drivers/staging/android/uapi/linux/ion.h b/drivers/staging/android/uapi/linux/ion.h new file mode 100644 index 00000000000..19d57ecde9e --- /dev/null +++ b/drivers/staging/android/uapi/linux/ion.h @@ -0,0 +1,198 @@ +/* + * include/linux/ion.h + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _UAPI_ION_H +#define _UAPI_ION_H + +#include <linux/ioctl.h> +#include <linux/types.h> + +typedef int ion_user_handle_t; + +/** + * enum ion_heap_types - list of all possible types of heaps + * @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc + * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc + * @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved + * carveout heap, allocations are physically + * contiguous + * @ION_HEAP_END: helper for iterating over heaps + */ +enum ion_heap_type { + ION_HEAP_TYPE_SYSTEM, + ION_HEAP_TYPE_SYSTEM_CONTIG, + ION_HEAP_TYPE_CARVEOUT, + ION_HEAP_TYPE_CHUNK, + ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always + are at the end of this enum */ + ION_NUM_HEAPS, +}; + +#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM) +#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG) +#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT) + +#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8 + +/** + * allocation flags - the lower 16 bits are used by core ion, the upper 16 + * bits are reserved for use by the heaps themselves. + */ +#define ION_FLAG_CACHED 1 /* mappings of this buffer should be + cached, ion will do cache + maintenance when the buffer is + mapped for dma */ +#define ION_FLAG_CACHED_NEEDS_SYNC 2 /* mappings of this buffer will created + at mmap time, if this is set + caches must be managed manually */ +#define ION_FLAG_FREED_FROM_SHRINKER 4 /* Skip any possible + heap-specific caching + mechanism (e.g. page + pools). Guarantees that any + buffer storage that came + from the system allocator + will be returned to the + system allocator. */ + +/** + * DOC: Ion Userspace API + * + * create a client by opening /dev/ion + * most operations handled via following ioctls + * + */ + +/** + * struct ion_allocation_data - metadata passed from userspace for allocations + * @len: size of the allocation + * @align: required alignment of the allocation + * @heap_id_mask: mask of heap ids to allocate from + * @flags: flags passed to heap + * @handle: pointer that will be populated with a cookie to use to + * refer to this allocation + * + * Provided by userspace as an argument to the ioctl + */ +struct ion_allocation_data { + size_t len; + size_t align; + unsigned int heap_mask; + unsigned int flags; + ion_user_handle_t handle; +}; + +/** + * struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair + * @handle: a handle + * @fd: a file descriptor representing that handle + * + * For ION_IOC_SHARE or ION_IOC_MAP userspace populates the handle field with + * the handle returned from ion alloc, and the kernel returns the file + * descriptor to share or map in the fd field. For ION_IOC_IMPORT, userspace + * provides the file descriptor and the kernel returns the handle. + */ +struct ion_fd_data { + ion_user_handle_t handle; + int fd; +}; + +/** + * struct ion_handle_data - a handle passed to/from the kernel + * @handle: a handle + */ +struct ion_handle_data { + ion_user_handle_t handle; +}; + +/** + * struct ion_custom_data - metadata passed to/from userspace for a custom ioctl + * @cmd: the custom ioctl function to call + * @arg: additional data to pass to the custom ioctl, typically a user + * pointer to a predefined structure + * + * This works just like the regular cmd and arg fields of an ioctl. + */ +struct ion_custom_data { + unsigned int cmd; + unsigned long arg; +}; +#define ION_IOC_MAGIC 'I' + +/** + * DOC: ION_IOC_ALLOC - allocate memory + * + * Takes an ion_allocation_data struct and returns it with the handle field + * populated with the opaque handle for the allocation. + */ +#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ + struct ion_allocation_data) + +/** + * DOC: ION_IOC_FREE - free memory + * + * Takes an ion_handle_data struct and frees the handle. + */ +#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data) + +/** + * DOC: ION_IOC_MAP - get a file descriptor to mmap + * + * Takes an ion_fd_data struct with the handle field populated with a valid + * opaque handle. Returns the struct with the fd field set to a file + * descriptor open in the current address space. This file descriptor + * can then be used as an argument to mmap. + */ +#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data) + +/** + * DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation + * + * Takes an ion_fd_data struct with the handle field populated with a valid + * opaque handle. Returns the struct with the fd field set to a file + * descriptor open in the current address space. This file descriptor + * can then be passed to another process. The corresponding opaque handle can + * be retrieved via ION_IOC_IMPORT. + */ +#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data) + +/** + * DOC: ION_IOC_IMPORT - imports a shared file descriptor + * + * Takes an ion_fd_data struct with the fd field populated with a valid file + * descriptor obtained from ION_IOC_SHARE and returns the struct with the handle + * filed set to the corresponding opaque handle. + */ +#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data) + +/** + * DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory + * + * Deprecated in favor of using the dma_buf api's correctly (syncing + * will happend automatically when the buffer is mapped to a device). + * If necessary should be used after touching a cached buffer from the cpu, + * this will make the buffer in memory coherent. + */ +#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data) + +/** + * DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl + * + * Takes the argument of the architecture specific ioctl to call and + * passes appropriate userdata for that ioctl + */ +#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data) + +#endif /* _UAPI_ION_H */ diff --git a/drivers/staging/android/uapi/linux/msm_ion.h b/drivers/staging/android/uapi/linux/msm_ion.h new file mode 100644 index 00000000000..905e8d7db5e --- /dev/null +++ b/drivers/staging/android/uapi/linux/msm_ion.h @@ -0,0 +1,176 @@ +#ifndef _UAPI_MSM_ION_H +#define _UAPI_MSM_ION_H + +#include "ion.h" + +enum msm_ion_heap_types { + ION_HEAP_TYPE_MSM_START = ION_HEAP_TYPE_CUSTOM + 1, + ION_HEAP_TYPE_DMA = ION_HEAP_TYPE_MSM_START, + ION_HEAP_TYPE_SECURE_DMA, + ION_HEAP_TYPE_REMOVED, + /* + * if you add a heap type here you should also add it to + * heap_types_info[] in msm_ion.c + */ +}; + +/** + * These are the only ids that should be used for Ion heap ids. + * The ids listed are the order in which allocation will be attempted + * if specified. Don't swap the order of heap ids unless you know what + * you are doing! + * Id's are spaced by purpose to allow new Id's to be inserted in-between (for + * possible fallbacks) + */ + +enum ion_heap_ids { + INVALID_HEAP_ID = -1, + ION_CP_MM_HEAP_ID = 8, + ION_CP_MFC_HEAP_ID = 12, + ION_CP_WB_HEAP_ID = 16, /* 8660 only */ + ION_CAMERA_HEAP_ID = 20, /* 8660 only */ + ION_SYSTEM_CONTIG_HEAP_ID = 21, + ION_ADSP_HEAP_ID = 22, + ION_PIL1_HEAP_ID = 23, /* Currently used for other PIL images */ + ION_SF_HEAP_ID = 24, + ION_SYSTEM_HEAP_ID = 25, + ION_PIL2_HEAP_ID = 26, /* Currently used for modem firmware images */ + ION_QSECOM_HEAP_ID = 27, + ION_AUDIO_HEAP_ID = 28, + + ION_MM_FIRMWARE_HEAP_ID = 29, + + ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_FLAG_SECURE flag */ +}; + +/* + * The IOMMU heap is deprecated! Here are some aliases for backwards + * compatibility: + */ +#define ION_IOMMU_HEAP_ID ION_SYSTEM_HEAP_ID +#define ION_HEAP_TYPE_IOMMU ION_HEAP_TYPE_SYSTEM + +enum ion_fixed_position { + NOT_FIXED, + FIXED_LOW, + FIXED_MIDDLE, + FIXED_HIGH, +}; + +enum cp_mem_usage { + VIDEO_BITSTREAM = 0x1, + VIDEO_PIXEL = 0x2, + VIDEO_NONPIXEL = 0x3, + MAX_USAGE = 0x4, + UNKNOWN = 0x7FFFFFFF, +}; + +#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA) + +/** + * Flag to use when allocating to indicate that a heap is secure. + */ +#define ION_FLAG_SECURE (1 << ION_HEAP_ID_RESERVED) + +/** + * Flag for clients to force contiguous memort allocation + * + * Use of this flag is carefully monitored! + */ +#define ION_FLAG_FORCE_CONTIGUOUS (1 << 30) + +/* + * Used in conjunction with heap which pool memory to force an allocation + * to come from the page allocator directly instead of from the pool allocation + */ +#define ION_FLAG_POOL_FORCE_ALLOC (1 << 16) + +/** +* Deprecated! Please use the corresponding ION_FLAG_* +*/ +#define ION_SECURE ION_FLAG_SECURE +#define ION_FORCE_CONTIGUOUS ION_FLAG_FORCE_CONTIGUOUS + +/** + * Macro should be used with ion_heap_ids defined above. + */ +#define ION_HEAP(bit) (1 << (bit)) + +#define ION_ADSP_HEAP_NAME "adsp" +#define ION_SYSTEM_HEAP_NAME "system" +#define ION_VMALLOC_HEAP_NAME ION_SYSTEM_HEAP_NAME +#define ION_KMALLOC_HEAP_NAME "kmalloc" +#define ION_AUDIO_HEAP_NAME "audio" +#define ION_SF_HEAP_NAME "sf" +#define ION_MM_HEAP_NAME "mm" +#define ION_CAMERA_HEAP_NAME "camera_preview" +#define ION_IOMMU_HEAP_NAME "iommu" +#define ION_MFC_HEAP_NAME "mfc" +#define ION_WB_HEAP_NAME "wb" +#define ION_MM_FIRMWARE_HEAP_NAME "mm_fw" +#define ION_PIL1_HEAP_NAME "pil_1" +#define ION_PIL2_HEAP_NAME "pil_2" +#define ION_QSECOM_HEAP_NAME "qsecom" + +#define ION_SET_CACHED(__cache) (__cache | ION_FLAG_CACHED) +#define ION_SET_UNCACHED(__cache) (__cache & ~ION_FLAG_CACHED) + +#define ION_IS_CACHED(__flags) ((__flags) & ION_FLAG_CACHED) + +/* struct ion_flush_data - data passed to ion for flushing caches + * + * @handle: handle with data to flush + * @fd: fd to flush + * @vaddr: userspace virtual address mapped with mmap + * @offset: offset into the handle to flush + * @length: length of handle to flush + * + * Performs cache operations on the handle. If p is the start address + * of the handle, p + offset through p + offset + length will have + * the cache operations performed + */ +struct ion_flush_data { + ion_user_handle_t handle; + int fd; + void *vaddr; + unsigned int offset; + unsigned int length; +}; + + +struct ion_prefetch_data { + int heap_id; + unsigned long len; +}; + +#define ION_IOC_MSM_MAGIC 'M' + +/** + * DOC: ION_IOC_CLEAN_CACHES - clean the caches + * + * Clean the caches of the handle specified. + */ +#define ION_IOC_CLEAN_CACHES _IOWR(ION_IOC_MSM_MAGIC, 0, \ + struct ion_flush_data) +/** + * DOC: ION_IOC_INV_CACHES - invalidate the caches + * + * Invalidate the caches of the handle specified. + */ +#define ION_IOC_INV_CACHES _IOWR(ION_IOC_MSM_MAGIC, 1, \ + struct ion_flush_data) +/** + * DOC: ION_IOC_CLEAN_INV_CACHES - clean and invalidate the caches + * + * Clean and invalidate the caches of the handle specified. + */ +#define ION_IOC_CLEAN_INV_CACHES _IOWR(ION_IOC_MSM_MAGIC, 2, \ + struct ion_flush_data) + +#define ION_IOC_PREFETCH _IOWR(ION_IOC_MSM_MAGIC, 3, \ + struct ion_prefetch_data) + +#define ION_IOC_DRAIN _IOWR(ION_IOC_MSM_MAGIC, 4, \ + struct ion_prefetch_data) + +#endif diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 87d2beba820..ffe06be75c6 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -40,6 +40,8 @@ #define MAX_RAILS 5 #define MAX_THRESHOLD 2 #define MONITOR_ALL_TSENS -1 +#define TSENS_NAME_MAX 20 +#define TSENS_NAME_FORMAT "tsens_tz_sensor%d" static struct msm_thermal_data msm_thermal_info; static struct delayed_work check_temp_work; @@ -98,9 +100,16 @@ enum thermal_threshold { THRESHOLD_MAX_NR, }; +enum sensor_id_type { + THERM_ZONE_ID, + THERM_TSENS_ID, + THERM_ID_MAX_NR, +}; + struct cpu_info { uint32_t cpu; const char *sensor_type; + enum sensor_id_type id_type; uint32_t sensor_id; bool offline; bool user_offline; @@ -117,6 +126,7 @@ struct cpu_info { struct threshold_info; struct therm_threshold { int32_t sensor_id; + enum sensor_id_type id_type; struct sensor_threshold threshold[MAX_THRESHOLD]; int32_t trip_triggered; void (*notify)(struct therm_threshold *); @@ -858,31 +868,63 @@ set_done: return ret; } -static int set_threshold(uint32_t sensor_id, - struct sensor_threshold *threshold) +static int therm_get_temp(uint32_t id, enum sensor_id_type type, long *temp) { + int ret = 0; struct tsens_device tsens_dev; + + if (!temp) { + pr_err("Invalid value\n"); + ret = -EINVAL; + goto get_temp_exit; + } + + switch (type) { + case THERM_ZONE_ID: + tsens_dev.sensor_num = tsens_id_map[id]; + break; + case THERM_TSENS_ID: + tsens_dev.sensor_num = id; + break; + default: + pr_err("Invalid type\n"); + ret = -EINVAL; + goto get_temp_exit; + break; + } + + ret = tsens_get_temp(&tsens_dev, temp); + if (ret) { + pr_err("Unable to read TSENS sensor %d\n", + tsens_dev.sensor_num); + goto get_temp_exit; + } + +get_temp_exit: + return ret; +} + +static int set_threshold(uint32_t zone_id, + struct sensor_threshold *threshold) +{ int i = 0, ret = 0; long temp; - if ((!threshold) || check_sensor_id(sensor_id)) { + if ((!threshold) || (zone_id >= max_tsens_num)) { pr_err("%s: Invalid input\n", KBUILD_MODNAME); ret = -EINVAL; goto set_threshold_exit; } - tsens_dev.sensor_num = sensor_id; - ret = tsens_get_temp(&tsens_dev, &temp); - if (ret) { - pr_err("%s: Unable to read TSENS sensor %d\n", - KBUILD_MODNAME, tsens_dev.sensor_num); + ret = therm_get_temp(zone_id, THERM_ZONE_ID, &temp); + if (ret) goto set_threshold_exit; - } + while (i < MAX_THRESHOLD) { switch (threshold[i].trip) { case THERMAL_TRIP_CONFIGURABLE_HI: if (threshold[i].temp >= temp) { - ret = set_and_activate_threshold(sensor_id, + ret = set_and_activate_threshold(zone_id, &threshold[i]); if (ret) goto set_threshold_exit; @@ -890,7 +932,7 @@ static int set_threshold(uint32_t sensor_id, break; case THERMAL_TRIP_CONFIGURABLE_LOW: if (threshold[i].temp <= temp) { - ret = set_and_activate_threshold(sensor_id, + ret = set_and_activate_threshold(zone_id, &threshold[i]); if (ret) goto set_threshold_exit; @@ -1026,7 +1068,6 @@ static __ref int do_hotplug(void *data) static int do_gfx_phase_cond(void) { - struct tsens_device tsens_dev; long temp = 0; int ret = 0; uint32_t new_req_band = curr_gfx_band; @@ -1035,12 +1076,14 @@ static int do_gfx_phase_cond(void) return ret; mutex_lock(&gfx_mutex); - tsens_dev.sensor_num = - thresh[MSM_GFX_PHASE_CTRL_WARM].thresh_list->sensor_id; - ret = tsens_get_temp(&tsens_dev, &temp); + ret = therm_get_temp( + thresh[MSM_GFX_PHASE_CTRL_WARM].thresh_list->sensor_id, + thresh[MSM_GFX_PHASE_CTRL_WARM].thresh_list->id_type, + &temp); if (ret) { pr_err("%s: Unable to read TSENS sensor %d\n", - KBUILD_MODNAME, tsens_dev.sensor_num); + KBUILD_MODNAME, + thresh[MSM_GFX_PHASE_CTRL_WARM].thresh_list->sensor_id); goto gfx_phase_cond_exit; } @@ -1084,7 +1127,6 @@ gfx_phase_cond_exit: static int do_cx_phase_cond(void) { - struct tsens_device tsens_dev; long temp = 0; int i, ret = 0, dis_cnt = 0; @@ -1092,12 +1134,14 @@ static int do_cx_phase_cond(void) return ret; mutex_lock(&cx_mutex); - for (i = 0; i < max_tsens_num; i++) { - tsens_dev.sensor_num = tsens_id_map[i]; - ret = tsens_get_temp(&tsens_dev, &temp); + for (i = 0; i < thresh[MSM_CX_PHASE_CTRL_HOT].thresh_ct; i++) { + ret = therm_get_temp( + thresh[MSM_CX_PHASE_CTRL_HOT].thresh_list[i].sensor_id, + thresh[MSM_CX_PHASE_CTRL_HOT].thresh_list[i].id_type, + &temp); if (ret) { - pr_err("%s: Unable to read TSENS sensor %d\n", - KBUILD_MODNAME, tsens_dev.sensor_num); + pr_err("Unable to read TSENS sensor %d\n", + thresh[MSM_CX_PHASE_CTRL_HOT].thresh_list[i].sensor_id); dis_cnt++; continue; } @@ -1126,7 +1170,6 @@ cx_phase_cond_exit: static int do_vdd_restriction(void) { - struct tsens_device tsens_dev; long temp = 0; int ret = 0; int i = 0; @@ -1141,12 +1184,14 @@ static int do_vdd_restriction(void) } mutex_lock(&vdd_rstr_mutex); - for (i = 0; i < max_tsens_num; i++) { - tsens_dev.sensor_num = tsens_id_map[i]; - ret = tsens_get_temp(&tsens_dev, &temp); + for (i = 0; i < thresh[MSM_VDD_RESTRICTION].thresh_ct; i++) { + ret = therm_get_temp( + thresh[MSM_VDD_RESTRICTION].thresh_list[i].sensor_id, + thresh[MSM_VDD_RESTRICTION].thresh_list[i].id_type, + &temp); if (ret) { - pr_debug("%s: Unable to read TSENS sensor %d\n", - __func__, tsens_dev.sensor_num); + pr_debug("Unable to read TSENS sensor %d\n", + thresh[MSM_VDD_RESTRICTION].thresh_list[i].sensor_id); dis_cnt++; continue; } @@ -1175,7 +1220,6 @@ exit: static int do_psm(void) { - struct tsens_device tsens_dev; long temp = 0; int ret = 0; int i = 0; @@ -1183,11 +1227,10 @@ static int do_psm(void) mutex_lock(&psm_mutex); for (i = 0; i < max_tsens_num; i++) { - tsens_dev.sensor_num = tsens_id_map[i]; - ret = tsens_get_temp(&tsens_dev, &temp); + ret = therm_get_temp(tsens_id_map[i], THERM_TSENS_ID, &temp); if (ret) { pr_debug("%s: Unable to read TSENS sensor %d\n", - __func__, tsens_dev.sensor_num); + __func__, tsens_id_map[i]); auto_cnt++; continue; } @@ -1264,15 +1307,13 @@ static void do_freq_control(long temp) static void check_temp(struct work_struct *work) { static int limit_init; - struct tsens_device tsens_dev; long temp = 0; int ret = 0; - tsens_dev.sensor_num = msm_thermal_info.sensor_id; - ret = tsens_get_temp(&tsens_dev, &temp); + ret = therm_get_temp(msm_thermal_info.sensor_id, THERM_TSENS_ID, &temp); if (ret) { - pr_debug("%s: Unable to read TSENS sensor %d\n", - KBUILD_MODNAME, tsens_dev.sensor_num); + pr_debug("Unable to read TSENS sensor %d\n", + msm_thermal_info.sensor_id); goto reschedule; } do_core_control(temp); @@ -1351,7 +1392,6 @@ static int hotplug_notify(enum thermal_trip_type type, int temp, void *data) /* Adjust cpus offlined bit based on temperature reading. */ static int hotplug_init_cpu_offlined(void) { - struct tsens_device tsens_dev; long temp = 0; uint32_t cpu = 0; @@ -1362,10 +1402,10 @@ static int hotplug_init_cpu_offlined(void) for_each_possible_cpu(cpu) { if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu))) continue; - tsens_dev.sensor_num = cpus[cpu].sensor_id; - if (tsens_get_temp(&tsens_dev, &temp)) { + if (therm_get_temp(cpus[cpu].sensor_id, cpus[cpu].id_type, + &temp)) { pr_err("%s: Unable to read TSENS sensor %d\n", - KBUILD_MODNAME, tsens_dev.sensor_num); + KBUILD_MODNAME, cpus[cpu].sensor_id); mutex_unlock(&core_control_mutex); return -EINVAL; } @@ -1402,6 +1442,7 @@ static void hotplug_init(void) for_each_possible_cpu(cpu) { cpus[cpu].sensor_id = sensor_get_id((char *)cpus[cpu].sensor_type); + cpus[cpu].id_type = THERM_ZONE_ID; if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu))) continue; @@ -1810,6 +1851,40 @@ static __ref int do_thermal_monitor(void *data) return ret; } +static int convert_to_zone_id(struct threshold_info *thresh_inp) +{ + int ret = 0, i, zone_id; + struct therm_threshold *thresh_array; + + if (!thresh_inp) { + pr_err("Invalid input\n"); + ret = -EINVAL; + goto convert_to_exit; + } + thresh_array = thresh_inp->thresh_list; + + for (i = 0; i < thresh_inp->thresh_ct; i++) { + char tsens_name[TSENS_NAME_MAX] = ""; + + if (thresh_array[i].id_type == THERM_ZONE_ID) + continue; + snprintf(tsens_name, TSENS_NAME_MAX, TSENS_NAME_FORMAT, + thresh_array[i].sensor_id); + zone_id = sensor_get_id(tsens_name); + if (zone_id < 0) { + pr_err("Error getting zone id for %s. err:%d\n", + tsens_name, ret); + ret = zone_id; + goto convert_to_exit; + } + thresh_array[i].sensor_id = zone_id; + thresh_array[i].id_type = THERM_ZONE_ID; + } + +convert_to_exit: + return ret; +} + static void thermal_monitor_init(void) { if (thermal_monitor_task) @@ -1824,11 +1899,17 @@ static void thermal_monitor_init(void) goto init_exit; } - if (cx_phase_ctrl_enabled) + if ((cx_phase_ctrl_enabled) && + !(convert_to_zone_id(&thresh[MSM_CX_PHASE_CTRL_HOT]))) therm_set_threshold(&thresh[MSM_CX_PHASE_CTRL_HOT]); - if (vdd_rstr_enabled) + + if ((vdd_rstr_enabled) && + !(convert_to_zone_id(&thresh[MSM_VDD_RESTRICTION]))) therm_set_threshold(&thresh[MSM_VDD_RESTRICTION]); - if (gfx_phase_ctrl_enabled) { + + if ((gfx_phase_ctrl_enabled) && + !(convert_to_zone_id(&thresh[MSM_GFX_PHASE_CTRL_WARM])) && + !(convert_to_zone_id(&thresh[MSM_GFX_PHASE_CTRL_HOT]))) { therm_set_threshold(&thresh[MSM_GFX_PHASE_CTRL_WARM]); therm_set_threshold(&thresh[MSM_GFX_PHASE_CTRL_HOT]); } @@ -1888,6 +1969,7 @@ static int init_threshold(enum msm_thresh_list index, if (sensor_id == MONITOR_ALL_TSENS) { for (i = 0; i < max_tsens_num; i++) { thresh_ptr[i].sensor_id = tsens_id_map[i]; + thresh_ptr[i].id_type = THERM_TSENS_ID; thresh_ptr[i].notify = callback; thresh_ptr[i].trip_triggered = -1; thresh_ptr[i].parent = &thresh[index]; @@ -1905,6 +1987,7 @@ static int init_threshold(enum msm_thresh_list index, } } else { thresh_ptr->sensor_id = sensor_id; + thresh_ptr->id_type = THERM_TSENS_ID; thresh_ptr->notify = callback; thresh_ptr->trip_triggered = -1; thresh_ptr->parent = &thresh[index]; @@ -2727,8 +2810,8 @@ static int probe_cc(struct device_node *node, struct msm_thermal_data *data, key = "qcom,cpu-sensors"; cpu_cnt = of_property_count_strings(node, key); - if (cpu_cnt != num_possible_cpus()) { - pr_err("%s: Wrong number of cpu\n", KBUILD_MODNAME); + if (cpu_cnt < num_possible_cpus()) { + pr_err("%s: Wrong number of cpu sensors\n", KBUILD_MODNAME); ret = -EINVAL; goto hotplug_node_fail; } diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c index 6ac93d4c669..7365871d957 100644 --- a/drivers/tty/n_smux.c +++ b/drivers/tty/n_smux.c @@ -26,8 +26,8 @@ #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/ipc_logging.h> -#include <mach/subsystem_notif.h> -#include <mach/subsystem_restart.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/subsystem_notif.h> #include <mach/msm_serial_hs.h> #include "smux_private.h" #include "smux_loopback.h" diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index 5f770d0a5c3..435c0e6c0c1 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -3,7 +3,7 @@ * MSM 7k High speed uart driver * * Copyright (c) 2008 Google Inc. - * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2007-2014, The Linux Foundation. All rights reserved. * Modified: Nick Pelly <npelly@google.com> * * All source code in this file is licensed under the following license @@ -447,11 +447,12 @@ static void msm_hs_clock_unvote(struct msm_hs_port *msm_uport) rc = atomic_dec_return(&msm_uport->clk_count); if (0 == rc) { - msm_hs_bus_voting(msm_uport, BUS_RESET); /* Turn off the core clk and iface clk*/ clk_disable_unprepare(msm_uport->clk); if (msm_uport->pclk) clk_disable_unprepare(msm_uport->pclk); + /* Unvote the PNOC clock */ + msm_hs_bus_voting(msm_uport, BUS_RESET); msm_uport->clk_state = MSM_HS_CLK_OFF; } } @@ -593,23 +594,24 @@ static void hex_dump_ipc(char *prefix, char *string, int size) */ static void dump_uart_hs_registers(struct msm_hs_port *msm_uport) { - msm_hs_clock_vote(msm_uport); - MSM_HS_DBG("============= UART Registers ================\n"); - MSM_HS_DBG("UART_DM_MR1:%x\n", msm_hs_read(&(msm_uport->uport), + struct uart_port *uport = &(msm_uport->uport); + if (msm_uport->clk_state != MSM_HS_CLK_ON) { + MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__); + return; + } + MSM_HS_DBG("UART_DM_MR1:%x\n", msm_hs_read(uport, UART_DM_MR1)); - MSM_HS_DBG("UART_DM_MR2:%x\n", msm_hs_read(&(msm_uport->uport), + MSM_HS_DBG("UART_DM_MR2:%x\n", msm_hs_read(uport, UART_DM_MR2)); - MSM_HS_DBG("UART_DM_IPR:%x\n", msm_hs_read(&(msm_uport->uport), + MSM_HS_DBG("UART_DM_IPR:%x\n", msm_hs_read(uport, UART_DM_IPR)); - MSM_HS_DBG("UART_DM_RFWR:%x\n", msm_hs_read(&(msm_uport->uport), + MSM_HS_DBG("UART_DM_RFWR:%x\n", msm_hs_read(uport, UART_DM_RFWR)); - MSM_HS_DBG("UART_DM_SR:%x\n", msm_hs_read(&(msm_uport->uport), + MSM_HS_DBG("UART_DM_SR:%x\n", msm_hs_read(uport, UART_DM_SR)); - MSM_HS_DBG("UART_DM_IMR: %x\n", msm_hs_read(&(msm_uport->uport), + MSM_HS_DBG("UART_DM_IMR: %x\n", msm_hs_read(uport, UART_DM_IMR)); MSM_HS_DBG("=============================================\n"); - msm_hs_clock_unvote(msm_uport); - } static void msm_hs_release_port(struct uart_port *port) @@ -1109,6 +1111,10 @@ static void msm_hs_set_termios(struct uart_port *uport, struct msm_hs_rx *rx = &msm_uport->rx; struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle; + if (msm_uport->clk_state != MSM_HS_CLK_ON) { + MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__); + return; + } mutex_lock(&msm_uport->clk_mutex); msm_hs_write(uport, UART_DM_IMR, 0); @@ -1208,6 +1214,8 @@ static void msm_hs_set_termios(struct uart_port *uport, msm_hs_write(uport, UART_DM_CR, RESET_RX); msm_hs_write(uport, UART_DM_CR, RESET_TX); + /* Issue TX BAM Start IFC command */ + msm_hs_write(uport, UART_DM_CR, START_TX_BAM_IFC); if (msm_uport->rx.flush == FLUSH_NONE) { wake_lock(&msm_uport->rx.wake_lock); @@ -1279,6 +1287,7 @@ unsigned int msm_hs_tx_empty(struct uart_port *uport) msm_hs_clock_vote(msm_uport); data = msm_hs_read(uport, UART_DM_SR); msm_hs_clock_unvote(msm_uport); + MSM_HS_DBG("%s(): SR Reg Read 0x%x", __func__, data); if (data & UARTDM_SR_TXEMT_BMSK) ret = TIOCSER_TEMT; @@ -1330,16 +1339,19 @@ static void msm_hs_stop_rx_locked(struct uart_port *uport) struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); unsigned int data; - /* disable dlink */ - data = msm_hs_read(uport, UART_DM_DMEN); - if (is_blsp_uart(msm_uport)) - data &= ~UARTDM_RX_BAM_ENABLE_BMSK; - else - data &= ~UARTDM_RX_DM_EN_BMSK; - msm_hs_write(uport, UART_DM_DMEN, data); + MSM_HS_DBG("In %s():\n", __func__); + if (msm_uport->clk_state == MSM_HS_CLK_ON) { + /* disable dlink */ + data = msm_hs_read(uport, UART_DM_DMEN); + if (is_blsp_uart(msm_uport)) + data &= ~UARTDM_RX_BAM_ENABLE_BMSK; + else + data &= ~UARTDM_RX_DM_EN_BMSK; + msm_hs_write(uport, UART_DM_DMEN, data); - /* calling DMOV or CLOCK API. Hence mb() */ - mb(); + /* calling DMOV or CLOCK API. Hence mb() */ + mb(); + } /* Disable the receiver */ if (msm_uport->rx.flush == FLUSH_NONE) { wake_lock(&msm_uport->rx.wake_lock); @@ -1366,7 +1378,7 @@ static void msm_hs_submit_tx_locked(struct uart_port *uport) int aligned_tx_count; dma_addr_t src_addr; dma_addr_t aligned_src_addr; - u32 flags = SPS_IOVEC_FLAG_EOT; + u32 flags = SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT; struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); struct msm_hs_tx *tx = &msm_uport->tx; struct circ_buf *tx_buf = &msm_uport->uport.state->xmit; @@ -1374,6 +1386,12 @@ static void msm_hs_submit_tx_locked(struct uart_port *uport) if (uart_circ_empty(tx_buf) || uport->state->port.tty->stopped) { msm_hs_stop_tx_locked(uport); + if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) { + MSM_HS_DBG("%s(): Clock off requested calling WQ", + __func__); + queue_work(msm_uport->hsuart_wq, + &msm_uport->clock_off_w); + } return; } @@ -1399,10 +1417,9 @@ static void msm_hs_submit_tx_locked(struct uart_port *uport) dma_sync_single_for_device(uport->dev, aligned_src_addr, aligned_tx_count, DMA_TO_DEVICE); - if (is_blsp_uart(msm_uport)) { - /* Issue TX BAM Start IFC command */ - msm_hs_write(uport, UART_DM_CR, START_TX_BAM_IFC); - } else { + if (is_blsp_uart(msm_uport)) + tx->tx_count = tx_count; + else { tx->command_ptr->num_rows = (((tx_count + 15) >> 4) << 16) | ((tx_count + 15) >> 4); @@ -1413,17 +1430,15 @@ static void msm_hs_submit_tx_locked(struct uart_port *uport) *tx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(tx->mapped_cmd_ptr); - } - - /* Save tx_count to use in Callback */ - tx->tx_count = tx_count; - msm_hs_write(uport, UART_DM_NCF_TX, tx_count); + /* Save tx_count to use in Callback */ + tx->tx_count = tx_count; + msm_hs_write(uport, UART_DM_NCF_TX, tx_count); + msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK; + msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg); + /* Calling next DMOV API. Hence mb() here. */ + mb(); - /* Disable the tx_ready interrupt */ - msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK; - msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg); - /* Calling next DMOV API. Hence mb() here. */ - mb(); + } msm_uport->tx.flush = FLUSH_NONE; @@ -1452,6 +1467,10 @@ static void msm_hs_start_rx_locked(struct uart_port *uport) unsigned int buffer_pending = msm_uport->rx.buffer_pending; unsigned int data; + if (msm_uport->clk_state != MSM_HS_CLK_ON) { + MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__); + return; + } msm_uport->rx.buffer_pending = 0; if (buffer_pending) MSM_HS_ERR("Error: rx started in buffer state =%x", @@ -1562,7 +1581,7 @@ static void flip_insert_work(struct work_struct *work) static void msm_serial_hs_rx_tlet(unsigned long tlet_ptr) { int retval; - int rx_count; + int rx_count = 0; unsigned long status; unsigned long flags; unsigned int error_f = 0; @@ -1667,7 +1686,8 @@ static void msm_serial_hs_rx_tlet(unsigned long tlet_ptr) } } - MSM_HS_DBG("%s() read rx buffer complete", __func__); + MSM_HS_DBG("%s() read rx buffer complete, issue sw stale", __func__); + msm_hs_write(uport, UART_DM_CR, FORCE_STALE_EVENT); /* order the read of rx.buffer and the start of next rx xfer */ wmb(); @@ -1705,8 +1725,12 @@ static void msm_hs_start_tx_locked(struct uart_port *uport ) { struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); + if (msm_uport->clk_state != MSM_HS_CLK_ON) { + MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__); + } if (msm_uport->tx.tx_ready_int_en == 0) { - msm_uport->tx.tx_ready_int_en = 1; + if (!is_blsp_uart(msm_uport)) + msm_uport->tx.tx_ready_int_en = 1; if (msm_uport->tx.dma_in_flight == 0) msm_hs_submit_tx_locked(uport); } @@ -1728,11 +1752,12 @@ static void msm_hs_sps_tx_callback(struct sps_event_notify *notify) ((struct sps_event_notify *)notify)->user; msm_uport->notify = *notify; - MSM_HS_DBG("%s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n", - __func__, notify->event_id, - notify->data.transfer.iovec.addr, - notify->data.transfer.iovec.size, - notify->data.transfer.iovec.flags); + MSM_HS_DBG("%s: ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x, line=%d\n", + __func__, notify->event_id, + notify->data.transfer.iovec.addr, + notify->data.transfer.iovec.size, + notify->data.transfer.iovec.flags, + msm_uport->uport.line); tasklet_schedule(&msm_uport->tx.tlet); } @@ -1766,6 +1791,35 @@ static void msm_serial_hs_tx_tlet(unsigned long tlet_ptr) unsigned long flags; struct msm_hs_port *msm_uport = container_of((struct tasklet_struct *) tlet_ptr, struct msm_hs_port, tx.tlet); + struct uart_port *uport = &msm_uport->uport; + struct circ_buf *tx_buf = &uport->state->xmit; + struct msm_hs_tx *tx = &msm_uport->tx; + + /* + * Do the work buffer related work in BAM + * mode that is equivalent to legacy mode + */ + + if (!msm_uport->tty_flush_receive) + tx_buf->tail = (tx_buf->tail + + tx->tx_count) & ~UART_XMIT_SIZE; + else + msm_uport->tty_flush_receive = false; + + tx->dma_in_flight = 0; + + uport->icount.tx += tx->tx_count; + + /* + * Calling to send next chunk of data + * If the circ buffer is empty, we stop + * If the clock off was requested, the clock + * off sequence is kicked off + */ + msm_hs_submit_tx_locked(uport); + + if (uart_circ_chars_pending(tx_buf) < WAKEUP_CHARS) + uart_write_wakeup(uport); spin_lock_irqsave(&(msm_uport->uport.lock), flags); if (msm_uport->tx.flush == FLUSH_STOP) { @@ -1775,10 +1829,14 @@ static void msm_serial_hs_tx_tlet(unsigned long tlet_ptr) return; } - msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK; - msm_hs_write(&(msm_uport->uport), UART_DM_IMR, msm_uport->imr_reg); - /* Calling clk API. Hence mb() requires. */ - mb(); + /* TX_READY_BMSK only if non BAM mode */ + if (!is_blsp_uart(msm_uport)) { + msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK; + msm_hs_write(&(msm_uport->uport), UART_DM_IMR, + msm_uport->imr_reg); + /* Calling clk API. Hence mb() requires. */ + mb(); + } spin_unlock_irqrestore(&(msm_uport->uport.lock), flags); MSM_HS_DBG("In %s()\n", __func__); @@ -1883,7 +1941,12 @@ void msm_hs_set_mctrl_locked(struct uart_port *uport, { unsigned int set_rts; unsigned int data; + struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); + if (msm_uport->clk_state != MSM_HS_CLK_ON) { + MSM_HS_WARN("%s:Failed.Clocks are OFF\n", __func__); + return; + } /* RTS is active low */ set_rts = TIOCM_RTS & mctrl ? 0 : 1; @@ -1921,6 +1984,11 @@ static void msm_hs_enable_ms_locked(struct uart_port *uport) { struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); + if (msm_uport->clk_state != MSM_HS_CLK_ON) { + MSM_HS_WARN("%s:Failed.Clocks are OFF\n", __func__); + return; + } + /* Enable DELTA_CTS Interrupt */ msm_uport->imr_reg |= UARTDM_ISR_DELTA_CTS_BMSK; msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg); @@ -1945,6 +2013,12 @@ static void msm_hs_flush_buffer(struct uart_port *uport) static void msm_hs_break_ctl(struct uart_port *uport, int ctl) { unsigned long flags; + struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); + + if (msm_uport->clk_state != MSM_HS_CLK_ON) { + MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__); + return; + } spin_lock_irqsave(&uport->lock, flags); msm_hs_write(uport, UART_DM_CR, ctl ? START_BREAK : STOP_BREAK); @@ -1977,6 +2051,12 @@ static void msm_hs_config_port(struct uart_port *uport, int cfg_flags) /* Handle CTS changes (Called from interrupt handler) */ static void msm_hs_handle_delta_cts_locked(struct uart_port *uport) { + struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); + + if (msm_uport->clk_state != MSM_HS_CLK_ON) { + MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__); + return; + } /* clear interrupt */ msm_hs_write(uport, UART_DM_CR, RESET_CTS); /* Calling CLOCK API. Hence mb() requires here. */ @@ -2004,20 +2084,25 @@ static int msm_hs_check_clock_off(struct uart_port *uport) spin_lock_irqsave(&uport->lock, flags); /* Cancel if tx tty buffer is not empty, dma is in flight, - * or tx fifo is not empty */ + * or tx fifo is not empty + */ if (msm_uport->clk_state != MSM_HS_CLK_REQUEST_OFF || !uart_circ_empty(tx_buf) || msm_uport->tx.dma_in_flight || msm_uport->imr_reg & UARTDM_ISR_TXLEV_BMSK) { spin_unlock_irqrestore(&uport->lock, flags); mutex_unlock(&msm_uport->clk_mutex); + MSM_HS_DBG("%s(): clkstate %d", __func__, msm_uport->clk_state); return -1; } - /* Make sure the uart is finished with the last byte */ - sr_status = msm_hs_read(uport, UARTDM_SR); + /* Make sure the uart is finished with the last byte, + * use BFamily Register + */ + sr_status = msm_hs_read(uport, UART_DM_SR); if (!(sr_status & UARTDM_SR_TXEMT_BMSK)) { spin_unlock_irqrestore(&uport->lock, flags); mutex_unlock(&msm_uport->clk_mutex); + MSM_HS_DBG("%s(): SR TXEMT fail %lx", __func__, sr_status); return 0; /* retry */ } @@ -2036,6 +2121,8 @@ static int msm_hs_check_clock_off(struct uart_port *uport) } spin_unlock_irqrestore(&uport->lock, flags); mutex_unlock(&msm_uport->clk_mutex); + MSM_HS_DBG("%s(): CLK_REQ_OFF_START -> %d", + __func__, msm_uport->clk_req_off_state); return 0; /* RXSTALE flush not complete - retry */ case CLK_REQ_OFF_RXSTALE_ISSUED: case CLK_REQ_OFF_FLUSH_ISSUED: @@ -2045,8 +2132,12 @@ static int msm_hs_check_clock_off(struct uart_port *uport) CLK_REQ_OFF_RXSTALE_FLUSHED; } mutex_unlock(&msm_uport->clk_mutex); + MSM_HS_DBG("%s(): CLK_REQ_OFF STALE/FLUSH ISSUED -> %d", + __func__, msm_uport->clk_req_off_state); return 0; /* RXSTALE flush not complete - retry */ case CLK_REQ_OFF_RXSTALE_FLUSHED: + MSM_HS_DBG("%s(): CLK_REQ_OFF STALE FLUSHED -> %d", + __func__, msm_uport->clk_req_off_state); break; /* continue */ } @@ -2087,8 +2178,6 @@ static int msm_hs_check_clock_off(struct uart_port *uport) spin_unlock_irqrestore(&uport->lock, flags); - /* Reset PNOC Bus Scaling */ - msm_hs_bus_voting(msm_uport, BUS_RESET); mutex_unlock(&msm_uport->clk_mutex); return 1; @@ -2180,7 +2269,8 @@ static irqreturn_t msm_hs_isr(int irq, void *dev) /* Complete DMA TX transactions and submit new transactions */ /* Do not update tx_buf.tail if uart_flush_buffer already - called in serial core */ + * called in serial core + */ if (!msm_uport->tty_flush_receive) tx_buf->tail = (tx_buf->tail + tx->tx_count) & ~UART_XMIT_SIZE; @@ -2229,7 +2319,8 @@ struct uart_port *msm_hs_get_uart_port(int port_index) /* The uart_driver structure stores the states in an array. * Thus the corresponding offset from the drv->state returns - * the state for the uart_port that is requested */ + * the state for the uart_port that is requested + */ if (port_index == state->uart_port->line) return state->uart_port; @@ -2249,17 +2340,17 @@ static struct msm_hs_port *msm_hs_get_hs_port(int port_index) void msm_hs_request_clock_off(struct uart_port *uport) { unsigned long flags; struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); + int data; spin_lock_irqsave(&uport->lock, flags); if (msm_uport->clk_state == MSM_HS_CLK_ON) { msm_uport->clk_state = MSM_HS_CLK_REQUEST_OFF; msm_uport->clk_req_off_state = CLK_REQ_OFF_START; - msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK; - msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg); - /* - * Complete device write before retuning back. - * Hence mb() requires here. - */ + data = msm_hs_read(uport, UART_DM_SR); + MSM_HS_DBG("%s(): TXEMT, queuing clock off work\n", + __func__); + queue_work(msm_uport->hsuart_wq, &msm_uport->clock_off_w); + mb(); } spin_unlock_irqrestore(&uport->lock, flags); @@ -2340,7 +2431,8 @@ static irqreturn_t msm_hs_wakeup_isr(int irq, void *dev) spin_lock_irqsave(&uport->lock, flags); if (msm_uport->clk_state == MSM_HS_CLK_OFF) { /* ignore the first irq - it is a pending irq that occured - * before enable_irq() */ + * before enable_irq() + */ if (msm_uport->wakeup.ignore) msm_uport->wakeup.ignore = 0; else @@ -2349,7 +2441,8 @@ static irqreturn_t msm_hs_wakeup_isr(int irq, void *dev) if (wakeup) { /* the uart was clocked off during an rx, wake up and - * optionally inject char into tty rx */ + * optionally inject char into tty rx + */ spin_unlock_irqrestore(&uport->lock, flags); msm_hs_request_clock_on(uport); spin_lock_irqsave(&uport->lock, flags); @@ -2528,6 +2621,7 @@ static int msm_hs_startup(struct uart_port *uport) } } + msm_hs_write(uport, UARTDM_BCR_ADDR, 0x003F); /* Set auto RFR Level */ data = msm_hs_read(uport, UART_DM_MR1); data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK; @@ -2953,7 +3047,6 @@ static int msm_hs_sps_init_ep_conn(struct msm_hs_port *msm_uport, sps_config->mode = SPS_MODE_SRC; sps_config->src_pipe_index = msm_uport->bam_rx_ep_pipe_index; sps_config->dest_pipe_index = 0; - sps_config->options = SPS_O_DESC_DONE; } else { /* For UART consumer transfer, source is system memory where as destination is UART peripheral */ @@ -2962,9 +3055,9 @@ static int msm_hs_sps_init_ep_conn(struct msm_hs_port *msm_uport, sps_config->mode = SPS_MODE_DEST; sps_config->src_pipe_index = 0; sps_config->dest_pipe_index = msm_uport->bam_tx_ep_pipe_index; - sps_config->options = SPS_O_EOT; } + sps_config->options = SPS_O_EOT | SPS_O_DESC_DONE | SPS_O_AUTO_ENABLE; sps_config->event_thresh = 0x10; /* Allocate maximum descriptor fifo size */ @@ -2984,12 +3077,11 @@ static int msm_hs_sps_init_ep_conn(struct msm_hs_port *msm_uport, if (is_producer) { sps_event->callback = msm_hs_sps_rx_callback; - sps_event->options = SPS_O_DESC_DONE; } else { sps_event->callback = msm_hs_sps_tx_callback; - sps_event->options = SPS_O_EOT; } + sps_event->options = SPS_O_DESC_DONE | SPS_O_EOT; sps_event->user = (void *)msm_uport; /* Now save the sps pipe handle */ @@ -3126,6 +3218,7 @@ static int msm_hs_probe(struct platform_device *pdev) int core_irqres, bam_irqres, wakeup_irqres; struct msm_serial_hs_platform_data *pdata = pdev->dev.platform_data; const struct of_device_id *match; + unsigned long data; if (pdev->dev.of_node) { dev_dbg(&pdev->dev, "device tree enabled\n"); @@ -3365,6 +3458,17 @@ static int msm_hs_probe(struct platform_device *pdev) */ mb(); + /* + * Set RX_BREAK_ZERO_CHAR_OFF and RX_ERROR_CHAR_OFF + * so any rx_break and character having parity of framing + * error don't enter inside UART RX FIFO. + */ + data = msm_hs_read(uport, UART_DM_MR2); + data |= (UARTDM_MR2_RX_BREAK_ZERO_CHAR_OFF | + UARTDM_MR2_RX_ERROR_CHAR_OFF); + msm_hs_write(uport, UART_DM_MR2, data); + mb(); + msm_uport->clk_state = MSM_HS_CLK_PORT_OFF; hrtimer_init(&msm_uport->clk_off_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c index a7663e683ce..243297976ce 100644 --- a/drivers/tty/serial/msm_smd_tty.c +++ b/drivers/tty/serial/msm_smd_tty.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/ipc_logging.h> #include <linux/of.h> +#include <soc/qcom/subsystem_restart.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -34,7 +35,6 @@ #include <mach/msm_smd.h> #include <mach/msm_smsm.h> -#include <mach/subsystem_restart.h> #define MODULE_NAME "msm_smdtty" #define MAX_SMD_TTYS 37 diff --git a/drivers/tty/smux_test.c b/drivers/tty/smux_test.c index 130b65e806b..19ac182a9f3 100644 --- a/drivers/tty/smux_test.c +++ b/drivers/tty/smux_test.c @@ -22,7 +22,7 @@ #include <linux/termios.h> #include <linux/sched.h> #include <linux/smux.h> -#include <mach/subsystem_restart.h> +#include <soc/qcom/subsystem_restart.h> #include "smux_private.h" #define DEBUG_BUFMAX 4096 diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index b645c47501b..2cea6217fb0 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -630,36 +630,58 @@ static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return 0; } -static const struct vm_operations_struct uio_vm_ops = { +static const struct vm_operations_struct uio_logical_vm_ops = { .open = uio_vma_open, .close = uio_vma_close, .fault = uio_vma_fault, }; +static int uio_mmap_logical(struct vm_area_struct *vma) +{ + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_ops = &uio_logical_vm_ops; + uio_vma_open(vma); + return 0; +} + +static const struct vm_operations_struct uio_physical_vm_ops = { +#ifdef CONFIG_HAVE_IOREMAP_PROT + .access = generic_access_phys, +#endif +}; + static int uio_mmap_physical(struct vm_area_struct *vma) { struct uio_device *idev = vma->vm_private_data; int mi = uio_find_mem_index(vma); + struct uio_mem *mem; if (mi < 0) return -EINVAL; + mem = idev->info->mem + mi; + + if (vma->vm_end - vma->vm_start > mem->size) + return -EINVAL; + vma->vm_ops = &uio_physical_vm_ops; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + /* + * We cannot use the vm_iomap_memory() helper here, + * because vma->vm_pgoff is the map index we looked + * up above in uio_find_mem_index(), rather than an + * actual page offset into the mmap. + * + * So we just do the physical mmap without a page + * offset. + */ + return remap_pfn_range(vma, vma->vm_start, - idev->info->mem[mi].addr >> PAGE_SHIFT, + mem->addr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot); } -static int uio_mmap_logical(struct vm_area_struct *vma) -{ - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_ops = &uio_vm_ops; - uio_vma_open(vma); - return 0; -} - static int uio_mmap(struct file *filep, struct vm_area_struct *vma) { struct uio_listener *listener = filep->private_data; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 96280f5f80e..748b1eb7caa 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -43,10 +43,10 @@ #include <linux/cdev.h> #include <linux/completion.h> #include <linux/clk/msm-clk.h> +#include <soc/qcom/scm.h> #include <mach/rpm-regulator.h> #include <mach/msm_bus.h> -#include <mach/scm.h> #include "dwc3_otg.h" #include "core.h" diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c index f229f91edbf..e79fb2960be 100644 --- a/drivers/usb/gadget/f_qc_rndis.c +++ b/drivers/usb/gadget/f_qc_rndis.c @@ -353,7 +353,7 @@ static struct usb_ss_ep_comp_descriptor rndis_qc_ss_bulk_comp_desc = { }; static struct usb_descriptor_header *eth_qc_ss_function[] = { - (struct usb_descriptor_header *) &rndis_iad_descriptor, + (struct usb_descriptor_header *) &rndis_qc_iad_descriptor, /* control interface matches ACM, not Ethernet */ (struct usb_descriptor_header *) &rndis_qc_control_intf, diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c index 26986de7725..8c39f37fec6 100644 --- a/drivers/usb/misc/ks_bridge.c +++ b/drivers/usb/misc/ks_bridge.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 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 @@ -104,6 +104,9 @@ struct ks_bridge { unsigned long flags; + /* to handle INT IN ep */ + unsigned int period; + #define DBG_MSG_LEN 40 #define DBG_MAX_MSG 500 unsigned int dbg_idx; @@ -440,6 +443,8 @@ static const struct usb_device_id ksb_usb_ids[] = { .driver_info = (unsigned long)&ksb_efs_hsic_dev, }, { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x908E, 3), .driver_info = (unsigned long)&ksb_efs_hsic_dev, }, + { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90A0, 2), + .driver_info = (unsigned long)&ksb_efs_hsic_dev, }, {} /* terminating entry */ }; @@ -459,9 +464,15 @@ submit_one_urb(struct ks_bridge *ksb, gfp_t flags, struct data_pkt *pkt) return; } - usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe, - pkt->buf, pkt->len, - ksb_rx_cb, pkt); + if (ksb->period) + usb_fill_int_urb(urb, ksb->udev, ksb->in_pipe, + pkt->buf, pkt->len, + ksb_rx_cb, pkt, ksb->period); + else + usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe, + pkt->buf, pkt->len, + ksb_rx_cb, pkt); + usb_anchor_urb(urb, &ksb->submitted); if (!test_bit(USB_DEV_CONNECTED, &ksb->flags)) { @@ -573,9 +584,15 @@ static void ksb_start_rx_work(struct work_struct *w) break; } - usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe, - pkt->buf, pkt->len, - ksb_rx_cb, pkt); + if (ksb->period) + usb_fill_int_urb(urb, ksb->udev, ksb->in_pipe, + pkt->buf, pkt->len, + ksb_rx_cb, pkt, ksb->period); + else + usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe, + pkt->buf, pkt->len, + ksb_rx_cb, pkt); + usb_anchor_urb(urb, &ksb->submitted); dbg_log_event(ksb, "S RX_URB", pkt->len, 0); @@ -635,6 +652,7 @@ ksb_usb_probe(struct usb_interface *ifc, const struct usb_device_id *id) case 0x9075: case 0x908A: case 0x908E: + case 0x90A0: ksb = __ksb[EFS_HSIC_BRIDGE_INDEX]; break; case 0x9079: @@ -659,8 +677,15 @@ ksb_usb_probe(struct usb_interface *ifc, const struct usb_device_id *id) for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) { ep_desc = &ifc_desc->endpoint[i].desc; - if (!ksb->in_epAddr && usb_endpoint_is_bulk_in(ep_desc)) + if (!ksb->in_epAddr && (usb_endpoint_is_bulk_in(ep_desc))) { + ksb->in_epAddr = ep_desc->bEndpointAddress; + ksb->period = 0; + } + + if (!ksb->in_epAddr && (usb_endpoint_is_int_in(ep_desc))) { ksb->in_epAddr = ep_desc->bEndpointAddress; + ksb->period = ep_desc->bInterval; + } if (!ksb->out_epAddr && usb_endpoint_is_bulk_out(ep_desc)) ksb->out_epAddr = ep_desc->bEndpointAddress; @@ -674,7 +699,10 @@ ksb_usb_probe(struct usb_interface *ifc, const struct usb_device_id *id) return -ENODEV; } - ksb->in_pipe = usb_rcvbulkpipe(ksb->udev, ksb->in_epAddr); + ksb->in_pipe = ksb->period ? + usb_rcvintpipe(ksb->udev, ksb->in_epAddr) : + usb_rcvbulkpipe(ksb->udev, ksb->in_epAddr); + ksb->out_pipe = usb_sndbulkpipe(ksb->udev, ksb->out_epAddr); usb_set_intfdata(ifc, ksb); diff --git a/drivers/usb/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c index 755fadbf0c3..f3c5c813360 100644 --- a/drivers/usb/misc/mdm_ctrl_bridge.c +++ b/drivers/usb/misc/mdm_ctrl_bridge.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -26,10 +26,6 @@ #include <asm/unaligned.h> #include <mach/usb_bridge.h> -/* polling interval for Interrupt ep */ -#define HS_INTERVAL 7 -#define FS_LS_INTERVAL 3 - #define ACM_CTRL_DTR (1 << 0) #define DEFAULT_READ_URB_LENGTH 4096 @@ -719,8 +715,7 @@ ctrl_bridge_probe(struct usb_interface *ifc, struct usb_host_endpoint *int_in, goto free_inturb; } - interval = - (udev->speed == USB_SPEED_HIGH) ? HS_INTERVAL : FS_LS_INTERVAL; + interval = int_in->desc.bInterval; usb_fill_int_urb(dev->inturb, udev, dev->int_pipe, dev->intbuf, wMaxPacketSize, diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 37ed14d4b9c..84f74bbc4ba 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2013, Linux Foundation. All rights reserved. +/* Copyright (c) 2009-2014, 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 @@ -31,6 +31,7 @@ #include <linux/dma-mapping.h> #include <linux/clk/msm-clk.h> #include <linux/irqchip/msm-mpm-irq.h> +#include <soc/qcom/scm.h> #include <linux/usb.h> #include <linux/usb/otg.h> @@ -46,7 +47,6 @@ #include <linux/mfd/pm8xxx/misc.h> #include <linux/mhl_8334.h> -#include <mach/scm.h> #include <mach/msm_xo.h> #include <mach/msm_bus.h> #include <mach/rpm-regulator.h> @@ -2659,6 +2659,8 @@ static void msm_otg_sm_work(struct work_struct *w) bool work = 0, srp_reqd, dcp; pm_runtime_resume(otg->phy->dev); + if (motg->pm_done) + pm_runtime_get_sync(otg->phy->dev); pr_debug("%s work\n", usb_otg_state_string(otg->phy->state)); switch (otg->phy->state) { case OTG_STATE_UNDEFINED: @@ -2804,6 +2806,7 @@ static void msm_otg_sm_work(struct work_struct *w) */ pm_runtime_mark_last_busy(otg->phy->dev); pm_runtime_autosuspend(otg->phy->dev); + motg->pm_done = 1; } break; case OTG_STATE_B_SRP_INIT: @@ -5031,6 +5034,7 @@ static int msm_otg_runtime_resume(struct device *dev) dev_dbg(dev, "OTG runtime resume\n"); pm_runtime_get_noresume(dev); + motg->pm_done = 0; return msm_otg_resume(motg); } #endif @@ -5058,6 +5062,7 @@ static int msm_otg_pm_resume(struct device *dev) dev_dbg(dev, "OTG PM resume\n"); + motg->pm_done = 0; atomic_set(&motg->pm_suspended, 0); if (motg->async_int || motg->sm_work_pending || !pm_runtime_suspended(dev)) { diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 35541b60d5c..35035826f96 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -23,8 +23,6 @@ source "drivers/gpu/drm/Kconfig" source "drivers/gpu/host1x/Kconfig" -source "drivers/gpu/ion/Kconfig" - source "drivers/gpu/msm/Kconfig" config VGASTATE diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index 700cac067b4..bdc515f5e97 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c @@ -361,39 +361,13 @@ void au1100fb_fb_rotate(struct fb_info *fbi, int angle) int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) { struct au1100fb_device *fbdev; - unsigned int len; - unsigned long start=0, off; fbdev = to_au1100fb_device(fbi); - if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) { - return -EINVAL; - } - - start = fbdev->fb_phys & PAGE_MASK; - len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len); - - off = vma->vm_pgoff << PAGE_SHIFT; - - if ((vma->vm_end - vma->vm_start + off) > len) { - return -EINVAL; - } - - off += start; - vma->vm_pgoff = off >> PAGE_SHIFT; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6 - vma->vm_flags |= VM_IO; - - if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) { - return -EAGAIN; - } - - return 0; + return vm_iomap_memory(vma, fbdev->fb_phys, fbdev->fb_len); } static struct fb_ops au1100fb_ops = diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index 1b59054fc6a..6ce6b837991 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c @@ -1235,36 +1235,12 @@ static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi) static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { - unsigned int len; - unsigned long start=0, off; struct au1200fb_device *fbdev = info->par; - if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) { - return -EINVAL; - } - - start = fbdev->fb_phys & PAGE_MASK; - len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len); - - off = vma->vm_pgoff << PAGE_SHIFT; - - if ((vma->vm_end - vma->vm_start + off) > len) { - return -EINVAL; - } - - off += start; - vma->vm_pgoff = off >> PAGE_SHIFT; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */ - vma->vm_flags |= VM_IO; - - return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot); - - return 0; + return vm_iomap_memory(vma, fbdev->fb_phys, fbdev->fb_len); } static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata) diff --git a/drivers/video/msm/mdp_ppp.c b/drivers/video/msm/mdp_ppp.c index c847a50acf6..d6e1afcb4e3 100644 --- a/drivers/video/msm/mdp_ppp.c +++ b/drivers/video/msm/mdp_ppp.c @@ -1,7 +1,7 @@ /* drivers/video/msm/src/drv/mdp/mdp_ppp.c * * Copyright (C) 2007 Google Incorporated - * Copyright (c) 2008-2009, 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2008-2009, 2012-2014 The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -1246,9 +1246,7 @@ int get_img(struct mdp_img *img, struct mdp_blit_req *req, { int put_needed, fb_num, ret = 0; struct file *file; -#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; -#endif if (req->flags & MDP_MEMORY_ID_TYPE_FB) { file = fget_light(img->memory_id, &put_needed); @@ -1270,26 +1268,23 @@ int get_img(struct mdp_img *img, struct mdp_blit_req *req, fput_light(file, put_needed); } } -#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION - *srcp_ihdl = ion_import_dma_buf(mfd->iclient, img->memory_id); - if (IS_ERR_OR_NULL(*srcp_ihdl)) - return PTR_ERR(*srcp_ihdl); - if (!ion_phys(mfd->iclient, *srcp_ihdl, - (ion_phys_addr_t *)start, (size_t *) len)) - return ret; - else - return -EINVAL; -#endif + *srcp_ihdl = ion_import_dma_buf(mfd->iclient, img->memory_id); + if (IS_ERR_OR_NULL(*srcp_ihdl)) + return PTR_ERR(*srcp_ihdl); + + if (!ion_phys(mfd->iclient, *srcp_ihdl, + (ion_phys_addr_t *)start, (size_t *) len)) + return ret; + else + return -EINVAL; } void put_img(struct file *p_src_file, struct ion_handle *p_ihdl) { -#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION if (!IS_ERR_OR_NULL(p_ihdl)) ion_free(ppp_display_iclient, p_ihdl); -#endif } diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c index 8f66134c693..93c0f2b86bf 100644 --- a/drivers/video/msm/mdss/mdp3.c +++ b/drivers/video/msm/mdss/mdp3.c @@ -103,6 +103,7 @@ static struct msm_bus_paths static struct mdss_panel_intf pan_types[] = { {"dsi", MDSS_PANEL_INTF_DSI}, }; +static char mdss_mdp3_panel[MDSS_MAX_PANEL_LEN]; static struct msm_bus_scale_pdata mdp_bus_ppp_scale_table = { .usecase = mdp_bus_ppp_usecases, @@ -957,10 +958,9 @@ static int mdp3_get_pan_cfg(struct mdss_panel_cfg *pan_cfg) if (!pan_cfg) return -EINVAL; - strlcpy(pan_name, &pan_cfg->arg_cfg[0], sizeof(pan_cfg->arg_cfg)); - if (pan_name[0] == '0') { + if (mdss_mdp3_panel[0] == '0') { pan_cfg->lk_cfg = false; - } else if (pan_name[0] == '1') { + } else if (mdss_mdp3_panel[0] == '1') { pan_cfg->lk_cfg = true; } else { /* read from dt */ @@ -970,7 +970,7 @@ static int mdp3_get_pan_cfg(struct mdss_panel_cfg *pan_cfg) } /* skip lk cfg and delimiter; ex: "0:" */ - strlcpy(pan_name, &pan_name[2], MDSS_MAX_PANEL_LEN); + strlcpy(pan_name, &mdss_mdp3_panel[2], MDSS_MAX_PANEL_LEN); t = strnstr(pan_name, ":", MDSS_MAX_PANEL_LEN); if (!t) { pr_err("%s: pan_name=[%s] invalid\n", @@ -1001,12 +1001,9 @@ static int mdp3_get_pan_cfg(struct mdss_panel_cfg *pan_cfg) return 0; } -static int mdp3_parse_bootarg(struct platform_device *pdev) +static int mdp3_get_cmdline_config(struct platform_device *pdev) { - struct device_node *chosen_node; - static const char *cmd_line; - char *disp_idx, *end_idx; - int rc, len = 0, name_len, cmd_len; + int rc, len = 0; int *intf_type; char *panel_name; struct mdss_panel_cfg *pan_cfg; @@ -1020,71 +1017,16 @@ static int mdp3_parse_bootarg(struct platform_device *pdev) /* reads from dt by default */ pan_cfg->lk_cfg = true; - chosen_node = of_find_node_by_name(NULL, "chosen"); - if (!chosen_node) { - pr_err("%s: get chosen node failed\n", __func__); - rc = -ENODEV; - goto get_dt_pan; - } - - cmd_line = of_get_property(chosen_node, "bootargs", &len); - if (!cmd_line || len <= 0) { - pr_err("%s: get bootargs failed\n", __func__); - rc = -ENODEV; - goto get_dt_pan; - } + len = strlen(mdss_mdp3_panel); - name_len = strlen("mdss_mdp.panel="); - cmd_len = strlen(cmd_line); - disp_idx = strnstr(cmd_line, "mdss_mdp.panel=", cmd_len); - if (!disp_idx) { - pr_err("%s:%d:cmdline panel not set disp_idx=[%p]\n", - __func__, __LINE__, disp_idx); - memset(panel_name, 0x00, MDSS_MAX_PANEL_LEN); - *intf_type = MDSS_PANEL_INTF_INVALID; - rc = MDSS_PANEL_INTF_INVALID; - goto get_dt_pan; - } - - disp_idx += name_len; - - end_idx = strnstr(disp_idx, " ", MDSS_MAX_PANEL_LEN); - pr_debug("%s:%d: pan_name=[%s] end=[%s]\n", __func__, __LINE__, - disp_idx, end_idx); - if (!end_idx) { - end_idx = disp_idx + strlen(disp_idx) + 1; - pr_warn("%s:%d: pan_name=[%s] end=[%s]\n", __func__, - __LINE__, disp_idx, end_idx); - } - - if (end_idx <= disp_idx) { - pr_err("%s:%d:cmdline pan incorrect end=[%p] disp=[%p]\n", - __func__, __LINE__, end_idx, disp_idx); - memset(panel_name, 0x00, MDSS_MAX_PANEL_LEN); - *intf_type = MDSS_PANEL_INTF_INVALID; - rc = MDSS_PANEL_INTF_INVALID; - goto get_dt_pan; - } - - *end_idx = 0; - len = end_idx - disp_idx + 1; - if (len <= 0) { - pr_warn("%s: panel name not rx", __func__); - rc = -EINVAL; - goto get_dt_pan; - } - - strlcpy(panel_name, disp_idx, min(++len, MDSS_MAX_PANEL_LEN)); - pr_debug("%s:%d panel:[%s]", __func__, __LINE__, panel_name); - of_node_put(chosen_node); - - rc = mdp3_get_pan_cfg(pan_cfg); - if (!rc) { - pan_cfg->init_done = true; - return rc; + if (len > 0) { + rc = mdp3_get_pan_cfg(pan_cfg); + if (!rc) { + pan_cfg->init_done = true; + return rc; + } } -get_dt_pan: rc = mdp3_parse_dt_pan_intf(pdev); /* if pref pan intf is not present */ if (rc) @@ -1093,7 +1035,6 @@ get_dt_pan: else pan_cfg->init_done = true; - of_node_put(chosen_node); return rc; } @@ -1128,7 +1069,7 @@ static int mdp3_parse_dt(struct platform_device *pdev) } mdp3_res->irq = res->start; - rc = mdp3_parse_bootarg(pdev); + rc = mdp3_get_cmdline_config(pdev); if (rc) { pr_err("%s: Error in panel override:rc=[%d]\n", __func__, rc); @@ -1851,7 +1792,8 @@ static int mdp3_is_display_on(struct mdss_panel_data *pdata) static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata) { struct mdss_panel_info *panel_info = &pdata->panel_info; - int ab, ib, rc; + u64 ab, ib; + int rc; pr_debug("mdp3__continuous_splash_on\n"); @@ -2338,4 +2280,13 @@ static int __init mdp3_driver_init(void) return 0; } +module_param_string(panel, mdss_mdp3_panel, MDSS_MAX_PANEL_LEN, 0); +MODULE_PARM_DESC(panel, + "panel=<lk_cfg>:<pan_intf>:<pan_intf_cfg> " + "where <lk_cfg> is "1"-lk/gcdb config or "0" non-lk/non-gcdb " + "config; <pan_intf> is dsi:0 " + "<pan_intf_cfg> is panel interface specific string " + "Ex: This string is panel's device node name from DT " + "for DSI interface"); + module_init(mdp3_driver_init); diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c index aef19cdcb54..106c4628e22 100644 --- a/drivers/video/msm/mdss/mdp3_ctrl.c +++ b/drivers/video/msm/mdss/mdp3_ctrl.c @@ -343,8 +343,8 @@ static int mdp3_ctrl_res_req_bus(struct msm_fb_data_type *mfd, int status) int rc = 0; if (status) { struct mdss_panel_info *panel_info = mfd->panel_info; - int ab = 0; - int ib = 0; + u64 ab = 0; + u64 ib = 0; ab = panel_info->xres * panel_info->yres * 4; ab *= panel_info->mipi.frame_rate; ib = (ab * 3) / 2; diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h index 36e3666e149..273d6084b34 100644 --- a/drivers/video/msm/mdss/mdss.h +++ b/drivers/video/msm/mdss/mdss.h @@ -154,10 +154,6 @@ struct mdss_data_type { u32 nvig_pipes; u32 nrgb_pipes; u32 ndma_pipes; - u32 size_sspp; - u32 size_sspp_vig; - u32 size_sspp_rgb; - u32 size_sspp_dma; DECLARE_BITMAP(mmb_alloc_map, MAX_DRV_SUP_MMB_BLKS); @@ -165,12 +161,9 @@ struct mdss_data_type { struct mdss_mdp_mixer *mixer_wb; u32 nmixers_intf; u32 nmixers_wb; - u32 size_mixer_intf; - u32 size_dspp; struct mdss_mdp_ctl *ctl_off; u32 nctl; - u32 size_ctl; struct mdss_mdp_dp_intf *dp_off; u32 ndp; @@ -194,6 +187,8 @@ struct mdss_data_type { bool mixer_switched; struct mdss_panel_cfg pan_cfg; struct mdss_prefill_data prefill_data; + + int handoff_pending; }; extern struct mdss_data_type *mdss_res; diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c index 3843ede5131..0e5342c752d 100644 --- a/drivers/video/msm/mdss/mdss_dsi.c +++ b/drivers/video/msm/mdss/mdss_dsi.c @@ -395,7 +395,7 @@ int mdss_dsi_on(struct mdss_panel_data *pdata) return ret; } } - ret = mdss_dsi_enable_bus_clocks(ctrl_pdata); + ret = mdss_dsi_bus_clk_start(ctrl_pdata); if (ret) { pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__, ret); @@ -412,7 +412,7 @@ int mdss_dsi_on(struct mdss_panel_data *pdata) pdata->panel_info.panel_power_on = 1; mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base)); mdss_dsi_phy_init(pdata); - mdss_dsi_disable_bus_clocks(ctrl_pdata); + mdss_dsi_bus_clk_stop(ctrl_pdata); mdss_dsi_clk_ctrl(ctrl_pdata, 1); @@ -659,33 +659,58 @@ static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps) if (new_fps != ctrl_pdata->panel_data.panel_info.mipi.frame_rate) { - rc = mdss_dsi_clk_div_config - (&ctrl_pdata->panel_data.panel_info, new_fps); - if (rc) { - pr_err("%s: unable to initialize the clk dividers\n", - __func__); - return rc; - } - ctrl_pdata->pclk_rate = - ctrl_pdata->panel_data.panel_info.mipi.dsi_pclk_rate; - ctrl_pdata->byte_clk_rate = - ctrl_pdata->panel_data.panel_info.clk_rate / 8; - if (pdata->panel_info.dfps_update - == DFPS_IMMEDIATE_CLK_UPDATE_MODE) { - dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + - 0x0004); - ctrl_pdata->panel_data.panel_info.mipi.frame_rate = - new_fps; - dsi_ctrl &= ~0x2; - MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, - dsi_ctrl); - mdss_dsi_controller_cfg(true, pdata); - mdss_dsi_clk_ctrl(ctrl_pdata, 0); - mdss_dsi_clk_ctrl(ctrl_pdata, 1); - dsi_ctrl |= 0x2; - MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, - dsi_ctrl); + == DFPS_IMMEDIATE_PORCH_UPDATE_MODE) { + u32 hsync_period, vsync_period; + u32 new_dsi_v_total, current_dsi_v_total; + vsync_period = + mdss_panel_get_vtotal(&pdata->panel_info); + hsync_period = + mdss_panel_get_htotal(&pdata->panel_info); + current_dsi_v_total = + MIPI_INP((ctrl_pdata->ctrl_base) + 0x2C); + new_dsi_v_total = + ((vsync_period - 1) << 16) | (hsync_period - 1); + MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C, + (current_dsi_v_total | 0x8000000)); + if (new_dsi_v_total & 0x8000000) { + MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C, + new_dsi_v_total); + } else { + MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C, + (new_dsi_v_total | 0x8000000)); + MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C, + (new_dsi_v_total & 0x7ffffff)); + } + pdata->panel_info.mipi.frame_rate = new_fps; + } else { + rc = mdss_dsi_clk_div_config + (&ctrl_pdata->panel_data.panel_info, new_fps); + if (rc) { + pr_err("%s: unable to initialize the clk dividers\n", + __func__); + return rc; + } + ctrl_pdata->pclk_rate = + pdata->panel_info.mipi.dsi_pclk_rate; + ctrl_pdata->byte_clk_rate = + pdata->panel_info.clk_rate / 8; + + if (pdata->panel_info.dfps_update + == DFPS_IMMEDIATE_CLK_UPDATE_MODE) { + dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + + 0x0004); + pdata->panel_info.mipi.frame_rate = new_fps; + dsi_ctrl &= ~0x2; + MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, + dsi_ctrl); + mdss_dsi_controller_cfg(true, pdata); + mdss_dsi_clk_ctrl(ctrl_pdata, 0); + mdss_dsi_clk_ctrl(ctrl_pdata, 1); + dsi_ctrl |= 0x2; + MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, + dsi_ctrl); + } } } else { pr_debug("%s: Panel is already at this FPS\n", __func__); @@ -1220,6 +1245,12 @@ int dsi_panel_device_register(struct device_node *pan_node, DFPS_IMMEDIATE_CLK_UPDATE_MODE; pr_debug("%s: dfps mode: Immediate clk\n", __func__); + } else if (!strcmp(data, + "dfps_immediate_porch_mode")) { + pinfo->dfps_update = + DFPS_IMMEDIATE_PORCH_UPDATE_MODE; + pr_debug("%s: dfps mode: Immediate porch\n", + __func__); } else { pr_debug("%s: dfps to default mode\n", __func__); diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h index a6990c2294e..8e522137e1a 100644 --- a/drivers/video/msm/mdss/mdss_dsi.h +++ b/drivers/video/msm/mdss/mdss_dsi.h @@ -15,10 +15,10 @@ #define MDSS_DSI_H #include <linux/list.h> +#include <linux/mdss_io_util.h> #include <mach/scm-io.h> #include "mdss_panel.h" -#include "mdss_io_util.h" #include "mdss_dsi_cmd.h" #define MMSS_SERDES_BASE_PHY 0x04f01000 /* mmss (De)Serializer CFG */ @@ -222,6 +222,8 @@ enum { #define DSI_EV_MDP_FIFO_UNDERFLOW 0x0002 #define DSI_EV_MDP_BUSY_RELEASE 0x80000000 +#define DSI_FLAG_CLOCK_MASTER 0x80000000 + struct mdss_dsi_ctrl_pdata { int ndx; /* panel_num */ int (*on) (struct mdss_panel_data *pdata); @@ -233,6 +235,8 @@ struct mdss_dsi_ctrl_pdata { unsigned char *ctrl_base; int reg_size; u32 clk_cnt; + int clk_cnt_sub; + u32 flags; struct clk *mdp_core_clk; struct clk *ahb_clk; struct clk *axi_clk; @@ -305,13 +309,20 @@ void mdp4_dsi_cmd_trigger(void); void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl); void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata); void mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl); -int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable); +void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable); +int mdss_dsi_link_clk_start(struct mdss_dsi_ctrl_pdata *ctrl); +void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl); +int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl); +void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl); void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable); void mdss_dsi_controller_cfg(int enable, struct mdss_panel_data *pdata); void mdss_dsi_sw_reset(struct mdss_panel_data *pdata); +struct mdss_dsi_ctrl_pdata *mdss_dsi_ctrl_slave( + struct mdss_dsi_ctrl_pdata *ctrl); + irqreturn_t mdss_dsi_isr(int irq, void *ptr); void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata); diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c index b5b32528b72..6e2f84ad593 100644 --- a/drivers/video/msm/mdss/mdss_dsi_host.c +++ b/drivers/video/msm/mdss/mdss_dsi_host.c @@ -92,6 +92,10 @@ void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl) ctrl_list[ctrl->ndx] = ctrl; /* keep it */ + if (ctrl->shared_pdata.broadcast_enable) + if (ctrl->ndx == DSI_CTRL_1) + ctrl->flags |= DSI_FLAG_CLOCK_MASTER; + if (mdss_register_irq(ctrl->dsi_hw)) pr_err("%s: mdss_register_irq failed.\n", __func__); @@ -117,6 +121,22 @@ void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl) } } +struct mdss_dsi_ctrl_pdata *mdss_dsi_ctrl_slave( + struct mdss_dsi_ctrl_pdata *ctrl) +{ + int ndx; + struct mdss_dsi_ctrl_pdata *sctrl = NULL; + + /* only two controllers */ + ndx = ctrl->ndx; + ndx += 1; + ndx %= DSI_CTRL_MAX; + sctrl = ctrl_list[ndx]; + + return sctrl; + +} + void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable) { if (enable == 0) { @@ -1463,10 +1483,10 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr) MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110, isr0); } - pr_debug("%s: isr=%x", __func__, isr); + pr_debug("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr); if (isr & DSI_INTR_ERROR) { - pr_err("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR); + pr_err("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr); mdss_dsi_error(ctrl); } diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c index f2c3c7df021..16bf10d1742 100644 --- a/drivers/video/msm/mdss/mdss_fb.c +++ b/drivers/video/msm/mdss/mdss_fb.c @@ -122,7 +122,11 @@ static int mdss_fb_notify_update(struct msm_fb_data_type *mfd, if (notify > NOTIFY_UPDATE_POWER_OFF) return -EINVAL; - if (notify == NOTIFY_UPDATE_START) { + if (mfd->update.is_suspend) { + to_user = NOTIFY_TYPE_SUSPEND; + mfd->update.is_suspend = 0; + ret = 1; + } else if (notify == NOTIFY_UPDATE_START) { INIT_COMPLETION(mfd->update.comp); ret = wait_for_completion_timeout( &mfd->update.comp, 4 * HZ); @@ -788,6 +792,7 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info, } mutex_lock(&mfd->update.lock); mfd->update.type = NOTIFY_TYPE_UPDATE; + mfd->update.is_suspend = 0; mutex_unlock(&mfd->update.lock); } break; @@ -802,7 +807,9 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info, mutex_lock(&mfd->update.lock); mfd->update.type = NOTIFY_TYPE_SUSPEND; + mfd->update.is_suspend = 1; mutex_unlock(&mfd->update.lock); + complete(&mfd->update.comp); del_timer(&mfd->no_update.timer); mfd->no_update.value = NOTIFY_TYPE_SUSPEND; complete(&mfd->no_update.comp); @@ -2451,3 +2458,27 @@ int __init mdss_fb_init(void) } module_init(mdss_fb_init); + +int mdss_fb_suspres_panel(struct device *dev, void *data) +{ + struct msm_fb_data_type *mfd; + int rc; + u32 event; + + if (!data) { + pr_err("Device state not defined\n"); + return -EINVAL; + } + mfd = dev_get_drvdata(dev); + if (!mfd) + return 0; + + event = *((bool *) data) ? MDSS_EVENT_RESUME : MDSS_EVENT_SUSPEND; + + rc = mdss_fb_send_panel_event(mfd, event, NULL); + if (rc) + pr_warn("unable to %s fb%d (%d)\n", + event == MDSS_EVENT_RESUME ? "resume" : "suspend", + mfd->index, rc); + return rc; +} diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h index c443d965e9b..d366b10bc51 100644 --- a/drivers/video/msm/mdss/mdss_fb.h +++ b/drivers/video/msm/mdss/mdss_fb.h @@ -88,6 +88,7 @@ struct disp_info_notify { struct completion comp; struct mutex lock; int value; + int is_suspend; }; struct msm_sync_pt_data { @@ -255,4 +256,5 @@ struct sync_fence *mdss_fb_sync_get_fence(struct sw_sync_timeline *timeline, const char *fence_name, int val); int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp); int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state); +int mdss_fb_suspres_panel(struct device *dev, void *data); #endif /* MDSS_FB_H */ diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c index 5cb9a8c7ba2..ae6fd583a59 100644 --- a/drivers/video/msm/mdss/mdss_hdmi_tx.c +++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c @@ -129,6 +129,7 @@ static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl, static inline void hdmi_tx_set_audio_switch_node(struct hdmi_tx_ctrl *hdmi_ctrl, int val, bool force); static int hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl); +static void hdmi_tx_en_encryption(struct hdmi_tx_ctrl *hdmi_ctrl, u32 on); struct mdss_hw hdmi_tx_hw = { .hw_ndx = MDSS_HW_HDMI, @@ -144,6 +145,7 @@ struct dss_gpio hpd_gpio_config[] = { }; struct dss_gpio ddc_gpio_config[] = { + {0, 1, COMPATIBLE_NAME "-ddc-mux-sel"}, {0, 1, COMPATIBLE_NAME "-ddc-clk"}, {0, 1, COMPATIBLE_NAME "-ddc-data"} }; @@ -1000,11 +1002,11 @@ void hdmi_tx_hdcp_cb(void *ptr, enum hdmi_hdcp_state status) switch (status) { case HDCP_STATE_AUTHENTICATED: if (hdmi_ctrl->hpd_state) { - /* Clear AV Mute */ - rc = hdmi_tx_config_avmute(hdmi_ctrl, 0); - if (rc) - DEV_ERR("%s: Failed to clear av mute. rc=%d\n", - __func__, rc); + if (hdmi_ctrl->pdata.primary) + hdmi_tx_en_encryption(hdmi_ctrl, true); + else + /* Clear AV Mute */ + rc = hdmi_tx_config_avmute(hdmi_ctrl, 0); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1, false); } break; @@ -1012,11 +1014,11 @@ void hdmi_tx_hdcp_cb(void *ptr, enum hdmi_hdcp_state status) hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false); if (hdmi_ctrl->hpd_state) { - /* Set AV Mute */ - rc = hdmi_tx_config_avmute(hdmi_ctrl, 1); - if (rc) - DEV_ERR("%s: Failed to set av mute. rc=%d\n", - __func__, rc); + if (hdmi_ctrl->pdata.primary) + hdmi_tx_en_encryption(hdmi_ctrl, false); + else + /* Set AV Mute */ + rc = hdmi_tx_config_avmute(hdmi_ctrl, 1); DEV_DBG("%s: Reauthenticating\n", __func__); rc = hdmi_hdcp_reauthenticate( @@ -1737,6 +1739,28 @@ static void hdmi_tx_set_spd_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl) DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control); } /* hdmi_tx_set_spd_infoframe */ +static void hdmi_tx_en_encryption(struct hdmi_tx_ctrl *hdmi_ctrl, u32 on) +{ + u32 reg_val; + struct dss_io_data *io = NULL; + + if (!hdmi_ctrl->hdcp_feature_on || !hdmi_ctrl->present_hdcp) + return; + + io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; + + mutex_lock(&hdmi_ctrl->mutex); + reg_val = DSS_REG_R_ND(io, HDMI_CTRL); + + if (on) + reg_val |= BIT(2); + else + reg_val &= ~BIT(2); + DSS_REG_W(io, HDMI_CTRL, reg_val); + + mutex_unlock(&hdmi_ctrl->mutex); +} /* hdmi_tx_en_encryption */ + static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on) { struct dss_io_data *io = NULL; @@ -1753,12 +1777,14 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on) return; } + mutex_lock(&hdmi_ctrl->mutex); if (power_on) { /* Enable the block */ reg_val |= BIT(0); /* HDMI Encryption, if HDCP is enabled */ - if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) + if (hdmi_ctrl->hdcp_feature_on && + hdmi_ctrl->present_hdcp && !hdmi_ctrl->pdata.primary) reg_val |= BIT(2); /* Set transmission mode to DVI based in EDID info */ @@ -1768,6 +1794,7 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on) } DSS_REG_W(io, HDMI_CTRL, reg_val); + mutex_unlock(&hdmi_ctrl->mutex); DEV_DBG("HDMI Core: %s, HDMI_CTRL=0x%08x\n", power_on ? "Enable" : "Disable", reg_val); @@ -2733,6 +2760,11 @@ static int hdmi_tx_power_on(struct mdss_panel_data *panel_data) hdmi_ctrl->panel_power_on = true; mutex_unlock(&hdmi_ctrl->mutex); + if (hdmi_ctrl->pdata.primary) { + if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, true)) + DEV_ERR("%s: Failed to enable ddc power\n", __func__); + } + hdmi_cec_config(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]); if (hdmi_ctrl->hpd_state) { @@ -3200,10 +3232,10 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data, case MDSS_EVENT_PANEL_ON: if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) { /* Set AV Mute before starting authentication */ - rc = hdmi_tx_config_avmute(hdmi_ctrl, 1); - if (rc) - DEV_ERR("%s: Failed to set av mute. rc=%d\n", - __func__, rc); + if (hdmi_ctrl->pdata.primary) + hdmi_tx_en_encryption(hdmi_ctrl, false); + else + rc = hdmi_tx_config_avmute(hdmi_ctrl, 1); DEV_DBG("%s: Starting HDCP authentication\n", __func__); rc = hdmi_hdcp_authenticate( diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h index 5f7878b9caa..378fdf6fd8c 100644 --- a/drivers/video/msm/mdss/mdss_hdmi_util.h +++ b/drivers/video/msm/mdss/mdss_hdmi_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,7 +12,7 @@ #ifndef __HDMI_UTIL_H__ #define __HDMI_UTIL_H__ -#include "mdss_io_util.h" +#include <linux/mdss_io_util.h> #include "video/msm_hdmi_modes.h" /* HDMI_TX Registers */ diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c index 0af99ecd862..d77951879c2 100644 --- a/drivers/video/msm/mdss/mdss_io_util.c +++ b/drivers/video/msm/mdss/mdss_io_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,7 +14,7 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/delay.h> -#include "mdss_io_util.h" +#include <linux/mdss_io_util.h> #define MAX_I2C_CMDS 16 void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug) @@ -40,6 +40,7 @@ void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug) value, in_val); } } /* dss_reg_w */ +EXPORT_SYMBOL(dss_reg_w); u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug) { @@ -62,6 +63,7 @@ u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug) return value; } /* dss_reg_r */ +EXPORT_SYMBOL(dss_reg_r); void dss_reg_dump(void __iomem *base, u32 length, const char *prefix, u32 debug) @@ -70,6 +72,7 @@ void dss_reg_dump(void __iomem *base, u32 length, const char *prefix, print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4, (void *)base, length, false); } /* dss_reg_dump */ +EXPORT_SYMBOL(dss_reg_dump); static struct resource *msm_dss_get_res_byname(struct platform_device *pdev, unsigned int type, const char *name) @@ -82,6 +85,7 @@ static struct resource *msm_dss_get_res_byname(struct platform_device *pdev, return res; } /* msm_dss_get_res_byname */ +EXPORT_SYMBOL(msm_dss_get_res_byname); int msm_dss_ioremap_byname(struct platform_device *pdev, struct dss_io_data *io_data, const char *name) @@ -111,6 +115,7 @@ int msm_dss_ioremap_byname(struct platform_device *pdev, return 0; } /* msm_dss_ioremap_byname */ +EXPORT_SYMBOL(msm_dss_ioremap_byname); void msm_dss_iounmap(struct dss_io_data *io_data) { @@ -126,6 +131,7 @@ void msm_dss_iounmap(struct dss_io_data *io_data) } io_data->len = 0; } /* msm_dss_iounmap */ +EXPORT_SYMBOL(msm_dss_iounmap); int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg, int num_vreg, int config) @@ -198,6 +204,7 @@ vreg_get_fail: } return rc; } /* msm_dss_config_vreg */ +EXPORT_SYMBOL(msm_dss_config_vreg); int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) { @@ -261,6 +268,7 @@ vreg_set_opt_mode_fail: return rc; } /* msm_dss_enable_vreg */ +EXPORT_SYMBOL(msm_dss_enable_vreg); int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable) { @@ -299,6 +307,7 @@ disable_gpio: return rc; } /* msm_dss_enable_gpio */ +EXPORT_SYMBOL(msm_dss_enable_gpio); void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk) { @@ -310,6 +319,7 @@ void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk) clk_arry[i].clk = NULL; } } /* msm_dss_put_clk */ +EXPORT_SYMBOL(msm_dss_put_clk); int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk) { @@ -333,6 +343,7 @@ error: return rc; } /* msm_dss_get_clk */ +EXPORT_SYMBOL(msm_dss_get_clk); int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk) { @@ -366,6 +377,7 @@ int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk) return rc; } /* msm_dss_clk_set_rate */ +EXPORT_SYMBOL(msm_dss_clk_set_rate); int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable) { @@ -413,6 +425,7 @@ int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable) return rc; } /* msm_dss_enable_clk */ +EXPORT_SYMBOL(msm_dss_enable_clk); int mdss_i2c_byte_read(struct i2c_client *client, uint8_t slave_addr, @@ -442,6 +455,7 @@ int mdss_i2c_byte_read(struct i2c_client *client, uint8_t slave_addr, pr_debug("%s: i2c buf is [%x]\n", __func__, *read_buf); return 0; } +EXPORT_SYMBOL(mdss_i2c_byte_read); int mdss_i2c_byte_write(struct i2c_client *client, uint8_t slave_addr, uint8_t reg_offset, uint8_t *value) @@ -469,3 +483,4 @@ int mdss_i2c_byte_write(struct i2c_client *client, uint8_t slave_addr, pr_debug("%s: I2C write status=%x\n", __func__, status); return status; } +EXPORT_SYMBOL(mdss_i2c_byte_write); diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c index efe0e2b7b35..e94f46a2d56 100644 --- a/drivers/video/msm/mdss/mdss_mdp.c +++ b/drivers/video/msm/mdss/mdss_mdp.c @@ -82,12 +82,14 @@ struct msm_mdp_interface mdp5 = { static DEFINE_SPINLOCK(mdp_lock); static DEFINE_MUTEX(mdp_clk_lock); static DEFINE_MUTEX(bus_bw_lock); +static DEFINE_MUTEX(mdp_iommu_lock); static struct mdss_panel_intf pan_types[] = { {"dsi", MDSS_PANEL_INTF_DSI}, {"edp", MDSS_PANEL_INTF_EDP}, {"hdmi", MDSS_PANEL_INTF_HDMI}, }; +static char mdss_mdp_panel[MDSS_MAX_PANEL_LEN]; struct mdss_iommu_map_type mdss_iommu_map[MDSS_IOMMU_MAX_DOMAIN] = { [MDSS_IOMMU_DOMAIN_UNSECURE] = { @@ -701,6 +703,8 @@ void mdss_bus_bandwidth_ctrl(int enable) pm_runtime_get_sync(&mdata->pdev->dev); msm_bus_scale_client_update_request( mdata->bus_hdl, mdata->curr_bw_uc_idx); + if (!mdata->handoff_pending) + mdss_iommu_attach(mdata); } } @@ -833,8 +837,10 @@ int mdss_iommu_attach(struct mdss_data_type *mdata) struct mdss_iommu_map_type *iomap; int i; + mutex_lock(&mdp_iommu_lock); if (mdata->iommu_attached) { pr_debug("mdp iommu already attached\n"); + mutex_unlock(&mdp_iommu_lock); return 0; } @@ -851,6 +857,7 @@ int mdss_iommu_attach(struct mdss_data_type *mdata) } mdata->iommu_attached = true; + mutex_unlock(&mdp_iommu_lock); return 0; } @@ -861,8 +868,10 @@ int mdss_iommu_dettach(struct mdss_data_type *mdata) struct mdss_iommu_map_type *iomap; int i; + mutex_lock(&mdp_iommu_lock); if (!mdata->iommu_attached) { pr_debug("mdp iommu already dettached\n"); + mutex_unlock(&mdp_iommu_lock); return 0; } @@ -879,6 +888,7 @@ int mdss_iommu_dettach(struct mdss_data_type *mdata) } mdata->iommu_attached = false; + mutex_unlock(&mdp_iommu_lock); return 0; } @@ -1013,8 +1023,8 @@ int mdss_hw_init(struct mdss_data_type *mdata) struct mdss_mdp_pipe *vig; mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); - mdata->mdp_rev = readl_relaxed(mdata->mdp_base + - MDSS_MDP_REG_HW_VERSION); + mdata->mdp_rev = readl_relaxed(mdata->mdss_base + MDSS_REG_HW_VERSION); + pr_info_once("MDP Rev=%x\n", mdata->mdp_rev); /* disable hw underrun recovery */ @@ -1104,6 +1114,7 @@ void mdss_mdp_footswitch_ctrl_splash(int on) if (mdata != NULL) { if (on) { pr_debug("Enable MDP FS for splash.\n"); + mdata->handoff_pending = true; ret = regulator_enable(mdata->fs); if (ret) pr_err("Footswitch failed to enable\n"); @@ -1111,12 +1122,138 @@ void mdss_mdp_footswitch_ctrl_splash(int on) } else { pr_debug("Disable MDP FS for splash.\n"); regulator_disable(mdata->fs); + mdata->handoff_pending = false; } } else { pr_warn("mdss mdata not initialized\n"); } } +static int mdss_mdp_get_pan_intf(const char *pan_intf) +{ + int i, rc = MDSS_PANEL_INTF_INVALID; + + if (!pan_intf) + return rc; + + for (i = 0; i < ARRAY_SIZE(pan_types); i++) { + if (!strcmp(pan_intf, pan_types[i].name)) { + rc = pan_types[i].type; + break; + } + } + return rc; +} + +static int mdss_mdp_get_pan_cfg(struct mdss_panel_cfg *pan_cfg) +{ + char *t = NULL; + char pan_intf_str[MDSS_MAX_PANEL_LEN]; + int rc, i, panel_len; + char pan_name[MDSS_MAX_PANEL_LEN]; + + if (!pan_cfg) + return -EINVAL; + + if (mdss_mdp_panel[0] == '0') { + pan_cfg->lk_cfg = false; + } else if (mdss_mdp_panel[0] == '1') { + pan_cfg->lk_cfg = true; + } else { + /* read from dt */ + pan_cfg->lk_cfg = true; + pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID; + return -EINVAL; + } + + /* skip lk cfg and delimiter; ex: "0:" */ + strlcpy(pan_name, &mdss_mdp_panel[2], MDSS_MAX_PANEL_LEN); + t = strnstr(pan_name, ":", MDSS_MAX_PANEL_LEN); + if (!t) { + pr_err("pan_name=[%s] invalid\n", pan_name); + pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID; + return -EINVAL; + } + + for (i = 0; ((pan_name + i) < t) && (i < 4); i++) + pan_intf_str[i] = *(pan_name + i); + pan_intf_str[i] = 0; + pr_debug("%d panel intf %s\n", __LINE__, pan_intf_str); + /* point to the start of panel name */ + t = t + 1; + strlcpy(&pan_cfg->arg_cfg[0], t, sizeof(pan_cfg->arg_cfg)); + pr_debug("%d: t=[%s] panel name=[%s]\n", __LINE__, + t, pan_cfg->arg_cfg); + + panel_len = strlen(pan_cfg->arg_cfg); + if (!panel_len) { + pr_err("Panel name is invalid\n"); + pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID; + return -EINVAL; + } + + rc = mdss_mdp_get_pan_intf(pan_intf_str); + pan_cfg->pan_intf = (rc < 0) ? MDSS_PANEL_INTF_INVALID : rc; + return 0; +} + +static int mdss_mdp_parse_dt_pan_intf(struct platform_device *pdev) +{ + int rc; + struct mdss_data_type *mdata = platform_get_drvdata(pdev); + const char *prim_intf = NULL; + + rc = of_property_read_string(pdev->dev.of_node, + "qcom,mdss-pref-prim-intf", &prim_intf); + if (rc) + return -ENODEV; + + rc = mdss_mdp_get_pan_intf(prim_intf); + if (rc < 0) { + mdata->pan_cfg.pan_intf = MDSS_PANEL_INTF_INVALID; + } else { + mdata->pan_cfg.pan_intf = rc; + rc = 0; + } + return rc; +} + +static int mdss_mdp_get_cmdline_config(struct platform_device *pdev) +{ + int rc, len = 0; + int *intf_type; + char *panel_name; + struct mdss_panel_cfg *pan_cfg; + struct mdss_data_type *mdata = platform_get_drvdata(pdev); + + mdata->pan_cfg.arg_cfg[MDSS_MAX_PANEL_LEN] = 0; + pan_cfg = &mdata->pan_cfg; + panel_name = &pan_cfg->arg_cfg[0]; + intf_type = &pan_cfg->pan_intf; + + /* reads from dt by default */ + pan_cfg->lk_cfg = true; + + len = strlen(mdss_mdp_panel); + + if (len > 0) { + rc = mdss_mdp_get_pan_cfg(pan_cfg); + if (!rc) { + pan_cfg->init_done = true; + return rc; + } + } + + rc = mdss_mdp_parse_dt_pan_intf(pdev); + /* if pref pan intf is not present */ + if (rc) + pr_err("unable to parse device tree for pan intf\n"); + else + pan_cfg->init_done = true; + + return rc; +} + static ssize_t mdss_mdp_show_capabilities(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1252,6 +1389,12 @@ static int mdss_mdp_probe(struct platform_device *pdev) goto probe_done; } + rc = mdss_mdp_get_cmdline_config(pdev); + if (rc) { + pr_err("Error in panel override:rc=[%d]\n", rc); + goto probe_done; + } + rc = mdss_mdp_res_init(mdata); if (rc) { pr_err("unable to initialize mdss mdp resources\n"); @@ -1360,193 +1503,6 @@ int mdss_mdp_parse_dt_hw_settings(struct platform_device *pdev) return 0; } -static int mdss_mdp_get_pan_intf(const char *pan_intf) -{ - int i, rc = MDSS_PANEL_INTF_INVALID; - - if (!pan_intf) - return rc; - - for (i = 0; i < ARRAY_SIZE(pan_types); i++) { - if (!strncmp(pan_intf, pan_types[i].name, MDSS_MAX_PANEL_LEN)) { - rc = pan_types[i].type; - break; - } - } - return rc; -} - -static int mdss_mdp_get_pan_cfg(struct mdss_panel_cfg *pan_cfg) -{ - char *t = NULL; - char pan_intf_str[MDSS_MAX_PANEL_LEN]; - int rc, i, panel_len; - char pan_name[MDSS_MAX_PANEL_LEN]; - - if (!pan_cfg) - return -EINVAL; - - strlcpy(pan_name, &pan_cfg->arg_cfg[0], sizeof(pan_cfg->arg_cfg)); - if (pan_name[0] == '0') { - pan_cfg->lk_cfg = false; - } else if (pan_name[0] == '1') { - pan_cfg->lk_cfg = true; - } else { - /* read from dt */ - pan_cfg->lk_cfg = true; - pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID; - return -EINVAL; - } - - /* skip lk cfg and delimiter; ex: "0:" */ - strlcpy(pan_name, &pan_name[2], MDSS_MAX_PANEL_LEN); - t = strnstr(pan_name, ":", MDSS_MAX_PANEL_LEN); - if (!t) { - pr_err("%s: pan_name=[%s] invalid\n", - __func__, pan_name); - pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID; - return -EINVAL; - } - - for (i = 0; ((pan_name + i) < t) && (i < 4); i++) - pan_intf_str[i] = *(pan_name + i); - pan_intf_str[i] = 0; - pr_debug("%s:%d panel intf %s\n", __func__, __LINE__, pan_intf_str); - /* point to the start of panel name */ - t = t + 1; - strlcpy(&pan_cfg->arg_cfg[0], t, sizeof(pan_cfg->arg_cfg)); - pr_debug("%s:%d: t=[%s] panel name=[%s]\n", __func__, __LINE__, - t, pan_cfg->arg_cfg); - - panel_len = strlen(pan_cfg->arg_cfg); - if (!panel_len) { - pr_err("%s: Panel name is invalid\n", __func__); - pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID; - return -EINVAL; - } - - rc = mdss_mdp_get_pan_intf(pan_intf_str); - pan_cfg->pan_intf = (rc < 0) ? MDSS_PANEL_INTF_INVALID : rc; - return 0; -} - -static int mdss_mdp_parse_dt_pan_intf(struct platform_device *pdev) -{ - int rc; - struct mdss_data_type *mdata = platform_get_drvdata(pdev); - const char *prim_intf = NULL; - - rc = of_property_read_string(pdev->dev.of_node, - "qcom,mdss-pref-prim-intf", &prim_intf); - if (rc) - return -ENODEV; - - rc = mdss_mdp_get_pan_intf(prim_intf); - if (rc < 0) { - mdata->pan_cfg.pan_intf = MDSS_PANEL_INTF_INVALID; - } else { - mdata->pan_cfg.pan_intf = rc; - rc = 0; - } - return rc; -} - -static int mdss_mdp_parse_bootarg(struct platform_device *pdev) -{ - struct device_node *chosen_node; - static const char *cmd_line; - char *disp_idx, *end_idx; - int rc, len = 0, name_len, cmd_len; - int *intf_type; - char *panel_name; - struct mdss_panel_cfg *pan_cfg; - struct mdss_data_type *mdata = platform_get_drvdata(pdev); - - mdata->pan_cfg.arg_cfg[MDSS_MAX_PANEL_LEN] = 0; - pan_cfg = &mdata->pan_cfg; - panel_name = &pan_cfg->arg_cfg[0]; - intf_type = &pan_cfg->pan_intf; - - /* reads from dt by default */ - pan_cfg->lk_cfg = true; - - chosen_node = of_find_node_by_name(NULL, "chosen"); - if (!chosen_node) { - pr_err("%s: get chosen node failed\n", __func__); - rc = -ENODEV; - goto get_dt_pan; - } - - cmd_line = of_get_property(chosen_node, "bootargs", &len); - if (!cmd_line || len <= 0) { - pr_err("%s: get bootargs failed\n", __func__); - rc = -ENODEV; - goto get_dt_pan; - } - - name_len = strlen("mdss_mdp.panel="); - cmd_len = strlen(cmd_line); - disp_idx = strnstr(cmd_line, "mdss_mdp.panel=", cmd_len); - if (!disp_idx) { - pr_err("%s:%d:cmdline panel not set disp_idx=[%p]\n", - __func__, __LINE__, disp_idx); - memset(panel_name, 0x00, MDSS_MAX_PANEL_LEN); - *intf_type = MDSS_PANEL_INTF_INVALID; - rc = MDSS_PANEL_INTF_INVALID; - goto get_dt_pan; - } - - disp_idx += name_len; - - end_idx = strnstr(disp_idx, " ", MDSS_MAX_PANEL_LEN); - pr_debug("%s:%d: pan_name=[%s] end=[%s]\n", __func__, __LINE__, - disp_idx, end_idx); - if (!end_idx) { - end_idx = disp_idx + strlen(disp_idx) + 1; - pr_warn("%s:%d: pan_name=[%s] end=[%s]\n", __func__, - __LINE__, disp_idx, end_idx); - } - - if (end_idx <= disp_idx) { - pr_err("%s:%d:cmdline pan incorrect end=[%p] disp=[%p]\n", - __func__, __LINE__, end_idx, disp_idx); - memset(panel_name, 0x00, MDSS_MAX_PANEL_LEN); - *intf_type = MDSS_PANEL_INTF_INVALID; - rc = MDSS_PANEL_INTF_INVALID; - goto get_dt_pan; - } - - *end_idx = 0; - len = end_idx - disp_idx + 1; - if (len <= 0) { - pr_warn("%s: panel name not rx", __func__); - rc = -EINVAL; - goto get_dt_pan; - } - - strlcpy(panel_name, disp_idx, min(++len, MDSS_MAX_PANEL_LEN)); - pr_debug("%s:%d panel:[%s]", __func__, __LINE__, panel_name); - of_node_put(chosen_node); - - rc = mdss_mdp_get_pan_cfg(pan_cfg); - if (!rc) { - pan_cfg->init_done = true; - return rc; - } - -get_dt_pan: - rc = mdss_mdp_parse_dt_pan_intf(pdev); - /* if pref pan intf is not present */ - if (rc) - pr_err("%s:unable to parse device tree for pan intf\n", - __func__); - else - pan_cfg->init_done = true; - - of_node_put(chosen_node); - return rc; -} - static int mdss_mdp_parse_dt(struct platform_device *pdev) { int rc, data; @@ -1606,13 +1562,6 @@ static int mdss_mdp_parse_dt(struct platform_device *pdev) return rc; } - rc = mdss_mdp_parse_bootarg(pdev); - if (rc) { - pr_err("%s: Error in panel override:rc=[%d]\n", - __func__, rc); - return rc; - } - rc = mdss_mdp_parse_dt_bus_scale(pdev); if (rc) { pr_err("Error in device tree : bus scale\n"); @@ -1630,6 +1579,89 @@ static int mdss_mdp_parse_dt(struct platform_device *pdev) return 0; } +static void mdss_mdp_parse_dt_pipe_sw_reset(struct platform_device *pdev, + u32 reg_off, char *prop_name, struct mdss_mdp_pipe *pipe_list, + u32 npipes) +{ + size_t len; + const u32 *arr; + + arr = of_get_property(pdev->dev.of_node, prop_name, &len); + if (arr) { + int i; + + len /= sizeof(u32); + if (len != npipes) { + pr_err("%s: invalid sw_reset entries req:%d found:%d\n", + prop_name, len, npipes); + return; + } + + for (i = 0; i < len; i++) { + pipe_list[i].sw_reset.reg_off = reg_off; + pipe_list[i].sw_reset.bit_off = be32_to_cpu(arr[i]); + + pr_debug("%s[%d]: sw_reset: reg_off:0x%x bit_off:%d\n", + prop_name, i, reg_off, be32_to_cpu(arr[i])); + } + } +} + +static int mdss_mdp_parse_dt_pipe_clk_ctrl(struct platform_device *pdev, + char *prop_name, struct mdss_mdp_pipe *pipe_list, u32 npipes) +{ + int rc = 0; + size_t len; + const u32 *arr; + + arr = of_get_property(pdev->dev.of_node, prop_name, &len); + if (arr) { + int i, j; + + len /= sizeof(u32); + for (i = 0, j = 0; i < len; j++) { + struct mdss_mdp_pipe *pipe = NULL; + + if (j >= npipes) { + pr_err("invalid clk ctrl enries for prop: %s\n", + prop_name); + return -EINVAL; + } + + pipe = &pipe_list[j]; + + pipe->clk_ctrl.reg_off = be32_to_cpu(arr[i++]); + pipe->clk_ctrl.bit_off = be32_to_cpu(arr[i++]); + + /* status register is next in line to ctrl register */ + pipe->clk_status.reg_off = pipe->clk_ctrl.reg_off + 4; + pipe->clk_status.bit_off = be32_to_cpu(arr[i++]); + + pr_debug("%s[%d]: ctrl: reg_off: 0x%x bit_off: %d\n", + prop_name, j, pipe->clk_ctrl.reg_off, + pipe->clk_ctrl.bit_off); + pr_debug("%s[%d]: status: reg_off: 0x%x bit_off: %d\n", + prop_name, j, pipe->clk_status.reg_off, + pipe->clk_status.bit_off); + } + if (j != npipes) { + pr_err("%s: %d entries found. required %d\n", + prop_name, j, npipes); + for (i = 0; i < npipes; i++) { + memset(&pipe_list[i].clk_ctrl, 0, + sizeof(pipe_list[i].clk_ctrl)); + memset(&pipe_list[i].clk_status, 0, + sizeof(pipe_list[i].clk_status)); + } + rc = -EINVAL; + } + } else { + pr_err("error mandatory property '%s' not found\n", prop_name); + rc = -EINVAL; + } + + return rc; +} static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev) { @@ -1637,6 +1669,7 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev) int rc = 0; u32 nfids = 0, setup_cnt = 0, len, nxids = 0; u32 *offsets = NULL, *ftch_id = NULL, *xin_id = NULL; + u32 sw_reset_offset = 0; struct mdss_data_type *mdata = platform_get_drvdata(pdev); @@ -1793,39 +1826,6 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev) setup_cnt += len; } - rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-sspp-len", - &mdata->size_sspp, 1); - if (rc) { - if (mdata->nvig_pipes == 1 || mdata->nrgb_pipes == 1 || - mdata->ndma_pipes == 1) { - pr_err("Cannot calculate length w/ only one offset\n"); - goto parse_fail; - } - - if (mdata->nvig_pipes >= 2) { - u32 *vigOff = offsets; - mdata->size_sspp_vig = vigOff[1] - vigOff[0]; - } else - mdata->size_sspp_vig = 0; - - if (mdata->nrgb_pipes >= 2) { - u32 *rgbOff = offsets + mdata->nvig_pipes; - mdata->size_sspp_rgb = rgbOff[1] - rgbOff[0]; - } else - mdata->size_sspp_rgb = 0; - - if (mdata->ndma_pipes >= 2) { - u32 *dmaOff = offsets + mdata->nvig_pipes + - mdata->nrgb_pipes; - mdata->size_sspp_dma = dmaOff[1] - dmaOff[0]; - } else - mdata->size_sspp_dma = 0; - } else { - mdata->size_sspp_vig = mdata->size_sspp; - mdata->size_sspp_rgb = mdata->size_sspp; - mdata->size_sspp_dma = mdata->size_sspp; - } - if (mdata->nvig_pipes > DEFAULT_TOTAL_VIG_PIPES) { rc = mdss_mdp_pipe_addr_setup(mdata, mdata->vig_pipes + DEFAULT_TOTAL_VIG_PIPES, @@ -1854,6 +1854,39 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev) setup_cnt += mdata->nrgb_pipes - DEFAULT_TOTAL_RGB_PIPES; } + rc = mdss_mdp_parse_dt_pipe_clk_ctrl(pdev, + "qcom,mdss-pipe-vig-clk-ctrl-offsets", mdata->vig_pipes, + mdata->nvig_pipes); + if (rc) + goto parse_fail; + + rc = mdss_mdp_parse_dt_pipe_clk_ctrl(pdev, + "qcom,mdss-pipe-rgb-clk-ctrl-offsets", mdata->rgb_pipes, + mdata->nrgb_pipes); + if (rc) + goto parse_fail; + + rc = mdss_mdp_parse_dt_pipe_clk_ctrl(pdev, + "qcom,mdss-pipe-dma-clk-ctrl-offsets", mdata->dma_pipes, + mdata->ndma_pipes); + if (rc) + goto parse_fail; + + + mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-sw-reset-off", + &sw_reset_offset, 1); + if (sw_reset_offset) { + mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset, + "qcom,mdss-pipe-vig-sw-reset-map", mdata->vig_pipes, + mdata->nvig_pipes); + mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset, + "qcom,mdss-pipe-rgb-sw-reset-map", mdata->rgb_pipes, + mdata->nrgb_pipes); + mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset, + "qcom,mdss-pipe-dma-sw-reset-map", mdata->dma_pipes, + mdata->ndma_pipes); + } + goto parse_done; parse_fail: @@ -1926,16 +1959,6 @@ static int mdss_mdp_parse_dt_mixer(struct platform_device *pdev) if (rc) goto parse_done; - rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-mixer-intf-len", - &mdata->size_mixer_intf, 1); - if (rc) { - if (mdata->nmixers_intf >= 2) - mdata->size_mixer_intf = mixer_offsets[1] - - mixer_offsets[0]; - else - goto parse_done; - } - rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-mixer-wb-off", mixer_offsets + mdata->nmixers_intf, mdata->nmixers_wb); if (rc) @@ -1946,15 +1969,6 @@ static int mdss_mdp_parse_dt_mixer(struct platform_device *pdev) if (rc) goto parse_done; - rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-dspp-len", - &mdata->size_dspp, 1); - if (rc) { - if (ndspp >= 2) - mdata->size_dspp = dspp_offsets[1] - dspp_offsets[0]; - else - goto parse_done; - } - rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pingpong-off", pingpong_offsets, npingpong); if (rc) @@ -2019,15 +2033,6 @@ static int mdss_mdp_parse_dt_ctl(struct platform_device *pdev) if (rc) goto parse_done; - rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-ctl-len", - &mdata->size_ctl, 1); - if (rc) { - if (mdata->nctl >= 2) - mdata->size_ctl = ctl_offsets[1] - ctl_offsets[0]; - else - goto parse_done; - } - rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-wb-off", wb_offsets, nwb); if (rc) @@ -2628,11 +2633,12 @@ static int mdss_mdp_resume(struct platform_device *pdev) static int mdss_mdp_runtime_resume(struct device *dev) { struct mdss_data_type *mdata = dev_get_drvdata(dev); + bool device_on = true; if (!mdata) return -ENODEV; dev_dbg(dev, "pm_runtime: resuming...\n"); - + device_for_each_child(dev, &device_on, mdss_fb_suspres_panel); mdss_mdp_footswitch_ctrl(mdata, true); return 0; @@ -2652,6 +2658,7 @@ static int mdss_mdp_runtime_idle(struct device *dev) static int mdss_mdp_runtime_suspend(struct device *dev) { struct mdss_data_type *mdata = dev_get_drvdata(dev); + bool device_on = false; if (!mdata) return -ENODEV; dev_dbg(dev, "pm_runtime: suspending...\n"); @@ -2660,6 +2667,7 @@ static int mdss_mdp_runtime_suspend(struct device *dev) pr_err("MDP suspend failed\n"); return -EBUSY; } + device_for_each_child(dev, &device_on, mdss_fb_suspres_panel); mdss_mdp_footswitch_ctrl(mdata, false); return 0; @@ -2727,4 +2735,14 @@ static int __init mdss_mdp_driver_init(void) } +module_param_string(panel, mdss_mdp_panel, MDSS_MAX_PANEL_LEN, 0); +MODULE_PARM_DESC(panel, + "panel=<lk_cfg>:<pan_intf>:<pan_intf_cfg> " + "where <lk_cfg> is "1"-lk/gcdb config or "0" non-lk/non-gcdb " + "config; <pan_intf> is dsi:<ctrl_id> or hdmi or edp " + "<pan_intf_cfg> is panel interface specific string " + "Ex: This string is panel's device node name from DT " + "for DSI interface " + "hdmi/edp interface does not use this string"); + module_init(mdss_mdp_driver_init); diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h index 86abd0a6e1c..08ec7a59cd5 100644 --- a/drivers/video/msm/mdss/mdss_mdp.h +++ b/drivers/video/msm/mdss/mdss_mdp.h @@ -186,7 +186,8 @@ struct mdss_mdp_ctl { struct mdss_mdp_vsync_handler *); int (*remove_vsync_handler) (struct mdss_mdp_ctl *, struct mdss_mdp_vsync_handler *); - int (*config_fps_fnc) (struct mdss_mdp_ctl *ctl, int new_fps); + int (*config_fps_fnc) (struct mdss_mdp_ctl *ctl, + struct mdss_mdp_ctl *sctl, int new_fps); struct blocking_notifier_head notifier_head; @@ -330,6 +331,11 @@ struct mdss_mdp_pipe_smp_map { DECLARE_BITMAP(fixed, MAX_DRV_SUP_MMB_BLKS); }; +struct mdss_mdp_shared_reg_ctrl { + u32 reg_off; + u32 bit_off; +}; + struct mdss_mdp_pipe { u32 num; u32 type; @@ -337,6 +343,10 @@ struct mdss_mdp_pipe { char __iomem *base; u32 ftch_id; u32 xin_id; + struct mdss_mdp_shared_reg_ctrl clk_ctrl; + struct mdss_mdp_shared_reg_ctrl clk_status; + struct mdss_mdp_shared_reg_ctrl sw_reset; + atomic_t ref_cnt; u32 play_cnt; int pid; @@ -481,6 +491,18 @@ static inline u32 mdss_mdp_pingpong_read(struct mdss_mdp_mixer *mixer, u32 reg) return readl_relaxed(mixer->pingpong_base + reg); } +static inline int mdss_mdp_pipe_is_sw_reset_available( + struct mdss_data_type *mdata) +{ + switch (mdata->mdp_rev) { + case MDSS_MDP_HW_REV_101_2: + case MDSS_MDP_HW_REV_103_1: + return true; + default: + return false; + } +} + irqreturn_t mdss_mdp_isr(int irq, void *ptr); int mdss_iommu_attach(struct mdss_data_type *mdata); int mdss_iommu_dettach(struct mdss_data_type *mdata); @@ -637,7 +659,6 @@ int mdss_mdp_ctl_addr_setup(struct mdss_data_type *mdata, u32 *ctl_offsets, int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe); int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe, struct mdss_mdp_data *src_data); -int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe); int mdss_mdp_vbif_axi_halt(struct mdss_data_type *mdata); int mdss_mdp_data_check(struct mdss_mdp_data *data, diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c index 10a323c2b31..e3d092c0e58 100644 --- a/drivers/video/msm/mdss/mdss_mdp_ctl.c +++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c @@ -2240,9 +2240,12 @@ static int mdss_mdp_mixer_update(struct mdss_mdp_mixer *mixer) int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl, int fps) { int ret = 0; + struct mdss_mdp_ctl *sctl = NULL; + + sctl = mdss_mdp_get_split_ctl(ctl); if (ctl->config_fps_fnc) - ret = ctl->config_fps_fnc(ctl, fps); + ret = ctl->config_fps_fnc(ctl, sctl, fps); return ret; } diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h index 54258fce81d..a2a3bb07269 100644 --- a/drivers/video/msm/mdss/mdss_mdp_hwio.h +++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h @@ -23,6 +23,7 @@ #define MDSS_MDP_FETCH_CONFIG_RESET_VALUE 0x00000087 +#define MDSS_REG_HW_VERSION 0x0 #define MDSS_REG_HW_INTR_STATUS 0x10 #define MDSS_INTR_MDP BIT(0) @@ -214,6 +215,9 @@ enum mdss_mdp_sspp_chroma_samp_type { #define MDSS_MDP_REG_VIG_MEM_COL_BASE 0x288 #define MDSS_MDP_REG_VIG_PA_BASE 0x310 +/* in mpq product */ +#define MDSS_MDP_REG_VIG_FLUSH_SEL 0x204 + #define MDSS_MDP_VIG_OP_PA_SAT_ZERO_EXP_EN BIT(2) #define MDSS_MDP_VIG_OP_PA_MEM_PROTECT_EN BIT(3) #define MDSS_MDP_VIG_OP_PA_EN BIT(4) diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c index 3819bb60ec6..1ae7fddb083 100644 --- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c +++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -466,7 +466,63 @@ static void mdss_mdp_video_underrun_intr_done(void *arg) ctl->underrun_cnt); } -static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps) +static int mdss_mdp_video_vfp_fps_update(struct mdss_mdp_ctl *ctl, int new_fps) +{ + int curr_fps; + u32 add_v_lines = 0; + u32 current_vsync_period_f0, new_vsync_period_f0; + struct mdss_panel_data *pdata; + struct mdss_mdp_video_ctx *ctx; + u32 vsync_period, hsync_period; + + ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data; + if (!ctx) { + pr_err("invalid ctx\n"); + return -ENODEV; + } + + pdata = ctl->panel_data; + if (pdata == NULL) { + pr_err("%s: Invalid panel data\n", __func__); + return -EINVAL; + } + + vsync_period = mdss_panel_get_vtotal(&pdata->panel_info); + hsync_period = mdss_panel_get_htotal(&pdata->panel_info); + curr_fps = mdss_panel_get_framerate(&pdata->panel_info); + + if (curr_fps > new_fps) { + add_v_lines = mult_frac(vsync_period, + (curr_fps - new_fps), new_fps); + pdata->panel_info.lcdc.v_front_porch += add_v_lines; + } else { + add_v_lines = mult_frac(vsync_period, + (new_fps - curr_fps), new_fps); + pdata->panel_info.lcdc.v_front_porch -= add_v_lines; + } + + vsync_period = mdss_panel_get_vtotal(&pdata->panel_info); + current_vsync_period_f0 = mdp_video_read(ctx, + MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0); + new_vsync_period_f0 = (vsync_period * hsync_period); + + mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0, + current_vsync_period_f0 | 0x800000); + if (new_vsync_period_f0 & 0x800000) { + mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0, + new_vsync_period_f0); + } else { + mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0, + new_vsync_period_f0 | 0x800000); + mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0, + new_vsync_period_f0 & 0x7fffff); + } + + return 0; +} + +static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, + struct mdss_mdp_ctl *sctl, int new_fps) { struct mdss_mdp_video_ctx *ctx; struct mdss_panel_data *pdata; @@ -529,6 +585,40 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps) ctl->force_screen_state = MDSS_SCREEN_DEFAULT; mdss_mdp_display_commit(ctl, NULL); mdss_mdp_display_wait4comp(ctl); + } else if (pdata->panel_info.dfps_update + == DFPS_IMMEDIATE_PORCH_UPDATE_MODE){ + if (!ctx->timegen_en) { + pr_err("TG is OFF. DFPS mode invalid\n"); + return -EINVAL; + } + + video_vsync_irq_enable(ctl, true); + INIT_COMPLETION(ctx->vsync_comp); + rc = wait_for_completion_timeout(&ctx->vsync_comp, + usecs_to_jiffies(VSYNC_TIMEOUT_US)); + WARN(rc <= 0, "timeout (%d) vsync interrupt on ctl=%d\n", + rc, ctl->num); + rc = 0; + video_vsync_irq_disable(ctl); + + rc = mdss_mdp_video_vfp_fps_update(ctl, new_fps); + if (rc < 0) { + pr_err("%s: Error during DFPS\n", __func__); + return rc; + } + if (sctl) { + rc = mdss_mdp_video_vfp_fps_update(sctl, + new_fps); + if (rc < 0) { + pr_err("%s: DFPS error\n", __func__); + return rc; + } + } + rc = mdss_mdp_ctl_intf_event(ctl, + MDSS_EVENT_PANEL_UPDATE_FPS, + (void *)new_fps); + WARN(rc, "intf %d panel fps update error (%d)\n", + ctl->intf_num, rc); } else { pr_err("intf %d panel, unknown FPS mode\n", ctl->intf_num); diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c index 97ae56ceea5..30e05b0fb94 100644 --- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c +++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -184,7 +184,8 @@ static int mdss_mdp_writeback_format_setup(struct mdss_mdp_writeback_ctx *ctx, } mdata = mdss_mdp_get_mdata(); - if (mdata && mdata->mdp_rev >= MDSS_MDP_HW_REV_102) { + if (mdata && mdata->mdp_rev >= MDSS_MDP_HW_REV_102 && + mdata->mdp_rev < MDSS_MDP_HW_REV_200) { pattern = (fmt->element[3] << 24) | (fmt->element[2] << 16) | (fmt->element[1] << 8) | @@ -207,6 +208,7 @@ static int mdss_mdp_writeback_format_setup(struct mdss_mdp_writeback_ctx *ctx, (ctx->dst_planes.ystride[3] << 16); outsize = (ctx->dst_rect.h << 16) | ctx->dst_rect.w; + mdp_wb_write(ctx, MDSS_MDP_REG_WB_ALPHA_X_VALUE, 0xFF); mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST_FORMAT, dst_format); mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST_OP_MODE, opmode); mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST_PACK_PATTERN, pattern); diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c index ab7559feec2..e037f842c66 100644 --- a/drivers/video/msm/mdss/mdss_mdp_overlay.c +++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c @@ -24,11 +24,11 @@ #include <linux/msm_mdp.h> #include <linux/memblock.h> #include <linux/sw_sync.h> +#include <soc/qcom/scm.h> #include <linux/msm_iommu_domains.h> #include <mach/event_timer.h> #include <mach/msm_bus.h> -#include <mach/scm.h> #include "mdss.h" #include "mdss_debug.h" #include "mdss_fb.h" @@ -611,12 +611,6 @@ static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd, !mdp5_data->mdata->has_wfd_blk) mdss_mdp_smp_release(pipe); - /* - * Clear previous SMP reservations and reserve according to the - * latest configuration - */ - mdss_mdp_smp_unreserve(pipe); - ret = mdss_mdp_smp_reserve(pipe); if (ret) { pr_debug("mdss_mdp_smp_reserve failed. ret=%d\n", ret); @@ -781,7 +775,6 @@ static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd) list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_cleanup, cleanup_list) { list_move(&pipe->cleanup_list, &destroy_pipes); - mdss_mdp_pipe_fetch_halt(pipe); mdss_mdp_overlay_free_buf(&pipe->back_buf); __mdss_mdp_overlay_free_list_add(mfd, &pipe->front_buf); pipe->mfd = NULL; @@ -1108,7 +1101,7 @@ static int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx) struct mdss_mdp_pipe *pipe; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); u32 pipe_ndx, unset_ndx = 0; - int i; + int i, destroy_pipe; for (i = 0; unset_ndx != ndx && i < MDSS_MDP_MAX_SSPP; i++) { pipe_ndx = BIT(i); @@ -1119,16 +1112,22 @@ static int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx) pr_warn("unknown pipe ndx=%x\n", pipe_ndx); continue; } + mutex_lock(&mfd->lock); pipe->pid = 0; + destroy_pipe = pipe->play_cnt == 0; + if (!list_empty(&pipe->used_list)) { list_del_init(&pipe->used_list); - list_add(&pipe->cleanup_list, - &mdp5_data->pipes_cleanup); + if (!destroy_pipe) + list_add(&pipe->cleanup_list, + &mdp5_data->pipes_cleanup); } mutex_unlock(&mfd->lock); mdss_mdp_mixer_pipe_unstage(pipe); mdss_mdp_pipe_unmap(pipe); + if (destroy_pipe) + mdss_mdp_pipe_destroy(pipe); } } return 0; @@ -2278,6 +2277,10 @@ static int mdss_fb_get_hw_caps(struct msm_fb_data_type *mfd, caps->features |= MDP_BWC_EN; if (mdata->has_decimation) caps->features |= MDP_DECIMATION_EN; + + caps->max_smp_cnt = mdss_res->smp_mb_cnt; + caps->smp_per_pipe = mdata->smp_mb_per_pipe; + return 0; } @@ -2617,8 +2620,8 @@ int mdss_panel_register_done(struct mdss_panel_data *pdata) * increasing ref_cnt to help balance clocks once done. */ if (pdata->panel_info.cont_splash_enabled) { - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); mdss_mdp_footswitch_ctrl_splash(1); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); } return 0; } diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c index 2c992b335a1..7f91143ccd5 100644 --- a/drivers/video/msm/mdss/mdss_mdp_pipe.c +++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c @@ -28,12 +28,21 @@ #define PIPE_HALT_TIMEOUT_US 0x4000 +/* following offsets are relative to ctrl register bit offset */ +#define CLK_FORCE_ON_OFFSET 0x0 +#define CLK_FORCE_OFF_OFFSET 0x1 +/* following offsets are relative to status register bit offset */ +#define CLK_STATUS_OFFSET 0x0 + static DEFINE_MUTEX(mdss_mdp_sspp_lock); static DEFINE_MUTEX(mdss_mdp_smp_lock); static int mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe); +static int mdss_mdp_smp_mmb_set(int client_id, unsigned long *smp); +static void mdss_mdp_smp_mmb_free(unsigned long *smp, bool write); static struct mdss_mdp_pipe *mdss_mdp_pipe_search_by_client_id( struct mdss_data_type *mdata, int client_id); +static int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe); static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe, u32 reg, u32 val) @@ -58,8 +67,27 @@ static u32 mdss_mdp_smp_mmb_reserve(struct mdss_mdp_pipe_smp_map *smp_map, else n -= fixed_cnt; - /* reserve more blocks if needed, but can't free mmb at this point */ - for (i = bitmap_weight(smp_map->allocated, SMP_MB_CNT); i < n; i++) { + i = bitmap_weight(smp_map->allocated, SMP_MB_CNT); + + /* + * SMP programming is not double buffered. Fail the request, + * that calls for change in smp configuration (addition/removal + * of smp blocks), so that fallback solution happens. + */ + if (i != 0 && n != i) { + pr_debug("Can't change mmb config, num_blks: %d alloc: %d\n", + n, i); + return 0; + } + + /* + * Clear previous SMP reservations and reserve according to the + * latest configuration + */ + mdss_mdp_smp_mmb_free(smp_map->reserved, false); + + /* Reserve mmb blocks*/ + for (; i < n; i++) { if (bitmap_full(mdata->mmb_alloc_map, SMP_MB_CNT)) break; @@ -192,7 +220,7 @@ int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe) u32 num_blks = 0, reserved = 0; struct mdss_mdp_plane_sizes ps; int i; - int rc = 0, rot_mode = 0; + int rc = 0, rot_mode = 0, wb_mixer = 0; u32 nlines, format, seg_w; u16 width; @@ -276,9 +304,21 @@ int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe) else nlines = pipe->bwc_mode ? 1 : 2; + if (pipe->mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK) + wb_mixer = 1; + mutex_lock(&mdss_mdp_smp_lock); + for (i = (MAX_PLANES - 1); i >= ps.num_planes; i--) { + if (bitmap_weight(pipe->smp_map[i].allocated, SMP_MB_CNT)) { + pr_debug("Extra mmb identified for pnum=%d plane=%d\n", + pipe->num, i); + mutex_unlock(&mdss_mdp_smp_lock); + return -EAGAIN; + } + } + for (i = 0; i < ps.num_planes; i++) { - if (rot_mode) { + if (rot_mode || wb_mixer) { num_blks = 1; } else { num_blks = DIV_ROUND_UP(ps.ystride[i] * nlines, @@ -473,7 +513,7 @@ static struct mdss_mdp_pipe *mdss_mdp_pipe_init(struct mdss_mdp_mixer *mixer, struct mdss_mdp_pipe *pipe_pool = NULL; u32 npipes; bool pipe_share = false; - u32 i; + u32 i, reg_val, force_off_mask; if (!mixer || !mixer->ctl || !mixer->ctl->mdata) return NULL; @@ -515,12 +555,24 @@ static struct mdss_mdp_pipe *mdss_mdp_pipe_init(struct mdss_mdp_mixer *mixer, } if (pipe && mdss_mdp_pipe_fetch_halt(pipe)) { - pr_err("%d failed because vbif client is in bad state\n", + pr_err("%d failed because pipe is in bad state\n", pipe->num); atomic_dec(&pipe->ref_cnt); return NULL; } + if (mdss_mdp_pipe_is_sw_reset_available(mdata)) { + force_off_mask = + BIT(pipe->clk_ctrl.bit_off + CLK_FORCE_OFF_OFFSET); + reg_val = readl_relaxed(mdata->mdp_base + + pipe->clk_ctrl.reg_off); + if (reg_val & force_off_mask) { + reg_val &= ~force_off_mask; + writel_relaxed(reg_val, + mdata->mdp_base + pipe->clk_ctrl.reg_off); + } + } + if (pipe) { pr_debug("type=%x pnum=%d\n", pipe->type, pipe->num); mutex_init(&pipe->pp_res.hist.hist_mutex); @@ -533,7 +585,7 @@ static struct mdss_mdp_pipe *mdss_mdp_pipe_init(struct mdss_mdp_mixer *mixer, pipe = mdata->dma_pipes + mixer->num; if (pipe->mixer->type != MDSS_MDP_MIXER_TYPE_WRITEBACK) return NULL; - mdss_mdp_pipe_map(pipe); + atomic_inc(&pipe->ref_cnt); pr_debug("pipe sharing for pipe=%d\n", pipe->num); } else { pr_err("no %d type pipes available\n", type); @@ -647,16 +699,69 @@ static int mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe) pr_debug("ndx=%x pnum=%d ref_cnt=%d\n", pipe->ndx, pipe->num, atomic_read(&pipe->ref_cnt)); - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); - mdss_mdp_pipe_sspp_term(pipe); - mdss_mdp_smp_free(pipe); + if (pipe->play_cnt) { + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); + mdss_mdp_pipe_fetch_halt(pipe); + mdss_mdp_pipe_sspp_term(pipe); + mdss_mdp_smp_free(pipe); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); + } else { + mdss_mdp_smp_unreserve(pipe); + } + pipe->flags = 0; pipe->bwc_mode = 0; + pipe->mfd = NULL; memset(&pipe->scale, 0, sizeof(struct mdp_scale_data)); + return 0; +} + +static int mdss_mdp_is_pipe_idle(struct mdss_mdp_pipe *pipe, + bool ignore_force_on) +{ + u32 reg_val; + u32 vbif_idle_mask, forced_on_mask, clk_status_idle_mask; + bool is_idle = false, is_forced_on; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); + + forced_on_mask = BIT(pipe->clk_ctrl.bit_off + CLK_FORCE_ON_OFFSET); + reg_val = readl_relaxed(mdata->mdp_base + pipe->clk_ctrl.reg_off); + is_forced_on = (reg_val & forced_on_mask) ? true : false; + + pr_debug("pipe#:%d clk_ctrl: 0x%x forced_on_mask: 0x%x\n", pipe->num, + reg_val, forced_on_mask); + /* if forced on then no need to check status */ + if (!is_forced_on) { + clk_status_idle_mask = + BIT(pipe->clk_status.bit_off + CLK_STATUS_OFFSET); + reg_val = readl_relaxed(mdata->mdp_base + + pipe->clk_status.reg_off); + + if (reg_val & clk_status_idle_mask) + is_idle = false; + + pr_debug("pipe#:%d clk_status:0x%x clk_status_idle_mask:0x%x\n", + pipe->num, reg_val, clk_status_idle_mask); + } + + if (!ignore_force_on && (is_forced_on || !is_idle)) + goto exit; + + vbif_idle_mask = BIT(pipe->xin_id + 16); + reg_val = readl_relaxed(mdata->vbif_base + MMSS_VBIF_XIN_HALT_CTRL1); + + if (reg_val & vbif_idle_mask) + is_idle = true; + + pr_debug("pipe#:%d XIN_HALT_CTRL1: 0x%x\n", pipe->num, reg_val); + +exit: mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); - return 0; + return is_idle; } /** @@ -671,29 +776,39 @@ static int mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe) * and would not fetch any more data. This function cannot be called from * interrupt context. */ -int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe) +static int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe) { bool is_idle; int rc = 0; u32 reg_val, idle_mask, status; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + bool sw_reset_avail = mdss_mdp_pipe_is_sw_reset_available(mdata); + u32 sw_reset_off = pipe->sw_reset.reg_off; + u32 clk_ctrl_off = pipe->clk_ctrl.reg_off; - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); - - idle_mask = BIT(pipe->xin_id + 16); - reg_val = readl_relaxed(mdata->vbif_base + MMSS_VBIF_XIN_HALT_CTRL1); - - is_idle = (reg_val & idle_mask) ? true : false; + is_idle = mdss_mdp_is_pipe_idle(pipe, true); if (!is_idle) { - pr_debug("%pS: pipe%d is not idle. xin_id=%d halt_ctrl1=0x%x\n", - __builtin_return_address(0), pipe->num, pipe->xin_id, - reg_val); + pr_err("%pS: pipe%d is not idle. xin_id=%d\n", + __builtin_return_address(0), pipe->num, pipe->xin_id); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); mutex_lock(&mdata->reg_lock); + idle_mask = BIT(pipe->xin_id + 16); + reg_val = readl_relaxed(mdata->vbif_base + MMSS_VBIF_XIN_HALT_CTRL0); writel_relaxed(reg_val | BIT(pipe->xin_id), mdata->vbif_base + MMSS_VBIF_XIN_HALT_CTRL0); + + if (sw_reset_avail) { + reg_val = readl_relaxed(mdata->mdp_base + sw_reset_off); + writel_relaxed(reg_val | BIT(pipe->sw_reset.bit_off), + mdata->mdp_base + sw_reset_off); + wmb(); + writel_relaxed(reg_val & ~BIT(pipe->sw_reset.bit_off), + mdata->mdp_base + sw_reset_off); + wmb(); + } mutex_unlock(&mdata->reg_lock); rc = readl_poll_timeout(mdata->vbif_base + @@ -710,9 +825,18 @@ int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe) MMSS_VBIF_XIN_HALT_CTRL0); writel_relaxed(reg_val & ~BIT(pipe->xin_id), mdata->vbif_base + MMSS_VBIF_XIN_HALT_CTRL0); + + if (sw_reset_avail) { + reg_val = readl_relaxed(mdata->mdp_base + clk_ctrl_off); + reg_val |= BIT(pipe->clk_ctrl.bit_off + + CLK_FORCE_OFF_OFFSET); + writel_relaxed(reg_val, + mdata->mdp_base + clk_ctrl_off); + } + mutex_unlock(&mdata->reg_lock); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); } - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); return rc; } @@ -789,6 +913,7 @@ int mdss_mdp_pipe_handoff(struct mdss_mdp_pipe *pipe) pipe->src_fmt->bpp); pipe->is_handed_off = true; + pipe->play_cnt = 1; atomic_inc(&pipe->ref_cnt); error: @@ -1041,6 +1166,11 @@ static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe, mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data.p[2].addr); mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, data.p[3].addr); + /* Flush Sel register only exists in mpq */ + if ((mdata->mdp_rev == MDSS_MDP_HW_REV_200) && + (pipe->flags & MDP_VPU_PIPE)) + mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_FLUSH_SEL, 0); + return 0; } diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c index d6ac4b69681..7571d3939de 100644 --- a/drivers/video/msm/mdss/mdss_mdp_pp.c +++ b/drivers/video/msm/mdss/mdss_mdp_pp.c @@ -815,9 +815,19 @@ static int pp_vig_pipe_setup(struct mdss_mdp_pipe *pipe, u32 *op) unsigned long flags = 0; char __iomem *offset; struct mdss_data_type *mdata; + struct msm_fb_data_type *mfd = NULL; + u32 current_opmode; + u32 csc_reset; pr_debug("pnum=%x\n", pipe->num); + if (!pipe->mixer || !pipe->mixer->ctl || !pipe->mixer->ctl->mfd) { + pr_err("Invalid input params for vig pipe setup\n"); + return -EINVAL; + } + + mfd = pipe->mixer->ctl->mfd; + mdata = mdss_mdp_get_mdata(); if ((pipe->flags & MDP_OVERLAY_PP_CFG_EN) && (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_CSC_CFG)) { @@ -849,6 +859,16 @@ static int pp_vig_pipe_setup(struct mdss_mdp_pipe *pipe, u32 *op) } } + /* Update CSC state only if tuning mode is enable */ + if (mfd->dcm_state == DTM_ENTER) { + /* Reset bit 16 to 19 for CSC_STATE in VIG_OP_MODE */ + csc_reset = 0xFFF0FFFF; + current_opmode = readl_relaxed(pipe->base + + MDSS_MDP_REG_VIG_OP_MODE); + *op |= ((current_opmode & csc_reset) | opmode); + return 0; + } + pp_hist_setup(&opmode, MDSS_PP_SSPP_CFG | pipe->num, pipe->mixer); if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) { @@ -1236,10 +1256,27 @@ int mdss_mdp_pipe_sspp_setup(struct mdss_mdp_pipe *pipe, u32 *op) char __iomem *pipe_base; u32 pipe_num; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct msm_fb_data_type *mfd = NULL; + u32 current_opmode; if (pipe == NULL) return -EINVAL; + if (!pipe->mixer || !pipe->mixer->ctl || !pipe->mixer->ctl->mfd) { + pr_err("Invalid input params for sspp pipe setup\n"); + return -EINVAL; + } + + mfd = pipe->mixer->ctl->mfd; + + /* Read IGC state and update the same if tuning mode is enable */ + if (mfd->dcm_state == DTM_ENTER) { + current_opmode = readl_relaxed(pipe->base + + MDSS_MDP_REG_SSPP_SRC_OP_MODE); + *op |= (current_opmode & BIT(16)); + return ret; + } + /* * TODO: should this function be responsible for masking multiple * pipes to be written in dual pipe case? @@ -4929,26 +4966,37 @@ static int is_valid_calib_addr(void *addr, u32 operation) ptr <= (mdss_res->mdp_base + MDSS_MDP_REG_IGC_VIG_BASE + MDSS_MDP_IGC_SSPP_SIZE)) { ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE; - } else if (ptr >= dspp_base && ptr < (dspp_base + - (mdss_res->nmixers_intf * mdss_res->size_dspp))) { - ret = is_valid_calib_dspp_addr(ptr); - } else if (ptr >= ctl_base && ptr < (ctl_base + (mdss_res->nctl - * mdss_res->size_ctl))) { - ret = is_valid_calib_ctrl_addr(ptr); - } else if (ptr >= vig_base && ptr < (vig_base + (mdss_res->nvig_pipes - * mdss_res->size_sspp_vig))) { - ret = is_valid_calib_vig_addr(ptr); - } else if (ptr >= rgb_base && ptr < (rgb_base + (mdss_res->nrgb_pipes - * mdss_res->size_sspp_rgb))) { - ret = is_valid_calib_rgb_addr(ptr); - } else if (ptr >= dma_base && ptr < (dma_base + (mdss_res->ndma_pipes - * mdss_res->size_sspp_dma))) { - ret = is_valid_calib_dma_addr(ptr); - } else if (ptr >= mixer_base && ptr < (mixer_base + - (mdss_res->nmixers_intf * mdss_res->size_mixer_intf))) { - ret = is_valid_calib_mixer_addr(ptr); + } else { + if (ptr >= dspp_base) { + ret = is_valid_calib_dspp_addr(ptr); + if (ret) + goto valid_addr; + } + if (ptr >= ctl_base) { + ret = is_valid_calib_ctrl_addr(ptr); + if (ret) + goto valid_addr; + } + if (ptr >= vig_base) { + ret = is_valid_calib_vig_addr(ptr); + if (ret) + goto valid_addr; + } + if (ptr >= rgb_base) { + ret = is_valid_calib_rgb_addr(ptr); + if (ret) + goto valid_addr; + } + if (ptr >= dma_base) { + ret = is_valid_calib_dma_addr(ptr); + if (ret) + goto valid_addr; + } + if (ptr >= mixer_base) + ret = is_valid_calib_mixer_addr(ptr); } +valid_addr: return ret & operation; } diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c index 0f7fa75a2e2..507631627ad 100644 --- a/drivers/video/msm/mdss/mdss_mdp_rotator.c +++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c @@ -224,12 +224,6 @@ static int __mdss_mdp_rotator_to_pipe(struct mdss_mdp_rotator_session *rot, pipe->params_changed++; rot->params_changed = 0; - /* - * Clear previous SMP reservations and reserve according - * to the latest configuration - */ - mdss_mdp_smp_unreserve(pipe); - ret = mdss_mdp_smp_reserve(pipe); if (ret) { pr_err("unable to mdss_mdp_smp_reserve rot data\n"); diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h index 59ff4959f20..46508f949f6 100644 --- a/drivers/video/msm/mdss/mdss_panel.h +++ b/drivers/video/msm/mdss/mdss_panel.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-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 @@ -234,6 +234,7 @@ struct edp_panel_info { enum dynamic_fps_update { DFPS_SUSPEND_RESUME_MODE, DFPS_IMMEDIATE_CLK_UPDATE_MODE, + DFPS_IMMEDIATE_PORCH_UPDATE_MODE, }; enum lvds_mode { diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c index c5d53666e81..70366a11a1f 100644 --- a/drivers/video/msm/mdss/mhl_sii8334.c +++ b/drivers/video/msm/mdss/mhl_sii8334.c @@ -22,13 +22,13 @@ #include <linux/input.h> #include <linux/usb/msm_hsusb.h> #include <linux/mhl_8334.h> +#include <linux/mdss_io_util.h> #include "mdss_fb.h" #include "mdss_hdmi_tx.h" #include "mdss_hdmi_edid.h" #include "mdss.h" #include "mdss_panel.h" -#include "mdss_io_util.h" #include "mhl_msc.h" #include "mdss_hdmi_mhl.h" diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c index 6ff8ed83897..dccc7fbeabb 100644 --- a/drivers/video/msm/mdss/msm_mdss_io_8974.c +++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -257,10 +257,12 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, return 0; } -int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { int rc = 0; + pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx); + rc = clk_prepare_enable(ctrl_pdata->mdp_core_clk); if (rc) { pr_err("%s: failed to enable mdp_core_clock. rc=%d\n", @@ -287,29 +289,14 @@ error: return rc; } -void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { - if (ctrl_pdata->shared_pdata.broadcast_enable) { - if (ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_1) { - pr_debug("%s: Broadcast mode enabled.\n", - __func__); - return; - } else if (left_ctrl && - (ctrl_pdata->panel_data.panel_info.pdest - == DISPLAY_2)) { - pr_debug("%s: disable_unprepare left ctrl bus clks\n", - __func__); - clk_disable_unprepare(left_ctrl->axi_clk); - clk_disable_unprepare(left_ctrl->ahb_clk); - clk_disable_unprepare(left_ctrl->mdp_core_clk); - } - } clk_disable_unprepare(ctrl_pdata->axi_clk); clk_disable_unprepare(ctrl_pdata->ahb_clk); clk_disable_unprepare(ctrl_pdata->mdp_core_clk); } -static int mdss_dsi_clk_prepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +static int mdss_dsi_link_clk_prepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { int rc = 0; @@ -341,34 +328,19 @@ esc_clk_err: return rc; } -static void mdss_dsi_clk_unprepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +static void mdss_dsi_link_clk_unprepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { if (!ctrl_pdata) { pr_err("%s: Invalid input data\n", __func__); return; } - if (ctrl_pdata->shared_pdata.broadcast_enable) { - if (ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_1) { - pr_debug("%s: Broadcast mode enabled.\n", - __func__); - return; - } else if (left_ctrl && - (ctrl_pdata->panel_data.panel_info.pdest - == DISPLAY_2)) { - pr_debug("%s: unprepare left ctrl clocks\n", __func__); - clk_unprepare(left_ctrl->pixel_clk); - clk_unprepare(left_ctrl->byte_clk); - clk_unprepare(left_ctrl->esc_clk); - } - } - clk_unprepare(ctrl_pdata->pixel_clk); clk_unprepare(ctrl_pdata->byte_clk); clk_unprepare(ctrl_pdata->esc_clk); } -static int mdss_dsi_clk_set_rate(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +static int mdss_dsi_link_clk_set_rate(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { u32 esc_clk_rate = 19200000; int rc = 0; @@ -409,7 +381,7 @@ error: return rc; } -static int mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +static int mdss_dsi_link_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { int rc = 0; @@ -418,6 +390,8 @@ static int mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl_pdata) return -EINVAL; } + pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx); + if (ctrl_pdata->mdss_dsi_clk_on) { pr_info("%s: mdss_dsi_clks already ON\n", __func__); return 0; @@ -453,34 +427,20 @@ esc_clk_err: return rc; } -static void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +static void mdss_dsi_link_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { if (!ctrl_pdata) { pr_err("%s: Invalid input data\n", __func__); return; } + pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx); + if (ctrl_pdata->mdss_dsi_clk_on == 0) { pr_info("%s: mdss_dsi_clks already OFF\n", __func__); return; } - if (ctrl_pdata->shared_pdata.broadcast_enable) { - if (ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_1) { - pr_debug("%s: Broadcast mode enabled.\n", - __func__); - return; - } else if (left_ctrl && - (ctrl_pdata->panel_data.panel_info.pdest - == DISPLAY_2)) { - pr_debug("%s: disabled left ctrl clocks\n", __func__); - clk_disable(left_ctrl->pixel_clk); - clk_disable(left_ctrl->byte_clk); - clk_disable(left_ctrl->esc_clk); - left_ctrl->mdss_dsi_clk_on = 0; - } - } - clk_disable(ctrl_pdata->esc_clk); clk_disable(ctrl_pdata->pixel_clk); clk_disable(ctrl_pdata->byte_clk); @@ -488,62 +448,110 @@ static void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata) ctrl_pdata->mdss_dsi_clk_on = 0; } -int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable) +int mdss_dsi_link_clk_start(struct mdss_dsi_ctrl_pdata *ctrl) { int rc = 0; - mutex_lock(&ctrl->mutex); + rc = mdss_dsi_link_clk_set_rate(ctrl); + if (rc) { + pr_err("%s: failed to set clk rates. rc=%d\n", + __func__, rc); + goto error; + } + + rc = mdss_dsi_link_clk_prepare(ctrl); + if (rc) { + pr_err("%s: failed to prepare clks. rc=%d\n", + __func__, rc); + goto error; + } + + rc = mdss_dsi_link_clk_enable(ctrl); + if (rc) { + pr_err("%s: failed to enable clks. rc=%d\n", + __func__, rc); + mdss_dsi_link_clk_unprepare(ctrl); + goto error; + } + +error: + return rc; +} + +void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl) +{ + mdss_dsi_link_clk_disable(ctrl); + mdss_dsi_link_clk_unprepare(ctrl); +} + +static void mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, int enable) +{ + int changed = 0; + if (enable) { - if (ctrl->clk_cnt == 0) { - rc = mdss_dsi_enable_bus_clocks(ctrl); - if (rc) { - pr_err("%s: failed to enable bus clks. rc=%d\n", - __func__, rc); - goto error; - } - - rc = mdss_dsi_clk_set_rate(ctrl); - if (rc) { - pr_err("%s: failed to set clk rates. rc=%d\n", - __func__, rc); - mdss_dsi_disable_bus_clocks(ctrl); - goto error; - } - - rc = mdss_dsi_clk_prepare(ctrl); - if (rc) { - pr_err("%s: failed to prepare clks. rc=%d\n", - __func__, rc); - mdss_dsi_disable_bus_clocks(ctrl); - goto error; - } - - rc = mdss_dsi_clk_enable(ctrl); - if (rc) { - pr_err("%s: failed to enable clks. rc=%d\n", - __func__, rc); - mdss_dsi_clk_unprepare(ctrl); - mdss_dsi_disable_bus_clocks(ctrl); - goto error; - } + if (ctrl->clk_cnt_sub == 0) + changed++; + ctrl->clk_cnt_sub++; + } else { + if (ctrl->clk_cnt_sub) { + ctrl->clk_cnt_sub--; + if (ctrl->clk_cnt_sub == 0) + changed++; + } else { + pr_debug("%s: Can not be turned off\n", __func__); + } + } + + pr_debug("%s: ndx=%d clk_cnt_sub=%d changed=%d enable=%d\n", + __func__, ctrl->ndx, ctrl->clk_cnt_sub, changed, enable); + if (changed) { + if (enable) { + if (mdss_dsi_bus_clk_start(ctrl) == 0) + mdss_dsi_link_clk_start(ctrl); + } else { + mdss_dsi_link_clk_stop(ctrl); + mdss_dsi_bus_clk_stop(ctrl); } + } +} + +static DEFINE_MUTEX(dsi_clk_lock); /* per system */ + +void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable) +{ + int changed = 0; + struct mdss_dsi_ctrl_pdata *sctrl = NULL; + + mutex_lock(&dsi_clk_lock); + if (enable) { + if (ctrl->clk_cnt == 0) + changed++; ctrl->clk_cnt++; } else { if (ctrl->clk_cnt) { ctrl->clk_cnt--; - if (ctrl->clk_cnt == 0) { - mdss_dsi_clk_disable(ctrl); - mdss_dsi_clk_unprepare(ctrl); - mdss_dsi_disable_bus_clocks(ctrl); - } + if (ctrl->clk_cnt == 0) + changed++; + } else { + pr_debug("%s: Can not be turned off\n", __func__); } } - pr_debug("%s: ctrl ndx=%d enabled=%d clk_cnt=%d\n", - __func__, ctrl->ndx, enable, ctrl->clk_cnt); -error: - mutex_unlock(&ctrl->mutex); - return rc; + pr_debug("%s: ndx=%d clk_cnt=%d changed=%d enable=%d\n", + __func__, ctrl->ndx, ctrl->clk_cnt, changed, enable); + if (ctrl->flags & DSI_FLAG_CLOCK_MASTER) + sctrl = mdss_dsi_ctrl_slave(ctrl); + + if (changed) { + if (enable && sctrl) + mdss_dsi_clk_ctrl_sub(sctrl, enable); + + mdss_dsi_clk_ctrl_sub(ctrl, enable); + + if (!enable && sctrl) + mdss_dsi_clk_ctrl_sub(sctrl, enable); + } + mutex_unlock(&dsi_clk_lock); } void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base) @@ -566,16 +574,19 @@ void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl) } if (left_ctrl && - (ctrl->panel_data.panel_info.pdest - == DISPLAY_1)) + (ctrl->panel_data.panel_info.pdest == DISPLAY_1)) return; if (left_ctrl && - (ctrl->panel_data.panel_info.pdest - == DISPLAY_2)) { - MIPI_OUTP(left_ctrl->ctrl_base + 0x0470, 0x000); - MIPI_OUTP(left_ctrl->ctrl_base + 0x0598, 0x000); + (ctrl->panel_data.panel_info.pdest + == + DISPLAY_2)) { + MIPI_OUTP(left_ctrl->ctrl_base + 0x0470, + 0x000); + MIPI_OUTP(left_ctrl->ctrl_base + 0x0598, + 0x000); } + MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x000); MIPI_OUTP(ctrl->ctrl_base + 0x0598, 0x000); diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h index 9975eef4cad..594d836df37 100644 --- a/include/linux/dma-contiguous.h +++ b/include/linux/dma-contiguous.h @@ -74,7 +74,8 @@ void dma_contiguous_reserve(phys_addr_t addr_limit); int dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base, phys_addr_t limit, const char *name, - bool in_system); + bool in_system, + bool remove); int dma_contiguous_add_device(struct device *dev, phys_addr_t base); @@ -95,7 +96,8 @@ static inline int dma_declare_contiguous(struct device *dev, phys_addr_t size, phys_addr_t base, phys_addr_t limit) { int ret; - ret = dma_contiguous_reserve_area(size, &base, limit, NULL, true); + ret = dma_contiguous_reserve_area(size, &base, limit, NULL, true, + false); if (ret == 0) ret = dma_contiguous_add_device(dev, base); return ret; @@ -107,15 +109,16 @@ static inline int dma_declare_contiguous_reserved(struct device *dev, phys_addr_t limit) { int ret; - ret = dma_contiguous_reserve_area(size, &base, limit, NULL, false); + ret = dma_contiguous_reserve_area(size, &base, limit, NULL, false, + false); if (ret == 0) ret = dma_contiguous_add_device(dev, base); return ret; } -struct page *dma_alloc_from_contiguous(struct device *dev, int count, +unsigned long dma_alloc_from_contiguous(struct device *dev, int count, unsigned int order); -bool dma_release_from_contiguous(struct device *dev, struct page *pages, +bool dma_release_from_contiguous(struct device *dev, unsigned long pfn, int count); #else @@ -132,14 +135,14 @@ int dma_declare_contiguous(struct device *dev, phys_addr_t size, } static inline -struct page *dma_alloc_from_contiguous(struct device *dev, int count, +unsigned long dma_alloc_from_contiguous(struct device *dev, int count, unsigned int order) { - return NULL; + return 0; } static inline -bool dma_release_from_contiguous(struct device *dev, struct page *pages, +bool dma_release_from_contiguous(struct device *dev, unsigned long pfn, int count) { return false; diff --git a/include/linux/dma-removed.h b/include/linux/dma-removed.h new file mode 100644 index 00000000000..3a0f1a4b45e --- /dev/null +++ b/include/linux/dma-removed.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/dma-mapping.h> + +extern struct dma_map_ops removed_dma_ops; diff --git a/include/linux/ion.h b/include/linux/ion.h index 7c55c7d27a8..242fef6ba99 100644 --- a/include/linux/ion.h +++ b/include/linux/ion.h @@ -1,276 +1,6 @@ -/* - * include/linux/ion.h - * - * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +#ifndef __LINUX_ION_H__ +#define __LINUX_ION_H__ -#ifndef _LINUX_ION_H -#define _LINUX_ION_H +#include "../../drivers/staging/android/ion/ion.h" -#include <linux/err.h> -#include <uapi/linux/ion.h> - -struct ion_device; -struct ion_heap; -struct ion_mapper; -struct ion_client; -struct ion_buffer; - -/* This should be removed some day when phys_addr_t's are fully - plumbed in the kernel, and all instances of ion_phys_addr_t should - be converted to phys_addr_t. For the time being many kernel interfaces - do not accept phys_addr_t's that would have to */ -#define ion_phys_addr_t dma_addr_t - -/** - * struct ion_platform_heap - defines a heap in the given platform - * @type: type of the heap from ion_heap_type enum - * @id: unique identifier for heap. When allocating higher numbers - * will be allocated from first. At allocation these are passed - * as a bit mask and therefore can not exceed ION_NUM_HEAP_IDS. - * @name: used for debug purposes - * @base: base address of heap in physical memory if applicable - * @size: size of the heap in bytes if applicable - * @has_outer_cache: set to 1 if outer cache is used, 0 otherwise. - * @extra_data: Extra data specific to each heap type - * @priv: heap private data - * @align: required alignment in physical memory if applicable - * @priv: private info passed from the board file - * - * Provided by the board file. - */ -struct ion_platform_heap { - enum ion_heap_type type; - unsigned int id; - const char *name; - ion_phys_addr_t base; - size_t size; - unsigned int has_outer_cache; - void *extra_data; - ion_phys_addr_t align; - void *priv; -}; - -/** - * struct ion_platform_data - array of platform heaps passed from board file - * @has_outer_cache: set to 1 if outer cache is used, 0 otherwise. - * @nr: number of structures in the array - * @heaps: array of platform_heap structions - * - * Provided by the board file in the form of platform data to a platform device. - */ -struct ion_platform_data { - unsigned int has_outer_cache; - int nr; - struct ion_platform_heap *heaps; -}; - -#ifdef CONFIG_ION - -/** - * ion_reserve() - reserve memory for ion heaps if applicable - * @data: platform data specifying starting physical address and - * size - * - * Calls memblock reserve to set aside memory for heaps that are - * located at specific memory addresses or of specfic sizes not - * managed by the kernel - */ -void ion_reserve(struct ion_platform_data *data); - -/** - * ion_client_create() - allocate a client and returns it - * @dev: the global ion device - * @heap_type_mask: mask of heaps this client can allocate from - * @name: used for debugging - */ -struct ion_client *ion_client_create(struct ion_device *dev, - const char *name); - -/** - * ion_client_destroy() - free's a client and all it's handles - * @client: the client - * - * Free the provided client and all it's resources including - * any handles it is holding. - */ -void ion_client_destroy(struct ion_client *client); - -/** - * ion_alloc - allocate ion memory - * @client: the client - * @len: size of the allocation - * @align: requested allocation alignment, lots of hardware blocks - * have alignment requirements of some kind - * @heap_id_mask: mask of heaps to allocate from, if multiple bits are set - * heaps will be tried in order from highest to lowest - * id - * @flags: heap flags, the low 16 bits are consumed by ion, the - * high 16 bits are passed on to the respective heap and - * can be heap custom - * - * Allocate memory in one of the heaps provided in heap mask and return - * an opaque handle to it. - */ -struct ion_handle *ion_alloc(struct ion_client *client, size_t len, - size_t align, unsigned int heap_id_mask, - unsigned int flags); - -/** - * ion_free - free a handle - * @client: the client - * @handle: the handle to free - * - * Free the provided handle. - */ -void ion_free(struct ion_client *client, struct ion_handle *handle); - -/** - * ion_phys - returns the physical address and len of a handle - * @client: the client - * @handle: the handle - * @addr: a pointer to put the address in - * @len: a pointer to put the length in - * - * This function queries the heap for a particular handle to get the - * handle's physical address. It't output is only correct if - * a heap returns physically contiguous memory -- in other cases - * this api should not be implemented -- ion_sg_table should be used - * instead. Returns -EINVAL if the handle is invalid. This has - * no implications on the reference counting of the handle -- - * the returned value may not be valid if the caller is not - * holding a reference. - */ -int ion_phys(struct ion_client *client, struct ion_handle *handle, - ion_phys_addr_t *addr, size_t *len); - -/** - * ion_map_dma - return an sg_table describing a handle - * @client: the client - * @handle: the handle - * - * This function returns the sg_table describing - * a particular ion handle. - */ -struct sg_table *ion_sg_table(struct ion_client *client, - struct ion_handle *handle); - -/** - * ion_map_kernel - create mapping for the given handle - * @client: the client - * @handle: handle to map - * - * Map the given handle into the kernel and return a kernel address that - * can be used to access this address. - */ -void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle); - -/** - * ion_unmap_kernel() - destroy a kernel mapping for a handle - * @client: the client - * @handle: handle to unmap - */ -void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle); - -/** - * ion_share_dma_buf() - share buffer as dma-buf - * @client: the client - * @handle: the handle - */ -struct dma_buf *ion_share_dma_buf(struct ion_client *client, - struct ion_handle *handle); - -/** - * ion_share_dma_buf_fd() - given an ion client, create a dma-buf fd - * @client: the client - * @handle: the handle - */ -int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle); - -/** - * ion_import_dma_buf() - given an dma-buf fd from the ion exporter get handle - * @client: the client - * @fd: the dma-buf fd - * - * Given an dma-buf fd that was allocated through ion via ion_share_dma_buf, - * import that fd and return a handle representing it. If a dma-buf from - * another exporter is passed in this function will return ERR_PTR(-EINVAL) - */ -struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd); - -#else -static inline void ion_reserve(struct ion_platform_data *data) -{ - -} - -static inline struct ion_client *ion_client_create(struct ion_device *dev, - unsigned int heap_mask, const char *name) -{ - return ERR_PTR(-ENODEV); -} - -static inline void ion_client_destroy(struct ion_client *client) { } - -static inline struct ion_handle *ion_alloc(struct ion_client *client, - size_t len, size_t align, - unsigned int heap_mask, - unsigned int flags) -{ - return ERR_PTR(-ENODEV); -} - -static inline void ion_free(struct ion_client *client, - struct ion_handle *handle) { } - - -static inline int ion_phys(struct ion_client *client, - struct ion_handle *handle, ion_phys_addr_t *addr, size_t *len) -{ - return -ENODEV; -} - -static inline struct sg_table *ion_sg_table(struct ion_client *client, - struct ion_handle *handle) -{ - return ERR_PTR(-ENODEV); -} - -static inline void *ion_map_kernel(struct ion_client *client, - struct ion_handle *handle) -{ - return ERR_PTR(-ENODEV); -} - -static inline void ion_unmap_kernel(struct ion_client *client, - struct ion_handle *handle) { } - -static inline int ion_share_dma_buf(struct ion_client *client, struct ion_handle *handle) -{ - return -ENODEV; -} - -static inline struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd) -{ - return ERR_PTR(-ENODEV); -} - -static inline int ion_handle_get_flags(struct ion_client *client, - struct ion_handle *handle, unsigned long *flags) -{ - return -ENODEV; -} - -#endif /* CONFIG_ION */ -#endif /* _LINUX_ION_H */ +#endif /* __LINUX_ION_H__ */ diff --git a/drivers/video/msm/mdss/mdss_io_util.h b/include/linux/mdss_io_util.h index 6ad21e88787..6ad21e88787 100644 --- a/drivers/video/msm/mdss/mdss_io_util.h +++ b/include/linux/mdss_io_util.h diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h index c84f67caa3d..04afdf58742 100644 --- a/include/linux/msm_ion.h +++ b/include/linux/msm_ion.h @@ -1,378 +1,6 @@ -#ifndef _LINUX_MSM_ION_H -#define _LINUX_MSM_ION_H +#ifndef __LINUX_MSM_ION_H__ +#define __LINUX_MSM_ION_H__ -#include <uapi/linux/msm_ion.h> +#include "../../drivers/staging/android/ion/msm/msm_ion.h" -enum ion_permission_type { - IPT_TYPE_MM_CARVEOUT = 0, - IPT_TYPE_MFC_SHAREDMEM = 1, - IPT_TYPE_MDP_WRITEBACK = 2, -}; - -/* - * This flag allows clients when mapping into the IOMMU to specify to - * defer un-mapping from the IOMMU until the buffer memory is freed. - */ -#define ION_IOMMU_UNMAP_DELAYED 1 - -/* - * This flag allows clients to defer unsecuring a buffer until the buffer - * is actually freed. - */ -#define ION_UNSECURE_DELAYED 1 - -/** - * struct ion_cp_heap_pdata - defines a content protection heap in the given - * platform - * @permission_type: Memory ID used to identify the memory to TZ - * @align: Alignment requirement for the memory - * @secure_base: Base address for securing the heap. - * Note: This might be different from actual base address - * of this heap in the case of a shared heap. - * @secure_size: Memory size for securing the heap. - * Note: This might be different from actual size - * of this heap in the case of a shared heap. - * @fixed_position If nonzero, position in the fixed area. - * @iommu_map_all: Indicates whether we should map whole heap into IOMMU. - * @iommu_2x_map_domain: Indicates the domain to use for overmapping. - * @request_region: function to be called when the number of allocations - * goes from 0 -> 1 - * @release_region: function to be called when the number of allocations - * goes from 1 -> 0 - * @setup_region: function to be called upon ion registration - * @allow_nonsecure_alloc: allow non-secure allocations from this heap. For - * secure heaps, this flag must be set so allow non-secure - * allocations. For non-secure heaps, this flag is ignored. - * - */ -struct ion_cp_heap_pdata { - enum ion_permission_type permission_type; - unsigned int align; - ion_phys_addr_t secure_base; /* Base addr used when heap is shared */ - size_t secure_size; /* Size used for securing heap when heap is shared*/ - int is_cma; - enum ion_fixed_position fixed_position; - int iommu_map_all; - int iommu_2x_map_domain; - int (*request_region)(void *); - int (*release_region)(void *); - void *(*setup_region)(void); - int allow_nonsecure_alloc; -}; - -/** - * struct ion_co_heap_pdata - defines a carveout heap in the given platform - * @adjacent_mem_id: Id of heap that this heap must be adjacent to. - * @align: Alignment requirement for the memory - * @fixed_position If nonzero, position in the fixed area. - * @request_region: function to be called when the number of allocations - * goes from 0 -> 1 - * @release_region: function to be called when the number of allocations - * goes from 1 -> 0 - * @setup_region: function to be called upon ion registration - * @memory_type:Memory type used for the heap - * - */ -struct ion_co_heap_pdata { - int adjacent_mem_id; - unsigned int align; - enum ion_fixed_position fixed_position; - int (*request_region)(void *); - int (*release_region)(void *); - void *(*setup_region)(void); -}; - -/** - * struct ion_cma_pdata - extra data for CMA regions - * @default_prefetch_size - default size to use for prefetching - */ -struct ion_cma_pdata { - unsigned long default_prefetch_size; -}; - -#ifdef CONFIG_ION -/** - * msm_ion_client_create - allocate a client using the ion_device specified in - * drivers/gpu/ion/msm/msm_ion.c - * - * heap_mask and name are the same as ion_client_create, return values - * are the same as ion_client_create. - */ - -struct ion_client *msm_ion_client_create(unsigned int heap_mask, - const char *name); - -/** - * ion_handle_get_flags - get the flags for a given handle - * - * @client - client who allocated the handle - * @handle - handle to get the flags - * @flags - pointer to store the flags - * - * Gets the current flags for a handle. These flags indicate various options - * of the buffer (caching, security, etc.) - */ -int ion_handle_get_flags(struct ion_client *client, struct ion_handle *handle, - unsigned long *flags); - - -/** - * ion_map_iommu - map the given handle into an iommu - * - * @client - client who allocated the handle - * @handle - handle to map - * @domain_num - domain number to map to - * @partition_num - partition number to allocate iova from - * @align - alignment for the iova - * @iova_length - length of iova to map. If the iova length is - * greater than the handle length, the remaining - * address space will be mapped to a dummy buffer. - * @iova - pointer to store the iova address - * @buffer_size - pointer to store the size of the buffer - * @flags - flags for options to map - * @iommu_flags - flags specific to the iommu. - * - * Maps the handle into the iova space specified via domain number. Iova - * will be allocated from the partition specified via partition_num. - * Returns 0 on success, negative value on error. - */ -int ion_map_iommu(struct ion_client *client, struct ion_handle *handle, - int domain_num, int partition_num, unsigned long align, - unsigned long iova_length, ion_phys_addr_t *iova, - unsigned long *buffer_size, - unsigned long flags, unsigned long iommu_flags); - - -/** - * ion_handle_get_size - get the allocated size of a given handle - * - * @client - client who allocated the handle - * @handle - handle to get the size - * @size - pointer to store the size - * - * gives the allocated size of a handle. returns 0 on success, negative - * value on error - * - * NOTE: This is intended to be used only to get a size to pass to map_iommu. - * You should *NOT* rely on this for any other usage. - */ - -int ion_handle_get_size(struct ion_client *client, struct ion_handle *handle, - unsigned long *size); - -/** - * ion_unmap_iommu - unmap the handle from an iommu - * - * @client - client who allocated the handle - * @handle - handle to unmap - * @domain_num - domain to unmap from - * @partition_num - partition to unmap from - * - * Decrement the reference count on the iommu mapping. If the count is - * 0, the mapping will be removed from the iommu. - */ -void ion_unmap_iommu(struct ion_client *client, struct ion_handle *handle, - int domain_num, int partition_num); - - -/** - * ion_secure_heap - secure a heap - * - * @client - a client that has allocated from the heap heap_id - * @heap_id - heap id to secure. - * @version - version of content protection - * @data - extra data needed for protection - * - * Secure a heap - * Returns 0 on success - */ -int ion_secure_heap(struct ion_device *dev, int heap_id, int version, - void *data); - -/** - * ion_unsecure_heap - un-secure a heap - * - * @client - a client that has allocated from the heap heap_id - * @heap_id - heap id to un-secure. - * @version - version of content protection - * @data - extra data needed for protection - * - * Un-secure a heap - * Returns 0 on success - */ -int ion_unsecure_heap(struct ion_device *dev, int heap_id, int version, - void *data); - -/** - * msm_ion_do_cache_op - do cache operations. - * - * @client - pointer to ION client. - * @handle - pointer to buffer handle. - * @vaddr - virtual address to operate on. - * @len - Length of data to do cache operation on. - * @cmd - Cache operation to perform: - * ION_IOC_CLEAN_CACHES - * ION_IOC_INV_CACHES - * ION_IOC_CLEAN_INV_CACHES - * - * Returns 0 on success - */ -int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, - void *vaddr, unsigned long len, unsigned int cmd); - -/** - * msm_ion_secure_heap - secure a heap. Wrapper around ion_secure_heap. - * - * @heap_id - heap id to secure. - * - * Secure a heap - * Returns 0 on success - */ -int msm_ion_secure_heap(int heap_id); - -/** - * msm_ion_unsecure_heap - unsecure a heap. Wrapper around ion_unsecure_heap. - * - * @heap_id - heap id to secure. - * - * Un-secure a heap - * Returns 0 on success - */ -int msm_ion_unsecure_heap(int heap_id); - -/** - * msm_ion_secure_heap_2_0 - secure a heap using 2.0 APIs - * Wrapper around ion_secure_heap. - * - * @heap_id - heap id to secure. - * @usage - usage hint to TZ - * - * Secure a heap - * Returns 0 on success - */ -int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage); - -/** - * msm_ion_unsecure_heap - unsecure a heap secured with 3.0 APIs. - * Wrapper around ion_unsecure_heap. - * - * @heap_id - heap id to secure. - * @usage - usage hint to TZ - * - * Un-secure a heap - * Returns 0 on success - */ -int msm_ion_unsecure_heap_2_0(int heap_id, enum cp_mem_usage usage); - -/** - * msm_ion_secure_buffer - secure an individual buffer - * - * @client - client who has access to the buffer - * @handle - buffer to secure - * @usage - usage hint to TZ - * @flags - flags for the securing - */ -int msm_ion_secure_buffer(struct ion_client *client, struct ion_handle *handle, - enum cp_mem_usage usage, int flags); - -/** - * msm_ion_unsecure_buffer - unsecure an individual buffer - * - * @client - client who has access to the buffer - * @handle - buffer to secure - */ -int msm_ion_unsecure_buffer(struct ion_client *client, - struct ion_handle *handle); -#else -static inline struct ion_client *msm_ion_client_create(unsigned int heap_mask, - const char *name) -{ - return ERR_PTR(-ENODEV); -} - -static inline int ion_map_iommu(struct ion_client *client, - struct ion_handle *handle, int domain_num, - int partition_num, unsigned long align, - unsigned long iova_length, ion_phys_addr_t *iova, - unsigned long *buffer_size, - unsigned long flags, - unsigned long iommu_flags) -{ - return -ENODEV; -} - -static inline int ion_handle_get_size(struct ion_client *client, - struct ion_handle *handle, unsigned long *size) -{ - return -ENODEV; -} - -static inline void ion_unmap_iommu(struct ion_client *client, - struct ion_handle *handle, int domain_num, - int partition_num) -{ - return; -} - -static inline int ion_secure_heap(struct ion_device *dev, int heap_id, - int version, void *data) -{ - return -ENODEV; - -} - -static inline int ion_unsecure_heap(struct ion_device *dev, int heap_id, - int version, void *data) -{ - return -ENODEV; -} - -static inline void ion_mark_dangling_buffers_locked(struct ion_device *dev) -{ -} - -static inline int msm_ion_do_cache_op(struct ion_client *client, - struct ion_handle *handle, void *vaddr, - unsigned long len, unsigned int cmd) -{ - return -ENODEV; -} - -static inline int msm_ion_secure_heap(int heap_id) -{ - return -ENODEV; - -} - -static inline int msm_ion_unsecure_heap(int heap_id) -{ - return -ENODEV; -} - -static inline int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage) -{ - return -ENODEV; -} - -static inline int msm_ion_unsecure_heap_2_0(int heap_id, - enum cp_mem_usage usage) -{ - return -ENODEV; -} - -static inline int msm_ion_secure_buffer(struct ion_client *client, - struct ion_handle *handle, - enum cp_mem_usage usage, - int flags) -{ - return -ENODEV; -} - -static inline int msm_ion_unsecure_buffer(struct ion_client *client, - struct ion_handle *handle) -{ - return -ENODEV; -} -#endif /* CONFIG_ION */ - -#endif +#endif /* __LINUX_MSM_ION_H__ */ diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h index 0203b64b024..8ee8ac14acc 100644 --- a/include/linux/msm_kgsl.h +++ b/include/linux/msm_kgsl.h @@ -79,6 +79,7 @@ struct kgsl_pwrlevel { * @csdev: Pointer to the coresight device for this device * @coresight_pdata: Coresight configuration for specific device * @chipid: Chip ID for the device's GPU + * @pm_qos_latency: latency value for cpu */ struct kgsl_device_platform_data { struct kgsl_pwrlevel pwrlevel[KGSL_MAX_PWRLEVELS]; @@ -95,6 +96,7 @@ struct kgsl_device_platform_data { struct coresight_device *csdev; struct coresight_platform_data *coresight_pdata; unsigned int chipid; + unsigned int pm_qos_latency; }; #ifdef CONFIG_MSM_KGSL_DRM diff --git a/include/linux/qdsp6v2/apr.h b/include/linux/qdsp6v2/apr.h index 7f7707f0490..e16cc338b58 100644 --- a/include/linux/qdsp6v2/apr.h +++ b/include/linux/qdsp6v2/apr.h @@ -14,7 +14,7 @@ #define __APR_H_ #include <linux/mutex.h> -#include <mach/subsystem_notif.h> +#include <soc/qcom/subsystem_notif.h> enum apr_subsys_state { APR_SUBSYS_DOWN, diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h index 2a24ca7f9c7..8bcec8b0a49 100644 --- a/include/linux/qpnp/qpnp-adc.h +++ b/include/linux/qpnp/qpnp-adc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -191,6 +191,7 @@ enum qpnp_adc_calib_type { * %CHAN_PATH_SCALING2: ratio of {1, 4} * %CHAN_PATH_SCALING3: ratio of {1, 6} * %CHAN_PATH_SCALING4: ratio of {1, 20} + * %CHAN_PATH_SCALING5: ratio of {1, 8} * %CHAN_PATH_NONE: Do not use this pre-scaling ratio type. * * The pre-scaling is applied for signals to be within the voltage range @@ -202,6 +203,7 @@ enum qpnp_adc_channel_scaling_param { PATH_SCALING2, PATH_SCALING3, PATH_SCALING4, + PATH_SCALING5, PATH_SCALING_NONE, }; @@ -900,7 +902,8 @@ static const struct qpnp_vadc_scaling_ratio qpnp_vadc_amux_scaling_ratio[] = { {1, 3}, {1, 4}, {1, 6}, - {1, 20} + {1, 20}, + {1, 8} }; /** diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h index 67f4d8c967e..56a3a5fdb02 100644 --- a/include/linux/slimbus/slimbus.h +++ b/include/linux/slimbus/slimbus.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 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 @@ -634,6 +634,10 @@ struct slim_pending_ch { * @driver: Device's driver. Pointer to access routines. * @ctrl: Slimbus controller managing the bus hosting this device. * @laddr: 1-byte Logical address of this device. + * @reported: Flag to indicate whether this device reported present. The flag + * is set when device reports present, and is reset when it reports + * absent. This flag alongwith notified flag below is used to call + * device_up, or device_down callbacks for driver of this device. * @mark_define: List of channels pending definition/activation. * @mark_suspend: List of channels pending suspend. * @mark_removal: List of channels pending removal. @@ -657,6 +661,7 @@ struct slim_device { struct slim_driver *driver; struct slim_controller *ctrl; u8 laddr; + bool reported; struct list_head mark_define; struct list_head mark_suspend; struct list_head mark_removal; diff --git a/include/linux/test-iosched.h b/include/linux/test-iosched.h index 3551b7efd31..0bfed06cc09 100644 --- a/include/linux/test-iosched.h +++ b/include/linux/test-iosched.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,6 +28,7 @@ #define TEST_PATTERN_FF 0xFFFFFFFF #define TEST_NO_PATTERN 0xDEADBEEF #define BIO_U32_SIZE 1024 +#define TEST_BIO_SIZE PAGE_SIZE /* use one page bios */ struct test_data; diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 894f157f418..66d6a9e1314 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -2,7 +2,7 @@ * * Copyright (C) 2008 Google, Inc. * Author: Brian Swetland <swetland@google.com> - * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -359,6 +359,7 @@ struct msm_otg_platform_data { * @chg_check_timer: The timer used to implement the workaround to detect * very slow plug in of wall charger. * @ui_enabled: USB Intterupt is enabled or disabled. + * @pm_done: Indicates whether USB is PM resumed */ struct msm_otg { struct usb_phy phy; @@ -478,6 +479,7 @@ struct msm_otg { bool ext_chg_active; struct completion ext_chg_wait; int ui_enabled; + bool pm_done; }; struct ci13xxx_platform_data { diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index b2bf1229fe3..08db46e4f1e 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -138,9 +138,6 @@ struct driver_info { /* link reset handling, called from defer_kevent */ int (*link_reset)(struct usbnet *); - /*in case if usbnet wrapper wants to override rx_complete()*/ - void (*rx_complete) (struct urb *); - /* fixup rx packet (strip framing) */ int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb); @@ -250,7 +247,6 @@ extern void usbnet_set_msglevel(struct net_device *, u32); extern void usbnet_get_drvinfo(struct net_device *, struct ethtool_drvinfo *); extern int usbnet_nway_reset(struct net_device *net); extern void usbnet_terminate_urbs(struct usbnet *dev); -extern void rx_complete(struct urb *urb); extern int usbnet_manage_power(struct usbnet *, int); extern void usbnet_link_change(struct usbnet *, bool, bool); diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h index 7f98fcc82ac..5808475eda2 100644 --- a/include/media/msm_cam_sensor.h +++ b/include/media/msm_cam_sensor.h @@ -51,6 +51,7 @@ #define MAX_EEPROM_NAME 32 #define MAX_AF_ITERATIONS 3 +#define MAX_NUMBER_OF_STEPS 47 #define MAX_LED_TRIGGERS 3 @@ -472,6 +473,7 @@ enum msm_actuator_cfg_type_t { CFG_GET_ACTUATOR_INFO, CFG_SET_ACTUATOR_INFO, CFG_SET_DEFAULT_FOCUS, + CFG_SET_POSITION, CFG_MOVE_FOCUS, CFG_ACTUATOR_POWERDOWN, }; @@ -580,6 +582,13 @@ enum af_camera_name { ACTUATOR_WEB_CAM_2, }; + +struct msm_actuator_set_position_t { + uint16_t number_of_steps; + uint16_t pos[MAX_NUMBER_OF_STEPS]; + uint16_t delay[MAX_NUMBER_OF_STEPS]; +}; + struct msm_actuator_cfg_data { int cfgtype; uint8_t is_af_supported; @@ -587,6 +596,7 @@ struct msm_actuator_cfg_data { struct msm_actuator_move_params_t move; struct msm_actuator_set_info_t set_info; struct msm_actuator_get_info_t get_info; + struct msm_actuator_set_position_t setpos; enum af_camera_name cam_name; } cfg; }; diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h index 6c7f4e55a32..9a1c750b0c5 100644 --- a/include/media/msmb_pproc.h +++ b/include/media/msmb_pproc.h @@ -229,6 +229,9 @@ struct msm_pproc_queue_buf_info { #define VIDIOC_MSM_CPP_QUEUE_BUF \ _IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct msm_camera_v4l2_ioctl_t) +#define VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_camera_v4l2_ioctl_t) + #define VIDIOC_MSM_CPP_SET_CLOCK \ _IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_camera_v4l2_ioctl_t) diff --git a/include/net/cnss.h b/include/net/cnss.h index 5917b099ab0..74ece63559c 100644 --- a/include/net/cnss.h +++ b/include/net/cnss.h @@ -47,6 +47,8 @@ extern int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver); extern void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver); extern int cnss_get_fw_files(struct cnss_fw_files *pfw_files); +extern void cnss_flush_work(void *work); +extern void cnss_flush_delayed_work(void *dwork); extern void cnss_pm_wake_lock_init(struct wakeup_source *ws, const char *name); extern void cnss_pm_wake_lock(struct wakeup_source *ws); @@ -54,4 +56,8 @@ extern void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec); extern void cnss_pm_wake_lock_release(struct wakeup_source *ws); extern void cnss_pm_wake_lock_destroy(struct wakeup_source *ws); +extern int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu); +extern void cnss_request_pm_qos(u32 qos_val); +extern void cnss_remove_pm_qos(void); + #endif /* _NET_CNSS_H_ */ diff --git a/arch/arm/mach-msm/clock-alpha-pll.h b/include/soc/qcom/clock-alpha-pll.h index 005119471c5..4d8e2b0c6d3 100644 --- a/arch/arm/mach-msm/clock-alpha-pll.h +++ b/include/soc/qcom/clock-alpha-pll.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -41,6 +41,7 @@ struct alpha_pll_vco_tbl { struct alpha_pll_clk { struct alpha_pll_masks *masks; void *const __iomem *base; + const u32 offset; struct alpha_pll_vco_tbl *vco_tbl; u32 num_vco; diff --git a/arch/arm/mach-msm/clock-local2.h b/include/soc/qcom/clock-local2.h index cfec62588b3..e9a4881531b 100644 --- a/arch/arm/mach-msm/clock-local2.h +++ b/include/soc/qcom/clock-local2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -41,7 +41,7 @@ struct clk_freq_tbl { const unsigned sys_vdd; }; -#define FREQ_END (UINT_MAX-1) +#define FREQ_END (ULONG_MAX-1) #define F_END { .freq_hz = FREQ_END } /* diff --git a/arch/arm/mach-msm/clock-pll.h b/include/soc/qcom/clock-pll.h index 795d72db216..795d72db216 100644 --- a/arch/arm/mach-msm/clock-pll.h +++ b/include/soc/qcom/clock-pll.h diff --git a/arch/arm/mach-msm/clock-rpm.h b/include/soc/qcom/clock-rpm.h index 98ae2a721bc..98ae2a721bc 100644 --- a/arch/arm/mach-msm/clock-rpm.h +++ b/include/soc/qcom/clock-rpm.h diff --git a/arch/arm/mach-msm/clock-voter.h b/include/soc/qcom/clock-voter.h index 9eb3898db1e..9eb3898db1e 100644 --- a/arch/arm/mach-msm/clock-voter.h +++ b/include/soc/qcom/clock-voter.h diff --git a/arch/arm/mach-msm/hsic_sysmon.h b/include/soc/qcom/hsic_sysmon.h index 9655dc030b0..9655dc030b0 100644 --- a/arch/arm/mach-msm/hsic_sysmon.h +++ b/include/soc/qcom/hsic_sysmon.h diff --git a/arch/arm/mach-msm/include/mach/msm_qmi_interface.h b/include/soc/qcom/msm_qmi_interface.h index 9867ddf8513..9867ddf8513 100644 --- a/arch/arm/mach-msm/include/mach/msm_qmi_interface.h +++ b/include/soc/qcom/msm_qmi_interface.h diff --git a/arch/arm/mach-msm/include/mach/ramdump.h b/include/soc/qcom/ramdump.h index 7cd59dd8904..7cd59dd8904 100644 --- a/arch/arm/mach-msm/include/mach/ramdump.h +++ b/include/soc/qcom/ramdump.h diff --git a/arch/arm/mach-msm/include/mach/scm.h b/include/soc/qcom/scm.h index 9d186ce1428..9d186ce1428 100644 --- a/arch/arm/mach-msm/include/mach/scm.h +++ b/include/soc/qcom/scm.h diff --git a/arch/arm/mach-msm/include/mach/smem_log.h b/include/soc/qcom/smem_log.h index 22982e2be0b..85b8bfd6d51 100644 --- a/arch/arm/mach-msm/include/mach/smem_log.h +++ b/include/soc/qcom/smem_log.h @@ -56,7 +56,7 @@ #define SMEM_LOG_EVENT_TASK (SMEM_LOG_SMEM_EVENT_BASE + 16) #define SMEM_LOG_EVENT_RS (SMEM_LOG_SMEM_EVENT_BASE + 17) -#ifdef CONFIG_MSM_SMD_LOGGING +#ifdef CONFIG_MSM_SMEM_LOGGING void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2, uint32_t data3); void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2, diff --git a/arch/arm/mach-msm/include/mach/subsystem_notif.h b/include/soc/qcom/subsystem_notif.h index 61be8f4268d..61be8f4268d 100644 --- a/arch/arm/mach-msm/include/mach/subsystem_notif.h +++ b/include/soc/qcom/subsystem_notif.h diff --git a/include/soc/qcom/subsystem_restart.h b/include/soc/qcom/subsystem_restart.h new file mode 100644 index 00000000000..60ff7d7fe5c --- /dev/null +++ b/include/soc/qcom/subsystem_restart.h @@ -0,0 +1,133 @@ +/* Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __SUBSYS_RESTART_H +#define __SUBSYS_RESTART_H + +#include <linux/spinlock.h> +#include <linux/interrupt.h> + +#define SUBSYS_NAME_MAX_LENGTH 40 + +struct subsys_device; + +enum { + RESET_SOC = 0, + RESET_SUBSYS_COUPLED, + RESET_LEVEL_MAX +}; + +struct device; +struct module; + +/** + * struct subsys_desc - subsystem descriptor + * @name: name of subsystem + * @depends_on: subsystem this subsystem depends on to operate + * @dev: parent device + * @owner: module the descriptor belongs to + * @shutdown: Stop a subsystem + * @powerup: Start a subsystem + * @crash_shutdown: Shutdown a subsystem when the system crashes (can't sleep) + * @ramdump: Collect a ramdump of the subsystem + * @is_not_loadable: Indicate if subsystem firmware is not loadable via pil + * framework + */ +struct subsys_desc { + const char *name; + const char *depends_on; + struct device *dev; + struct module *owner; + + int (*shutdown)(const struct subsys_desc *desc, bool force_stop); + int (*powerup)(const struct subsys_desc *desc); + void (*crash_shutdown)(const struct subsys_desc *desc); + int (*ramdump)(int, const struct subsys_desc *desc); + irqreturn_t (*err_fatal_handler) (int irq, void *dev_id); + irqreturn_t (*stop_ack_handler) (int irq, void *dev_id); + irqreturn_t (*wdog_bite_handler) (int irq, void *dev_id); + int is_not_loadable; + unsigned int err_fatal_irq; + unsigned int err_ready_irq; + unsigned int stop_ack_irq; + unsigned int wdog_bite_irq; + int force_stop_gpio; +}; + +#if defined(CONFIG_MSM_SUBSYSTEM_RESTART) + +extern int subsys_get_restart_level(struct subsys_device *dev); +extern int subsystem_restart_dev(struct subsys_device *dev); +extern int subsystem_restart(const char *name); +extern int subsystem_crashed(const char *name); + +extern void *subsystem_get(const char *name); +extern void subsystem_put(void *subsystem); + +extern struct subsys_device *subsys_register(struct subsys_desc *desc); +extern void subsys_unregister(struct subsys_device *dev); + +extern void subsys_default_online(struct subsys_device *dev); +extern void subsys_set_crash_status(struct subsys_device *dev, bool crashed); +extern bool subsys_get_crash_status(struct subsys_device *dev); +void notify_proxy_vote(struct device *device); +void notify_proxy_unvote(struct device *device); +#else + +static inline int subsys_get_restart_level(struct subsys_device *dev) +{ + return 0; +} + +static inline int subsystem_restart_dev(struct subsys_device *dev) +{ + return 0; +} + +static inline int subsystem_restart(const char *name) +{ + return 0; +} + +static inline int subsystem_crashed(const char *name) +{ + return 0; +} + +static inline void *subsystem_get(const char *name) +{ + return NULL; +} + +static inline void subsystem_put(void *subsystem) { } + +static inline +struct subsys_device *subsys_register(struct subsys_desc *desc) +{ + return NULL; +} + +static inline void subsys_unregister(struct subsys_device *dev) { } + +static inline void subsys_default_online(struct subsys_device *dev) { } +static inline +void subsys_set_crash_status(struct subsys_device *dev, bool crashed) { } +static inline bool subsys_get_crash_status(struct subsys_device *dev) +{ + return false; +} +static inline void notify_proxy_vote(struct device *device) { } +static inline void notify_proxy_unvote(struct device *device) { } +#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */ + +#endif diff --git a/arch/arm/mach-msm/include/mach/sysmon.h b/include/soc/qcom/sysmon.h index 3f122cd2f8c..ad399c9cdc6 100644 --- a/arch/arm/mach-msm/include/mach/sysmon.h +++ b/include/soc/qcom/sysmon.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -16,7 +16,7 @@ #define __MSM_SYSMON_H #include <mach/msm_smd.h> -#include <mach/subsystem_notif.h> +#include <soc/qcom/subsystem_notif.h> /** * enum subsys_id - Destination subsystems for events. diff --git a/include/uapi/Kbuild b/include/uapi/Kbuild index 3098462d692..d7a03482342 100644 --- a/include/uapi/Kbuild +++ b/include/uapi/Kbuild @@ -13,3 +13,4 @@ header-y += drm/ header-y += xen/ header-y += scsi/ header-y += media/ +header-y += ../../drivers/staging/android/uapi/ diff --git a/include/uapi/linux/esoc_ctrl.h b/include/uapi/linux/esoc_ctrl.h index 69139dc5b9e..78c9fc3939c 100644 --- a/include/uapi/linux/esoc_ctrl.h +++ b/include/uapi/linux/esoc_ctrl.h @@ -30,6 +30,7 @@ enum esoc_cmd { enum esoc_notify { ESOC_IMG_XFER_DONE = 1, + ESOC_BOOT_DONE, ESOC_IMG_XFER_RETRY, ESOC_IMG_XFER_FAIL, ESOC_UPGRADE_AVAILABLE, diff --git a/include/uapi/linux/ion.h b/include/uapi/linux/ion.h index 46451a0557c..46b02b5364d 100644 --- a/include/uapi/linux/ion.h +++ b/include/uapi/linux/ion.h @@ -1,199 +1,6 @@ -/* - * include/linux/ion.h - * - * Copyright (C) 2011 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +#ifndef __UAPI_LINUX_ION_H__ +#define __UAPI_LINUX_ION_H__ -#ifndef _UAPI_ION_H -#define _UAPI_ION_H +#include "../../drivers/staging/android/linux/ion.h" -#include <linux/ioctl.h> -#include <linux/types.h> - -struct ion_handle; -typedef struct ion_handle *ion_user_handle_t; - -/** - * enum ion_heap_types - list of all possible types of heaps - * @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc - * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc - * @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved - * carveout heap, allocations are physically - * contiguous - * @ION_HEAP_END: helper for iterating over heaps - */ -enum ion_heap_type { - ION_HEAP_TYPE_SYSTEM, - ION_HEAP_TYPE_SYSTEM_CONTIG, - ION_HEAP_TYPE_CARVEOUT, - ION_HEAP_TYPE_CHUNK, - ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always - are at the end of this enum */ - ION_NUM_HEAPS, -}; - -#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM) -#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG) -#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT) - -#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8 - -/** - * allocation flags - the lower 16 bits are used by core ion, the upper 16 - * bits are reserved for use by the heaps themselves. - */ -#define ION_FLAG_CACHED 1 /* mappings of this buffer should be - cached, ion will do cache - maintenance when the buffer is - mapped for dma */ -#define ION_FLAG_CACHED_NEEDS_SYNC 2 /* mappings of this buffer will created - at mmap time, if this is set - caches must be managed manually */ -#define ION_FLAG_FREED_FROM_SHRINKER 4 /* Skip any possible - heap-specific caching - mechanism (e.g. page - pools). Guarantees that any - buffer storage that came - from the system allocator - will be returned to the - system allocator. */ - -/** - * DOC: Ion Userspace API - * - * create a client by opening /dev/ion - * most operations handled via following ioctls - * - */ - -/** - * struct ion_allocation_data - metadata passed from userspace for allocations - * @len: size of the allocation - * @align: required alignment of the allocation - * @heap_id_mask: mask of heap ids to allocate from - * @flags: flags passed to heap - * @handle: pointer that will be populated with a cookie to use to - * refer to this allocation - * - * Provided by userspace as an argument to the ioctl - */ -struct ion_allocation_data { - size_t len; - size_t align; - unsigned int heap_mask; - unsigned int flags; - ion_user_handle_t handle; -}; - -/** - * struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair - * @handle: a handle - * @fd: a file descriptor representing that handle - * - * For ION_IOC_SHARE or ION_IOC_MAP userspace populates the handle field with - * the handle returned from ion alloc, and the kernel returns the file - * descriptor to share or map in the fd field. For ION_IOC_IMPORT, userspace - * provides the file descriptor and the kernel returns the handle. - */ -struct ion_fd_data { - ion_user_handle_t handle; - int fd; -}; - -/** - * struct ion_handle_data - a handle passed to/from the kernel - * @handle: a handle - */ -struct ion_handle_data { - ion_user_handle_t handle; -}; - -/** - * struct ion_custom_data - metadata passed to/from userspace for a custom ioctl - * @cmd: the custom ioctl function to call - * @arg: additional data to pass to the custom ioctl, typically a user - * pointer to a predefined structure - * - * This works just like the regular cmd and arg fields of an ioctl. - */ -struct ion_custom_data { - unsigned int cmd; - unsigned long arg; -}; -#define ION_IOC_MAGIC 'I' - -/** - * DOC: ION_IOC_ALLOC - allocate memory - * - * Takes an ion_allocation_data struct and returns it with the handle field - * populated with the opaque handle for the allocation. - */ -#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ - struct ion_allocation_data) - -/** - * DOC: ION_IOC_FREE - free memory - * - * Takes an ion_handle_data struct and frees the handle. - */ -#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data) - -/** - * DOC: ION_IOC_MAP - get a file descriptor to mmap - * - * Takes an ion_fd_data struct with the handle field populated with a valid - * opaque handle. Returns the struct with the fd field set to a file - * descriptor open in the current address space. This file descriptor - * can then be used as an argument to mmap. - */ -#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data) - -/** - * DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation - * - * Takes an ion_fd_data struct with the handle field populated with a valid - * opaque handle. Returns the struct with the fd field set to a file - * descriptor open in the current address space. This file descriptor - * can then be passed to another process. The corresponding opaque handle can - * be retrieved via ION_IOC_IMPORT. - */ -#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data) - -/** - * DOC: ION_IOC_IMPORT - imports a shared file descriptor - * - * Takes an ion_fd_data struct with the fd field populated with a valid file - * descriptor obtained from ION_IOC_SHARE and returns the struct with the handle - * filed set to the corresponding opaque handle. - */ -#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data) - -/** - * DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory - * - * Deprecated in favor of using the dma_buf api's correctly (syncing - * will happend automatically when the buffer is mapped to a device). - * If necessary should be used after touching a cached buffer from the cpu, - * this will make the buffer in memory coherent. - */ -#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data) - -/** - * DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl - * - * Takes the argument of the architecture specific ioctl to call and - * passes appropriate userdata for that ioctl - */ -#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data) - -#endif /* _UAPI_ION_H */ +#endif /* __UAPI_LINUX_ION_H__ */ diff --git a/include/uapi/linux/msm_ion.h b/include/uapi/linux/msm_ion.h index 60469ddfa00..784101a30b0 100644 --- a/include/uapi/linux/msm_ion.h +++ b/include/uapi/linux/msm_ion.h @@ -1,194 +1,6 @@ -/* - * include/linux/ion.h - * - * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +#ifndef __UAPI_LINUX_MSM_ION_H__ +#define __UAPI_LINUX_MSM_ION_H__ -#ifndef _UAPI_MSM_ION_H -#define _UAPI_MSM_ION_H +#include "../../drivers/staging/android/linux/msm_ion.h" -#include <linux/ion.h> - -enum msm_ion_heap_types { - ION_HEAP_TYPE_MSM_START = ION_HEAP_TYPE_CUSTOM + 1, - ION_HEAP_TYPE_DMA = ION_HEAP_TYPE_MSM_START, - ION_HEAP_TYPE_CP, - ION_HEAP_TYPE_SECURE_DMA, - ION_HEAP_TYPE_REMOVED, - /* - * if you add a heap type here you should also add it to - * heap_types_info[] in msm_ion.c - */ -}; - -/** - * These are the only ids that should be used for Ion heap ids. - * The ids listed are the order in which allocation will be attempted - * if specified. Don't swap the order of heap ids unless you know what - * you are doing! - * Id's are spaced by purpose to allow new Id's to be inserted in-between (for - * possible fallbacks) - */ - -enum ion_heap_ids { - INVALID_HEAP_ID = -1, - ION_CP_MM_HEAP_ID = 8, - ION_CP_MFC_HEAP_ID = 12, - ION_CP_WB_HEAP_ID = 16, /* 8660 only */ - ION_CAMERA_HEAP_ID = 20, /* 8660 only */ - ION_SYSTEM_CONTIG_HEAP_ID = 21, - ION_ADSP_HEAP_ID = 22, - ION_PIL1_HEAP_ID = 23, /* Currently used for other PIL images */ - ION_SF_HEAP_ID = 24, - ION_SYSTEM_HEAP_ID = 25, - ION_PIL2_HEAP_ID = 26, /* Currently used for modem firmware images */ - ION_QSECOM_HEAP_ID = 27, - ION_AUDIO_HEAP_ID = 28, - - ION_MM_FIRMWARE_HEAP_ID = 29, - - ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_FLAG_SECURE flag */ -}; - -/* - * The IOMMU heap is deprecated! Here are some aliases for backwards - * compatibility: - */ -#define ION_IOMMU_HEAP_ID ION_SYSTEM_HEAP_ID -#define ION_HEAP_TYPE_IOMMU ION_HEAP_TYPE_SYSTEM - -enum ion_fixed_position { - NOT_FIXED, - FIXED_LOW, - FIXED_MIDDLE, - FIXED_HIGH, -}; - -enum cp_mem_usage { - VIDEO_BITSTREAM = 0x1, - VIDEO_PIXEL = 0x2, - VIDEO_NONPIXEL = 0x3, - MAX_USAGE = 0x4, - UNKNOWN = 0x7FFFFFFF, -}; - -#define ION_HEAP_CP_MASK (1 << ION_HEAP_TYPE_CP) -#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA) - -/** - * Flag to use when allocating to indicate that a heap is secure. - */ -#define ION_FLAG_SECURE (1 << ION_HEAP_ID_RESERVED) - -/** - * Flag for clients to force contiguous memort allocation - * - * Use of this flag is carefully monitored! - */ -#define ION_FLAG_FORCE_CONTIGUOUS (1 << 30) - -/* - * Used in conjunction with heap which pool memory to force an allocation - * to come from the page allocator directly instead of from the pool allocation - */ -#define ION_FLAG_POOL_FORCE_ALLOC (1 << 16) - -/** -* Deprecated! Please use the corresponding ION_FLAG_* -*/ -#define ION_SECURE ION_FLAG_SECURE -#define ION_FORCE_CONTIGUOUS ION_FLAG_FORCE_CONTIGUOUS - -/** - * Macro should be used with ion_heap_ids defined above. - */ -#define ION_HEAP(bit) (1 << (bit)) - -#define ION_ADSP_HEAP_NAME "adsp" -#define ION_SYSTEM_HEAP_NAME "system" -#define ION_VMALLOC_HEAP_NAME ION_SYSTEM_HEAP_NAME -#define ION_KMALLOC_HEAP_NAME "kmalloc" -#define ION_AUDIO_HEAP_NAME "audio" -#define ION_SF_HEAP_NAME "sf" -#define ION_MM_HEAP_NAME "mm" -#define ION_CAMERA_HEAP_NAME "camera_preview" -#define ION_IOMMU_HEAP_NAME "iommu" -#define ION_MFC_HEAP_NAME "mfc" -#define ION_WB_HEAP_NAME "wb" -#define ION_MM_FIRMWARE_HEAP_NAME "mm_fw" -#define ION_PIL1_HEAP_NAME "pil_1" -#define ION_PIL2_HEAP_NAME "pil_2" -#define ION_QSECOM_HEAP_NAME "qsecom" - -#define ION_SET_CACHED(__cache) (__cache | ION_FLAG_CACHED) -#define ION_SET_UNCACHED(__cache) (__cache & ~ION_FLAG_CACHED) - -#define ION_IS_CACHED(__flags) ((__flags) & ION_FLAG_CACHED) - -/* struct ion_flush_data - data passed to ion for flushing caches - * - * @handle: handle with data to flush - * @fd: fd to flush - * @vaddr: userspace virtual address mapped with mmap - * @offset: offset into the handle to flush - * @length: length of handle to flush - * - * Performs cache operations on the handle. If p is the start address - * of the handle, p + offset through p + offset + length will have - * the cache operations performed - */ -struct ion_flush_data { - struct ion_handle *handle; - int fd; - void *vaddr; - unsigned int offset; - unsigned int length; -}; - - -struct ion_prefetch_data { - int heap_id; - unsigned long len; -}; - -#define ION_IOC_MSM_MAGIC 'M' - -/** - * DOC: ION_IOC_CLEAN_CACHES - clean the caches - * - * Clean the caches of the handle specified. - */ -#define ION_IOC_CLEAN_CACHES _IOWR(ION_IOC_MSM_MAGIC, 0, \ - struct ion_flush_data) -/** - * DOC: ION_IOC_INV_CACHES - invalidate the caches - * - * Invalidate the caches of the handle specified. - */ -#define ION_IOC_INV_CACHES _IOWR(ION_IOC_MSM_MAGIC, 1, \ - struct ion_flush_data) -/** - * DOC: ION_IOC_CLEAN_INV_CACHES - clean and invalidate the caches - * - * Clean and invalidate the caches of the handle specified. - */ -#define ION_IOC_CLEAN_INV_CACHES _IOWR(ION_IOC_MSM_MAGIC, 2, \ - struct ion_flush_data) - -#define ION_IOC_PREFETCH _IOWR(ION_IOC_MSM_MAGIC, 3, \ - struct ion_prefetch_data) - -#define ION_IOC_DRAIN _IOWR(ION_IOC_MSM_MAGIC, 4, \ - struct ion_prefetch_data) - -#endif +#endif /* __UAPI_LINUX_MSM_ION_H__ */ diff --git a/include/uapi/linux/msm_mdp.h b/include/uapi/linux/msm_mdp.h index 66eab0c400e..fa0bd3e5fd6 100644 --- a/include/uapi/linux/msm_mdp.h +++ b/include/uapi/linux/msm_mdp.h @@ -180,6 +180,7 @@ enum { #define MDP_BLEND_FG_PREMULT 0x20000 #define MDP_IS_FG 0x40000 #define MDP_SOLID_FILL 0x00000020 +#define MDP_VPU_PIPE 0x00000040 #define MDP_DEINTERLACE 0x80000000 #define MDP_SHARPENING 0x40000000 #define MDP_NO_DMA_BARRIER_START 0x20000000 @@ -975,6 +976,8 @@ struct mdss_hw_caps { uint8_t rgb_pipes; uint8_t vig_pipes; uint8_t dma_pipes; + uint8_t max_smp_cnt; + uint8_t smp_per_pipe; uint32_t features; }; diff --git a/include/uapi/linux/rmnet_data.h b/include/uapi/linux/rmnet_data.h index 7ba00f217b1..d978caafcbd 100644 --- a/include/uapi/linux/rmnet_data.h +++ b/include/uapi/linux/rmnet_data.h @@ -55,6 +55,7 @@ struct rmnet_nl_msg_s { uint32_t flags; uint16_t agg_size; uint16_t agg_count; + uint8_t tail_spacing; } data_format; struct { uint8_t dev[RMNET_MAX_STR_LEN]; diff --git a/lib/Kconfig b/lib/Kconfig index 19d58eb1b8f..bbf6bf06e58 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -408,7 +408,7 @@ config UCS2_STRING tristate config QMI_ENCDEC - bool + bool "QMI Encode/Decode Library" help Library to encode & decode QMI messages from within the kernel. The kernel drivers encode the C structure into @@ -417,7 +417,7 @@ config QMI_ENCDEC and then decode it into a C structure. config QMI_ENCDEC_DEBUG - bool + bool "QMI Encode/Decode Library Debug" help Kernel config option to enable debugging QMI Encode/Decode library. This will log the information regarding the element diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c index f3b889419ee..e24f979c1be 100644 --- a/net/ipc_router/ipc_router_core.c +++ b/net/ipc_router/ipc_router_core.c @@ -32,11 +32,11 @@ #include <linux/uaccess.h> #include <linux/ipc_router.h> #include <linux/ipc_router_xprt.h> +#include <soc/qcom/subsystem_notif.h> #include <asm/byteorder.h> -#include <mach/smem_log.h> -#include <mach/subsystem_notif.h> +#include <soc/qcom/smem_log.h> #include "ipc_router_private.h" #include "ipc_router_security.h" @@ -2056,7 +2056,7 @@ static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info, struct rr_header_v1 *hdr; if (pkt->length != sizeof(*msg)) { - pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length, + pr_err("%s: r2r msg size %d != %zu\n", __func__, pkt->length, sizeof(*msg)); return -EINVAL; } @@ -2135,8 +2135,7 @@ static void do_read_data(struct work_struct *work) release_pkt(pkt); continue; } -#if defined(CONFIG_MSM_SMD_LOGGING) -#if defined(DEBUG) + if (msm_ipc_router_debug_mask & SMEM_LOG) { smem_log_event((SMEM_LOG_PROC_ID_APPS | SMEM_LOG_IPC_ROUTER_EVENT_BASE | @@ -2148,8 +2147,6 @@ static void do_read_data(struct work_struct *work) (hdr->type << 24) | (hdr->control_flag << 16) | (hdr->size & 0xffff)); } -#endif -#endif down_read(&local_ports_lock_lha2); port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id); @@ -2444,8 +2441,6 @@ static int msm_ipc_router_write_pkt(struct msm_ipc_port *src, hdr->control_flag, hdr->size, hdr->dst_node_id, hdr->dst_port_id); -#if defined(CONFIG_MSM_SMD_LOGGING) -#if defined(DEBUG) if (msm_ipc_router_debug_mask & SMEM_LOG) { smem_log_event((SMEM_LOG_PROC_ID_APPS | SMEM_LOG_IPC_ROUTER_EVENT_BASE | @@ -2457,8 +2452,6 @@ static int msm_ipc_router_write_pkt(struct msm_ipc_port *src, (hdr->type << 24) | (hdr->control_flag << 16) | (hdr->size & 0xffff)); } -#endif -#endif return hdr->size; } diff --git a/net/ipc_router/ipc_router_security.c b/net/ipc_router/ipc_router_security.c index 9deab65f925..50db88d0c4e 100644 --- a/net/ipc_router/ipc_router_security.c +++ b/net/ipc_router/ipc_router_security.c @@ -118,7 +118,7 @@ int msm_ipc_config_sec_rules(void *arg) return -EINVAL; if (sec_rules_arg.num_group_info > (SIZE_MAX / sizeof(gid_t))) { - pr_err("%s: Integer Overflow %d * %d\n", __func__, + pr_err("%s: Integer Overflow %zu * %d\n", __func__, sizeof(gid_t), sec_rules_arg.num_group_info); return -EINVAL; } diff --git a/net/ipc_router/ipc_router_socket.c b/net/ipc_router/ipc_router_socket.c index 979b4832850..ab1b83f1f04 100644 --- a/net/ipc_router/ipc_router_socket.c +++ b/net/ipc_router/ipc_router_socket.c @@ -489,7 +489,7 @@ static int msm_ipc_router_ioctl(struct socket *sock, if (server_arg.num_entries_in_array) { if (server_arg.num_entries_in_array > (SIZE_MAX / sizeof(*srv_info))) { - pr_err("%s: Integer Overflow %d * %d\n", + pr_err("%s: Integer Overflow %zu * %d\n", __func__, sizeof(*srv_info), server_arg.num_entries_in_array); ret = -EINVAL; diff --git a/net/rmnet_data/rmnet_data_config.c b/net/rmnet_data/rmnet_data_config.c index d013425d9bf..2eca68b4b66 100644 --- a/net/rmnet_data/rmnet_data_config.c +++ b/net/rmnet_data/rmnet_data_config.c @@ -77,13 +77,13 @@ int rmnet_config_init(void) int rc; nl_socket_handle = _rmnet_config_start_netlink(); if (!nl_socket_handle) { - LOGE("%s(): Failed to init netlink socket\n", __func__); + LOGE("%s", "Failed to init netlink socket"); return RMNET_INIT_ERROR; } rc = register_netdevice_notifier(&rmnet_dev_notifier); if (rc != 0) { - LOGE("%s(): Failed to register device notifier\n", __func__); + LOGE("Failed to register device notifier; rc=%d", rc); /* TODO: Cleanup the nl socket */ return RMNET_INIT_ERROR; } @@ -218,9 +218,10 @@ static void _rmnet_netlink_set_link_ingress_data_format return; } - resp_rmnet->return_code = - rmnet_set_ingress_data_format(dev, - rmnet_header->data_format.flags); + resp_rmnet->return_code = rmnet_set_ingress_data_format( + dev, + rmnet_header->data_format.flags, + rmnet_header->data_format.tail_spacing); dev_put(dev); } @@ -384,6 +385,7 @@ static void _rmnet_netlink_get_link_ingress_data_format resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNDATA; resp_rmnet->arg_length = RMNET_NL_MSG_SIZE(data_format); resp_rmnet->data_format.flags = config->ingress_data_format; + resp_rmnet->data_format.tail_spacing = config->tail_spacing; dev_put(dev); } @@ -436,8 +438,7 @@ static void _rmnet_netlink_add_del_vnd_tc_flow tc_flow_id); break; default: - LOGM("%s(): called with unhandled command %d\n", - __func__, command); + LOGM("Called with unhandled command %d", command); resp_rmnet->return_code = RMNET_CONFIG_INVALID_REQUEST; break; } @@ -461,8 +462,7 @@ void rmnet_config_netlink_msg_handler(struct sk_buff *skb) nlmsg_header = (struct nlmsghdr *) skb->data; rmnet_header = (struct rmnet_nl_msg_s *) nlmsg_data(nlmsg_header); - LOGL("%s(): Netlink message pid=%d, seq=%d, length=%d, rmnet_type=%d\n", - __func__, + LOGL("Netlink message pid=%d, seq=%d, length=%d, rmnet_type=%d", nlmsg_header->nlmsg_pid, nlmsg_header->nlmsg_seq, nlmsg_header->nlmsg_len, @@ -475,7 +475,7 @@ void rmnet_config_netlink_msg_handler(struct sk_buff *skb) GFP_KERNEL); if (!skb_response) { - LOGH("%s(): Failed to allocate response buffer\n", __func__); + LOGH("%s", "Failed to allocate response buffer"); return; } @@ -574,7 +574,7 @@ void rmnet_config_netlink_msg_handler(struct sk_buff *skb) } rtnl_unlock(); nlmsg_unicast(nl_socket_handle, skb_response, return_pid); - LOGD("%s(): Done processing command\n", __func__); + LOGD("%s", "Done processing command"); } @@ -601,7 +601,7 @@ int rmnet_unassociate_network_device(struct net_device *dev) struct rmnet_logical_ep_conf_s *epconfig_l; ASSERT_RTNL(); - LOGL("%s(%s);", __func__, dev->name); + LOGL("(%s);", dev->name); if (!dev) return RMNET_CONFIG_NO_SUCH_DEVICE; @@ -643,12 +643,13 @@ int rmnet_unassociate_network_device(struct net_device *dev) * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null */ int rmnet_set_ingress_data_format(struct net_device *dev, - uint32_t ingress_data_format) + uint32_t ingress_data_format, + uint8_t tail_spacing) { struct rmnet_phys_ep_conf_s *config; ASSERT_RTNL(); - LOGL("%s(%s,0x%08X);", __func__, dev->name, ingress_data_format); + LOGL("(%s,0x%08X);", dev->name, ingress_data_format); if (!dev) return RMNET_CONFIG_NO_SUCH_DEVICE; @@ -659,6 +660,7 @@ int rmnet_set_ingress_data_format(struct net_device *dev, return RMNET_CONFIG_INVALID_REQUEST; config->ingress_data_format = ingress_data_format; + config->tail_spacing = tail_spacing; return RMNET_CONFIG_OK; } @@ -684,8 +686,8 @@ int rmnet_set_egress_data_format(struct net_device *dev, struct rmnet_phys_ep_conf_s *config; ASSERT_RTNL(); - LOGL("%s(%s,0x%08X, %d, %d);", - __func__, dev->name, egress_data_format, agg_size, agg_count); + LOGL("(%s,0x%08X, %d, %d);", + dev->name, egress_data_format, agg_size, agg_count); if (!dev) return RMNET_CONFIG_NO_SUCH_DEVICE; @@ -722,18 +724,18 @@ int rmnet_associate_network_device(struct net_device *dev) int rc; ASSERT_RTNL(); - LOGL("%s(%s);\n", __func__, dev->name); + LOGL("(%s);\n", dev->name); if (!dev) return RMNET_CONFIG_NO_SUCH_DEVICE; if (_rmnet_is_physical_endpoint_associated(dev)) { - LOGM("%s(): %s is already regestered\n", __func__, dev->name); + LOGM("%s is already regestered", dev->name); return RMNET_CONFIG_DEVICE_IN_USE; } if (rmnet_vnd_is_vnd(dev)) { - LOGM("%s(): %s is a vnd\n", __func__, dev->name); + LOGM("%s is a vnd", dev->name); return RMNET_CONFIG_INVALID_REQUEST; } @@ -750,8 +752,7 @@ int rmnet_associate_network_device(struct net_device *dev) rc = netdev_rx_handler_register(dev, rmnet_rx_handler, config); if (rc) { - LOGM("%s(): netdev_rx_handler_register returns %d\n", - __func__, rc); + LOGM("netdev_rx_handler_register returns %d", rc); kfree(config); return RMNET_CONFIG_DEVICE_IN_USE; } @@ -847,7 +848,7 @@ int _rmnet_unset_logical_endpoint_config(struct net_device *dev, } /** - * rmnet_set_logical_endpoint_config() - Set logical endpoing configuration on a device + * rmnet_set_logical_endpoint_config() - Set logical endpoint config on a device * @dev: Device to set endpoint configuration on * @config_id: logical endpoint id on device * @rmnet_mode: endpoint mode. Values from: rmnet_config_endpoint_modes_e @@ -875,8 +876,8 @@ int rmnet_set_logical_endpoint_config(struct net_device *dev, { struct rmnet_logical_ep_conf_s epconfig; - LOGL("%s(%s, %d, %d, %s);\n", - __func__, dev->name, config_id, rmnet_mode, egress_dev->name); + LOGL("(%s, %d, %d, %s);", + dev->name, config_id, rmnet_mode, egress_dev->name); if (!egress_dev || ((!_rmnet_is_physical_endpoint_associated(egress_dev)) @@ -910,8 +911,7 @@ int rmnet_set_logical_endpoint_config(struct net_device *dev, int rmnet_unset_logical_endpoint_config(struct net_device *dev, int config_id) { - LOGL("%s(%s, %d);\n", - __func__, dev->name, config_id); + LOGL("(%s, %d);", dev->name, config_id); if (!dev || ((!_rmnet_is_physical_endpoint_associated(dev)) @@ -933,7 +933,7 @@ int rmnet_create_vnd(int id) { struct net_device *dev; ASSERT_RTNL(); - LOGL("%s(%d);\n", __func__, id); + LOGL("(%d);", id); return rmnet_vnd_create_dev(id, &dev, NULL); } @@ -949,7 +949,7 @@ int rmnet_create_vnd_prefix(int id, const char *prefix) { struct net_device *dev; ASSERT_RTNL(); - LOGL("%s(%d, \"%s\");\n", __func__, id, prefix); + LOGL("(%d, \"%s\");", id, prefix); return rmnet_vnd_create_dev(id, &dev, prefix); } @@ -962,7 +962,7 @@ int rmnet_create_vnd_prefix(int id, const char *prefix) */ int rmnet_free_vnd(int id) { - LOGL("%s(%d);\n", __func__, id); + LOGL("(%d);", id); return rmnet_vnd_free_dev(id); } @@ -981,8 +981,7 @@ static void rmnet_force_unassociate_device(struct net_device *dev) BUG(); if (!_rmnet_is_physical_endpoint_associated(dev)) { - LOGM("%s(): Called on unassociated device, skipping\n", - __func__); + LOGM("%s", "Called on unassociated device, skipping"); return; } @@ -1009,20 +1008,19 @@ int rmnet_config_notify_cb(struct notifier_block *nb, if (!dev) BUG(); - LOGL("%s(..., %lu, %s)\n", __func__, event, dev->name); + LOGL("(..., %lu, %s)", event, dev->name); switch (event) { case NETDEV_UNREGISTER_FINAL: case NETDEV_UNREGISTER: if (_rmnet_is_physical_endpoint_associated(dev)) { - LOGH("%s(): Kernel is trying to unregister %s\n", - __func__, dev->name); + LOGH("Kernel is trying to unregister %s", dev->name); rmnet_force_unassociate_device(dev); } break; default: - LOGD("%s(): Unhandeled event\n", __func__); + LOGD("Unhandeled event [%lu]", event); break; } diff --git a/net/rmnet_data/rmnet_data_config.h b/net/rmnet_data/rmnet_data_config.h index b408c4f0110..e6b5481bdcb 100644 --- a/net/rmnet_data/rmnet_data_config.h +++ b/net/rmnet_data/rmnet_data_config.h @@ -43,6 +43,7 @@ struct rmnet_phys_ep_conf_s { struct sk_buff *agg_skb; uint8_t agg_state; uint8_t agg_count; + uint8_t tail_spacing; }; int rmnet_config_init(void); @@ -50,7 +51,8 @@ void rmnet_config_exit(void); int rmnet_unassociate_network_device(struct net_device *dev); int rmnet_set_ingress_data_format(struct net_device *dev, - uint32_t ingress_data_format); + uint32_t ingress_data_format, + uint8_t tail_spacing); int rmnet_set_egress_data_format(struct net_device *dev, uint32_t egress_data_format, uint16_t agg_size, diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c index 7c9a8263f14..e5912d6da3c 100644 --- a/net/rmnet_data/rmnet_data_handlers.c +++ b/net/rmnet_data/rmnet_data_handlers.c @@ -147,8 +147,8 @@ static rx_handler_result_t rmnet_bridge_handler(struct sk_buff *skb, struct rmnet_logical_ep_conf_s *ep) { if (!ep->egress_dev) { - LOGD("%s(): Missing egress device for packet arriving on %s", - __func__, skb->dev->name); + LOGD("Missing egress device for packet arriving on %s", + skb->dev->name); kfree_skb(skb); } else { rmnet_egress_handler(skb, ep); @@ -192,8 +192,7 @@ static rx_handler_result_t __rmnet_deliver_skb(struct sk_buff *skb, return RX_HANDLER_PASS; default: - LOGD("%s() unkown ep mode %d", __func__, - ep->rmnet_mode); + LOGD("Unkown ep mode %d", ep->rmnet_mode); kfree_skb(skb); return RX_HANDLER_CONSUMED; } @@ -212,16 +211,15 @@ static rx_handler_result_t __rmnet_deliver_skb(struct sk_buff *skb, static rx_handler_result_t rmnet_ingress_deliver_packet(struct sk_buff *skb, struct rmnet_phys_ep_conf_s *config) { - if (0 == config) { - LOGD("%s(): NULL physical EP provided\n", - __func__); + if (!config) { + LOGD("%s", "NULL physical EP provided"); kfree_skb(skb); return RX_HANDLER_CONSUMED; } if (!(config->local_ep.refcount)) { - LOGD("%s(): Packet on %s has no local endpoint configuration\n", - __func__, skb->dev->name); + LOGD("Packet on %s has no local endpoint configuration", + skb->dev->name); kfree_skb(skb); return RX_HANDLER_CONSUMED; } @@ -253,11 +251,13 @@ static rx_handler_result_t _rmnet_map_ingress_handler(struct sk_buff *skb, uint16_t len; mux_id = RMNET_MAP_GET_MUX_ID(skb); - len = RMNET_MAP_GET_LENGTH(skb) - RMNET_MAP_GET_PAD(skb); + len = RMNET_MAP_GET_LENGTH(skb) + - RMNET_MAP_GET_PAD(skb) + - config->tail_spacing; if (mux_id >= RMNET_DATA_MAX_LOGICAL_EP) { - LOGD("%s(): Got packet on %s with bad mux id %d\n", - __func__, skb->dev->name, mux_id); + LOGD("Got packet on %s with bad mux id %d", + skb->dev->name, mux_id); kfree_skb(skb); return RX_HANDLER_CONSUMED; } @@ -265,8 +265,8 @@ static rx_handler_result_t _rmnet_map_ingress_handler(struct sk_buff *skb, ep = &(config->muxed_ep[mux_id]); if (!ep->refcount) { - LOGD("%s(): Packet on %s:%d; has no logical endpoint config\n", - __func__, skb->dev->name, mux_id); + LOGD("Packet on %s:%d; has no logical endpoint config", + skb->dev->name, mux_id); kfree_skb(skb); return RX_HANDLER_CONSUMED; @@ -305,7 +305,7 @@ static rx_handler_result_t rmnet_map_ingress_handler(struct sk_buff *skb, if (config->ingress_data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) { while ((skbn = rmnet_map_deaggregate(skb, config)) != 0) { - LOGD("co=%d\n", co); + LOGD("co=%d", co); _rmnet_map_ingress_handler(skbn, config); co++; } @@ -344,12 +344,12 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, required_headroom = sizeof(struct rmnet_map_header_s); - LOGD("%s(): headroom of %d bytes\n", __func__, required_headroom); + LOGD("headroom of %d bytes", required_headroom); if (skb_headroom(skb) < required_headroom) { if (pskb_expand_head(skb, required_headroom, 0, GFP_KERNEL)) { - LOGD("%s(): Failed to add headroom of %d bytes\n", - __func__, required_headroom); + LOGD("Failed to add headroom of %d bytes", + required_headroom); return 1; } } @@ -357,8 +357,7 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, map_header = rmnet_map_add_map_header(skb, additional_header_length); if (!map_header) { - LOGD("%s(): Failed to add MAP header to egress packet", - __func__); + LOGD("%s", "Failed to add MAP header to egress packet"); return 1; } @@ -409,8 +408,7 @@ rx_handler_result_t rmnet_ingress_handler(struct sk_buff *skb) rcu_dereference(skb->dev->rx_handler_data); if (!config) { - LOGD("%s(): %s is not associated with rmnet_data", - __func__, skb->dev->name); + LOGD("%s is not associated with rmnet_data", skb->dev->name); kfree_skb(skb); return RX_HANDLER_CONSUMED; } @@ -431,8 +429,7 @@ rx_handler_result_t rmnet_ingress_handler(struct sk_buff *skb) & RMNET_INGRESS_FORMAT_MAP_COMMANDS) { rc = rmnet_map_command(skb, config); } else { - LOGM("%s(): MAP command packet on %s; %s\n", - __func__, dev->name, + LOGM("MAP command packet on %s; %s", dev->name, "Not configured for MAP commands"); kfree_skb(skb); return RX_HANDLER_CONSUMED; @@ -447,8 +444,8 @@ rx_handler_result_t rmnet_ingress_handler(struct sk_buff *skb) RMNET_EPMODE_BRIDGE) { rc = rmnet_ingress_deliver_packet(skb, config); } else { - LOGD("%s(): MAP packet on %s; MAP not set\n", - __func__, dev->name); + LOGD("MAP packet on %s; MAP not set", + dev->name); kfree_skb(skb); rc = RX_HANDLER_CONSUMED; } @@ -461,8 +458,8 @@ rx_handler_result_t rmnet_ingress_handler(struct sk_buff *skb) break; default: - LOGD("%s(): Unknown skb->proto 0x%04X\n", - __func__, ntohs(skb->protocol) & 0xFFFF); + LOGD("Unknown skb->proto 0x%04X\n", + ntohs(skb->protocol) & 0xFFFF); rc = RX_HANDLER_PASS; } } @@ -507,27 +504,26 @@ void rmnet_egress_handler(struct sk_buff *skb, rcu_dereference(skb->dev->rx_handler_data); if (!config) { - LOGD("%s(): %s is not associated with rmnet_data", - __func__, skb->dev->name); + LOGD("%s is not associated with rmnet_data", skb->dev->name); kfree_skb(skb); return; } - LOGD("%s(): Packet going out on %s with egress format 0x%08X\n", - __func__, skb->dev->name, config->egress_data_format); + LOGD("Packet going out on %s with egress format 0x%08X", + skb->dev->name, config->egress_data_format); if (config->egress_data_format & RMNET_EGRESS_FORMAT_MAP) { switch (rmnet_map_egress_handler(skb, config, ep)) { case RMNET_MAP_CONSUMED: - LOGD("%s(): MAP process consumed packet\n", __func__); + LOGD("%s", "MAP process consumed packet"); return; case RMNET_MAP_SUCCESS: break; default: - LOGD("%s(): MAP egress failed on packet on %s", - __func__, skb->dev->name); + LOGD("MAP egress failed on packet on %s", + skb->dev->name); kfree_skb(skb); return; } @@ -538,7 +534,7 @@ void rmnet_egress_handler(struct sk_buff *skb, rmnet_print_packet(skb, skb->dev->name, 't'); if (dev_queue_xmit(skb) != 0) { - LOGD("%s(): Failed to queue packet for transmission on [%s]\n", - __func__, skb->dev->name); + LOGD("Failed to queue packet for transmission on [%s]", + skb->dev->name); } } diff --git a/net/rmnet_data/rmnet_data_main.c b/net/rmnet_data/rmnet_data_main.c index 0f58ba2545f..d17211434b3 100644 --- a/net/rmnet_data/rmnet_data_main.c +++ b/net/rmnet_data/rmnet_data_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -43,7 +43,7 @@ static int __init rmnet_init(void) rmnet_config_init(); rmnet_vnd_init(); - LOGL("%s", "RMNET Data driver loaded successfully\n"); + LOGL("%s", "RMNET Data driver loaded successfully"); return 0; } diff --git a/net/rmnet_data/rmnet_data_private.h b/net/rmnet_data/rmnet_data_private.h index cb7b80578b9..7ddcad61320 100644 --- a/net/rmnet_data/rmnet_data_private.h +++ b/net/rmnet_data/rmnet_data_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -43,20 +43,24 @@ extern unsigned int rmnet_data_log_module_mask; #define RMNET_DATA_LOGMASK_MAPC (1<<4) #define LOGE(fmt, ...) do { if (rmnet_data_log_level & RMNET_LOG_LVL_ERR) \ - pr_err(fmt, ##__VA_ARGS__); \ + pr_err("[RMNET:ERR] %s(): " fmt "\n", __func__, \ + ##__VA_ARGS__); \ } while (0) #define LOGH(fmt, ...) do { if (rmnet_data_log_level & RMNET_LOG_LVL_HI) \ - pr_err(fmt, ##__VA_ARGS__); \ + pr_err("[RMNET:HI] %s(): " fmt "\n" , __func__, \ + ##__VA_ARGS__); \ } while (0) #define LOGM(fmt, ...) do { if (rmnet_data_log_level & RMNET_LOG_LVL_MED) \ - pr_warn(fmt, ##__VA_ARGS__); \ + pr_warn("[RMNET:MED] %s(): " fmt "\n", __func__, \ + ##__VA_ARGS__); \ } while (0) #define LOGL(fmt, ...) do { if (unlikely \ (rmnet_data_log_level & RMNET_LOG_LVL_LOW)) \ - pr_notice(fmt, ##__VA_ARGS__); \ + pr_notice("[RMNET:LOW] %s(): " fmt "\n", __func__, \ + ##__VA_ARGS__); \ } while (0) /* Don't use pr_debug as it is compiled out of the kernel. We can be sure of @@ -65,7 +69,8 @@ extern unsigned int rmnet_data_log_module_mask; #define LOGD(fmt, ...) do { if (unlikely( \ (rmnet_data_log_level & RMNET_LOG_LVL_DBG) \ && (rmnet_data_log_module_mask & rmnet_mod_mask))) \ - pr_notice(fmt, ##__VA_ARGS__); \ + pr_notice("[RMNET:DBG] %s(): " fmt "\n", __func__, \ + ##__VA_ARGS__); \ } while (0) #endif /* _RMNET_DATA_PRIVATE_H_ */ diff --git a/net/rmnet_data/rmnet_data_vnd.c b/net/rmnet_data/rmnet_data_vnd.c index 3fd583fedf1..76e111c1791 100644 --- a/net/rmnet_data/rmnet_data_vnd.c +++ b/net/rmnet_data/rmnet_data_vnd.c @@ -217,39 +217,32 @@ static int _rmnet_vnd_do_qos_ioctl(struct net_device *dev, switch (cmd) { case RMNET_IOCTL_SET_QOS_ENABLE: - LOGM("%s(): RMNET_IOCTL_SET_QOS_ENABLE on %s\n", - __func__, dev->name); + LOGM("RMNET_IOCTL_SET_QOS_ENABLE on %s", dev->name); if (!dev_conf->qos_version) dev_conf->qos_version = RMNET_IOCTL_QOS_MODE_6; break; case RMNET_IOCTL_SET_QOS_DISABLE: - LOGM("%s(): RMNET_IOCTL_SET_QOS_DISABLE on %s\n", - __func__, dev->name); + LOGM("RMNET_IOCTL_SET_QOS_DISABLE on %s", dev->name); dev_conf->qos_version = 0; break; case RMNET_IOCTL_GET_QOS: /* Get QoS header state */ - LOGM("%s(): RMNET_IOCTL_GET_QOS on %s\n", - __func__, dev->name); + LOGM("RMNET_IOCTL_GET_QOS on %s", dev->name); ifr->ifr_ifru.ifru_data = (void *)(dev_conf->qos_version == RMNET_IOCTL_QOS_MODE_6); break; case RMNET_IOCTL_FLOW_ENABLE: - LOGL("%s(): RMNET_IOCTL_FLOW_ENABLE on %s\n", - __func__, dev->name); + LOGL("RMNET_IOCTL_FLOW_ENABLE on %s", dev->name); tc_qdisc_flow_control(dev, (u32)ifr->ifr_data, 1); break; case RMNET_IOCTL_FLOW_DISABLE: - LOGL("%s(): RMNET_IOCTL_FLOW_DISABLE on %s\n", - __func__, dev->name); + LOGL("RMNET_IOCTL_FLOW_DISABLE on %s", dev->name); tc_qdisc_flow_control(dev, (u32)ifr->ifr_data, 0); break; - - default: rc = -EINVAL; } @@ -273,8 +266,8 @@ static void _rmnet_vnd_wq_flow_control(struct work_struct *work) tc_qdisc_flow_control(fcwork->dev, fcwork->tc_handle, fcwork->enable); rtnl_unlock(); - LOGL("%s(): [%s] handle:%08X enable:%d\n", - __func__, fcwork->dev->name, fcwork->tc_handle, fcwork->enable); + LOGL("[%s] handle:%08X enable:%d", + fcwork->dev->name, fcwork->tc_handle, fcwork->enable); kfree(work); } @@ -311,7 +304,7 @@ static inline int _rmnet_vnd_do_flow_control(struct net_device *dev, uint32_t tc_handle, int enable) { - LOGD("%s(): [%s] called with no QoS support", __func__, dev->name); + LOGD("[%s] called with no QoS support", dev->name); return RMNET_VND_FC_NOT_ENABLED; } #endif /* CONFIG_RMNET_DATA_FC */ @@ -404,29 +397,25 @@ static int rmnet_vnd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) switch (cmd) { case RMNET_IOCTL_OPEN: /* Do nothing. Support legacy behavior */ - LOGM("%s(): RMNET_IOCTL_OPEN on %s (ignored)\n", - __func__, dev->name); + LOGM("RMNET_IOCTL_OPEN on %s (ignored)", dev->name); break; case RMNET_IOCTL_CLOSE: /* Do nothing. Support legacy behavior */ - LOGM("%s(): RMNET_IOCTL_CLOSE on %s (ignored)\n", - __func__, dev->name); + LOGM("RMNET_IOCTL_CLOSE on %s (ignored)", dev->name); break; case RMNET_IOCTL_SET_LLP_ETHERNET: - LOGM("%s(): RMNET_IOCTL_SET_LLP_ETHERNET on %s (no support)\n", - __func__, dev->name); + LOGM("RMNET_IOCTL_SET_LLP_ETHERNET on %s (no support)", + dev->name); rc = -EINVAL; break; case RMNET_IOCTL_SET_LLP_IP: /* Do nothing. Support legacy behavior */ - LOGM("%s(): RMNET_IOCTL_SET_LLP_IP on %s (ignored)\n", - __func__, dev->name); + LOGM("RMNET_IOCTL_SET_LLP_IP on %s (ignored)", dev->name); break; case RMNET_IOCTL_GET_LLP: /* Always return IP mode */ - LOGM("%s(): RMNET_IOCTL_GET_LLP on %s\n", - __func__, dev->name); + LOGM("RMNET_IOCTL_GET_LLP on %s", dev->name); ifr->ifr_ifru.ifru_data = (void *)(RMNET_MODE_LLP_IP); break; @@ -435,7 +424,7 @@ static int rmnet_vnd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) break; default: - LOGH("%s(): Unkown IOCTL 0x%08X\n", __func__, cmd); + LOGH("Unkown IOCTL 0x%08X", cmd); rc = -EINVAL; } @@ -463,7 +452,7 @@ static const struct net_device_ops rmnet_data_vnd_ops = { static void rmnet_vnd_setup(struct net_device *dev) { struct rmnet_vnd_private_s *dev_conf; - LOGM("%s(): Setting up device %s\n", __func__, dev->name); + LOGM("Setting up device %s", dev->name); /* Clear out private data */ dev_conf = (struct rmnet_vnd_private_s *) netdev_priv(dev); @@ -555,7 +544,7 @@ int rmnet_vnd_create_dev(int id, struct net_device **new_device, p = scnprintf(dev_prefix, IFNAMSIZ, "%s%%d", prefix); if (p >= (IFNAMSIZ-1)) { - LOGE("%s(): Specified prefix longer than IFNAMSIZ", __func__); + LOGE("Specified prefix (%d) longer than IFNAMSIZ", p); return -EINVAL; } @@ -563,16 +552,14 @@ int rmnet_vnd_create_dev(int id, struct net_device **new_device, dev_prefix, rmnet_vnd_setup); if (!dev) { - LOGE("%s(): Failed to to allocate netdev for id %d", - __func__, id); + LOGE("Failed to to allocate netdev for id %d", id); *new_device = 0; return -EINVAL; } rc = register_netdevice(dev); if (rc != 0) { - LOGE("%s(): Failed to to register netdev [%s]", - __func__, dev->name); + LOGE("Failed to to register netdev [%s]", dev->name); free_netdev(dev); *new_device = 0; } else { @@ -580,7 +567,7 @@ int rmnet_vnd_create_dev(int id, struct net_device **new_device, *new_device = dev; } - LOGM("%s(): Registered device %s\n", __func__, dev->name); + LOGM("Registered device %s", dev->name); return rc; } @@ -605,7 +592,7 @@ int rmnet_vnd_free_dev(int id) struct rmnet_logical_ep_conf_s *epconfig_l; if ((id < 0) || (id >= RMNET_DATA_MAX_VND) || !rmnet_devices[id]) { - LOGM("%s(): Invalid id [%d]\n", __func__, id); + LOGM("Invalid id [%d]", id); return RMNET_CONFIG_NO_SUCH_DEVICE; } @@ -641,21 +628,21 @@ int rmnet_vnd_get_name(int id, char *name, int name_len) int p; if (!name) { - LOGM("%s(): Bad arguments; name buffer null", __func__); + LOGM("%s", "Bad arguments; name buffer null"); return -EINVAL; } if ((id < 0) || (id >= RMNET_DATA_MAX_VND) || !rmnet_devices[id]) { - LOGM("%s(): Invalid id [%d]", __func__, id); + LOGM("Invalid id [%d]", id); return -EINVAL; } p = strlcpy(name, rmnet_devices[id]->name, name_len); if (p >= name_len) { - LOGM("%s(): Buffer to small to fit device name", __func__); + LOGM("Buffer to small (%d) to fit device name", name_len); return -EINVAL; } - LOGL("%s(): Found mapping [%d]->\"%s\"", __func__, id, name); + LOGL("Found mapping [%d]->\"%s\"", id, name); return 0; } @@ -779,8 +766,8 @@ static int _rmnet_vnd_update_flow_map(uint8_t action, itm->tc_flow_valid[i] = 1; itm->tc_flow_id[i] = tc_flow; rc = RMNET_VND_UPDATE_FLOW_OK; - LOGD("%s(): {%p}->tc_flow_id[%d] = %08X\n", - __func__, itm, i, tc_flow); + LOGD("{%p}->tc_flow_id[%d]=%08X", + itm, i, tc_flow); break; } } @@ -795,8 +782,7 @@ static int _rmnet_vnd_update_flow_map(uint8_t action, itm->tc_flow_valid[i] = 0; itm->tc_flow_id[i] = 0; j++; - LOGD("%s(): {%p}->tc_flow_id[%d] = 0\n", - __func__, itm, i); + LOGD("{%p}->tc_flow_id[%d]=0", itm, i); } } else { j++; @@ -837,7 +823,7 @@ int rmnet_vnd_add_tc_flow(uint32_t id, uint32_t map_flow, uint32_t tc_flow) unsigned long flags; if ((id < 0) || (id >= RMNET_DATA_MAX_VND) || !rmnet_devices[id]) { - LOGM("%s(): Invalid id [%d]\n", __func__, id); + LOGM("Invalid VND id [%d]", id); return RMNET_CONFIG_NO_SUCH_DEVICE; } @@ -866,7 +852,7 @@ int rmnet_vnd_add_tc_flow(uint32_t id, uint32_t map_flow, uint32_t tc_flow) kmalloc(sizeof(struct rmnet_map_flow_mapping_s), GFP_KERNEL); if (!itm) { - LOGM("%s(): failure allocating flow mapping\n", __func__); + LOGM("%s", "Failure allocating flow mapping"); return RMNET_CONFIG_NOMEM; } memset(itm, 0, sizeof(struct rmnet_map_flow_mapping_s)); @@ -885,8 +871,8 @@ int rmnet_vnd_add_tc_flow(uint32_t id, uint32_t map_flow, uint32_t tc_flow) list_add(&(itm->list), &(dev_conf->flow_head)); write_unlock_irqrestore(&dev_conf->flow_map_lock, flags); - LOGD("%s(): Created flow mapping [%s][0x%08X][0x%08X]@%p\n", __func__, - dev->name, itm->map_flow_id, itm->tc_flow_id[0], itm); + LOGD("Created flow mapping [%s][0x%08X][0x%08X]@%p", + dev->name, itm->map_flow_id, itm->tc_flow_id[0], itm); return RMNET_CONFIG_OK; } @@ -916,7 +902,7 @@ int rmnet_vnd_del_tc_flow(uint32_t id, uint32_t map_flow, uint32_t tc_flow) int rc = RMNET_CONFIG_OK; if ((id < 0) || (id >= RMNET_DATA_MAX_VND) || !rmnet_devices[id]) { - LOGM("%s(): Invalid id [%d]\n", __func__, id); + LOGM("Invalid VND id [%d]", id); return RMNET_CONFIG_NO_SUCH_DEVICE; } @@ -941,8 +927,8 @@ int rmnet_vnd_del_tc_flow(uint32_t id, uint32_t map_flow, uint32_t tc_flow) if (r == RMNET_VND_UPDATE_FLOW_NO_VALID_LEFT) { if (itm) - LOGD("%s(): Removed flow mapping [%s][0x%08X]@%p\n", - __func__, dev->name, itm->map_flow_id, itm); + LOGD("Removed flow mapping [%s][0x%08X]@%p", + dev->name, itm->map_flow_id, itm); kfree(itm); } @@ -990,16 +976,16 @@ int rmnet_vnd_do_flow_control(struct net_device *dev, itm = _rmnet_vnd_get_flow_map(dev_conf, map_flow_id); if (!itm) { - LOGL("%s(): Got flow control request for unknown flow %08X\n", - __func__, map_flow_id); + LOGL("Got flow control request for unknown flow %08X", + map_flow_id); goto fcdone; } if (v4_seq == 0 || v4_seq >= atomic_read(&(itm->v4_seq))) { atomic_set(&(itm->v4_seq), v4_seq); for (i = 0; i < RMNET_MAP_FLOW_NUM_TC_HANDLE; i++) { if (itm->tc_flow_valid[i] == 1) { - LOGD("%s(): Found [%s][0x%08X][%d:0x%08X]\n", - __func__, dev->name, itm->map_flow_id, i, + LOGD("Found [%s][0x%08X][%d:0x%08X]", + dev->name, itm->map_flow_id, i, itm->tc_flow_id[i]); _rmnet_vnd_do_flow_control(dev, @@ -1008,8 +994,8 @@ int rmnet_vnd_do_flow_control(struct net_device *dev, } } } else { - LOGD("%s(): Internal seq(%hd) higher than called(%hd)\n", - __func__, atomic_read(&(itm->v4_seq)), v4_seq); + LOGD("Internal seq(%hd) higher than called(%hd)", + atomic_read(&(itm->v4_seq)), v4_seq); } fcdone: diff --git a/net/rmnet_data/rmnet_map_command.c b/net/rmnet_data/rmnet_map_command.c index a3a5bfc705d..56ac4131252 100644 --- a/net/rmnet_data/rmnet_map_command.c +++ b/net/rmnet_data/rmnet_map_command.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -61,8 +61,8 @@ static uint8_t rmnet_map_do_flow_control(struct sk_buff *skb, cmd = RMNET_MAP_GET_CMD_START(skb); if (mux_id >= RMNET_DATA_MAX_LOGICAL_EP) { - LOGD("%s(): Got packet on %s with bad mux id %d\n", - __func__, skb->dev->name, mux_id); + LOGD("Got packet on %s with bad mux id %d", + skb->dev->name, mux_id); kfree_skb(skb); return RX_HANDLER_CONSUMED; } @@ -70,8 +70,8 @@ static uint8_t rmnet_map_do_flow_control(struct sk_buff *skb, ep = &(config->muxed_ep[mux_id]); if (!ep->refcount) { - LOGD("%s(): Packet on %s:%d; has no logical endpoint config\n", - __func__, skb->dev->name, mux_id); + LOGD("Packet on %s:%d; has no logical endpoint config", + skb->dev->name, mux_id); kfree_skb(skb); return RX_HANDLER_CONSUMED; @@ -88,8 +88,8 @@ static uint8_t rmnet_map_do_flow_control(struct sk_buff *skb, * the 2 protocols */ r = rmnet_vnd_do_flow_control(vnd, qos_id, fc_seq, fc_seq, enable); - LOGD("%s(): dev:%s, qos_id:0x%08X, ip_family:%hd, fc_seq %hd, en:%d\n", - __func__, skb->dev->name, qos_id, ip_family & 3, fc_seq, enable); + LOGD("dev:%s, qos_id:0x%08X, ip_family:%hd, fc_seq %hd, en:%d", + skb->dev->name, qos_id, ip_family & 3, fc_seq, enable); if (r) return RMNET_MAP_COMMAND_UNSUPPORTED; @@ -168,7 +168,7 @@ rx_handler_result_t rmnet_map_command(struct sk_buff *skb, default: rmnet_map_command_stats[RMNET_MAP_COMMAND_UNKNOWN]++; - LOGM("%s(): Uknown MAP command: %d\n", __func__, command_name); + LOGM("Uknown MAP command: %d", command_name); rc = RMNET_MAP_COMMAND_UNSUPPORTED; break; } diff --git a/net/rmnet_data/rmnet_map_data.c b/net/rmnet_data/rmnet_map_data.c index 9c8fb5d656a..b39f906dcaa 100644 --- a/net/rmnet_data/rmnet_map_data.c +++ b/net/rmnet_data/rmnet_map_data.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -72,7 +72,7 @@ struct rmnet_map_header_s *rmnet_map_add_map_header(struct sk_buff *skb, return 0; padbytes = (uint8_t *) skb_put(skb, padding); - LOGD("pad: %d\n", padding); + LOGD("pad: %d", padding); memset(padbytes, 0, padding); map_header->pkt_len = htons(map_datalen + padding); @@ -108,16 +108,17 @@ struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb, maph = (struct rmnet_map_header_s *) skb->data; packet_len = ntohs(maph->pkt_len) + sizeof(struct rmnet_map_header_s); + if ((((int)skb->len) - ((int)packet_len)) < 0) { - LOGM("%s(): Got malformed packet. Dropping\n", __func__); + LOGM("%s", "Got malformed packet. Dropping"); return 0; } - skbn = skb_copy(skb, GFP_ATOMIC); + skbn = skb_clone(skb, GFP_ATOMIC); if (!skbn) return 0; - LOGD("Trimming to %d bytes\n", packet_len); + LOGD("Trimming to %d bytes", packet_len); LOGD("before skbn->len = %d", skbn->len); skb_trim(skbn, packet_len); skb_pull(skb, packet_len); @@ -126,7 +127,7 @@ struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb, /* Sanity check */ ip_byte = (skbn->data[4]) & 0xF0; if (ip_byte != 0x40 && ip_byte != 0x60) { - LOGM("%s() Unknown IP type: 0x%02X\n", __func__, ip_byte); + LOGM("Unknown IP type: 0x%02X", ip_byte); kfree_skb(skbn); return 0; } @@ -153,21 +154,21 @@ static void rmnet_map_flush_packet_queue(struct work_struct *work) skb = 0; real_work = (struct agg_work *)work; config = real_work->config; - LOGD("Entering flush thread\n"); + LOGD("%s", "Entering flush thread"); spin_lock_irqsave(&config->agg_lock, flags); if (likely(config->agg_state == RMNET_MAP_TXFER_SCHEDULED)) { if (likely(config->agg_skb)) { /* Buffer may have already been shipped out */ if (config->agg_count > 1) - LOGL("Agg count: %d\n", config->agg_count); + LOGL("Agg count: %d", config->agg_count); skb = config->agg_skb; config->agg_skb = 0; } config->agg_state = RMNET_MAP_AGG_IDLE; } else { /* How did we get here? */ - LOGE("%s(): Ran queued command when state %s\n", - "is idle. State machine likely broken", __func__); + LOGE("Ran queued command when state %s", + "is idle. State machine likely broken"); } spin_unlock_irqrestore(&config->agg_lock, flags); @@ -199,7 +200,7 @@ void rmnet_map_aggregate(struct sk_buff *skb, size = config->egress_agg_size-skb->len; if (size < 2000) { - LOGL("Invalid length %d\n", size); + LOGL("Invalid length %d", size); return; } @@ -221,7 +222,7 @@ new_packet: if (skb->len > (config->egress_agg_size - config->agg_skb->len)) { if (config->agg_count > 1) - LOGL("Agg count: %d\n", config->agg_count); + LOGL("Agg count: %d", config->agg_count); agg_skb = config->agg_skb; config->agg_skb = 0; config->agg_count = 0; @@ -240,8 +241,8 @@ schedule: work = (struct agg_work *) kmalloc(sizeof(struct agg_work), GFP_ATOMIC); if (!work) { - LOGE("%s(): Failed to allocate work item for packet %s", - "transfer. DATA PATH LIKELY BROKEN!\n", __func__); + LOGE("Failed to allocate work item for packet %s", + "transfer. DATA PATH LIKELY BROKEN!"); config->agg_state = RMNET_MAP_AGG_IDLE; spin_unlock_irqrestore(&config->agg_lock, flags); return; diff --git a/net/wireless/db.txt b/net/wireless/db.txt index a29d6e94bf9..c27f1658135 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -14,14 +14,6 @@ country 00: (57240 - 63720 @ 2160), (N/A, 0) -country AD: - (2402 - 2482 @ 40), (N/A, 20) - (5170 - 5250 @ 80), (N/A, 20) - (5250 - 5330 @ 80), (N/A, 20), DFS - (5490 - 5710 @ 80), (N/A, 27), DFS - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR - country AE: (2402 - 2482 @ 40), (N/A, 20) (5170 - 5250 @ 80), (3, 17) @@ -126,11 +118,6 @@ country BH: (5250 - 5330 @ 20), (N/A, 20), DFS (5735 - 5835 @ 20), (N/A, 20) -country BL: - (2402 - 2482 @ 40), (N/A, 20) - (5170 - 5250 @ 40), (N/A, 18) - (5250 - 5330 @ 40), (N/A, 18), DFS - country BM: (2402 - 2472 @ 40), (N/A, 30) (5150 - 5250 @ 80), (6, 17) diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c index a1a457d7b41..2ea8009fc07 100644 --- a/sound/soc/codecs/msm8x10-wcd.c +++ b/sound/soc/codecs/msm8x10-wcd.c @@ -28,13 +28,13 @@ #include <linux/of_gpio.h> #include <linux/regulator/consumer.h> #include <linux/mfd/wcd9xxx/pdata.h> +#include <soc/qcom/subsystem_notif.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/tlv.h> #include <linux/qdsp6v2/apr.h> -#include <mach/subsystem_notif.h> #include "msm8x10-wcd.h" #include "wcd9xxx-resmgr.h" #include "msm8x10_wcd_registers.h" diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c index 7702a8a1a0b..c5cb5d52039 100644 --- a/sound/soc/codecs/wcd9xxx-mbhc.c +++ b/sound/soc/codecs/wcd9xxx-mbhc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -64,6 +64,7 @@ #define STATUS_REL_DETECTION 0x0C #define HS_DETECT_PLUG_TIME_MS (5 * 1000) +#define ANC_HPH_DETECT_PLUG_TIME_MS (5 * 1000) #define HS_DETECT_PLUG_INERVAL_MS 100 #define SWCH_REL_DEBOUNCE_TIME_MS 50 #define SWCH_IRQ_DEBOUNCE_TIME_US 5000 @@ -900,6 +901,7 @@ static void wcd9xxx_report_plug(struct wcd9xxx_mbhc *mbhc, int insertion, } else if (jack_type == SND_JACK_LINEOUT) { mbhc->current_plug = PLUG_TYPE_HIGH_HPH; } else if (jack_type == SND_JACK_ANC_HEADPHONE) { + mbhc->polling_active = BUTTON_POLLING_SUPPORTED; mbhc->current_plug = PLUG_TYPE_ANC_HEADPHONE; } @@ -1709,10 +1711,10 @@ static int wcd9xxx_pull_down_micbias(struct wcd9xxx_mbhc *mbhc, int us) return 0; } -void wcd9xxx_turn_onoff_current_source(struct wcd9xxx_mbhc *mbhc, bool on, - bool highhph) +void wcd9xxx_turn_onoff_current_source(struct wcd9xxx_mbhc *mbhc, + struct mbhc_micbias_regs *mbhc_micb_regs, + bool on, bool highhph) { - struct snd_soc_codec *codec; struct wcd9xxx_mbhc_btn_detect_cfg *btn_det; const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det = @@ -1727,7 +1729,7 @@ void wcd9xxx_turn_onoff_current_source(struct wcd9xxx_mbhc *mbhc, bool on, snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78, 0x48); /* pull down diode bit to 0 */ - snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, + snd_soc_update_bits(codec, mbhc_micb_regs->mbhc_reg, 0x01, 0x00); /* * Keep the low power insertion/removal @@ -1742,7 +1744,7 @@ void wcd9xxx_turn_onoff_current_source(struct wcd9xxx_mbhc *mbhc, bool on, * (INS_DET_ISRC_EN__ENABLE) * MICB_2_MBHC__SCHT_TRIG_EN to 1 */ - snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, + snd_soc_update_bits(codec, mbhc_micb_regs->mbhc_reg, 0xF0, 0xF0); /* Disconnect MBHC Override from MicBias and LDOH */ snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 0x10, 0x00); @@ -1751,16 +1753,16 @@ void wcd9xxx_turn_onoff_current_source(struct wcd9xxx_mbhc *mbhc, bool on, /* Connect MBHC Override from MicBias and LDOH */ snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 0x10, 0x10); /* INS_DET_ISRC_CTL to acdb value */ - snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, + snd_soc_update_bits(codec, mbhc_micb_regs->mbhc_reg, 0x60, plug_det->mic_current << 5); if (!highhph) { /* INS_DET_ISRC_EN__ENABLE to 0 */ snd_soc_update_bits(codec, - mbhc->mbhc_bias_regs.mbhc_reg, + mbhc_micb_regs->mbhc_reg, 0x80, 0x00); /* MICB_2_MBHC__SCHT_TRIG_EN to 0 */ snd_soc_update_bits(codec, - mbhc->mbhc_bias_regs.mbhc_reg, + mbhc_micb_regs->mbhc_reg, 0x10, 0x00); } /* Nsc to acdb value */ @@ -1800,11 +1802,15 @@ wcd9xxx_codec_cs_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph) wcd9xxx_codec_hphr_gnd_switch(codec, true); if (rt[i].mic_bias) - wcd9xxx_turn_onoff_current_source(mbhc, false, false); + wcd9xxx_turn_onoff_current_source(mbhc, + &mbhc->mbhc_bias_regs, + false, false); rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, !highhph, true); if (rt[i].mic_bias) - wcd9xxx_turn_onoff_current_source(mbhc, true, false); + wcd9xxx_turn_onoff_current_source(mbhc, + &mbhc->mbhc_bias_regs, + true, false); if (rt[i].swap_gnd) wcd9xxx_codec_hphr_gnd_switch(codec, false); } @@ -2057,14 +2063,18 @@ static int wcd9xxx_enable_hs_detect(struct wcd9xxx_mbhc *mbhc, */ static bool wcd9xxx_detect_anc_plug_type(struct wcd9xxx_mbhc *mbhc) { - struct wcd9xxx_mbhc_detect rt[4]; + struct wcd9xxx_mbhc_detect rt[NUM_DCE_PLUG_INS_DETECT - 1]; bool anc_mic_found = true; - int i; + int i, mb_mv; const struct wcd9xxx_mbhc_plug_type_cfg *plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration); - const s16 hs_max = plug_type->v_hs_max; - const s16 no_mic = plug_type->v_no_mic; + s16 hs_max, dce_z; + s16 no_mic; bool override_en; + bool timedout; + unsigned long timeout, retry = 0; + enum wcd9xxx_mbhc_plug_type type; + bool cs_enable; if (mbhc->mbhc_cfg->anc_micbias != MBHC_MICBIAS3 && mbhc->mbhc_cfg->anc_micbias != MBHC_MICBIAS2) @@ -2074,79 +2084,141 @@ static bool wcd9xxx_detect_anc_plug_type(struct wcd9xxx_mbhc *mbhc) override_en = (snd_soc_read(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL) & 0x04) ? true : false; + cs_enable = ((mbhc->mbhc_cfg->cs_enable_flags & + (1 << MBHC_CS_ENABLE_DET_ANC)) != 0) && + (!(snd_soc_read(mbhc->codec, + mbhc->mbhc_anc_bias_regs.ctl_reg) & 0x80)) && + (mbhc->mbhc_cfg->micbias != mbhc->mbhc_cfg->anc_micbias); - if (mbhc->mbhc_cfg->anc_micbias == MBHC_MICBIAS3) { - if (mbhc->micbias_enable_cb) - mbhc->micbias_enable_cb(mbhc->codec, true, + if (cs_enable) { + wcd9xxx_turn_onoff_current_source(mbhc, + &mbhc->mbhc_anc_bias_regs, + true, false); + } else { + if (mbhc->mbhc_cfg->anc_micbias == MBHC_MICBIAS3) { + if (mbhc->micbias_enable_cb) + mbhc->micbias_enable_cb(mbhc->codec, true, mbhc->mbhc_cfg->anc_micbias); - else - return false; + else + return false; + } else { + /* Enable override */ + if (!override_en) + wcd9xxx_turn_onoff_override(mbhc, true); + } + } + + if (!cs_enable) { + hs_max = plug_type->v_hs_max; + no_mic = plug_type->v_no_mic; + dce_z = mbhc->mbhc_data.dce_z; + mb_mv = mbhc->mbhc_data.micb_mv; } else { - /* Enable override */ - if (!override_en) - wcd9xxx_turn_onoff_override(mbhc, true); + hs_max = WCD9XXX_V_CS_HS_MAX; + no_mic = WCD9XXX_V_CS_NO_MIC; + mb_mv = VDDIO_MICBIAS_MV; + dce_z = mbhc->mbhc_data.dce_nsc_cs_z; } wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true); - rt[0].hphl_status = wcd9xxx_hphl_status(mbhc); - rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, - &mbhc->mbhc_anc_bias_regs, - false); - rt[0]._vdces = wcd9xxx_codec_sta_dce_v(mbhc, true, rt[0].dce); + timeout = jiffies + msecs_to_jiffies(ANC_HPH_DETECT_PLUG_TIME_MS); + anc_mic_found = true; - if (rt[0]._vdces >= no_mic && rt[0]._vdces < hs_max) - rt[0]._type = PLUG_TYPE_HEADSET; - else if (rt[0]._vdces < no_mic) - rt[0]._type = PLUG_TYPE_HEADPHONE; - else - rt[0]._type = PLUG_TYPE_HIGH_HPH; + while (!(timedout = time_after(jiffies, timeout))) { + retry++; - pr_debug("%s: DCE #%d, V %04d, HPHL %d TYPE %d\n", - __func__, 0, rt[0]._vdces, - rt[0].hphl_status & 0x01, - rt[0]._type); + if (wcd9xxx_swch_level_remove(mbhc)) { + pr_debug("%s: Switch level is low\n", __func__); + anc_mic_found = false; + break; + } - for (i = 1; i < 4; i++) { - rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true); - rt[i]._vdces = wcd9xxx_codec_sta_dce_v(mbhc, true, rt[i].dce); + pr_debug("%s: Retry attempt %lu", __func__, retry - 1); - if (rt[i]._vdces >= no_mic && rt[i]._vdces < hs_max) - rt[i]._type = PLUG_TYPE_HEADSET; - else if (rt[i]._vdces < no_mic) - rt[i]._type = PLUG_TYPE_HEADPHONE; + rt[0].hphl_status = wcd9xxx_hphl_status(mbhc); + rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, + &mbhc->mbhc_anc_bias_regs, + cs_enable); + rt[0]._vdces = __wcd9xxx_codec_sta_dce_v(mbhc, true, rt[0].dce, + dce_z, (u32)mb_mv); + + if (rt[0]._vdces >= no_mic && rt[0]._vdces < hs_max) + rt[0]._type = PLUG_TYPE_HEADSET; + else if (rt[0]._vdces < no_mic) + rt[0]._type = PLUG_TYPE_HEADPHONE; else - rt[i]._type = PLUG_TYPE_HIGH_HPH; - - rt[i].hphl_status = wcd9xxx_hphl_status(mbhc); + rt[0]._type = PLUG_TYPE_HIGH_HPH; pr_debug("%s: DCE #%d, V %04d, HPHL %d TYPE %d\n", - __func__, i, rt[i]._vdces, - rt[i].hphl_status & 0x01, - rt[i]._type); - } + __func__, 0, rt[0]._vdces, + rt[0].hphl_status & 0x01, + rt[0]._type); + + for (i = 1; i < NUM_DCE_PLUG_INS_DETECT - 1; i++) { + rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, + true, true); + rt[i]._vdces = __wcd9xxx_codec_sta_dce_v(mbhc, true, + rt[i].dce, dce_z, + (u32) mb_mv); + + if (rt[i]._vdces >= no_mic && rt[i]._vdces < hs_max) + rt[i]._type = PLUG_TYPE_HEADSET; + else if (rt[i]._vdces < no_mic) + rt[i]._type = PLUG_TYPE_HEADPHONE; + else + rt[i]._type = PLUG_TYPE_HIGH_HPH; - /* - * Check for the "type" of all the 4 measurements - * If all 4 measurements have the Type as PLUG_TYPE_HEADSET - * then it is proper mic and declare that the plug has two mics - */ - for (i = 0; i < 4; i++) { - if (rt[i]._type != PLUG_TYPE_HEADSET) + rt[i].hphl_status = wcd9xxx_hphl_status(mbhc); + + pr_debug("%s: DCE #%d, V %04d, HPHL %d TYPE %d\n", + __func__, i, rt[i]._vdces, + rt[i].hphl_status & 0x01, + rt[i]._type); + } + + /* + * Check for the "type" of all the 4 measurements + * If all 4 measurements have the Type as PLUG_TYPE_HEADSET + * then it is proper mic and declare that the plug has two mics + */ + for (i = 0; i < NUM_DCE_PLUG_INS_DETECT - 1; i++) { + if (i > 0 && (rt[i - 1]._type != rt[i]._type)) { + type = PLUG_TYPE_INVALID; + break; + } else { + type = rt[0]._type; + } + } + + pr_debug("%s: Plug type found in ANC detection :%d", + __func__, type); + + if (type != PLUG_TYPE_HEADSET) anc_mic_found = false; + if (anc_mic_found || (type == PLUG_TYPE_HEADPHONE && + mbhc->mbhc_cfg->hw_jack_type == FIVE_POLE_JACK) || + (type == PLUG_TYPE_HIGH_HPH && + mbhc->mbhc_cfg->hw_jack_type == SIX_POLE_JACK)) + break; } wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false); - if (mbhc->mbhc_cfg->anc_micbias == MBHC_MICBIAS3) { - if (mbhc->micbias_enable_cb) - mbhc->micbias_enable_cb(mbhc->codec, false, - mbhc->mbhc_cfg->anc_micbias); + if (cs_enable) { + wcd9xxx_turn_onoff_current_source(mbhc, + &mbhc->mbhc_anc_bias_regs, + false, false); } else { - /* Disable override */ - if (!override_en) - wcd9xxx_turn_onoff_override(mbhc, false); + if (mbhc->mbhc_cfg->anc_micbias == MBHC_MICBIAS3) { + if (mbhc->micbias_enable_cb) + mbhc->micbias_enable_cb(mbhc->codec, false, + mbhc->mbhc_cfg->anc_micbias); + } else { + /* Disable override */ + if (!override_en) + wcd9xxx_turn_onoff_override(mbhc, false); + } } - pr_debug("%s: leave\n", __func__); return anc_mic_found; } @@ -2197,37 +2269,35 @@ static void wcd9xxx_find_plug_and_report(struct wcd9xxx_mbhc *mbhc, if (anc_mic_found) { /* Report ANC headphone */ wcd9xxx_report_plug(mbhc, 1, SND_JACK_ANC_HEADPHONE); - wcd9xxx_cleanup_hs_polling(mbhc); } else { - /* * If Headphone was reported previously, this will * only report the mic line */ wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADSET); - /* Button detection required RC oscillator */ - wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true); - - /* - * sleep so that audio path completely tears down - * before report plug insertion to the user space - */ - msleep(100); - - /* - * if PA is already on, switch micbias - * source to VDDIO - */ - if (mbhc->event_state & - (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)) - __wcd9xxx_switch_micbias(mbhc, 1, false, - false); - wcd9xxx_start_hs_polling(mbhc); } + /* Button detection required RC oscillator */ + wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true); + /* + * sleep so that audio path completely tears down + * before report plug insertion to the user space + */ + msleep(100); + + /* + * if PA is already on, switch micbias + * source to VDDIO + */ + if (mbhc->event_state & + (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)) + __wcd9xxx_switch_micbias(mbhc, 1, false, + false); + wcd9xxx_start_hs_polling(mbhc); } else if (plug_type == PLUG_TYPE_HIGH_HPH) { if (mbhc->mbhc_cfg->detect_extn_cable) { /* High impedance device found. Report as LINEOUT*/ - wcd9xxx_report_plug(mbhc, 1, SND_JACK_LINEOUT); + if (mbhc->current_plug == PLUG_TYPE_NONE) + wcd9xxx_report_plug(mbhc, 1, SND_JACK_LINEOUT); wcd9xxx_cleanup_hs_polling(mbhc); pr_debug("%s: setup mic trigger for further detection\n", __func__); @@ -2274,9 +2344,11 @@ static void wcd9xxx_mbhc_decide_swch_plug(struct wcd9xxx_mbhc *mbhc) mbhc->scaling_mux_in = 0x04; if (current_source_enable) { - wcd9xxx_turn_onoff_current_source(mbhc, true, false); + wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs, + true, false); plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc, false); - wcd9xxx_turn_onoff_current_source(mbhc, false, false); + wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs, + false, false); } else { wcd9xxx_turn_onoff_override(mbhc, true); plug_type = wcd9xxx_codec_get_plug_type(mbhc, true); @@ -2307,12 +2379,6 @@ static void wcd9xxx_mbhc_decide_swch_plug(struct wcd9xxx_mbhc *mbhc) pr_debug("%s: Valid plug found, determine plug type %d\n", __func__, plug_type); wcd9xxx_find_plug_and_report(mbhc, plug_type); - if (mbhc->mbhc_cfg->detect_extn_cable && - mbhc->current_plug == PLUG_TYPE_ANC_HEADPHONE) { - /* Enable removal detection */ - wcd9xxx_cleanup_hs_polling(mbhc); - wcd9xxx_enable_hs_detect(mbhc, 0, 0, false); - } } pr_debug("%s: leave\n", __func__); } @@ -2407,7 +2473,8 @@ static bool wcd9xxx_hs_remove_settle(struct wcd9xxx_mbhc *mbhc) (!(snd_soc_read(mbhc->codec, mbhc->mbhc_bias_regs.ctl_reg) & 0x80))); if (cs_enable) - wcd9xxx_turn_onoff_current_source(mbhc, true, false); + wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs, + true, false); timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS); while (!(timedout = time_after(jiffies, timeout))) { @@ -2475,7 +2542,8 @@ static bool wcd9xxx_hs_remove_settle(struct wcd9xxx_mbhc *mbhc) } if (cs_enable) - wcd9xxx_turn_onoff_current_source(mbhc, false, false); + wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs, + false, false); if (timedout) pr_debug("%s: Microphone did not settle in %d seconds\n", @@ -2506,7 +2574,8 @@ static void wcd9xxx_hs_remove_irq_noswch(struct wcd9xxx_mbhc *mbhc) u32 mb_mv; pr_debug("%s: enter\n", __func__); - if (mbhc->current_plug != PLUG_TYPE_HEADSET) { + if (mbhc->current_plug != PLUG_TYPE_HEADSET && + mbhc->current_plug != PLUG_TYPE_ANC_HEADPHONE) { pr_debug("%s(): Headset is not inserted, ignore removal\n", __func__); snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, @@ -2523,7 +2592,8 @@ static void wcd9xxx_hs_remove_irq_noswch(struct wcd9xxx_mbhc *mbhc) (!(snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg) & 0x80))); if (cs_enable) - wcd9xxx_turn_onoff_current_source(mbhc, true, false); + wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs, + true, false); timeout = jiffies + msecs_to_jiffies(FAKE_REMOVAL_MIN_PERIOD_MS); do { @@ -2554,7 +2624,8 @@ static void wcd9xxx_hs_remove_irq_noswch(struct wcd9xxx_mbhc *mbhc) removed ? "" : "not "); if (cs_enable) - wcd9xxx_turn_onoff_current_source(mbhc, false, false); + wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs, + false, false); if (removed) { if (mbhc->mbhc_cfg->detect_extn_cable) { @@ -2936,8 +3007,8 @@ static void wcd9xxx_correct_swch_plug(struct work_struct *work) * headphone detection. */ if (current_source_enable) - wcd9xxx_turn_onoff_current_source(mbhc, true, - false); + wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs, + true, false); else wcd9xxx_turn_onoff_override(mbhc, true); @@ -2995,6 +3066,14 @@ static void wcd9xxx_correct_swch_plug(struct work_struct *work) } else if (plug_type == PLUG_TYPE_HIGH_HPH) { pr_debug("%s: High HPH detected, continue polling\n", __func__); + if (mbhc->mbhc_cfg->detect_extn_cable) { + if (mbhc->current_plug != plug_type) + wcd9xxx_report_plug(mbhc, 1, + SND_JACK_LINEOUT); + } else if (mbhc->current_plug == PLUG_TYPE_NONE) { + wcd9xxx_report_plug(mbhc, 1, + SND_JACK_HEADPHONE); + } } else { if (plug_type == PLUG_TYPE_GND_MIC_SWAP) { pt_gnd_mic_swap_cnt++; @@ -3021,8 +3100,9 @@ static void wcd9xxx_correct_swch_plug(struct work_struct *work) WCD9XXX_BCL_LOCK(mbhc->resmgr); /* Turn off override/current source */ if (current_source_enable) - wcd9xxx_turn_onoff_current_source(mbhc, false, - false); + wcd9xxx_turn_onoff_current_source(mbhc, + &mbhc->mbhc_bias_regs, + false, false); else wcd9xxx_turn_onoff_override(mbhc, false); /* @@ -3048,7 +3128,8 @@ static void wcd9xxx_correct_swch_plug(struct work_struct *work) } if (!correction && current_source_enable) - wcd9xxx_turn_onoff_current_source(mbhc, false, highhph); + wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs, + false, highhph); else if (!correction) wcd9xxx_turn_onoff_override(mbhc, false); @@ -3058,8 +3139,6 @@ static void wcd9xxx_correct_swch_plug(struct work_struct *work) WCD9XXX_BCL_LOCK(mbhc->resmgr); if ((mbhc->current_plug == PLUG_TYPE_HEADPHONE && wrk_complete) || - (mbhc->current_plug == PLUG_TYPE_ANC_HEADPHONE && - wrk_complete) || mbhc->current_plug == PLUG_TYPE_GND_MIC_SWAP || mbhc->current_plug == PLUG_TYPE_INVALID || (plug_type == PLUG_TYPE_INVALID && wrk_complete)) { @@ -3133,6 +3212,9 @@ static void wcd9xxx_swch_irq_handler(struct wcd9xxx_mbhc *mbhc) wcd9xxx_report_plug(mbhc, 0, SND_JACK_LINEOUT); is_removed = true; } else if (mbhc->current_plug == PLUG_TYPE_ANC_HEADPHONE) { + wcd9xxx_pause_hs_polling(mbhc); + wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false); + wcd9xxx_cleanup_hs_polling(mbhc); wcd9xxx_report_plug(mbhc, 0, SND_JACK_ANC_HEADPHONE); is_removed = true; } diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h index 20aeb80db26..526b9e5a732 100644 --- a/sound/soc/codecs/wcd9xxx-mbhc.h +++ b/sound/soc/codecs/wcd9xxx-mbhc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -94,6 +94,12 @@ enum wcd9xxx_micbias_num { MBHC_MICBIAS4, }; +enum hw_jack_type { + FOUR_POLE_JACK = 0, + FIVE_POLE_JACK, + SIX_POLE_JACK, +}; + enum wcd9xx_mbhc_micbias_enable_bits { MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET, MBHC_MICBIAS_ENABLE_REGULAR_HEADSET, @@ -103,6 +109,7 @@ enum wcd9xx_mbhc_cs_enable_bits { MBHC_CS_ENABLE_POLLING, MBHC_CS_ENABLE_INSERTION, MBHC_CS_ENABLE_REMOVAL, + MBHC_CS_ENABLE_DET_ANC, }; enum wcd9xxx_mbhc_state { @@ -240,6 +247,7 @@ struct wcd9xxx_mbhc_config { bool do_recalibration; bool use_vddio_meas; bool enable_anc_mic_detect; + enum hw_jack_type hw_jack_type; }; struct wcd9xxx_cfilt_mode { diff --git a/sound/soc/msm/apq8074.c b/sound/soc/msm/apq8074.c index 0ccfd750212..4f9eb8bf984 100644 --- a/sound/soc/msm/apq8074.c +++ b/sound/soc/msm/apq8074.c @@ -20,6 +20,7 @@ #include <linux/qpnp/clkdiv.h> #include <linux/regulator/consumer.h> #include <linux/io.h> +#include <soc/qcom/subsystem_notif.h> #include <sound/core.h> #include <sound/soc.h> #include <sound/soc-dapm.h> @@ -27,7 +28,6 @@ #include <sound/jack.h> #include <sound/q6afe-v2.h> #include <sound/pcm_params.h> -#include <mach/subsystem_notif.h> #include <mach/socinfo.h> #include "qdsp6v2/msm-pcm-routing-v2.h" diff --git a/sound/soc/msm/apq8084.c b/sound/soc/msm/apq8084.c index b9ebfb25571..2090bd2f7b8 100644 --- a/sound/soc/msm/apq8084.c +++ b/sound/soc/msm/apq8084.c @@ -22,6 +22,7 @@ #include <linux/io.h> #include <linux/pm_runtime.h> #include <linux/slimbus/slimbus.h> +#include <soc/qcom/subsystem_notif.h> #include <sound/core.h> #include <sound/soc.h> #include <sound/soc-dapm.h> @@ -29,7 +30,6 @@ #include <sound/jack.h> #include <sound/q6afe-v2.h> #include <sound/pcm_params.h> -#include <mach/subsystem_notif.h> #include "qdsp6v2/msm-pcm-routing-v2.h" #include "qdsp6v2/q6core.h" #include "../codecs/wcd9xxx-common.h" diff --git a/sound/soc/msm/mpq8092.c b/sound/soc/msm/mpq8092.c index ab93a877d78..912caf57622 100644 --- a/sound/soc/msm/mpq8092.c +++ b/sound/soc/msm/mpq8092.c @@ -19,6 +19,7 @@ #include <linux/qpnp/clkdiv.h> #include <linux/regulator/consumer.h> #include <linux/io.h> +#include <soc/qcom/subsystem_notif.h> #include <sound/core.h> #include <sound/soc.h> #include <sound/soc-dapm.h> @@ -27,7 +28,6 @@ #include <sound/q6afe-v2.h> #include <sound/pcm_params.h> #include <asm/mach-types.h> -#include <mach/subsystem_notif.h> #include "qdsp6v2/msm-pcm-routing-v2.h" #include "qdsp6v2/q6core.h" #include "../codecs/wcd9xxx-common.h" diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c index fb34d2ec827..09343622a32 100644 --- a/sound/soc/msm/msm8226.c +++ b/sound/soc/msm/msm8226.c @@ -18,6 +18,7 @@ #include <linux/slab.h> #include <linux/mfd/pm8xxx/pm8921.h> #include <linux/io.h> +#include <soc/qcom/subsystem_notif.h> #include <sound/core.h> #include <sound/soc.h> #include <sound/soc-dapm.h> @@ -25,7 +26,6 @@ #include <sound/jack.h> #include <sound/q6afe-v2.h> #include <mach/socinfo.h> -#include <mach/subsystem_notif.h> #include <qdsp6v2/msm-pcm-routing-v2.h> #include "qdsp6v2/q6core.h" #include "../codecs/wcd9xxx-common.h" @@ -93,10 +93,12 @@ static struct wcd9xxx_mbhc_config mbhc_cfg = { .swap_gnd_mic = NULL, .cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING | 1 << MBHC_CS_ENABLE_INSERTION | - 1 << MBHC_CS_ENABLE_REMOVAL), + 1 << MBHC_CS_ENABLE_REMOVAL | + 1 << MBHC_CS_ENABLE_DET_ANC), .do_recalibration = true, .use_vddio_meas = true, .enable_anc_mic_detect = false, + .hw_jack_type = FOUR_POLE_JACK, }; struct msm_auxpcm_gpio { @@ -1974,6 +1976,7 @@ static int msm8226_asoc_machine_probe(struct platform_device *pdev) struct msm8226_asoc_mach_data *pdata; int ret; const char *auxpcm_pri_gpio_set = NULL; + const char *mbhc_audio_jack_type = NULL; if (!pdev->dev.of_node) { dev_err(&pdev->dev, "No platform supplied from device tree\n"); @@ -2038,6 +2041,35 @@ static int msm8226_asoc_machine_probe(struct platform_device *pdev) mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node, "qcom,headset-jack-type-NC"); + ret = of_property_read_string(pdev->dev.of_node, + "qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type); + if (ret) { + dev_dbg(&pdev->dev, "Looking up %s property in node %s failed", + "qcom,mbhc-audio-jack-type", + pdev->dev.of_node->full_name); + mbhc_cfg.hw_jack_type = FOUR_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "Jack type properties set to default"); + } else { + if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) { + mbhc_cfg.hw_jack_type = FOUR_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "This hardware has 4 pole jack"); + } else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) { + mbhc_cfg.hw_jack_type = FIVE_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = true; + dev_dbg(&pdev->dev, "This hardware has 5 pole jack"); + } else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) { + mbhc_cfg.hw_jack_type = SIX_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = true; + dev_dbg(&pdev->dev, "This hardware has 6 pole jack"); + } else { + mbhc_cfg.hw_jack_type = FOUR_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "Unknown value, hence setting to default"); + } + } + ret = snd_soc_register_card(card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c index 2279d4fc817..75bcda270ce 100644 --- a/sound/soc/msm/msm8974.c +++ b/sound/soc/msm/msm8974.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -20,6 +20,7 @@ #include <linux/qpnp/clkdiv.h> #include <linux/regulator/consumer.h> #include <linux/io.h> +#include <soc/qcom/subsystem_notif.h> #include <sound/core.h> #include <sound/soc.h> #include <sound/soc-dapm.h> @@ -27,7 +28,6 @@ #include <sound/jack.h> #include <sound/q6afe-v2.h> #include <sound/pcm_params.h> -#include <mach/subsystem_notif.h> #include "qdsp6v2/msm-pcm-routing-v2.h" #include "qdsp6v2/q6core.h" #include "../codecs/wcd9xxx-common.h" @@ -128,10 +128,12 @@ static struct wcd9xxx_mbhc_config mbhc_cfg = { .swap_gnd_mic = NULL, .cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING | 1 << MBHC_CS_ENABLE_INSERTION | - 1 << MBHC_CS_ENABLE_REMOVAL), + 1 << MBHC_CS_ENABLE_REMOVAL | + 1 << MBHC_CS_ENABLE_DET_ANC), .do_recalibration = true, .use_vddio_meas = true, .enable_anc_mic_detect = false, + .hw_jack_type = SIX_POLE_JACK, }; struct msm_auxpcm_gpio { @@ -2711,6 +2713,7 @@ static int msm8974_asoc_machine_probe(struct platform_device *pdev) int ret; const char *auxpcm_pri_gpio_set = NULL; const char *prop_name_ult_lo_gpio = "qcom,ext-ult-lo-amp-gpio"; + const char *mbhc_audio_jack_type = NULL; struct resource *pri_muxsel; struct resource *sec_muxsel; @@ -2770,6 +2773,34 @@ static int msm8974_asoc_machine_probe(struct platform_device *pdev) if (ret) goto err; + ret = of_property_read_string(pdev->dev.of_node, + "qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type); + if (ret) { + dev_dbg(&pdev->dev, "Looking up %s property in node %s failed", + "qcom,mbhc-audio-jack-type", + pdev->dev.of_node->full_name); + mbhc_cfg.hw_jack_type = FOUR_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "Jack type properties set to default"); + } else { + if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) { + mbhc_cfg.hw_jack_type = FOUR_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "This hardware has 4 pole jack"); + } else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) { + mbhc_cfg.hw_jack_type = FIVE_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = true; + dev_dbg(&pdev->dev, "This hardware has 5 pole jack"); + } else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) { + mbhc_cfg.hw_jack_type = SIX_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = true; + dev_dbg(&pdev->dev, "This hardware has 6 pole jack"); + } else { + mbhc_cfg.hw_jack_type = FOUR_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "Unknown value, hence setting to default"); + } + } if (of_property_read_bool(pdev->dev.of_node, "qcom,hdmi-audio-rx")) { dev_info(&pdev->dev, "%s(): hdmi audio support present\n", __func__); diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c index e027211374e..a3a68535b53 100644 --- a/sound/soc/msm/msm8x10.c +++ b/sound/soc/msm/msm8x10.c @@ -1,4 +1,4 @@ - /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + /* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -80,6 +80,7 @@ static struct wcd9xxx_mbhc_config mbhc_cfg = { 1 << MBHC_CS_ENABLE_REMOVAL), .do_recalibration = false, .use_vddio_meas = false, + .hw_jack_type = FOUR_POLE_JACK, }; /* @@ -1046,6 +1047,7 @@ struct snd_soc_card snd_soc_card_msm8x10 = { static int msm8x10_asoc_machine_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_card_msm8x10; + const char *mbhc_audio_jack_type = NULL; int ret; dev_dbg(&pdev->dev, "%s\n", __func__); @@ -1073,6 +1075,35 @@ static int msm8x10_asoc_machine_probe(struct platform_device *pdev) mbhc_cfg.use_int_rbias = of_property_read_bool(pdev->dev.of_node, "qcom,mbhc-bias-internal"); + ret = of_property_read_string(pdev->dev.of_node, + "qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type); + if (ret) { + dev_dbg(&pdev->dev, "Looking up %s property in node %s failed", + "qcom,mbhc-audio-jack-type", + pdev->dev.of_node->full_name); + mbhc_cfg.hw_jack_type = FOUR_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "Jack type properties set to default"); + } else { + if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) { + mbhc_cfg.hw_jack_type = FOUR_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "This hardware has 4 pole jack"); + } else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) { + mbhc_cfg.hw_jack_type = FIVE_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = true; + dev_dbg(&pdev->dev, "This hardware has 5 pole jack"); + } else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) { + mbhc_cfg.hw_jack_type = SIX_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = true; + dev_dbg(&pdev->dev, "This hardware has 6 pole jack"); + } else { + mbhc_cfg.hw_jack_type = FOUR_POLE_JACK; + mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "Unknown value, hence setting to default"); + } + } + spdev = pdev; mutex_init(&cdc_mclk_mutex); ret = snd_soc_register_card(card); diff --git a/sound/soc/msm/msmsamarium.c b/sound/soc/msm/msmsamarium.c index 72ca91b0d6d..d8e87f878d6 100644 --- a/sound/soc/msm/msmsamarium.c +++ b/sound/soc/msm/msmsamarium.c @@ -20,6 +20,7 @@ #include <linux/qpnp/clkdiv.h> #include <linux/regulator/consumer.h> #include <linux/io.h> +#include <soc/qcom/subsystem_notif.h> #include <sound/core.h> #include <sound/soc.h> #include <sound/soc-dapm.h> @@ -28,7 +29,6 @@ #include <sound/q6afe-v2.h> #include <sound/pcm_params.h> #include <mach/socinfo.h> -#include <mach/subsystem_notif.h> #include "qdsp6v2/msm-pcm-routing-v2.h" #include "qdsp6v2/q6core.h" #include "../codecs/wcd9xxx-common.h" diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c index 56c454e2738..525cf8a3aa9 100644 --- a/sound/soc/msm/qdsp6v2/audio_ocmem.c +++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c @@ -23,13 +23,13 @@ #include <linux/io.h> #include <linux/of_device.h> #include <linux/dma-mapping.h> +#include <soc/qcom/subsystem_restart.h> +#include <soc/qcom/subsystem_notif.h> +#include <soc/qcom/ramdump.h> #include <mach/msm_bus.h> #include <mach/msm_bus_board.h> #include <mach/ocmem.h> -#include <mach/subsystem_notif.h> -#include <mach/subsystem_restart.h> #include <mach/msm_memtypes.h> -#include <mach/ramdump.h> #include "q6core.h" #include "audio_ocmem.h" diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 1ab175b5b33..6dcf23816ae 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -525,7 +525,7 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, prtd->sample_rate; wma_pro_cfg.avg_bytes_per_sec = prtd->codec_param.codec.bit_rate/8; - wma_cfg.block_align = + wma_pro_cfg.block_align = prtd->codec_param.codec.options.wma.super_block_align; wma_pro_cfg.valid_bits_per_sample = prtd->codec_param.codec.options.wma.bits_per_sample; diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index f9480c5444c..fd151fff293 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -2526,9 +2526,6 @@ static const struct snd_kcontrol_new tx_voice_mixer_controls[] = { SOC_SINGLE_EXT("MI2S_TX_Voice", MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX_Voice", MSM_BACKEND_DAI_PRI_MI2S_TX, - MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, - msm_routing_put_voice_mixer), SOC_SINGLE_EXT("SLIM_0_TX_Voice", MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c index d9dbd8f5557..207d8d4376c 100644 --- a/sound/soc/msm/qdsp6v2/q6voice.c +++ b/sound/soc/msm/qdsp6v2/q6voice.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,7 +28,7 @@ #include "q6voice.h" -#define TIMEOUT_MS 200 +#define TIMEOUT_MS 300 #define CMD_STATUS_SUCCESS 0 |
