Merge "drm/msm: handle gem bo flags during dma buffer mapping" into msm-4.9
diff --git a/Documentation/devicetree/bindings/arm/msm/board-id.txt b/Documentation/devicetree/bindings/arm/msm/board-id.txt
new file mode 100644
index 0000000..e07a1c9
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/board-id.txt
@@ -0,0 +1,64 @@
+* BOARD-ID
+
+The qcom,board-id entry specifies the MSM platform and subtype revision.
+It can optionally be an array of these to indicate multiple hardware that use
+the same device tree. It is expected that the bootloader will use this
+information at boot-up to decide which device tree to use when given multiple
+device trees, some of which may not be compatible with the actual hardware. It
+is the bootloader's responsibility to pass the correct device tree to the kernel.
+
+Legacy format:
+
+It is expected that the qcom,board-id entry be at the top level of the device
+tree structure. The format of the entry is:
+
+ qcom,board-id = <platform_id, subtype_id> [, <p2, s2> ...]
+
+where platform_id and subtype_id are the numeric values for the platform and
+subtype of the current hardware.
+
+The "subtype_id" cell is a 32-bit integer whose bit values are defined as follows:
+ bits 31-20 = Reserved bits
+ bits 19-16 = Boot Device Type.
+ MSM:
+ 0: default (eMMC)
+ 2: EMMC_SDC1
+ 4: BOOT_UFS
+ MDM:
+ 0: default (NAND)
+ 3: EMMC_SDC1
+ bits 15-8 = DDR Size. For devices with DDR Size as 512MB the value is 0x1, default value as 0x0
+ bits 7-0 = Platform Subtype
+
+In the event that a given device tree is applicable to all hardware versions
+matching a given Platform Type / Subtype ID, the major/minior platform version
+fields in the board_id property shall both be specified as 0xff.
+
+Modern format:
+The cell layout of the qcom,board-id property is as follows:
+
+ qcom,board-id = <board_id, reserved>
+
+where board_id is a 32-bit integer whose bit values are defined as follows:
+ bits 31-24 = Platform Subtype ID
+ bits 23-16 = Platform Version (Major)
+ bits 15-8 = Platform Version (Minor)
+ bits 7-0 = Platform Type ID
+
+and the 'reserved' cell is a 32-bit integer whose bit values are defined as follows:
+ bits 31-13 = Reserved Bits
+ bits 12-11 = Panel Detection. 00 - limit to HD, 01 - limit to 720p,
+ 10 - limit to qHD, 11 - limit to FWVGA
+ bits 10-8 = DDR Size. For devices with DDR Size as 512MB the value is 0x1,
+ default value as 0x0
+ bits 7-0 = Platform Subtype
+
+In the event that a given device tree is applicable to all hardware versions
+matching a given Platform Type / Subtype ID, the major/minior platform version
+fields in the board_id property shall both be specified as 0xff.
+
+Example:
+ qcom,board-id = <15 0>;
+ qcom,board-id = <0x01040708, 0>;
+ qcom,board-id = <0x01ffff08, 0>;
+ qcom,board-id = <8, 0x100>;
diff --git a/Documentation/devicetree/bindings/arm/msm/msm-id.txt b/Documentation/devicetree/bindings/arm/msm/msm-id.txt
new file mode 100644
index 0000000..c243154
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm-id.txt
@@ -0,0 +1,33 @@
+* MSM-ID
+
+The qcom,msm-id entry specifies the MSM chipset, platform, hardware revision
+and optional manufactured foundry. It can optionally be an array of these to
+indicate multiple hardware that use the same device tree. It is expected that
+the bootloader will use this information at boot-up to decide which device tree
+to use when given multiple device trees, some of which may not be compatible
+with the actual hardware. It is the bootloader's responsibility to pass the
+correct device tree to the kernel.
+
+Format:
+
+It is expected that the qcom,msm-id entry be at the top level of the device
+tree structure. The format can take one of the two forms below:
+
+ qcom,msm-id = <chipset_foundry_id, platform_id, rev_id> [, <c2, p2, r2> ...]
+ qcom,msm-id = <chipset_foundry_id, rev_id> [, <c2, r2> ...]
+
+If the second format is used one must also define the board-id.
+
+The "chipset_foundry_id" consists of three fields as below:
+
+ bits 0-15 = The unique MSM chipset id.
+ bits 16-23 = The optional foundry id. If bootloader doesn't find a device
+ tree which has exact matching foundry-id with hardware it
+ chooses the device tree with foundry-id = 0.
+ bits 24-31 = Reserved.
+
+Example:
+ qcom,msm-id = <0x1007e 15 0>;
+
+ qcom,board-id= <15 2>;
+ qcom,msm-id = <0x1007e 0>;
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_memory_dump.txt b/Documentation/devicetree/bindings/arm/msm/msm_memory_dump.txt
new file mode 100644
index 0000000..a415c8f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm_memory_dump.txt
@@ -0,0 +1,31 @@
+Qualcomm Technologies Inc. memory dump driver
+
+QTI memory dump driver allows various client subsystems to register and allocate respective
+dump regions. At the time of deadlocks or cpu hangs these dump regions
+are captured to give a snapshot of the system at the time of the crash.
+
+Required properties:
+
+-compatible: "qcom,mem-dump"
+-memory-region: phandle to the CMA region. The size of the CMA region
+ should be greater than sum of size of all child nodes
+ to account for padding.
+
+If any child nodes exist the following property are required:
+
+-qcom,dump-size: The size of memory that needs to be allocated for the
+ particular node.
+-qcom,dump-id: The ID within the data dump table where this entry needs
+ to be added.
+
+Example:
+
+ mem_dump {
+ compatible = "qcom,mem-dump";
+ memory-region = <&dump_mem>;
+
+ rpmh_dump {
+ qcom,dump-size = <0x2000000>;
+ qcom,dump-id = <0xEC>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
new file mode 100644
index 0000000..790da12
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
@@ -0,0 +1,146 @@
+Qualcomm Technologies, Inc.
+sde-dp is the master Display Port device which supports DP host controllers that are compatible with VESA Display Port interface specification.
+DP Controller: Required properties:
+- compatible: Should be "qcom,dp-display".
+- reg: Base address and length of DP hardware's memory mapped regions.
+- reg-names: A list of strings that name the list of regs. "dp_ctrl" - DP controller memory region.
+ "dp_phy" - DP PHY memory region.
+ "dp_ln_tx0" - USB3 DP PHY combo TX-0 lane memory region.
+ "dp_ln_tx1" - USB3 DP PHY combo TX-1 lane memory region.
+ "dp_mmss_cc" - Display Clock Control memory region.
+ "qfprom_physical" - QFPROM Phys memory region.
+ "dp_pll" - USB3 DP combo PLL memory region.
+ "hdcp_physical" - DP HDCP memory region.
+- cell-index: Specifies the controller instance.
+- clocks: Clocks required for Display Port operation.
+- clock-names: Names of the clocks corresponding to handles. Following clocks are required:
+ "core_aux_clk", "core_usb_ref_clk_src","core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+ "core_usb_pipe_clk", "ctrl_link_clk", "ctrl_link_iface_clk", "ctrl_crypto_clk",
+ "ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent".
+- gdsc-supply: phandle to gdsc regulator node.
+- vdda-1p2-supply: phandle to vdda 1.2V regulator node.
+- vdda-0p9-supply: phandle to vdda 0.9V regulator node.
+- interrupt-parent phandle to the interrupt parent device node.
+- interrupts: The interrupt signal from the DSI block.
+- qcom,aux-en-gpio: Specifies the aux-channel enable gpio.
+- qcom,aux-sel-gpio: Specifies the aux-channel select gpio.
+- qcom,usbplug-cc-gpio: Specifies the usbplug orientation gpio.
+- qcom,aux-cfg-settings: An array that specifies the DP AUX configuration settings.
+- qcom,max-pclk-frequency-khz: An integer specifying the max. pixel clock in KHz supported by Display Port.
+- qcom,dp-usbpd-detection: Phandle for the PMI regulator node for USB PHY PD detection.
+- qcom,<type>-supply-entries: A node that lists the elements of the supply used by the a particular "type" of DSI module. The module "types"
+ can be "core", "ctrl", and "phy". Within the same type,
+ there can be more than one instance of this binding,
+ in which case the entry would be appended with the
+ supply entry index.
+ e.g. qcom,ctrl-supply-entry@0
+ -- qcom,supply-name: name of the supply (vdd/vdda/vddio)
+ -- qcom,supply-min-voltage: minimum voltage level (uV)
+ -- qcom,supply-max-voltage: maximum voltage level (uV)
+ -- qcom,supply-enable-load: load drawn (uA) from enabled supply
+ -- qcom,supply-disable-load: load drawn (uA) from disabled supply
+ -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on
+ -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on
+ -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off
+ -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off
+- pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node
+ Refer to pinctrl-bindings.txt
+- pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin
+ controller. These pin configurations are installed in the pinctrl
+ device node. Refer to pinctrl-bindings.txt
+
+Example:
+ sde_dp: qcom,dp_display@0{
+ cell-index = <0>;
+ compatible = "qcom,dp-display";
+
+ gdsc-supply = <&mdss_core_gdsc>;
+ vdda-1p2-supply = <&pm8998_l26>;
+ vdda-0p9-supply = <&pm8998_l1>;
+
+ reg = <0xae90000 0xa84>,
+ <0x88eaa00 0x200>,
+ <0x88ea200 0x200>,
+ <0x88ea600 0x200>,
+ <0xaf02000 0x1a0>,
+ <0x780000 0x621c>,
+ <0x88ea030 0x10>,
+ <0x88e8000 0x621c>,
+ <0x0aee1000 0x034>;
+ reg-names = "dp_ctrl", "dp_phy", "dp_ln_tx0", "dp_ln_tx1",
+ "dp_mmss_cc", "qfprom_physical", "dp_pll",
+ "usb3_dp_com", "hdcp_physical";
+
+ interrupt-parent = <&mdss_mdp>;
+ interrupts = <12 0>;
+
+ clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>,
+ <&clock_rpmh RPMH_CXO_CLK>,
+ <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>,
+ <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+ <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>,
+ <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>;
+ clock-names = "core_aux_clk", "core_usb_ref_clk_src",
+ "core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+ "core_usb_pipe_clk", "ctrl_link_clk",
+ "ctrl_link_iface_clk", "ctrl_crypto_clk",
+ "ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent";
+
+ qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
+
+ qcom,aux-cfg-settings = [00 13 04 00 0a 26 0a 03 bb 03];
+ qcom,max-pclk-frequency-khz = <593470>;
+ pinctrl-names = "mdss_dp_active", "mdss_dp_sleep";
+ pinctrl-0 = <&sde_dp_aux_active &sde_dp_usbplug_cc_active>;
+ pinctrl-1 = <&sde_dp_aux_suspend &sde_dp_usbplug_cc_suspend>;
+ qcom,aux-en-gpio = <&tlmm 43 0>;
+ qcom,aux-sel-gpio = <&tlmm 51 0>;
+ qcom,usbplug-cc-gpio = <&tlmm 38 0>;
+ qcom,core-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,core-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+
+ qcom,ctrl-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ctrl-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-1p2";
+ qcom,supply-min-voltage = <1200000>;
+ qcom,supply-max-voltage = <1200000>;
+ qcom,supply-enable-load = <21800>;
+ qcom,supply-disable-load = <4>;
+ };
+ };
+
+ qcom,phy-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,phy-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-0p9";
+ qcom,supply-min-voltage = <880000>;
+ qcom,supply-max-voltage = <880000>;
+ qcom,supply-enable-load = <36000>;
+ qcom,supply-disable-load = <32>;
+ };
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt
new file mode 100644
index 0000000..8598d0c
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt
@@ -0,0 +1,63 @@
+QTI PDC interrupt controller
+
+PDC is QTI's platform parent interrupt controller that serves as wakeup source.
+
+Newer QTI SOCs are replacing MPM (MSM sleep Power Manager) with PDC (Power
+Domain Controller) to manage subsystem wakeups and resources during sleep.
+This driver marks the wakeup interrupts in APSS PDC such that it monitors the
+interrupts when the system is asleep, wakes up the APSS when one of these
+interrupts occur and replays it to the subsystem interrupt controller after it
+becomes operational.
+
+Earlier MPM architecture used arch-extension of GIC interrupt
+controller to mark enabled wake-up interrupts and monitor these when the
+system goes to sleep. Since the arch-extensions are no-longer available
+on newer kernel versions, this driver is implemented as hierarchical irq
+domain. GIC is parent interrupt controller at the highest level.
+Platform interrupt controller PDC is next in hierarchy, followed by others.
+This driver only configures the interrupts, does not handle them.
+
+PDC interrupt configuration involves programming of 2 set of registers:
+IRQ_ENABLE_BANK - Enable the irq
+IRQ_i_CFG - Configure the interrupt i
+
+Properties:
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: Should contain "qcom,pdc-<target>"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Specifies the base physical address for PDC hardware
+ block for DRV2.
+
+- interrupt-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: Specifies the number of cells needed to encode an interrupt source.
+ Value must be 3.
+ The encoding of these cells are same as described in
+ Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
+
+- interrupt-parent:
+ Usage: required
+ Value type: <phandle>
+ Definition: Specifies the interrupt parent necessary for hierarchical domain to operate.
+
+- interrupt-controller:
+ Usage: required
+ Value type: <bool>
+ Definition: Identifies the node as an interrupt controller.
+
+Example:
+
+pdcgic: interrupt-controller@0xb220000{
+ compatible = "qcom,pdc-sdm845";
+ reg = <0xb220000 0x30000>;
+ #interrupt-cells = <3>;
+ interrupt-parent = <&intc>;
+ interrupt-controller;
+};
diff --git a/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt b/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
index 0295e1b..937ccb9 100644
--- a/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
@@ -81,6 +81,32 @@
limits.
- qcom,mdss-rot-vbif-qos-setting: This array is used to program vbif qos remapper register
priority for rotator clients.
+- qcom,mdss-rot-cdp-setting: Integer array of size two, to indicate client driven
+ prefetch is available or not. Index 0 represents
+ if CDP is enabled for read and index 1, if CDP
+ is enabled for write operation.
+- qcom,mdss-rot-qos-lut A 4 cell property with the format of <rd_lut_0,
+ rd_lut_1, wr_lut_0, wr_lut_1> indicating the qos
+ lut settings for the rotator sspp and writeback
+ client.
+- qcom,mdss-rot-danger-lut A two cell property with the format of <rd_lut,
+ wr_lut> indicating the danger lut settings for
+ the rotator sspp and writeback client.
+- qcom,mdss-rot-safe-lut A two cell property with the format of <rd_lut,
+ wr_lut> indicating the safe lut settings for the
+ rotator sspp and writeback client.
+- qcom,mdss-inline-rot-qos-lut: A 4 cell property with the format of <rd_lut_0,
+ rd_lut_1, wr_lut_0, wr_lut_1> indicating the qos
+ lut settings for the inline rotator sspp and
+ writeback client.
+- qcom,mdss-inline-rot-danger-lut: A two cell property with the format of
+ <rd_lut, wr_lut> indicating the danger lut
+ settings for the inline rotator sspp and
+ writeback client.
+- qcom,mdss-inline-rot-safe-lut: A two cell property with the format of
+ <rd_lut, wr_lut> indicating the safe lut
+ settings for the inline rotator sspp and
+ writeback client.
- qcom,mdss-rot-mode: This is integer value indicates operation mode
of the rotator device
- qcom,mdss-sbuf-headroom: This integer value indicates stream buffer headroom in lines.
@@ -146,9 +172,19 @@
/* VBIF QoS remapper settings*/
qcom,mdss-rot-vbif-qos-setting = <1 1 1 1>;
+ com,mdss-rot-cdp-setting = <1 1>;
+
qcom,mdss-default-ot-rd-limit = <8>;
qcom,mdss-default-ot-wr-limit = <16>;
+ qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>;
+ qcom,mdss-rot-danger-lut = <0x0 0x0>;
+ qcom,mdss-rot-safe-lut = <0x0000ffff 0x0>;
+
+ qcom,mdss-inline-rot-qos-lut = <0x0 0x0 0x00112233 0x44556677>;
+ qcom,mdss-inline-rot-danger-lut = <0x0 0x0000ffff>;
+ qcom,mdss-inline-rot-safe-lut = <0x0 0x0000ff00>;
+
qcom,mdss-sbuf-headroom = <20>;
cache-slice-names = "rotator";
cache-slices = <&llcc 4>;
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
index 5529e308..92ef23c 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
@@ -22,8 +22,7 @@
Definition: String which indicates the charging mode. Can be one of the
following:
Standalone/Parallel Master - "qcom,smb138x-charger"
- smb138x Parallel Slave - "qcom,smb138x-parallel-slave"
- smb1355 Parallel Slave - "qcom,smb1355-parallel-slave",
+ Parallel Slave - "qcom,smb138x-parallel-slave"
- qcom,pmic-revid
Usage: required
@@ -36,8 +35,7 @@
Usage: optional
Value type: <u32>
Definition: Specifies parallel charging mode. If not specified, MID-MID
- option is selected by default. Note that smb1355 can only
- run in MID-MID configuration.
+ option is selected by default.
- qcom,suspend-input
Usage: optional
@@ -127,7 +125,7 @@
=======
smb138x_charger: qcom,smb138x-charger {
- compatible = "qcom,smb138x-charger";
+ compatible = "qcom,qpnp-smb138x-charger";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/Documentation/devicetree/bindings/qbt1000/qbt1000.txt b/Documentation/devicetree/bindings/qbt1000/qbt1000.txt
new file mode 100644
index 0000000..c9861e4
--- /dev/null
+++ b/Documentation/devicetree/bindings/qbt1000/qbt1000.txt
@@ -0,0 +1,54 @@
+Qualcomm Technologies, Inc. QBT1000 Specific Bindings
+
+QBT is a fingerprint sensor ASIC capable of performing fingerprint image scans
+and detecting finger presence on the sensor using programmable firmware.
+
+=======================
+Required Node Structure
+=======================
+
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: "qcom,qbt1000".
+
+- clock-names
+ Usage: required
+ Value type: <stringlist>
+ Definition: List of clock names that need to be voted on/off.
+
+- clocks
+ Usage: required
+ Value type: <prop_encoded-array>
+ Definition: Property pair that represents the clock controller and the clock
+ id. This in combination with the clock-name is used to obtain
+ the handle for the clock that needs to be voted on/off.
+
+- clock-frequency
+ Usage: required
+ Value type: <u32>
+ Definition: Frequency of clock in Hz.
+
+- qcom,ipc-gpio
+ Usage: required
+ Value type: <phandle>
+ Definition: phandle for GPIO to be used for IPC.
+
+- qcom,finger-detect-gpio
+ Usage: required
+ Value type: <phandle>
+ Definition: phandle for GPIO to be used for finger detect.
+
+=======
+Example
+=======
+
+qcom,qbt1000 {
+ compatible = "qcom,qbt1000";
+ clock-names = "core", "iface";
+ clocks = <&clock_gcc clk_gcc_blsp2_qup6_spi_apps_clk>,
+ <&clock_gcc clk_gcc_blsp2_ahb_clk>;
+ clock-frequency = <15000000>;
+ qcom,ipc-gpio = <&tlmm 121 0>;
+ qcom,finger-detect-gpio = <&pmcobalt_gpios 2 0>;
+};
diff --git a/Makefile b/Makefile
index f47cd95..b9aba93 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 4
PATCHLEVEL = 9
-SUBLEVEL = 28
+SUBLEVEL = 29
EXTRAVERSION =
NAME = Roaring Lionus
diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c
index c2b1315..a08d7a9 100644
--- a/arch/arm/kvm/psci.c
+++ b/arch/arm/kvm/psci.c
@@ -208,9 +208,10 @@
static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
{
- int ret = 1;
+ struct kvm *kvm = vcpu->kvm;
unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
unsigned long val;
+ int ret = 1;
switch (psci_fn) {
case PSCI_0_2_FN_PSCI_VERSION:
@@ -230,7 +231,9 @@
break;
case PSCI_0_2_FN_CPU_ON:
case PSCI_0_2_FN64_CPU_ON:
+ mutex_lock(&kvm->lock);
val = kvm_psci_vcpu_on(vcpu);
+ mutex_unlock(&kvm->lock);
break;
case PSCI_0_2_FN_AFFINITY_INFO:
case PSCI_0_2_FN64_AFFINITY_INFO:
@@ -279,6 +282,7 @@
static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
{
+ struct kvm *kvm = vcpu->kvm;
unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
unsigned long val;
@@ -288,7 +292,9 @@
val = PSCI_RET_SUCCESS;
break;
case KVM_PSCI_FN_CPU_ON:
+ mutex_lock(&kvm->lock);
val = kvm_psci_vcpu_on(vcpu);
+ mutex_unlock(&kvm->lock);
break;
default:
val = PSCI_RET_NOT_SUPPORTED;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index 9b7865f..97573ea 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -1396,25 +1396,61 @@
};
};
- cti_ddr0: cti@69e1000 {
+ cti0_ddr0: cti@69e1000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b966>;
reg = <0x69e1000 0x1000>;
reg-names = "cti-base";
- coresight-name = "coresight-cti-ddr0";
+ coresight-name = "coresight-cti0-ddr0";
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
};
- cti_ddr1: cti@69e4000 {
+ cti0_ddr1: cti@69e4000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b966>;
reg = <0x69e4000 0x1000>;
reg-names = "cti-base";
- coresight-name = "coresight-cti-ddr1";
+ coresight-name = "coresight-cti0-ddr1";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+ };
+
+ cti1_ddr1: cti@69e5000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+ reg = <0x69e5000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti1-ddr1";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+ };
+
+ cti0_dlmm: cti@6c09000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+ reg = <0x6c09000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti0-dlmm";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+ };
+
+ cti1_dlmm: cti@6c0a000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+ reg = <0x6c0a000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti1-dlmm";
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index 59b3396..1744574 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -2667,11 +2667,11 @@
trigout_a: trigout_a {
mux {
- pins = "gpio62", "gpio51";
+ pins = "gpio90";
function = "qdss_cti";
};
config {
- pins = "gpio62", "gpio51";
+ pins = "gpio90";
drive-strength = <2>;
bias-disable;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index b51996d..0aaac6f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -14,6 +14,27 @@
#include <dt-bindings/gpio/gpio.h>
/{
+ bluetooth: bt_wcn3990 {
+ compatible = "qca,wcn3990";
+ qca,bt-vdd-io-supply = <&pm8998_s3>;
+ qca,bt-vdd-xtal-supply = <&pm8998_s5>;
+ qca,bt-vdd-core-supply = <&pm8998_l7>;
+ qca,bt-vdd-pa-supply = <&pm8998_l17>;
+ qca,bt-vdd-ldo-supply = <&pm8998_l25>;
+
+ qca,bt-vdd-io-voltage-level = <1352000 1352000>;
+ qca,bt-vdd-xtal-voltage-level = <2040000 2040000>;
+ qca,bt-vdd-core-voltage-level = <1800000 1800000>;
+ qca,bt-vdd-pa-voltage-level = <1304000 1304000>;
+ qca,bt-vdd-ldo-voltage-level = <3312000 3312000>;
+
+ qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
+ };
+
qrd_batterydata: qcom,battery-data {
qcom,batt-id-range-pct = <15>;
#include "fg-gen3-batterydata-itech-3000mah.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 79ac3b1..19b8744 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -36,7 +36,7 @@
reg = <0x3500 0x100>;
regulator-name = "pm8998_s12";
regulator-min-microvolt = <568000>;
- regulator-max-microvolt = <1056000>;
+ regulator-max-microvolt = <1136000>;
qcom,enable-time = <500>;
regulator-always-on;
};
@@ -114,9 +114,9 @@
regulator-max-microvolt = <19>;
qcom,cpr-fuse-corners = <4>;
- qcom,cpr-fuse-combos = <16>;
- qcom,cpr-speed-bins = <2>;
- qcom,cpr-speed-bin-corners = <19 19>;
+ qcom,cpr-fuse-combos = <24>;
+ qcom,cpr-speed-bins = <3>;
+ qcom,cpr-speed-bin-corners = <19 19 19>;
qcom,cpr-corners = <19>;
qcom,cpr-corner-fmax-map = <6 12 17 19>;
@@ -137,6 +137,11 @@
<568000 568000 568000 568000 568000
568000 568000 568000 568000 584000
584000 584000 632000 632000 632000
+ 632000 672000 712000 712000>,
+ /* Speed bin 2 */
+ <568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 584000
+ 584000 584000 632000 632000 632000
632000 672000 712000 712000>;
qcom,cpr-floor-to-ceiling-max-range =
@@ -146,13 +151,30 @@
32000 32000 40000 40000>;
qcom,corner-frequencies =
+ /* Speed bin 0 */
<300000000 422400000 499200000
576000000 652800000 748800000
825600000 902400000 979200000
1056000000 1132800000 1209600000
1286400000 1363200000 1440000000
1516800000 1593600000 1651200000
- 1708800000>;
+ 1708800000>,
+ /* Speed bin 1 */
+ <300000000 422400000 499200000
+ 576000000 652800000 748800000
+ 825600000 902400000 979200000
+ 1056000000 1132800000 1209600000
+ 1286400000 1363200000 1440000000
+ 1516800000 1593600000 1651200000
+ 1708800000>,
+ /* Speed bin 2 */
+ <300000000 422400000 499200000
+ 576000000 652800000 748800000
+ 825600000 902400000 979200000
+ 1056000000 1132800000 1209600000
+ 1286400000 1363200000 1440000000
+ 1516800000 1593600000 1670400000
+ 1747200000>;
qcom,cpr-ro-scaling-factor =
<2594 2795 2576 2761 2469 2673 2198
@@ -185,6 +207,8 @@
/* Speed bin 0 */
<0 1 1 1 1 1 1 1>,
/* Speed bin 1 */
+ <0 1 1 1 1 1 1 1>,
+ /* Speed bin 2 */
<0 1 1 1 1 1 1 1>;
qcom,allow-aging-open-loop-voltage-adjustment =
<1>;
@@ -201,20 +225,41 @@
apc0_l3_vreg: regulator {
regulator-name = "apc0_l3_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <11>;
+ regulator-max-microvolt = <13>;
qcom,cpr-fuse-corners = <4>;
- qcom,cpr-fuse-combos = <16>;
- qcom,cpr-speed-bins = <2>;
- qcom,cpr-speed-bin-corners = <11 11>;
- qcom,cpr-corners = <11>;
+ qcom,cpr-fuse-combos = <24>;
+ qcom,cpr-speed-bins = <3>;
+ qcom,cpr-speed-bin-corners = <11 11 13>;
+ qcom,cpr-corners =
+ /* Speed bin 0 */
+ <11 11 11 11 11 11 11 11>,
+ /* Speed bin 1 */
+ <11 11 11 11 11 11 11 11>,
+ /* Speed bin 2 */
+ <13 13 13 13 13 13 13 13>;
- qcom,cpr-corner-fmax-map = <4 7 9 11>;
+ qcom,cpr-corner-fmax-map =
+ /* Speed bin 0 */
+ <4 7 9 11>,
+ /* Speed bin 1 */
+ <4 7 9 11>,
+ /* Speed bin 2 */
+ <4 7 9 13>;
qcom,cpr-voltage-ceiling =
+ /* Speed bin 0 */
<872000 872000 872000 872000 872000
872000 872000 872000 928000 996000
- 996000>;
+ 996000>,
+ /* Speed bin 1 */
+ <872000 872000 872000 872000 872000
+ 872000 872000 872000 928000 996000
+ 996000>,
+ /* Speed bin 2 */
+ <872000 872000 872000 872000 872000
+ 872000 872000 872000 928000 996000
+ 996000 996000 996000>;
qcom,cpr-voltage-floor =
/* Speed bin 0 */
@@ -224,18 +269,43 @@
/* Speed bin 1 */
<568000 568000 568000 568000 568000
584000 584000 632000 672000 712000
- 712000>;
+ 712000>,
+ /* Speed bin 2 */
+ <568000 568000 568000 568000 568000
+ 584000 584000 632000 672000 712000
+ 712000 712000 712000>;
qcom,cpr-floor-to-ceiling-max-range =
+ /* Speed bin 0 */
<32000 32000 32000 32000 32000
32000 32000 32000 32000 40000
- 40000>;
+ 40000>,
+ /* Speed bin 1 */
+ <32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 40000
+ 40000>,
+ /* Speed bin 2 */
+ <32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 40000
+ 40000 40000 40000>;
qcom,corner-frequencies =
+ /* Speed bin 0 */
<300000000 422400000 499200000
576000000 652800000 729600000
806400000 883200000 960000000
- 1036800000 1094400000>;
+ 1036800000 1094400000>,
+ /* Speed bin 1 */
+ <300000000 422400000 499200000
+ 576000000 652800000 729600000
+ 806400000 883200000 960000000
+ 1036800000 1094400000>,
+ /* Speed bin 2 */
+ <300000000 422400000 499200000
+ 576000000 652800000 729600000
+ 806400000 883200000 960000000
+ 1036800000 1113600000 1209600000
+ 1305600000>;
qcom,cpr-ro-scaling-factor =
<2857 3056 2828 2952 2699 2796 2447
@@ -262,12 +332,14 @@
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
qcom,cpr-aging-max-voltage-adjustment = <15000>;
- qcom,cpr-aging-ref-corner = <11>;
+ qcom,cpr-aging-ref-corner = <11 11 13>;
qcom,cpr-aging-ro-scaling-factor = <1620>;
qcom,allow-aging-voltage-adjustment =
/* Speed bin 0 */
<0 1 1 1 1 1 1 1>,
/* Speed bin 1 */
+ <0 1 1 1 1 1 1 1>,
+ /* Speed bin 2 */
<0 1 1 1 1 1 1 1>;
qcom,allow-aging-open-loop-voltage-adjustment =
<1>;
@@ -320,7 +392,7 @@
qcom,cpr-panic-reg-name-list =
"APSS_GOLD_CPRH_STATUS_0", "GOLD_SAW4_PMIC_STS";
- qcom,cpr-aging-ref-voltage = <1056000>;
+ qcom,cpr-aging-ref-voltage = <1136000>;
vdd-supply = <&pm8998_s12>;
thread@0 {
@@ -333,23 +405,27 @@
apc1_perfcl_vreg: regulator {
regulator-name = "apc1_perfcl_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <26>;
+ regulator-max-microvolt = <27>;
qcom,cpr-fuse-corners = <3>;
- qcom,cpr-fuse-combos = <16>;
- qcom,cpr-speed-bins = <2>;
- qcom,cpr-speed-bin-corners = <22 24>;
+ qcom,cpr-fuse-combos = <24>;
+ qcom,cpr-speed-bins = <3>;
+ qcom,cpr-speed-bin-corners = <22 24 25>;
qcom,cpr-corners =
/* Speed bin 0 */
<22 22 22 22 22 22 22 22>,
/* Speed bin 1 */
- <24 24 24 24 24 24 24 24>;
+ <24 24 24 24 24 24 24 24>,
+ /* Speed bin 2 */
+ <25 25 25 25 25 25 25 25>;
qcom,cpr-corner-fmax-map =
/* Speed bin 0 */
<10 17 22>,
/* Speed bin 1 */
- <10 17 24>;
+ <10 17 24>,
+ /* Speed bin 2 */
+ <10 17 25>;
qcom,cpr-voltage-ceiling =
/* Speed bin 0 */
@@ -357,13 +433,20 @@
828000 828000 828000 828000 828000
828000 828000 828000 828000 828000
828000 828000 884000 952000 952000
- 1056000 1056000>,
+ 1136000 1136000>,
/* Speed bin 1 */
<828000 828000 828000 828000 828000
828000 828000 828000 828000 828000
828000 828000 828000 828000 828000
828000 828000 884000 952000 952000
- 1056000 1056000 1056000 1056000>;
+ 1136000 1136000 1136000 1136000>,
+ /* Speed bin 2 */
+ <828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 828000 884000 952000 952000
+ 1136000 1136000 1136000 1136000
+ 1136000>;
qcom,cpr-voltage-floor =
/* Speed bin 0 */
@@ -377,7 +460,14 @@
568000 568000 568000 568000 568000
584000 584000 632000 632000 632000
632000 632000 672000 712000 712000
- 772000 772000 772000 772000>;
+ 772000 772000 772000 772000>,
+ /* Speed bin 2 */
+ <568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 584000 584000 632000 632000 632000
+ 632000 632000 672000 712000 712000
+ 772000 772000 772000 772000
+ 772000>;
qcom,cpr-floor-to-ceiling-max-range =
/* Speed bin 0 */
@@ -391,7 +481,13 @@
32000 32000 32000 32000 32000
32000 32000 32000 32000 32000
32000 32000 40000 40000 40000
- 40000 40000 40000 40000>;
+ 40000 40000 40000 40000>,
+ /* Speed bin 2 */
+ <32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 40000 40000 40000
+ 40000 40000 40000 40000 40000>;
qcom,corner-frequencies =
/* Speed bin 0 */
@@ -411,7 +507,17 @@
1267200000 1344000000 1420800000
1497600000 1574400000 1651200000
1728000000 1804800000 1881600000
- 1958400000 2035200000 2092800000>;
+ 1958400000 2035200000 2092800000>,
+ /* Speed bin 2 */
+ <300000000 422400000 499200000
+ 576000000 652800000 729600000
+ 806400000 883200000 960000000
+ 1036800000 1113600000 1190400000
+ 1267200000 1344000000 1420800000
+ 1497600000 1574400000 1651200000
+ 1728000000 1804800000 1881600000
+ 1958400000 2035200000 2112000000
+ 2208000000>;
qcom,cpr-ro-scaling-factor =
<2857 3056 2828 2952 2699 2796 2447
@@ -425,22 +531,76 @@
2003 1675>;
qcom,cpr-open-loop-voltage-fuse-adjustment =
- <100000 100000 100000>;
+ /* Speed bin 0 */
+ <100000 100000 100000>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ /* Speed bin 1 */
+ <100000 100000 100000>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ /* Speed bin 2 */
+ <100000 100000 100000>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>;
qcom,cpr-closed-loop-voltage-fuse-adjustment =
- <100000 100000 100000>;
+ /* Speed bin 0 */
+ <100000 100000 100000>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ /* Speed bin 1 */
+ <100000 100000 100000>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ /* Speed bin 2 */
+ <100000 100000 100000>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>;
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
qcom,cpr-aging-max-voltage-adjustment = <15000>;
- qcom,cpr-aging-ref-corner = <22 24>;
+ qcom,cpr-aging-ref-corner = <22 24 25>;
qcom,cpr-aging-ro-scaling-factor = <1700>;
qcom,allow-aging-voltage-adjustment =
/* Speed bin 0 */
<0 1 1 1 1 1 1 1>,
/* Speed bin 1 */
+ <0 1 1 1 1 1 1 1>,
+ /* Speed bin 2 */
<0 1 1 1 1 1 1 1>;
qcom,allow-aging-open-loop-voltage-adjustment =
<1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 6d9e321..e92bfd9 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -130,6 +130,8 @@
qcom,sde-max-bw-high-kbps = <9600000>;
qcom,sde-dram-channels = <2>;
qcom,sde-num-nrt-paths = <0>;
+ qcom,sde-dspp-ad-version = <0x00040000>;
+ qcom,sde-dspp-ad-off = <0x28000 0x27000>;
qcom,sde-vbif-off = <0>;
qcom,sde-vbif-size = <0x1040>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 6038b6e..c806627 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -387,7 +387,7 @@
1024 1131 /* 1958400 */
>;
idle-cost-data = <
- 520 500 480 460
+ 100 80 60 40
>;
};
CLUSTER_COST_0: cluster-cost0 {
@@ -567,6 +567,12 @@
size = <0 0x5c00000>;
};
+ dump_mem: mem_dump_region {
+ compatible = "shared-dma-pool";
+ reusable;
+ size = <0 0x2400000>;
+ };
+
/* global autoconfigured region for contiguous allocations */
linux,cma {
compatible = "shared-dma-pool";
@@ -1011,6 +1017,35 @@
interrupts = <1 5 4>;
};
+ mincpubw: qcom,mincpubw {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 4943 /* 1296 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ devfreq-cpufreq {
+ mincpubw-cpufreq {
+ target-dev = <&mincpubw>;
+ cpu-to-dev-map-0 =
+ < 1708800 762 >;
+ cpu-to-dev-map-4 =
+ < 2035200 762 >,
+ < 2092800 2597 >;
+ };
+ };
+
clock_rpmh: qcom,rpmhclk {
compatible = "qcom,rpmh-clk-sdm845";
#clock-cells = <1>;
@@ -1683,7 +1718,7 @@
qcom,ssc@5c00000 {
compatible = "qcom,pil-tz-generic";
reg = <0x5c00000 0x4000>;
- interrupts = <0 377 1>;
+ interrupts = <0 494 1>;
vdd_cx-supply = <&pm8998_l27_level>;
vdd_px-supply = <&pm8998_lvs2>;
@@ -2486,6 +2521,14 @@
qcom,pipe-attr-ee;
};
+ qcom,qbt1000 {
+ compatible = "qcom,qbt1000";
+ clock-names = "core", "iface";
+ clock-frequency = <25000000>;
+ qcom,ipc-gpio = <&tlmm 121 0>;
+ qcom,finger-detect-gpio = <&pm8998_gpios 5 0>;
+ };
+
qcom_seecom: qseecom@86d00000 {
compatible = "qcom,qseecom";
reg = <0x86d00000 0x2200000>;
@@ -3875,6 +3918,41 @@
#thermal-sensor-cells = <1>;
};
+ mem_dump {
+ compatible = "qcom,mem-dump";
+ memory-region = <&dump_mem>;
+
+ rpmh_dump {
+ qcom,dump-size = <0x2000000>;
+ qcom,dump-id = <0xec>;
+ };
+
+ rpm_sw_dump {
+ qcom,dump-size = <0x28000>;
+ qcom,dump-id = <0xea>;
+ };
+
+ pmic_dump {
+ qcom,dump-size = <0x10000>;
+ qcom,dump-id = <0xe4>;
+ };
+
+ tmc_etf_dump {
+ qcom,dump-size = <0x10000>;
+ qcom,dump-id = <0xf0>;
+ };
+
+ tmc_etf_swao_dump {
+ qcom,dump-size = <0x8400>;
+ qcom,dump-id = <0xf1>;
+ };
+
+ misc_data_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0xe8>;
+ };
+ };
+
gpi_dma0: qcom,gpi-dma@0x800000 {
#dma-cells = <6>;
compatible = "qcom,gpi-dma";
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 10b44f8..19a6db8 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -491,6 +491,7 @@
CONFIG_MSM_AVTIMER=y
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_PM=y
+CONFIG_MSM_QBT1000=y
CONFIG_APSS_CORE_EA=y
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 737f47f..04a0d3e 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -513,6 +513,7 @@
CONFIG_MSM_AVTIMER=y
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_PM=y
+CONFIG_MSM_QBT1000=y
CONFIG_APSS_CORE_EA=y
CONFIG_QCOM_DCC_V2=y
CONFIG_QTI_RPM_STATS_LOG=y
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index f5ea0ba..fe39e68 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -240,6 +240,12 @@
return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_FSC_TYPE;
}
+static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
+{
+ u32 esr = kvm_vcpu_get_hsr(vcpu);
+ return (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT;
+}
+
static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
{
return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index da845fd..fe8f94a 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -277,12 +277,10 @@
}
if (!user_mode(regs))
show_extra_register_data(regs, 64);
- printk("\n");
}
void show_regs(struct pt_regs * regs)
{
- printk("\n");
__show_regs(regs);
}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 87e7e66..7cee552 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1573,8 +1573,8 @@
{
struct sys_reg_params params;
u32 hsr = kvm_vcpu_get_hsr(vcpu);
- int Rt = (hsr >> 5) & 0xf;
- int Rt2 = (hsr >> 10) & 0xf;
+ int Rt = kvm_vcpu_sys_get_rt(vcpu);
+ int Rt2 = (hsr >> 10) & 0x1f;
params.is_aarch32 = true;
params.is_32bit = false;
@@ -1625,7 +1625,7 @@
{
struct sys_reg_params params;
u32 hsr = kvm_vcpu_get_hsr(vcpu);
- int Rt = (hsr >> 5) & 0xf;
+ int Rt = kvm_vcpu_sys_get_rt(vcpu);
params.is_aarch32 = true;
params.is_32bit = true;
@@ -1740,7 +1740,7 @@
{
struct sys_reg_params params;
unsigned long esr = kvm_vcpu_get_hsr(vcpu);
- int Rt = (esr >> 5) & 0x1f;
+ int Rt = kvm_vcpu_sys_get_rt(vcpu);
int ret;
trace_kvm_handle_sys_reg(esr);
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 34d2c59..7362267 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -561,6 +561,7 @@
static struct pstore_info nvram_pstore_info = {
.owner = THIS_MODULE,
.name = "nvram",
+ .flags = PSTORE_FLAGS_DMESG,
.open = nvram_pstore_open,
.read = nvram_pstore_read,
.write = nvram_pstore_write,
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
index e5612f3..d7ac721 100644
--- a/arch/x86/boot/boot.h
+++ b/arch/x86/boot/boot.h
@@ -16,7 +16,7 @@
#ifndef BOOT_BOOT_H
#define BOOT_BOOT_H
-#define STACK_SIZE 512 /* Minimum number of bytes for stack */
+#define STACK_SIZE 1024 /* Minimum number of bytes for stack */
#ifndef __ASSEMBLY__
diff --git a/arch/x86/events/intel/rapl.c b/arch/x86/events/intel/rapl.c
index 0a535ce..8b902b6 100644
--- a/arch/x86/events/intel/rapl.c
+++ b/arch/x86/events/intel/rapl.c
@@ -759,7 +759,7 @@
X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_CORE, hsw_rapl_init),
X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_GT3E, hsw_rapl_init),
- X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_X, hsw_rapl_init),
+ X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_X, hsx_rapl_init),
X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, hsw_rapl_init),
X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, knl_rapl_init),
diff --git a/arch/x86/include/asm/pmem.h b/arch/x86/include/asm/pmem.h
index 529bb4a..e290437 100644
--- a/arch/x86/include/asm/pmem.h
+++ b/arch/x86/include/asm/pmem.h
@@ -103,7 +103,7 @@
if (bytes < 8) {
if (!IS_ALIGNED(dest, 4) || (bytes != 4))
- arch_wb_cache_pmem(addr, 1);
+ arch_wb_cache_pmem(addr, bytes);
} else {
if (!IS_ALIGNED(dest, 8)) {
dest = ALIGN(dest, boot_cpu_data.x86_clflush_size);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e5bc139..43c1528 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3051,6 +3051,12 @@
(events->exception.nr > 31 || events->exception.nr == NMI_VECTOR))
return -EINVAL;
+ /* INITs are latched while in SMM */
+ if (events->flags & KVM_VCPUEVENT_VALID_SMM &&
+ (events->smi.smm || events->smi.pending) &&
+ vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED)
+ return -EINVAL;
+
process_nmi(vcpu);
vcpu->arch.exception.pending = events->exception.injected;
vcpu->arch.exception.nr = events->exception.nr;
@@ -7162,6 +7168,12 @@
mp_state->mp_state != KVM_MP_STATE_RUNNABLE)
return -EINVAL;
+ /* INITs are latched while in SMM */
+ if ((is_smm(vcpu) || vcpu->arch.smi_pending) &&
+ (mp_state->mp_state == KVM_MP_STATE_SIPI_RECEIVED ||
+ mp_state->mp_state == KVM_MP_STATE_INIT_RECEIVED))
+ return -EINVAL;
+
if (mp_state->mp_state == KVM_MP_STATE_SIPI_RECEIVED) {
vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED;
set_bit(KVM_APIC_SIPI, &vcpu->arch.apic->pending_events);
diff --git a/arch/x86/um/ptrace_64.c b/arch/x86/um/ptrace_64.c
index e30202b..7c16017 100644
--- a/arch/x86/um/ptrace_64.c
+++ b/arch/x86/um/ptrace_64.c
@@ -125,7 +125,7 @@
else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
(addr <= offsetof(struct user, u_debugreg[7]))) {
addr -= offsetof(struct user, u_debugreg[0]);
- addr = addr >> 2;
+ addr = addr >> 3;
if ((addr == 4) || (addr == 5))
return -EIO;
child->thread.arch.debugregs[addr] = data;
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 7d5afdb..418f1b8 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -2028,7 +2028,8 @@
/*
* Translate a virtual address to a physical one without relying on mapped
- * page tables.
+ * page tables. Don't rely on big pages being aligned in (guest) physical
+ * space!
*/
static phys_addr_t __init xen_early_virt_to_phys(unsigned long vaddr)
{
@@ -2049,7 +2050,7 @@
sizeof(pud)));
if (!pud_present(pud))
return 0;
- pa = pud_pfn(pud) << PAGE_SHIFT;
+ pa = pud_val(pud) & PTE_PFN_MASK;
if (pud_large(pud))
return pa + (vaddr & ~PUD_MASK);
@@ -2057,7 +2058,7 @@
sizeof(pmd)));
if (!pmd_present(pmd))
return 0;
- pa = pmd_pfn(pmd) << PAGE_SHIFT;
+ pa = pmd_val(pmd) & PTE_PFN_MASK;
if (pmd_large(pmd))
return pa + (vaddr & ~PMD_MASK);
diff --git a/block/blk-integrity.c b/block/blk-integrity.c
index 319f2e4..478f572 100644
--- a/block/blk-integrity.c
+++ b/block/blk-integrity.c
@@ -412,7 +412,8 @@
bi->flags = BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE |
template->flags;
- bi->interval_exp = ilog2(queue_logical_block_size(disk->queue));
+ bi->interval_exp = template->interval_exp ? :
+ ilog2(queue_logical_block_size(disk->queue));
bi->profile = template->profile ? template->profile : &nop_profile;
bi->tuple_size = template->tuple_size;
bi->tag_size = template->tag_size;
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
index fde8d88..6c11537 100644
--- a/crypto/algif_aead.c
+++ b/crypto/algif_aead.c
@@ -44,6 +44,11 @@
char iv[];
};
+struct aead_tfm {
+ struct crypto_aead *aead;
+ bool has_key;
+};
+
struct aead_ctx {
struct aead_sg_list tsgl;
struct aead_async_rsgl first_rsgl;
@@ -732,24 +737,146 @@
.poll = aead_poll,
};
+static int aead_check_key(struct socket *sock)
+{
+ int err = 0;
+ struct sock *psk;
+ struct alg_sock *pask;
+ struct aead_tfm *tfm;
+ struct sock *sk = sock->sk;
+ struct alg_sock *ask = alg_sk(sk);
+
+ lock_sock(sk);
+ if (ask->refcnt)
+ goto unlock_child;
+
+ psk = ask->parent;
+ pask = alg_sk(ask->parent);
+ tfm = pask->private;
+
+ err = -ENOKEY;
+ lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
+ if (!tfm->has_key)
+ goto unlock;
+
+ if (!pask->refcnt++)
+ sock_hold(psk);
+
+ ask->refcnt = 1;
+ sock_put(psk);
+
+ err = 0;
+
+unlock:
+ release_sock(psk);
+unlock_child:
+ release_sock(sk);
+
+ return err;
+}
+
+static int aead_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
+ size_t size)
+{
+ int err;
+
+ err = aead_check_key(sock);
+ if (err)
+ return err;
+
+ return aead_sendmsg(sock, msg, size);
+}
+
+static ssize_t aead_sendpage_nokey(struct socket *sock, struct page *page,
+ int offset, size_t size, int flags)
+{
+ int err;
+
+ err = aead_check_key(sock);
+ if (err)
+ return err;
+
+ return aead_sendpage(sock, page, offset, size, flags);
+}
+
+static int aead_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
+ size_t ignored, int flags)
+{
+ int err;
+
+ err = aead_check_key(sock);
+ if (err)
+ return err;
+
+ return aead_recvmsg(sock, msg, ignored, flags);
+}
+
+static struct proto_ops algif_aead_ops_nokey = {
+ .family = PF_ALG,
+
+ .connect = sock_no_connect,
+ .socketpair = sock_no_socketpair,
+ .getname = sock_no_getname,
+ .ioctl = sock_no_ioctl,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .getsockopt = sock_no_getsockopt,
+ .mmap = sock_no_mmap,
+ .bind = sock_no_bind,
+ .accept = sock_no_accept,
+ .setsockopt = sock_no_setsockopt,
+
+ .release = af_alg_release,
+ .sendmsg = aead_sendmsg_nokey,
+ .sendpage = aead_sendpage_nokey,
+ .recvmsg = aead_recvmsg_nokey,
+ .poll = aead_poll,
+};
+
static void *aead_bind(const char *name, u32 type, u32 mask)
{
- return crypto_alloc_aead(name, type, mask);
+ struct aead_tfm *tfm;
+ struct crypto_aead *aead;
+
+ tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
+ if (!tfm)
+ return ERR_PTR(-ENOMEM);
+
+ aead = crypto_alloc_aead(name, type, mask);
+ if (IS_ERR(aead)) {
+ kfree(tfm);
+ return ERR_CAST(aead);
+ }
+
+ tfm->aead = aead;
+
+ return tfm;
}
static void aead_release(void *private)
{
- crypto_free_aead(private);
+ struct aead_tfm *tfm = private;
+
+ crypto_free_aead(tfm->aead);
+ kfree(tfm);
}
static int aead_setauthsize(void *private, unsigned int authsize)
{
- return crypto_aead_setauthsize(private, authsize);
+ struct aead_tfm *tfm = private;
+
+ return crypto_aead_setauthsize(tfm->aead, authsize);
}
static int aead_setkey(void *private, const u8 *key, unsigned int keylen)
{
- return crypto_aead_setkey(private, key, keylen);
+ struct aead_tfm *tfm = private;
+ int err;
+
+ err = crypto_aead_setkey(tfm->aead, key, keylen);
+ tfm->has_key = !err;
+
+ return err;
}
static void aead_sock_destruct(struct sock *sk)
@@ -766,12 +893,14 @@
af_alg_release_parent(sk);
}
-static int aead_accept_parent(void *private, struct sock *sk)
+static int aead_accept_parent_nokey(void *private, struct sock *sk)
{
struct aead_ctx *ctx;
struct alg_sock *ask = alg_sk(sk);
- unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(private);
- unsigned int ivlen = crypto_aead_ivsize(private);
+ struct aead_tfm *tfm = private;
+ struct crypto_aead *aead = tfm->aead;
+ unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(aead);
+ unsigned int ivlen = crypto_aead_ivsize(aead);
ctx = sock_kmalloc(sk, len, GFP_KERNEL);
if (!ctx)
@@ -798,7 +927,7 @@
ask->private = ctx;
- aead_request_set_tfm(&ctx->aead_req, private);
+ aead_request_set_tfm(&ctx->aead_req, aead);
aead_request_set_callback(&ctx->aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG,
af_alg_complete, &ctx->completion);
@@ -807,13 +936,25 @@
return 0;
}
+static int aead_accept_parent(void *private, struct sock *sk)
+{
+ struct aead_tfm *tfm = private;
+
+ if (!tfm->has_key)
+ return -ENOKEY;
+
+ return aead_accept_parent_nokey(private, sk);
+}
+
static const struct af_alg_type algif_type_aead = {
.bind = aead_bind,
.release = aead_release,
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
.accept = aead_accept_parent,
+ .accept_nokey = aead_accept_parent_nokey,
.ops = &algif_aead_ops,
+ .ops_nokey = &algif_aead_ops_nokey,
.name = "aead",
.owner = THIS_MODULE
};
diff --git a/drivers/Makefile b/drivers/Makefile
index 413dff9..990f63c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -103,6 +103,7 @@
obj-$(CONFIG_USB) += usb/
obj-$(CONFIG_PCI) += usb/
obj-$(CONFIG_USB_GADGET) += usb/
+obj-$(CONFIG_OF) += usb/
obj-$(CONFIG_SERIO) += input/serio/
obj-$(CONFIG_GAMEPORT) += input/gameport/
obj-$(CONFIG_INPUT) += input/
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 8f6c23c..deed580 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -287,6 +287,9 @@
hu->priv = bcm;
+ if (!hu->tty->dev)
+ goto out;
+
mutex_lock(&bcm_device_lock);
list_for_each(p, &bcm_device_list) {
struct bcm_device *dev = list_entry(p, struct bcm_device, list);
@@ -307,7 +310,7 @@
}
mutex_unlock(&bcm_device_lock);
-
+out:
return 0;
}
diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c
index 9e27128..7330638 100644
--- a/drivers/bluetooth/hci_intel.c
+++ b/drivers/bluetooth/hci_intel.c
@@ -307,6 +307,9 @@
struct list_head *p;
int err = -ENODEV;
+ if (!hu->tty->dev)
+ return err;
+
mutex_lock(&intel_device_list_lock);
list_for_each(p, &intel_device_list) {
@@ -379,6 +382,9 @@
struct intel_data *intel = container_of(work, struct intel_data,
busy_work);
+ if (!intel->hu->tty->dev)
+ return;
+
/* Link is busy, delay the suspend */
mutex_lock(&intel_device_list_lock);
list_for_each(p, &intel_device_list) {
@@ -889,6 +895,8 @@
list_for_each(p, &intel_device_list) {
struct intel_device *dev = list_entry(p, struct intel_device,
list);
+ if (!hu->tty->dev)
+ break;
if (hu->tty->dev->parent == dev->pdev->dev.parent) {
if (device_may_wakeup(&dev->pdev->dev)) {
set_bit(STATE_LPM_ENABLED, &intel->flags);
@@ -1056,6 +1064,9 @@
BT_DBG("hu %p skb %p", hu, skb);
+ if (!hu->tty->dev)
+ goto out_enqueue;
+
/* Be sure our controller is resumed and potential LPM transaction
* completed before enqueuing any packet.
*/
@@ -1072,7 +1083,7 @@
}
}
mutex_unlock(&intel_device_list_lock);
-
+out_enqueue:
skb_queue_tail(&intel->txq, skb);
return 0;
diff --git a/drivers/char/diag/diagfwd_glink.h b/drivers/char/diag/diagfwd_glink.h
index bad4629..73f2fe8 100644
--- a/drivers/char/diag/diagfwd_glink.h
+++ b/drivers/char/diag/diagfwd_glink.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index 5673fff..6958b5c 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -892,6 +892,7 @@
* for details on the intricacies of this.
*/
int left;
+ unsigned char *data_to_send;
ssif_inc_stat(ssif_info, sent_messages_parts);
@@ -900,6 +901,7 @@
left = 32;
/* Length byte. */
ssif_info->multi_data[ssif_info->multi_pos] = left;
+ data_to_send = ssif_info->multi_data + ssif_info->multi_pos;
ssif_info->multi_pos += left;
if (left < 32)
/*
@@ -913,7 +915,7 @@
rv = ssif_i2c_send(ssif_info, msg_written_handler,
I2C_SMBUS_WRITE,
SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE,
- ssif_info->multi_data + ssif_info->multi_pos,
+ data_to_send,
I2C_SMBUS_BLOCK_DATA);
if (rv < 0) {
/* request failed, just return the error. */
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index d15d1bb..fd3617b 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -59,7 +59,6 @@
#define FABIA_USER_CTL_LO 0xc
#define FABIA_USER_CTL_HI 0x10
-#define FABIA_CAL_L_VAL 0x8
#define FABIA_FRAC_VAL 0x38
#define FABIA_OPMODE 0x2c
#define FABIA_PLL_STANDBY 0x0
@@ -463,12 +462,9 @@
{
u32 val, mask;
- if (config->l) {
+ if (config->l)
regmap_write(regmap, pll->offset + PLL_L_VAL,
config->l);
- regmap_write(regmap, pll->offset + FABIA_CAL_L_VAL,
- config->l);
- }
if (config->frac)
regmap_write(regmap, pll->offset + FABIA_FRAC_VAL,
@@ -627,12 +623,6 @@
}
regmap_write(pll->clkr.regmap, off + PLL_L_VAL, l);
- /*
- * pll_cal_l_val is set to pll_l_val on MOST targets. Set it
- * explicitly here for PLL out-of-reset calibration to work
- * without a glitch on ALL of them.
- */
- regmap_write(pll->clkr.regmap, off + FABIA_CAL_L_VAL, l);
regmap_write(pll->clkr.regmap, off + FABIA_FRAC_VAL, a);
/* Latch the PLL input */
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index 3a38d37..7f56fb6 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -174,6 +174,7 @@
struct clk_regmap clkr;
u8 flags;
#define FORCE_ENABLE_RCG BIT(0)
+#define DFS_ENABLE_RCG BIT(1)
};
#define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)
@@ -187,4 +188,6 @@
extern const struct clk_ops clk_gfx3d_ops;
extern const struct clk_ops clk_dp_ops;
+extern int clk_rcg2_get_dfs_clock_rate(struct clk_rcg2 *clk,
+ struct device *dev, u8 rcg_flags);
#endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 3d101ac..6bdea53 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -18,6 +18,7 @@
#include <linux/export.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/regmap.h>
#include <linux/rational.h>
#include <linux/math64.h>
@@ -50,6 +51,14 @@
#define N_REG 0xc
#define D_REG 0x10
+/* Dynamic Frequency Scaling */
+#define MAX_PERF_LEVEL 16
+#define SE_CMD_DFSR_OFFSET 0x14
+#define SE_CMD_DFS_EN BIT(0)
+#define SE_PERF_DFSR(level) (0x1c + 0x4 * (level))
+#define SE_PERF_M_DFSR(level) (0x5c + 0x4 * (level))
+#define SE_PERF_N_DFSR(level) (0x9c + 0x4 * (level))
+
static struct freq_tbl cxo_f = {
.freq = 19200000,
.src = 0,
@@ -127,6 +136,9 @@
int ret;
u32 cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
+ if (rcg->flags & DFS_ENABLE_RCG)
+ return 0;
+
ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
CFG_SRC_SEL_MASK, cfg);
if (ret)
@@ -236,6 +248,9 @@
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask;
+ if (rcg->flags & DFS_ENABLE_RCG)
+ return rcg->current_freq;
+
if (rcg->enable_safe_config && !clk_hw_is_prepared(hw)) {
if (!rcg->current_freq)
rcg->current_freq = cxo_f.freq;
@@ -333,6 +348,9 @@
struct clk_hw *hw = &rcg->clkr.hw;
int ret, index = qcom_find_src_index(hw, rcg->parent_map, f->src);
+ if (rcg->flags & DFS_ENABLE_RCG)
+ return -EPERM;
+
if (index < 0)
return index;
@@ -461,7 +479,7 @@
}
ret = clk_rcg2_configure(rcg, f);
- if (ret)
+ if (ret && ret != -EPERM)
return ret;
if (rcg->flags & FORCE_ENABLE_RCG) {
@@ -1170,3 +1188,167 @@
.list_registers = clk_rcg2_list_registers,
};
EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
+
+/* Common APIs to be used for DFS based RCGR */
+static u8 clk_parent_index_pre_div_and_mode(struct clk_hw *hw, u32 offset,
+ u32 *mode, u32 *pre_div)
+{
+ struct clk_rcg2 *rcg;
+ int num_parents = clk_hw_get_num_parents(hw);
+ u32 cfg, mask;
+ int i, ret;
+
+ if (!hw)
+ return -EINVAL;
+
+ rcg = to_clk_rcg2(hw);
+
+ ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + offset, &cfg);
+ if (ret)
+ goto err;
+
+ mask = BIT(rcg->hid_width) - 1;
+ *pre_div = cfg & mask ? (cfg & mask) : 1;
+
+ *mode = cfg & CFG_MODE_MASK;
+ *mode >>= CFG_MODE_SHIFT;
+
+ cfg &= CFG_SRC_SEL_MASK;
+ cfg >>= CFG_SRC_SEL_SHIFT;
+
+ for (i = 0; i < num_parents; i++)
+ if (cfg == rcg->parent_map[i].cfg)
+ return i;
+err:
+ pr_debug("%s: Clock %s has invalid parent, using default.\n",
+ __func__, clk_hw_get_name(hw));
+ return 0;
+}
+
+static int calculate_m_and_n(struct clk_hw *hw, u32 m_offset, u32 n_offset,
+ u32 mode, u32 *m, u32 *n)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ u32 val, mask;
+ int ret = 0;
+
+ if (!hw)
+ return -EINVAL;
+
+ *m = *n = 0;
+
+ if (mode) {
+ /* Calculate M & N values */
+ mask = BIT(rcg->mnd_width) - 1;
+ ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + m_offset,
+ &val);
+ if (ret) {
+ pr_err("Failed to read M offset register\n");
+ goto err;
+ }
+
+ val &= mask;
+ *m = val;
+
+ ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + n_offset,
+ &val);
+ if (ret) {
+ pr_err("Failed to read N offset register\n");
+ goto err;
+ }
+
+ /* val ~(N-M) */
+ val = ~val;
+ val &= mask;
+ val += *m;
+ *n = val;
+ }
+err:
+ return ret;
+}
+
+int clk_rcg2_get_dfs_clock_rate(struct clk_rcg2 *clk, struct device *dev,
+ u8 rcg_flags)
+{
+ int i, j, index, ret = 0;
+ unsigned long calc_freq, prate;
+ u32 val, pre_div = 0, mode = 0, m = 0, n = 0;
+ struct freq_tbl *dfs_freq_tbl;
+ struct clk_hw *phw;
+
+ if (!clk)
+ return -EINVAL;
+
+ /* Check for DFS_EN */
+ ret = regmap_read(clk->clkr.regmap, clk->cmd_rcgr + SE_CMD_DFSR_OFFSET,
+ &val);
+ if (ret) {
+ dev_err(dev, "Failed to read DFS enable register\n");
+ return -EINVAL;
+ }
+
+ if (!(val & SE_CMD_DFS_EN))
+ return ret;
+
+ dfs_freq_tbl = devm_kzalloc(dev, MAX_PERF_LEVEL *
+ sizeof(struct freq_tbl), GFP_KERNEL);
+ if (!dfs_freq_tbl)
+ return -ENOMEM;
+
+ /* Populate the Perf Level */
+ for (i = 0; i < MAX_PERF_LEVEL; i++) {
+ /* Get parent index and mode */
+ index = clk_parent_index_pre_div_and_mode(&clk->clkr.hw,
+ SE_PERF_DFSR(i), &mode,
+ &pre_div);
+ if (index < 0) {
+ pr_err("Failed to get parent index & mode %d\n", index);
+ return index;
+ }
+
+ /* clock pre_div */
+ dfs_freq_tbl[i].pre_div = pre_div;
+
+ /* Fill the parent src */
+ dfs_freq_tbl[i].src = clk->parent_map[index].src;
+
+ /* Get the parent clock and parent rate */
+ phw = clk_hw_get_parent_by_index(&clk->clkr.hw, index);
+ prate = clk_hw_get_rate(phw);
+
+ ret = calculate_m_and_n(&clk->clkr.hw, SE_PERF_M_DFSR(i),
+ SE_PERF_N_DFSR(i), mode, &m, &n);
+ if (ret)
+ goto err;
+
+ dfs_freq_tbl[i].m = m;
+ dfs_freq_tbl[i].n = n;
+
+ /* calculate the final frequency */
+ calc_freq = calc_rate(prate, dfs_freq_tbl[i].m,
+ dfs_freq_tbl[i].n, mode,
+ dfs_freq_tbl[i].pre_div);
+
+ /* Check for duplicate frequencies */
+ for (j = 0; j < i; j++) {
+ if (dfs_freq_tbl[j].freq == calc_freq)
+ goto done;
+ }
+
+ dfs_freq_tbl[i].freq = calc_freq;
+ }
+done:
+ j = i;
+
+ for (i = 0; i < j; i++)
+ pr_debug("Index[%d]\tfreq_table.freq %ld\tfreq_table.src %d\t"
+ "freq_table.pre_div %d\tfreq_table.m %d\tfreq_table.n %d\t"
+ "RCG flags %x\n", i, dfs_freq_tbl[i].freq, dfs_freq_tbl[i].src,
+ dfs_freq_tbl[i].pre_div, dfs_freq_tbl[i].m,
+ dfs_freq_tbl[i].n, rcg_flags);
+
+ clk->flags |= rcg_flags;
+ clk->freq_tbl = dfs_freq_tbl;
+err:
+ return ret;
+}
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index fffcbaf..b2ff04a 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2017, 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
@@ -275,4 +275,26 @@
}
EXPORT_SYMBOL_GPL(qcom_cc_probe);
+int qcom_cc_register_rcg_dfs(struct platform_device *pdev,
+ const struct qcom_cc_dfs_desc *desc)
+{
+ struct clk_dfs *clks = desc->clks;
+ size_t num_clks = desc->num_clks;
+ int i, ret = 0;
+
+ for (i = 0; i < num_clks; i++) {
+ ret = clk_rcg2_get_dfs_clock_rate(clks[i].rcg, &pdev->dev,
+ clks[i].rcg_flags);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed calculating DFS frequencies for %s\n",
+ clk_hw_get_name(&(clks[i].rcg)->clkr.hw));
+ break;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(qcom_cc_register_rcg_dfs);
+
MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index e728dec..5e26763 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -14,6 +14,7 @@
#define __QCOM_CLK_COMMON_H__
#include <linux/reset-controller.h>
+#include "clk-rcg.h"
struct platform_device;
struct regmap_config;
@@ -40,6 +41,16 @@
unsigned long rrate;
};
+struct clk_dfs {
+ struct clk_rcg2 *rcg;
+ u8 rcg_flags;
+};
+
+struct qcom_cc_dfs_desc {
+ struct clk_dfs *clks;
+ size_t num_clks;
+};
+
extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f,
unsigned long rate);
extern int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map,
@@ -56,6 +67,10 @@
struct regmap *regmap);
extern int qcom_cc_probe(struct platform_device *pdev,
const struct qcom_cc_desc *desc);
+
+extern int qcom_cc_register_rcg_dfs(struct platform_device *pdev,
+ const struct qcom_cc_dfs_desc *desc);
+
extern struct clk_ops clk_dummy_ops;
#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 228f716..2742ab3 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -245,28 +245,6 @@
},
};
-static struct clk_alpha_pll gpll1 = {
- .offset = 0x1000,
- .vco_table = fabia_vco,
- .num_vco = ARRAY_SIZE(fabia_vco),
- .type = FABIA_PLL,
- .clkr = {
- .enable_reg = 0x52000,
- .enable_mask = BIT(1),
- .hw.init = &(struct clk_init_data){
- .name = "gpll1",
- .parent_names = (const char *[]){ "bi_tcxo" },
- .num_parents = 1,
- .ops = &clk_fabia_fixed_pll_ops,
- VDD_CX_FMAX_MAP4(
- MIN, 615000000,
- LOW, 1066000000,
- LOW_L1, 1600000000,
- NOMINAL, 2000000000),
- },
- },
-};
-
static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = {
F(19200000, P_BI_TCXO, 1, 0, 0),
{ }
@@ -314,6 +292,7 @@
};
static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0),
F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
@@ -448,6 +427,7 @@
};
static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = {
+ F(9600000, P_BI_TCXO, 2, 0, 0),
F(19200000, P_BI_TCXO, 1, 0, 0),
F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0),
{ }
@@ -808,6 +788,7 @@
static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
F(400000, P_BI_TCXO, 12, 1, 4),
+ F(9600000, P_BI_TCXO, 2, 0, 0),
F(19200000, P_BI_TCXO, 1, 0, 0),
F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2),
F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0),
@@ -839,6 +820,7 @@
static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = {
F(400000, P_BI_TCXO, 12, 1, 4),
+ F(9600000, P_BI_TCXO, 2, 0, 0),
F(19200000, P_BI_TCXO, 1, 0, 0),
F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2),
F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0),
@@ -889,12 +871,20 @@
},
};
+static const struct freq_tbl ftbl_gcc_ufs_card_axi_clk_src[] = {
+ F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0),
+ F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
static struct clk_rcg2 gcc_ufs_card_axi_clk_src = {
.cmd_rcgr = 0x7501c,
.mnd_width = 8,
.hid_width = 5,
.parent_map = gcc_parent_map_0,
- .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .freq_tbl = ftbl_gcc_ufs_card_axi_clk_src,
.flags = FORCE_ENABLE_RCG,
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_card_axi_clk_src",
@@ -1102,6 +1092,7 @@
};
static const struct freq_tbl ftbl_gcc_usb30_prim_mock_utmi_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
F(20000000, P_GPLL0_OUT_EVEN, 15, 0, 0),
F(40000000, P_GPLL0_OUT_EVEN, 7.5, 0, 0),
F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0),
@@ -3476,7 +3467,6 @@
[GCC_VIDEO_XO_CLK] = &gcc_video_xo_clk.clkr,
[GPLL0] = &gpll0.clkr,
[GPLL0_OUT_EVEN] = &gpll0_out_even.clkr,
- [GPLL1] = &gpll1.clkr,
};
static const struct qcom_reset_map gcc_sdm845_resets[] = {
@@ -3509,6 +3499,31 @@
[GCC_PCIE_1_PHY_BCR] = { 0x8e01c },
};
+/* List of RCG clocks and corresponding flags requested for DFS Mode */
+static struct clk_dfs gcc_dfs_clocks[] = {
+ { &gcc_qupv3_wrap0_s0_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s1_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s2_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s3_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s4_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s5_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s6_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s7_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s0_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s1_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s2_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s3_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s4_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s5_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s6_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s7_clk_src, DFS_ENABLE_RCG },
+};
+
+static const struct qcom_cc_dfs_desc gcc_sdm845_dfs_desc = {
+ .clks = gcc_dfs_clocks,
+ .num_clks = ARRAY_SIZE(gcc_dfs_clocks),
+};
+
static const struct regmap_config gcc_sdm845_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -3599,10 +3614,10 @@
clk_prepare_enable(gcc_camera_ahb_clk.clkr.hw.clk);
clk_prepare_enable(gcc_video_ahb_clk.clkr.hw.clk);
- /*
- * TODO:
- * 1. QUPv3 support
- */
+ /* DFS clock registration */
+ ret = qcom_cc_register_rcg_dfs(pdev, &gcc_sdm845_dfs_desc);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to register with DFS!\n");
dev_info(&pdev->dev, "Registered GCC clocks\n");
return ret;
diff --git a/drivers/crypto/ccp/ccp-dev-v3.c b/drivers/crypto/ccp/ccp-dev-v3.c
index 8d2dbac..e68966b 100644
--- a/drivers/crypto/ccp/ccp-dev-v3.c
+++ b/drivers/crypto/ccp/ccp-dev-v3.c
@@ -315,17 +315,73 @@
return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
}
+static void ccp_disable_queue_interrupts(struct ccp_device *ccp)
+{
+ iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG);
+}
+
+static void ccp_enable_queue_interrupts(struct ccp_device *ccp)
+{
+ iowrite32(ccp->qim, ccp->io_regs + IRQ_MASK_REG);
+}
+
+static void ccp_irq_bh(unsigned long data)
+{
+ struct ccp_device *ccp = (struct ccp_device *)data;
+ struct ccp_cmd_queue *cmd_q;
+ u32 q_int, status;
+ unsigned int i;
+
+ status = ioread32(ccp->io_regs + IRQ_STATUS_REG);
+
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ cmd_q = &ccp->cmd_q[i];
+
+ q_int = status & (cmd_q->int_ok | cmd_q->int_err);
+ if (q_int) {
+ cmd_q->int_status = status;
+ cmd_q->q_status = ioread32(cmd_q->reg_status);
+ cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
+
+ /* On error, only save the first error value */
+ if ((q_int & cmd_q->int_err) && !cmd_q->cmd_error)
+ cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
+
+ cmd_q->int_rcvd = 1;
+
+ /* Acknowledge the interrupt and wake the kthread */
+ iowrite32(q_int, ccp->io_regs + IRQ_STATUS_REG);
+ wake_up_interruptible(&cmd_q->int_queue);
+ }
+ }
+ ccp_enable_queue_interrupts(ccp);
+}
+
+static irqreturn_t ccp_irq_handler(int irq, void *data)
+{
+ struct device *dev = data;
+ struct ccp_device *ccp = dev_get_drvdata(dev);
+
+ ccp_disable_queue_interrupts(ccp);
+ if (ccp->use_tasklet)
+ tasklet_schedule(&ccp->irq_tasklet);
+ else
+ ccp_irq_bh((unsigned long)ccp);
+
+ return IRQ_HANDLED;
+}
+
static int ccp_init(struct ccp_device *ccp)
{
struct device *dev = ccp->dev;
struct ccp_cmd_queue *cmd_q;
struct dma_pool *dma_pool;
char dma_pool_name[MAX_DMAPOOL_NAME_LEN];
- unsigned int qmr, qim, i;
+ unsigned int qmr, i;
int ret;
/* Find available queues */
- qim = 0;
+ ccp->qim = 0;
qmr = ioread32(ccp->io_regs + Q_MASK_REG);
for (i = 0; i < MAX_HW_QUEUES; i++) {
if (!(qmr & (1 << i)))
@@ -370,7 +426,7 @@
init_waitqueue_head(&cmd_q->int_queue);
/* Build queue interrupt mask (two interrupts per queue) */
- qim |= cmd_q->int_ok | cmd_q->int_err;
+ ccp->qim |= cmd_q->int_ok | cmd_q->int_err;
#ifdef CONFIG_ARM64
/* For arm64 set the recommended queue cache settings */
@@ -388,14 +444,14 @@
dev_notice(dev, "%u command queues available\n", ccp->cmd_q_count);
/* Disable and clear interrupts until ready */
- iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG);
+ ccp_disable_queue_interrupts(ccp);
for (i = 0; i < ccp->cmd_q_count; i++) {
cmd_q = &ccp->cmd_q[i];
ioread32(cmd_q->reg_int_status);
ioread32(cmd_q->reg_status);
}
- iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG);
+ iowrite32(ccp->qim, ccp->io_regs + IRQ_STATUS_REG);
/* Request an irq */
ret = ccp->get_irq(ccp);
@@ -408,6 +464,11 @@
init_waitqueue_head(&ccp->sb_queue);
init_waitqueue_head(&ccp->suspend_queue);
+ /* Initialize the ISR tasklet? */
+ if (ccp->use_tasklet)
+ tasklet_init(&ccp->irq_tasklet, ccp_irq_bh,
+ (unsigned long)ccp);
+
dev_dbg(dev, "Starting threads...\n");
/* Create a kthread for each queue */
for (i = 0; i < ccp->cmd_q_count; i++) {
@@ -430,7 +491,7 @@
dev_dbg(dev, "Enabling interrupts...\n");
/* Enable interrupts */
- iowrite32(qim, ccp->io_regs + IRQ_MASK_REG);
+ ccp_enable_queue_interrupts(ccp);
dev_dbg(dev, "Registering device...\n");
ccp_add_device(ccp);
@@ -467,7 +528,7 @@
{
struct ccp_cmd_queue *cmd_q;
struct ccp_cmd *cmd;
- unsigned int qim, i;
+ unsigned int i;
/* Unregister the DMA engine */
ccp_dmaengine_unregister(ccp);
@@ -478,22 +539,15 @@
/* Remove this device from the list of available units */
ccp_del_device(ccp);
- /* Build queue interrupt mask (two interrupt masks per queue) */
- qim = 0;
- for (i = 0; i < ccp->cmd_q_count; i++) {
- cmd_q = &ccp->cmd_q[i];
- qim |= cmd_q->int_ok | cmd_q->int_err;
- }
-
/* Disable and clear interrupts */
- iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG);
+ ccp_disable_queue_interrupts(ccp);
for (i = 0; i < ccp->cmd_q_count; i++) {
cmd_q = &ccp->cmd_q[i];
ioread32(cmd_q->reg_int_status);
ioread32(cmd_q->reg_status);
}
- iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG);
+ iowrite32(ccp->qim, ccp->io_regs + IRQ_STATUS_REG);
/* Stop the queue kthreads */
for (i = 0; i < ccp->cmd_q_count; i++)
@@ -520,40 +574,6 @@
}
}
-static irqreturn_t ccp_irq_handler(int irq, void *data)
-{
- struct device *dev = data;
- struct ccp_device *ccp = dev_get_drvdata(dev);
- struct ccp_cmd_queue *cmd_q;
- u32 q_int, status;
- unsigned int i;
-
- status = ioread32(ccp->io_regs + IRQ_STATUS_REG);
-
- for (i = 0; i < ccp->cmd_q_count; i++) {
- cmd_q = &ccp->cmd_q[i];
-
- q_int = status & (cmd_q->int_ok | cmd_q->int_err);
- if (q_int) {
- cmd_q->int_status = status;
- cmd_q->q_status = ioread32(cmd_q->reg_status);
- cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
-
- /* On error, only save the first error value */
- if ((q_int & cmd_q->int_err) && !cmd_q->cmd_error)
- cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
-
- cmd_q->int_rcvd = 1;
-
- /* Acknowledge the interrupt and wake the kthread */
- iowrite32(q_int, ccp->io_regs + IRQ_STATUS_REG);
- wake_up_interruptible(&cmd_q->int_queue);
- }
- }
-
- return IRQ_HANDLED;
-}
-
static const struct ccp_actions ccp3_actions = {
.aes = ccp_perform_aes,
.xts_aes = ccp_perform_xts_aes,
diff --git a/drivers/crypto/ccp/ccp-dev-v5.c b/drivers/crypto/ccp/ccp-dev-v5.c
index a388bf2..2c0ce5f 100644
--- a/drivers/crypto/ccp/ccp-dev-v5.c
+++ b/drivers/crypto/ccp/ccp-dev-v5.c
@@ -644,6 +644,65 @@
return rc;
}
+static void ccp5_disable_queue_interrupts(struct ccp_device *ccp)
+{
+ unsigned int i;
+
+ for (i = 0; i < ccp->cmd_q_count; i++)
+ iowrite32(0x0, ccp->cmd_q[i].reg_int_enable);
+}
+
+static void ccp5_enable_queue_interrupts(struct ccp_device *ccp)
+{
+ unsigned int i;
+
+ for (i = 0; i < ccp->cmd_q_count; i++)
+ iowrite32(SUPPORTED_INTERRUPTS, ccp->cmd_q[i].reg_int_enable);
+}
+
+static void ccp5_irq_bh(unsigned long data)
+{
+ struct ccp_device *ccp = (struct ccp_device *)data;
+ u32 status;
+ unsigned int i;
+
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i];
+
+ status = ioread32(cmd_q->reg_interrupt_status);
+
+ if (status) {
+ cmd_q->int_status = status;
+ cmd_q->q_status = ioread32(cmd_q->reg_status);
+ cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
+
+ /* On error, only save the first error value */
+ if ((status & INT_ERROR) && !cmd_q->cmd_error)
+ cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
+
+ cmd_q->int_rcvd = 1;
+
+ /* Acknowledge the interrupt and wake the kthread */
+ iowrite32(status, cmd_q->reg_interrupt_status);
+ wake_up_interruptible(&cmd_q->int_queue);
+ }
+ }
+ ccp5_enable_queue_interrupts(ccp);
+}
+
+static irqreturn_t ccp5_irq_handler(int irq, void *data)
+{
+ struct device *dev = data;
+ struct ccp_device *ccp = dev_get_drvdata(dev);
+
+ ccp5_disable_queue_interrupts(ccp);
+ if (ccp->use_tasklet)
+ tasklet_schedule(&ccp->irq_tasklet);
+ else
+ ccp5_irq_bh((unsigned long)ccp);
+ return IRQ_HANDLED;
+}
+
static int ccp5_init(struct ccp_device *ccp)
{
struct device *dev = ccp->dev;
@@ -728,19 +787,18 @@
dev_notice(dev, "%u command queues available\n", ccp->cmd_q_count);
/* Turn off the queues and disable interrupts until ready */
+ ccp5_disable_queue_interrupts(ccp);
for (i = 0; i < ccp->cmd_q_count; i++) {
cmd_q = &ccp->cmd_q[i];
cmd_q->qcontrol = 0; /* Start with nothing */
iowrite32(cmd_q->qcontrol, cmd_q->reg_control);
- /* Disable the interrupts */
- iowrite32(0x00, cmd_q->reg_int_enable);
ioread32(cmd_q->reg_int_status);
ioread32(cmd_q->reg_status);
- /* Clear the interrupts */
- iowrite32(ALL_INTERRUPTS, cmd_q->reg_interrupt_status);
+ /* Clear the interrupt status */
+ iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_interrupt_status);
}
dev_dbg(dev, "Requesting an IRQ...\n");
@@ -750,6 +808,10 @@
dev_err(dev, "unable to allocate an IRQ\n");
goto e_pool;
}
+ /* Initialize the ISR tasklet */
+ if (ccp->use_tasklet)
+ tasklet_init(&ccp->irq_tasklet, ccp5_irq_bh,
+ (unsigned long)ccp);
/* Initialize the queue used to suspend */
init_waitqueue_head(&ccp->suspend_queue);
@@ -821,11 +883,7 @@
}
dev_dbg(dev, "Enabling interrupts...\n");
- /* Enable interrupts */
- for (i = 0; i < ccp->cmd_q_count; i++) {
- cmd_q = &ccp->cmd_q[i];
- iowrite32(ALL_INTERRUPTS, cmd_q->reg_int_enable);
- }
+ ccp5_enable_queue_interrupts(ccp);
dev_dbg(dev, "Registering device...\n");
/* Put this on the unit list to make it available */
@@ -877,17 +935,15 @@
ccp_del_device(ccp);
/* Disable and clear interrupts */
+ ccp5_disable_queue_interrupts(ccp);
for (i = 0; i < ccp->cmd_q_count; i++) {
cmd_q = &ccp->cmd_q[i];
/* Turn off the run bit */
iowrite32(cmd_q->qcontrol & ~CMD5_Q_RUN, cmd_q->reg_control);
- /* Disable the interrupts */
- iowrite32(ALL_INTERRUPTS, cmd_q->reg_interrupt_status);
-
/* Clear the interrupt status */
- iowrite32(0x00, cmd_q->reg_int_enable);
+ iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_interrupt_status);
ioread32(cmd_q->reg_int_status);
ioread32(cmd_q->reg_status);
}
@@ -920,38 +976,6 @@
}
}
-static irqreturn_t ccp5_irq_handler(int irq, void *data)
-{
- struct device *dev = data;
- struct ccp_device *ccp = dev_get_drvdata(dev);
- u32 status;
- unsigned int i;
-
- for (i = 0; i < ccp->cmd_q_count; i++) {
- struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i];
-
- status = ioread32(cmd_q->reg_interrupt_status);
-
- if (status) {
- cmd_q->int_status = status;
- cmd_q->q_status = ioread32(cmd_q->reg_status);
- cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
-
- /* On error, only save the first error value */
- if ((status & INT_ERROR) && !cmd_q->cmd_error)
- cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
-
- cmd_q->int_rcvd = 1;
-
- /* Acknowledge the interrupt and wake the kthread */
- iowrite32(ALL_INTERRUPTS, cmd_q->reg_interrupt_status);
- wake_up_interruptible(&cmd_q->int_queue);
- }
- }
-
- return IRQ_HANDLED;
-}
-
static void ccp5_config(struct ccp_device *ccp)
{
/* Public side */
diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h
index 340aef1..8ac7ae1 100644
--- a/drivers/crypto/ccp/ccp-dev.h
+++ b/drivers/crypto/ccp/ccp-dev.h
@@ -109,9 +109,8 @@
#define INT_COMPLETION 0x1
#define INT_ERROR 0x2
#define INT_QUEUE_STOPPED 0x4
-#define ALL_INTERRUPTS (INT_COMPLETION| \
- INT_ERROR| \
- INT_QUEUE_STOPPED)
+#define INT_EMPTY_QUEUE 0x8
+#define SUPPORTED_INTERRUPTS (INT_COMPLETION | INT_ERROR)
#define LSB_REGION_WIDTH 5
#define MAX_LSB_CNT 8
@@ -333,7 +332,10 @@
void *dev_specific;
int (*get_irq)(struct ccp_device *ccp);
void (*free_irq)(struct ccp_device *ccp);
+ unsigned int qim;
unsigned int irq;
+ bool use_tasklet;
+ struct tasklet_struct irq_tasklet;
/* I/O area used for device communication. The register mapping
* starts at an offset into the mapped bar.
diff --git a/drivers/crypto/ccp/ccp-pci.c b/drivers/crypto/ccp/ccp-pci.c
index 28a9996..e880d4cf4 100644
--- a/drivers/crypto/ccp/ccp-pci.c
+++ b/drivers/crypto/ccp/ccp-pci.c
@@ -69,6 +69,7 @@
goto e_irq;
}
}
+ ccp->use_tasklet = true;
return 0;
@@ -100,6 +101,7 @@
dev_notice(dev, "unable to allocate MSI IRQ (%d)\n", ret);
goto e_msi;
}
+ ccp->use_tasklet = true;
return 0;
diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c
index 1932248..586f954 100644
--- a/drivers/dax/dax.c
+++ b/drivers/dax/dax.c
@@ -553,13 +553,10 @@
kfree(dax_dev);
}
-static void unregister_dax_dev(void *dev)
+static void kill_dax_dev(struct dax_dev *dax_dev)
{
- struct dax_dev *dax_dev = to_dax_dev(dev);
struct cdev *cdev = &dax_dev->cdev;
- dev_dbg(dev, "%s\n", __func__);
-
/*
* Note, rcu is not protecting the liveness of dax_dev, rcu is
* ensuring that any fault handlers that might have seen
@@ -571,6 +568,15 @@
synchronize_srcu(&dax_srcu);
unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1);
cdev_del(cdev);
+}
+
+static void unregister_dax_dev(void *dev)
+{
+ struct dax_dev *dax_dev = to_dax_dev(dev);
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ kill_dax_dev(dax_dev);
device_unregister(dev);
}
@@ -647,6 +653,7 @@
dev_set_name(dev, "dax%d.%d", dax_region->id, dax_dev->id);
rc = device_add(dev);
if (rc) {
+ kill_dax_dev(dax_dev);
put_device(dev);
return ERR_PTR(rc);
}
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
new file mode 100644
index 0000000..30f477e
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -0,0 +1,578 @@
+/*
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
+
+#include <linux/delay.h>
+
+#include "dp_aux.h"
+
+#define DP_AUX_ENUM_STR(x) #x
+
+struct aux_buf {
+ u8 *start; /* buffer start addr */
+ u8 *end; /* buffer end addr */
+ u8 *data; /* data pou32er */
+ u32 size; /* size of buffer */
+ u32 len; /* dara length */
+ u8 trans_num; /* transaction number */
+ enum aux_tx_mode tx_mode;
+};
+
+struct dp_aux_private {
+ struct device *dev;
+ struct dp_aux dp_aux;
+ struct dp_catalog_aux *catalog;
+
+ struct mutex mutex;
+ struct completion comp;
+
+ struct aux_cmd *cmds;
+ struct aux_buf txp;
+ struct aux_buf rxp;
+
+ u32 aux_error_num;
+
+ u8 txbuf[256];
+ u8 rxbuf[256];
+};
+
+static char *dp_aux_get_error(u32 aux_error)
+{
+ switch (aux_error) {
+ case DP_AUX_ERR_NONE:
+ return DP_AUX_ENUM_STR(DP_AUX_ERR_NONE);
+ case DP_AUX_ERR_ADDR:
+ return DP_AUX_ENUM_STR(DP_AUX_ERR_ADDR);
+ case DP_AUX_ERR_TOUT:
+ return DP_AUX_ENUM_STR(DP_AUX_ERR_TOUT);
+ case DP_AUX_ERR_NACK:
+ return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK);
+ case DP_AUX_ERR_DEFER:
+ return DP_AUX_ENUM_STR(DP_AUX_ERR_DEFER);
+ case DP_AUX_ERR_NACK_DEFER:
+ return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK_DEFER);
+ default:
+ return "unknown";
+ }
+}
+
+static void dp_aux_buf_init(struct aux_buf *buf, u8 *data, u32 size)
+{
+ buf->start = data;
+ buf->size = size;
+ buf->data = buf->start;
+ buf->end = buf->start + buf->size;
+ buf->len = 0;
+ buf->trans_num = 0;
+ buf->tx_mode = AUX_NATIVE;
+}
+
+static void dp_aux_buf_set(struct dp_aux_private *aux)
+{
+ init_completion(&aux->comp);
+ mutex_init(&aux->mutex);
+
+ dp_aux_buf_init(&aux->txp, aux->txbuf, sizeof(aux->txbuf));
+ dp_aux_buf_init(&aux->rxp, aux->rxbuf, sizeof(aux->rxbuf));
+}
+
+static void dp_aux_buf_reset(struct aux_buf *buf)
+{
+ buf->data = buf->start;
+ buf->len = 0;
+ buf->trans_num = 0;
+ buf->tx_mode = AUX_NATIVE;
+
+ memset(buf->start, 0x0, 256);
+}
+
+static void dp_aux_buf_push(struct aux_buf *buf, u32 len)
+{
+ buf->data += len;
+ buf->len += len;
+}
+
+static u32 dp_aux_buf_trailing(struct aux_buf *buf)
+{
+ return (u32)(buf->end - buf->data);
+}
+
+static u32 dp_aux_add_cmd(struct aux_buf *buf, struct aux_cmd *cmd)
+{
+ u8 data;
+ u8 *bp, *cp;
+ u32 i, len;
+
+ if (cmd->ex_mode == AUX_READ)
+ len = 4;
+ else
+ len = cmd->len + 4;
+
+ if (dp_aux_buf_trailing(buf) < len) {
+ pr_err("buf trailing error\n");
+ return 0;
+ }
+
+ /*
+ * cmd fifo only has depth of 144 bytes
+ * limit buf length to 128 bytes here
+ */
+ if ((buf->len + len) > 128) {
+ pr_err("buf len error\n");
+ return 0;
+ }
+
+ bp = buf->data;
+ data = cmd->addr >> 16;
+ data &= 0x0f; /* 4 addr bits */
+
+ if (cmd->ex_mode == AUX_READ)
+ data |= BIT(4);
+
+ *bp++ = data;
+ *bp++ = cmd->addr >> 8;
+ *bp++ = cmd->addr;
+ *bp++ = cmd->len - 1;
+
+ if (cmd->ex_mode == AUX_WRITE) {
+ cp = cmd->buf;
+
+ for (i = 0; i < cmd->len; i++)
+ *bp++ = *cp++;
+ }
+
+ dp_aux_buf_push(buf, len);
+
+ buf->tx_mode = cmd->tx_mode;
+
+ buf->trans_num++;
+
+ return cmd->len - 1;
+}
+
+static u32 dp_aux_cmd_fifo_tx(struct dp_aux_private *aux)
+{
+ u8 *dp;
+ u32 data, len, cnt;
+ struct aux_buf *tp = &aux->txp;
+
+ len = tp->len;
+ if (len == 0) {
+ pr_err("invalid len\n");
+ return 0;
+ }
+
+ cnt = 0;
+ dp = tp->start;
+
+ while (cnt < len) {
+ data = *dp;
+ data <<= 8;
+ data &= 0x00ff00;
+ if (cnt == 0)
+ data |= BIT(31);
+
+ aux->catalog->data = data;
+ aux->catalog->write_data(aux->catalog);
+
+ cnt++;
+ dp++;
+ }
+
+ data = (tp->trans_num - 1);
+ if (tp->tx_mode == AUX_I2C) {
+ data |= BIT(8); /* I2C */
+ data |= BIT(10); /* NO SEND ADDR */
+ data |= BIT(11); /* NO SEND STOP */
+ }
+
+ data |= BIT(9); /* GO */
+ aux->catalog->data = data;
+ aux->catalog->write_trans(aux->catalog);
+
+ return tp->len;
+}
+
+static u32 dp_cmd_fifo_rx(struct dp_aux_private *aux, u32 len)
+{
+ u32 data;
+ u8 *dp;
+ u32 i;
+ struct aux_buf *rp = &aux->rxp;
+
+ data = 0;
+ data |= BIT(31); /* INDEX_WRITE */
+ data |= BIT(0); /* read */
+
+ aux->catalog->data = data;
+ aux->catalog->write_data(aux->catalog);
+
+ dp = rp->data;
+
+ /* discard first byte */
+ data = aux->catalog->read_data(aux->catalog);
+
+ for (i = 0; i < len; i++) {
+ data = aux->catalog->read_data(aux->catalog);
+ *dp++ = (u8)((data >> 8) & 0xff);
+ }
+
+ rp->len = len;
+ return len;
+}
+
+static void dp_aux_native_handler(struct dp_aux_private *aux)
+{
+ u32 isr = aux->catalog->isr1;
+
+ if (isr & DP_INTR_AUX_I2C_DONE)
+ aux->aux_error_num = DP_AUX_ERR_NONE;
+ else if (isr & DP_INTR_WRONG_ADDR)
+ aux->aux_error_num = DP_AUX_ERR_ADDR;
+ else if (isr & DP_INTR_TIMEOUT)
+ aux->aux_error_num = DP_AUX_ERR_TOUT;
+ if (isr & DP_INTR_NACK_DEFER)
+ aux->aux_error_num = DP_AUX_ERR_NACK;
+
+ complete(&aux->comp);
+}
+
+static void dp_aux_i2c_handler(struct dp_aux_private *aux)
+{
+ u32 isr = aux->catalog->isr1;
+
+ if (isr & DP_INTR_AUX_I2C_DONE) {
+ if (isr & (DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER))
+ aux->aux_error_num = DP_AUX_ERR_NACK;
+ else
+ aux->aux_error_num = DP_AUX_ERR_NONE;
+ } else {
+ if (isr & DP_INTR_WRONG_ADDR)
+ aux->aux_error_num = DP_AUX_ERR_ADDR;
+ else if (isr & DP_INTR_TIMEOUT)
+ aux->aux_error_num = DP_AUX_ERR_TOUT;
+ if (isr & DP_INTR_NACK_DEFER)
+ aux->aux_error_num = DP_AUX_ERR_NACK_DEFER;
+ if (isr & DP_INTR_I2C_NACK)
+ aux->aux_error_num = DP_AUX_ERR_NACK;
+ if (isr & DP_INTR_I2C_DEFER)
+ aux->aux_error_num = DP_AUX_ERR_DEFER;
+ }
+
+ complete(&aux->comp);
+}
+
+static void dp_aux_isr(struct dp_aux *dp_aux)
+{
+ struct dp_aux_private *aux;
+
+ if (!dp_aux) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+ aux->catalog->get_irq(aux->catalog);
+
+ if (aux->cmds->tx_mode == AUX_NATIVE)
+ dp_aux_native_handler(aux);
+ else
+ dp_aux_i2c_handler(aux);
+}
+
+
+
+static int dp_aux_write(struct dp_aux_private *aux)
+{
+ struct aux_cmd *cm;
+ struct aux_buf *tp;
+ u32 len, ret, timeout;
+
+ mutex_lock(&aux->mutex);
+
+ tp = &aux->txp;
+ dp_aux_buf_reset(tp);
+
+ cm = aux->cmds;
+ while (cm) {
+ ret = dp_aux_add_cmd(tp, cm);
+ if (ret <= 0)
+ break;
+
+ if (!cm->next)
+ break;
+ cm++;
+ }
+
+ reinit_completion(&aux->comp);
+
+ len = dp_aux_cmd_fifo_tx(aux);
+
+ timeout = wait_for_completion_timeout(&aux->comp, HZ/4);
+ if (!timeout)
+ pr_err("aux write timeout\n");
+
+ pr_debug("aux status %s\n",
+ dp_aux_get_error(aux->aux_error_num));
+
+ if (aux->aux_error_num == DP_AUX_ERR_NONE)
+ ret = len;
+ else
+ ret = aux->aux_error_num;
+
+ mutex_unlock(&aux->mutex);
+ return ret;
+}
+
+static int dp_aux_read(struct dp_aux_private *aux)
+{
+ struct aux_cmd *cm;
+ struct aux_buf *tp, *rp;
+ u32 len, ret, timeout;
+
+ mutex_lock(&aux->mutex);
+
+ tp = &aux->txp;
+ rp = &aux->rxp;
+
+ dp_aux_buf_reset(tp);
+ dp_aux_buf_reset(rp);
+
+ cm = aux->cmds;
+ len = 0;
+
+ while (cm) {
+ ret = dp_aux_add_cmd(tp, cm);
+ len += cm->len;
+
+ if (ret <= 0)
+ break;
+
+ if (!cm->next)
+ break;
+ cm++;
+ }
+
+ reinit_completion(&aux->comp);
+
+ dp_aux_cmd_fifo_tx(aux);
+
+ timeout = wait_for_completion_timeout(&aux->comp, HZ/4);
+ if (!timeout)
+ pr_err("aux read timeout\n");
+
+ pr_debug("aux status %s\n",
+ dp_aux_get_error(aux->aux_error_num));
+
+ if (aux->aux_error_num == DP_AUX_ERR_NONE)
+ ret = dp_cmd_fifo_rx(aux, len);
+ else
+ ret = aux->aux_error_num;
+
+ aux->cmds->buf = rp->data;
+
+ mutex_unlock(&aux->mutex);
+
+ return ret;
+}
+
+static int dp_aux_write_ex(struct dp_aux *dp_aux, u32 addr, u32 len,
+ enum aux_tx_mode mode, u8 *buf)
+{
+ struct aux_cmd cmd = {0};
+ struct dp_aux_private *aux;
+
+ if (!dp_aux || !len) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+ cmd.ex_mode = AUX_WRITE;
+ cmd.tx_mode = mode;
+ cmd.addr = addr;
+ cmd.len = len;
+ cmd.buf = buf;
+
+ aux->cmds = &cmd;
+
+ return dp_aux_write(aux);
+}
+
+static int dp_aux_read_ex(struct dp_aux *dp_aux, u32 addr, u32 len,
+ enum aux_tx_mode mode, u8 **buf)
+{
+ int rc = 0;
+ struct aux_cmd cmd = {0};
+ struct dp_aux_private *aux;
+
+ if (!dp_aux || !len) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+ cmd.ex_mode = AUX_READ;
+ cmd.tx_mode = mode;
+ cmd.addr = addr;
+ cmd.len = len;
+
+ aux->cmds = &cmd;
+
+ rc = dp_aux_read(aux);
+ if (rc <= 0) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ *buf = cmd.buf;
+end:
+ return rc;
+}
+
+static int dp_aux_process(struct dp_aux *dp_aux, struct aux_cmd *cmds)
+{
+ struct dp_aux_private *aux;
+
+ if (!dp_aux || !cmds) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+ aux->cmds = cmds;
+
+ if (cmds->ex_mode == AUX_READ)
+ return dp_aux_read(aux);
+ else
+ return dp_aux_write(aux);
+}
+
+static bool dp_aux_ready(struct dp_aux *dp_aux)
+{
+ u8 data = 0;
+ int count, ret;
+ struct dp_aux_private *aux;
+
+ if (!dp_aux) {
+ pr_err("invalid input\n");
+ goto error;
+ }
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+ for (count = 5; count; count--) {
+ ret = dp_aux_write_ex(dp_aux, 0x50, 1, AUX_I2C, &data);
+ if (ret >= 0)
+ break;
+
+ msleep(100);
+ }
+
+ if (count <= 0) {
+ pr_err("aux chan NOT ready\n");
+ goto error;
+ }
+
+ return true;
+error:
+ return false;
+}
+
+static void dp_aux_init(struct dp_aux *dp_aux, u32 *aux_cfg)
+{
+ struct dp_aux_private *aux;
+
+ if (!dp_aux) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+ aux->catalog->reset(aux->catalog);
+ aux->catalog->enable(aux->catalog, true);
+ aux->catalog->setup(aux->catalog, aux_cfg);
+}
+
+static void dp_aux_deinit(struct dp_aux *dp_aux)
+{
+ struct dp_aux_private *aux;
+
+ if (!dp_aux) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+ aux->catalog->enable(aux->catalog, false);
+}
+
+struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog)
+{
+ int rc = 0;
+ struct dp_aux_private *aux;
+ struct dp_aux *dp_aux;
+
+ if (!catalog) {
+ pr_err("invalid input\n");
+ rc = -ENODEV;
+ goto error;
+ }
+
+ aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL);
+ if (!aux) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ aux->dev = dev;
+
+ dp_aux_buf_set(aux);
+
+ aux->catalog = catalog;
+
+ dp_aux = &aux->dp_aux;
+
+ dp_aux->process = dp_aux_process;
+ dp_aux->read = dp_aux_read_ex;
+ dp_aux->write = dp_aux_write_ex;
+ dp_aux->ready = dp_aux_ready;
+ dp_aux->isr = dp_aux_isr;
+ dp_aux->init = dp_aux_init;
+ dp_aux->deinit = dp_aux_deinit;
+
+ return dp_aux;
+error:
+ return ERR_PTR(rc);
+}
+
+void dp_aux_put(struct dp_aux *dp_aux)
+{
+ struct dp_aux_private *aux;
+
+ if (!dp_aux)
+ return;
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+ devm_kfree(aux->dev, aux);
+}
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h
new file mode 100644
index 0000000..0603c15
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_aux.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 _DP_AUX_H_
+#define _DP_AUX_H_
+
+#include "dp_catalog.h"
+
+enum dp_aux_error {
+ DP_AUX_ERR_NONE = 0,
+ DP_AUX_ERR_ADDR = -1,
+ DP_AUX_ERR_TOUT = -2,
+ DP_AUX_ERR_NACK = -3,
+ DP_AUX_ERR_DEFER = -4,
+ DP_AUX_ERR_NACK_DEFER = -5,
+};
+
+enum aux_tx_mode {
+ AUX_NATIVE,
+ AUX_I2C,
+};
+
+enum aux_exe_mode {
+ AUX_WRITE,
+ AUX_READ,
+};
+
+struct aux_cmd {
+ enum aux_exe_mode ex_mode;
+ enum aux_tx_mode tx_mode;
+ u32 addr;
+ u32 len;
+ u8 *buf;
+ bool next;
+};
+
+struct dp_aux {
+ int (*process)(struct dp_aux *aux, struct aux_cmd *cmd);
+ int (*write)(struct dp_aux *aux, u32 addr, u32 len,
+ enum aux_tx_mode mode, u8 *buf);
+ int (*read)(struct dp_aux *aux, u32 addr, u32 len,
+ enum aux_tx_mode mode, u8 **buf);
+ bool (*ready)(struct dp_aux *aux);
+ void (*isr)(struct dp_aux *aux);
+ void (*init)(struct dp_aux *aux, u32 *aux_cfg);
+ void (*deinit)(struct dp_aux *aux);
+};
+
+struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog);
+void dp_aux_put(struct dp_aux *aux);
+
+#endif /*__DP_AUX_H_*/
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c
new file mode 100644
index 0000000..722c436
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
+
+#include <linux/of_gpio.h>
+
+#include "dp_parser.h"
+
+static void dp_parser_unmap_io_resources(struct dp_parser *parser)
+{
+ struct dp_io *io = &parser->io;
+
+ if (&io->ctrl_io)
+ msm_dss_iounmap(&io->ctrl_io);
+ if (&io->phy_io)
+ msm_dss_iounmap(&io->phy_io);
+ if (&io->ln_tx0_io)
+ msm_dss_iounmap(&io->ln_tx0_io);
+ if (&io->ln_tx1_io)
+ msm_dss_iounmap(&io->ln_tx0_io);
+ if (&io->dp_pll_io)
+ msm_dss_iounmap(&io->dp_pll_io);
+ if (&io->dp_cc_io)
+ msm_dss_iounmap(&io->dp_cc_io);
+ if (&io->qfprom_io)
+ msm_dss_iounmap(&io->qfprom_io);
+ if (&io->hdcp_io)
+ msm_dss_iounmap(&io->hdcp_io);
+}
+
+static int dp_parser_ctrl_res(struct dp_parser *parser)
+{
+ int rc = 0;
+ u32 index;
+ struct platform_device *pdev = parser->pdev;
+ struct device_node *of_node = parser->pdev->dev.of_node;
+ struct dp_io *io = &parser->io;
+
+ rc = of_property_read_u32(of_node, "cell-index", &index);
+ if (rc) {
+ pr_err("cell-index not specified, rc=%d\n", rc);
+ goto err;
+ }
+
+ rc = msm_dss_ioremap_byname(pdev, &io->ctrl_io, "dp_ctrl");
+ if (rc) {
+ pr_err("unable to remap dp io resources\n");
+ goto err;
+ }
+
+ rc = msm_dss_ioremap_byname(pdev, &io->phy_io, "dp_phy");
+ if (rc) {
+ pr_err("unable to remap dp PHY resources\n");
+ goto err;
+ }
+
+ rc = msm_dss_ioremap_byname(pdev, &io->ln_tx0_io, "dp_ln_tx0");
+ if (rc) {
+ pr_err("unable to remap dp TX0 resources\n");
+ goto err;
+ }
+
+ rc = msm_dss_ioremap_byname(pdev, &io->ln_tx1_io, "dp_ln_tx1");
+ if (rc) {
+ pr_err("unable to remap dp TX1 resources\n");
+ goto err;
+ }
+
+ rc = msm_dss_ioremap_byname(pdev, &io->dp_pll_io, "dp_pll");
+ if (rc) {
+ pr_err("unable to remap DP PLL resources\n");
+ goto err;
+ }
+
+ if (msm_dss_ioremap_byname(pdev, &io->dp_cc_io, "dp_mmss_cc")) {
+ pr_err("unable to remap dp MMSS_CC resources\n");
+ goto err;
+ }
+
+ if (msm_dss_ioremap_byname(pdev, &io->qfprom_io, "qfprom_physical"))
+ pr_warn("unable to remap dp qfprom resources\n");
+
+ if (msm_dss_ioremap_byname(pdev, &io->hdcp_io, "hdcp_physical"))
+ pr_warn("unable to remap dp hdcp resources\n");
+
+ return 0;
+err:
+ dp_parser_unmap_io_resources(parser);
+ return rc;
+}
+
+static int dp_parser_aux(struct dp_parser *parser)
+{
+ int len = 0, i = 0, rc = 0;
+ struct device_node *of_node = parser->pdev->dev.of_node;
+ const char *data;
+
+ data = of_get_property(of_node, "qcom,aux-cfg-settings", &len);
+ if (!data || (len != AUX_CFG_LEN)) {
+ pr_err("Unable to read DP AUX CFG settings\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ for (i = 0; i < len; i++)
+ parser->aux_cfg[i] = data[i];
+end:
+ return rc;
+}
+
+static int dp_parser_misc(struct dp_parser *parser)
+{
+ int rc = 0;
+ struct device_node *of_node = parser->pdev->dev.of_node;
+
+ rc = of_property_read_u32(of_node,
+ "qcom,max-pclk-frequency-khz", &parser->max_pclk_khz);
+ if (rc)
+ parser->max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ;
+
+ return 0;
+}
+
+static int dp_parser_pinctrl(struct dp_parser *parser)
+{
+ int rc = 0;
+ struct dp_pinctrl *pinctrl = &parser->pinctrl;
+
+ pinctrl->pin = devm_pinctrl_get(&parser->pdev->dev);
+
+ if (IS_ERR_OR_NULL(pinctrl->pin)) {
+ rc = PTR_ERR(pinctrl->pin);
+ pr_err("failed to get pinctrl, rc=%d\n", rc);
+ goto error;
+ }
+
+ pinctrl->state_active = pinctrl_lookup_state(pinctrl->pin,
+ "mdss_dp_active");
+ if (IS_ERR_OR_NULL(pinctrl->state_active)) {
+ rc = PTR_ERR(pinctrl->state_active);
+ pr_err("failed to get pinctrl active state, rc=%d\n", rc);
+ goto error;
+ }
+
+ pinctrl->state_suspend = pinctrl_lookup_state(pinctrl->pin,
+ "mdss_dp_sleep");
+ if (IS_ERR_OR_NULL(pinctrl->state_suspend)) {
+ rc = PTR_ERR(pinctrl->state_suspend);
+ pr_err("failed to get pinctrl suspend state, rc=%d\n", rc);
+ goto error;
+ }
+error:
+ return rc;
+}
+
+static int dp_parser_gpio(struct dp_parser *parser)
+{
+ int i = 0;
+ struct device *dev = &parser->pdev->dev;
+ struct device_node *of_node = dev->of_node;
+ struct dss_module_power *mp = &parser->mp[DP_CORE_PM];
+ static const char * const dp_gpios[] = {
+ "qcom,aux-en-gpio",
+ "qcom,aux-sel-gpio",
+ "qcom,usbplug-cc-gpio",
+ };
+
+ mp->gpio_config = devm_kzalloc(dev,
+ sizeof(struct dss_gpio) * ARRAY_SIZE(dp_gpios), GFP_KERNEL);
+ mp->num_gpio = ARRAY_SIZE(dp_gpios);
+
+ for (i = 0; i < ARRAY_SIZE(dp_gpios); i++) {
+ mp->gpio_config[i].gpio = of_get_named_gpio(of_node,
+ dp_gpios[i], 0);
+
+ if (!gpio_is_valid(mp->gpio_config[i].gpio)) {
+ pr_err("%s gpio not specified\n", dp_gpios[i]);
+ return -EINVAL;
+ }
+
+ strlcpy(mp->gpio_config[i].gpio_name, dp_gpios[i],
+ sizeof(mp->gpio_config[i].gpio_name));
+
+ mp->gpio_config[i].value = 0;
+ }
+
+ return 0;
+}
+
+static const char *dp_parser_supply_node_name(enum dp_pm_type module)
+{
+ switch (module) {
+ case DP_CORE_PM: return "qcom,core-supply-entries";
+ case DP_CTRL_PM: return "qcom,ctrl-supply-entries";
+ case DP_PHY_PM: return "qcom,phy-supply-entries";
+ default: return "???";
+ }
+}
+
+static int dp_parser_get_vreg(struct dp_parser *parser,
+ enum dp_pm_type module)
+{
+ int i = 0, rc = 0;
+ u32 tmp = 0;
+ const char *pm_supply_name = NULL;
+ struct device_node *supply_node = NULL;
+ struct device_node *of_node = parser->pdev->dev.of_node;
+ struct device_node *supply_root_node = NULL;
+ struct dss_module_power *mp = &parser->mp[module];
+
+ mp->num_vreg = 0;
+ pm_supply_name = dp_parser_supply_node_name(module);
+ supply_root_node = of_get_child_by_name(of_node, pm_supply_name);
+ if (!supply_root_node) {
+ pr_err("no supply entry present: %s\n", pm_supply_name);
+ goto novreg;
+ }
+
+ mp->num_vreg = of_get_available_child_count(supply_root_node);
+
+ if (mp->num_vreg == 0) {
+ pr_debug("no vreg\n");
+ goto novreg;
+ } else {
+ pr_debug("vreg found. count=%d\n", mp->num_vreg);
+ }
+
+ mp->vreg_config = devm_kzalloc(&parser->pdev->dev,
+ sizeof(struct dss_vreg) * mp->num_vreg, GFP_KERNEL);
+ if (!mp->vreg_config) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ for_each_child_of_node(supply_root_node, supply_node) {
+ const char *st = NULL;
+ /* vreg-name */
+ rc = of_property_read_string(supply_node,
+ "qcom,supply-name", &st);
+ if (rc) {
+ pr_err("error reading name. rc=%d\n",
+ rc);
+ goto error;
+ }
+ snprintf(mp->vreg_config[i].vreg_name,
+ ARRAY_SIZE((mp->vreg_config[i].vreg_name)), "%s", st);
+ /* vreg-min-voltage */
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-min-voltage", &tmp);
+ if (rc) {
+ pr_err("error reading min volt. rc=%d\n",
+ rc);
+ goto error;
+ }
+ mp->vreg_config[i].min_voltage = tmp;
+
+ /* vreg-max-voltage */
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-max-voltage", &tmp);
+ if (rc) {
+ pr_err("error reading max volt. rc=%d\n",
+ rc);
+ goto error;
+ }
+ mp->vreg_config[i].max_voltage = tmp;
+
+ /* enable-load */
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-enable-load", &tmp);
+ if (rc) {
+ pr_err("error reading enable load. rc=%d\n",
+ rc);
+ goto error;
+ }
+ mp->vreg_config[i].enable_load = tmp;
+
+ /* disable-load */
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-disable-load", &tmp);
+ if (rc) {
+ pr_err("error reading disable load. rc=%d\n",
+ rc);
+ goto error;
+ }
+ mp->vreg_config[i].disable_load = tmp;
+
+ pr_debug("%s min=%d, max=%d, enable=%d, disable=%d\n",
+ mp->vreg_config[i].vreg_name,
+ mp->vreg_config[i].min_voltage,
+ mp->vreg_config[i].max_voltage,
+ mp->vreg_config[i].enable_load,
+ mp->vreg_config[i].disable_load
+ );
+ ++i;
+ }
+
+ return rc;
+
+error:
+ if (mp->vreg_config) {
+ devm_kfree(&parser->pdev->dev, mp->vreg_config);
+ mp->vreg_config = NULL;
+ }
+novreg:
+ mp->num_vreg = 0;
+
+ return rc;
+}
+
+static void dp_parser_put_vreg_data(struct device *dev,
+ struct dss_module_power *mp)
+{
+ if (!mp) {
+ DEV_ERR("invalid input\n");
+ return;
+ }
+
+ if (mp->vreg_config) {
+ devm_kfree(dev, mp->vreg_config);
+ mp->vreg_config = NULL;
+ }
+ mp->num_vreg = 0;
+}
+
+static int dp_parser_regulator(struct dp_parser *parser)
+{
+ int i, rc = 0;
+ struct platform_device *pdev = parser->pdev;
+
+ /* Parse the regulator information */
+ for (i = DP_CORE_PM; i < DP_MAX_PM; i++) {
+ rc = dp_parser_get_vreg(parser, i);
+ if (rc) {
+ pr_err("get_dt_vreg_data failed for %s. rc=%d\n",
+ dp_parser_pm_name(i), rc);
+ i--;
+ for (; i >= DP_CORE_PM; i--)
+ dp_parser_put_vreg_data(&pdev->dev,
+ &parser->mp[i]);
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static bool dp_parser_check_prefix(const char *clk_prefix, const char *clk_name)
+{
+ return !!strnstr(clk_name, clk_prefix, strlen(clk_name));
+}
+
+static void dp_parser_put_clk_data(struct device *dev,
+ struct dss_module_power *mp)
+{
+ if (!mp) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ if (mp->clk_config) {
+ devm_kfree(dev, mp->clk_config);
+ mp->clk_config = NULL;
+ }
+
+ mp->num_clk = 0;
+}
+
+static int dp_parser_init_clk_data(struct dp_parser *parser)
+{
+ int num_clk = 0, i = 0, rc = 0;
+ int core_clk_count = 0, ctrl_clk_count = 0;
+ const char *core_clk = "core";
+ const char *ctrl_clk = "ctrl";
+ const char *clk_name;
+ struct device *dev = &parser->pdev->dev;
+ struct dss_module_power *core_power = &parser->mp[DP_CORE_PM];
+ struct dss_module_power *ctrl_power = &parser->mp[DP_CTRL_PM];
+
+ num_clk = of_property_count_strings(dev->of_node, "clock-names");
+ if (num_clk <= 0) {
+ pr_err("no clocks are defined\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ for (i = 0; i < num_clk; i++) {
+ of_property_read_string_index(dev->of_node,
+ "clock-names", i, &clk_name);
+
+ if (dp_parser_check_prefix(core_clk, clk_name))
+ core_clk_count++;
+
+ if (dp_parser_check_prefix(ctrl_clk, clk_name))
+ ctrl_clk_count++;
+ }
+
+ /* Initialize the CORE power module */
+ if (core_clk_count <= 0) {
+ pr_err("no core clocks are defined\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ core_power->num_clk = core_clk_count;
+ core_power->clk_config = devm_kzalloc(dev,
+ sizeof(struct dss_clk) * core_power->num_clk,
+ GFP_KERNEL);
+ if (!core_power->clk_config) {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* Initialize the CTRL power module */
+ if (ctrl_clk_count <= 0) {
+ pr_err("no ctrl clocks are defined\n");
+ rc = -EINVAL;
+ goto ctrl_clock_error;
+ }
+
+ ctrl_power->num_clk = ctrl_clk_count;
+ ctrl_power->clk_config = devm_kzalloc(dev,
+ sizeof(struct dss_clk) * ctrl_power->num_clk,
+ GFP_KERNEL);
+ if (!ctrl_power->clk_config) {
+ ctrl_power->num_clk = 0;
+ rc = -EINVAL;
+ goto ctrl_clock_error;
+ }
+
+ return rc;
+
+ctrl_clock_error:
+ dp_parser_put_clk_data(dev, core_power);
+exit:
+ return rc;
+}
+
+static int dp_parser_clock(struct dp_parser *parser)
+{
+ int rc = 0, i = 0;
+ int num_clk = 0;
+ int core_clk_index = 0, ctrl_clk_index = 0;
+ int core_clk_count = 0, ctrl_clk_count = 0;
+ const char *clk_name;
+ const char *core_clk = "core";
+ const char *ctrl_clk = "ctrl";
+ struct device *dev = &parser->pdev->dev;
+ struct dss_module_power *core_power = &parser->mp[DP_CORE_PM];
+ struct dss_module_power *ctrl_power = &parser->mp[DP_CTRL_PM];
+
+ core_power = &parser->mp[DP_CORE_PM];
+ ctrl_power = &parser->mp[DP_CTRL_PM];
+
+ rc = dp_parser_init_clk_data(parser);
+ if (rc) {
+ pr_err("failed to initialize power data\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ core_clk_count = core_power->num_clk;
+ ctrl_clk_count = ctrl_power->num_clk;
+
+ num_clk = core_clk_count + ctrl_clk_count;
+
+ for (i = 0; i < num_clk; i++) {
+ of_property_read_string_index(dev->of_node, "clock-names",
+ i, &clk_name);
+
+ if (dp_parser_check_prefix(core_clk, clk_name) &&
+ core_clk_index < core_clk_count) {
+ struct dss_clk *clk =
+ &core_power->clk_config[core_clk_index];
+ strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
+ clk->type = DSS_CLK_AHB;
+ core_clk_index++;
+ } else if (dp_parser_check_prefix(ctrl_clk, clk_name) &&
+ ctrl_clk_index < ctrl_clk_count) {
+ struct dss_clk *clk =
+ &ctrl_power->clk_config[ctrl_clk_index];
+ strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
+ ctrl_clk_index++;
+
+ if (!strcmp(clk_name, "ctrl_link_clk") ||
+ !strcmp(clk_name, "ctrl_pixel_clk") ||
+ !strcmp(clk_name, "ctrl_crypto_clk"))
+ clk->type = DSS_CLK_PCLK;
+ else
+ clk->type = DSS_CLK_AHB;
+ }
+ }
+
+ pr_debug("clock parsing successful\n");
+
+exit:
+ return rc;
+}
+
+static int dp_parser_parse(struct dp_parser *parser)
+{
+ int rc = 0;
+
+ if (!parser) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto err;
+ }
+
+ rc = dp_parser_ctrl_res(parser);
+ if (rc)
+ goto err;
+
+ rc = dp_parser_aux(parser);
+ if (rc)
+ goto err;
+
+ rc = dp_parser_misc(parser);
+ if (rc)
+ goto err;
+
+ rc = dp_parser_clock(parser);
+ if (rc)
+ goto err;
+
+ rc = dp_parser_regulator(parser);
+ if (rc)
+ goto err;
+
+ rc = dp_parser_gpio(parser);
+ if (rc)
+ goto err;
+
+ rc = dp_parser_pinctrl(parser);
+err:
+ return rc;
+}
+
+struct dp_parser *dp_parser_get(struct platform_device *pdev)
+{
+ struct dp_parser *parser;
+
+ parser = devm_kzalloc(&pdev->dev, sizeof(*parser), GFP_KERNEL);
+ if (!parser)
+ return ERR_PTR(-ENOMEM);
+
+ parser->parse = dp_parser_parse;
+ parser->pdev = pdev;
+
+ return parser;
+}
+
+void dp_parser_put(struct dp_parser *parser)
+{
+ int i = 0;
+ struct dss_module_power *power = NULL;
+
+ if (!parser) {
+ pr_err("invalid parser module\n");
+ return;
+ }
+
+ power = parser->mp;
+
+ for (i = 0; i < DP_MAX_PM; i++) {
+ struct dss_module_power *mp = &power[i];
+
+ devm_kfree(&parser->pdev->dev, mp->clk_config);
+ devm_kfree(&parser->pdev->dev, mp->vreg_config);
+ devm_kfree(&parser->pdev->dev, mp->gpio_config);
+ }
+
+ devm_kfree(&parser->pdev->dev, parser);
+}
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h
new file mode 100644
index 0000000..fdcdd3a
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 _DP_PARSER_H_
+#define _DP_PARSER_H_
+
+#include <linux/sde_io_util.h>
+
+#define DP_LABEL "MDSS DP DISPLAY"
+#define AUX_CFG_LEN 10
+#define DP_MAX_PIXEL_CLK_KHZ 675000
+
+enum dp_pm_type {
+ DP_CORE_PM,
+ DP_CTRL_PM,
+ DP_PHY_PM,
+ DP_MAX_PM
+};
+
+static inline const char *dp_parser_pm_name(enum dp_pm_type module)
+{
+ switch (module) {
+ case DP_CORE_PM: return "DP_CORE_PM";
+ case DP_CTRL_PM: return "DP_CTRL_PM";
+ case DP_PHY_PM: return "DP_PHY_PM";
+ default: return "???";
+ }
+}
+
+/**
+ * struct dp_display_data - display related device tree data.
+ *
+ * @ctrl_node: referece to controller device
+ * @phy_node: reference to phy device
+ * @is_active: is the controller currently active
+ * @name: name of the display
+ * @display_type: type of the display
+ */
+struct dp_display_data {
+ struct device_node *ctrl_node;
+ struct device_node *phy_node;
+ bool is_active;
+ const char *name;
+ const char *display_type;
+};
+
+/**
+ * struct dp_ctrl_resource - controller's IO related data
+ *
+ * @ctrl_io: controller's mapped memory address
+ * @phy_io: phy's mapped memory address
+ * @ln_tx0_io: USB-DP lane TX0's mapped memory address
+ * @ln_tx1_io: USB-DP lane TX1's mapped memory address
+ * @dp_cc_io: DP cc's mapped memory address
+ * @qfprom_io: qfprom's mapped memory address
+ * @dp_pll_io: DP PLL mapped memory address
+ * @hdcp_io: hdcp's mapped memory address
+ */
+struct dp_io {
+ struct dss_io_data ctrl_io;
+ struct dss_io_data phy_io;
+ struct dss_io_data ln_tx0_io;
+ struct dss_io_data ln_tx1_io;
+ struct dss_io_data dp_cc_io;
+ struct dss_io_data qfprom_io;
+ struct dss_io_data dp_pll_io;
+ struct dss_io_data hdcp_io;
+};
+
+/**
+ * struct dp_pinctrl - DP's pin control
+ *
+ * @pin: pin-controller's instance
+ * @state_active: active state pin control
+ * @state_hpd_active: hpd active state pin control
+ * @state_suspend: suspend state pin control
+ */
+struct dp_pinctrl {
+ struct pinctrl *pin;
+ struct pinctrl_state *state_active;
+ struct pinctrl_state *state_hpd_active;
+ struct pinctrl_state *state_suspend;
+};
+
+/**
+ * struct dp_parser - DP parser's data exposed to clients
+ *
+ * @pdev: platform data of the client
+ * @mp: gpio, regulator and clock related data
+ * @pinctrl: pin-control related data
+ * @ctrl_resouce: controller's register address realated data
+ * @disp_data: controller's display related data
+ * @parse: function to be called by client to parse device tree.
+ */
+struct dp_parser {
+ struct platform_device *pdev;
+ struct dss_module_power mp[DP_MAX_PM];
+ struct dp_pinctrl pinctrl;
+ struct dp_io io;
+ struct dp_display_data disp_data;
+
+ u8 l_map[4];
+ u32 aux_cfg[AUX_CFG_LEN];
+ u32 max_pclk_khz;
+
+ int (*parse)(struct dp_parser *parser);
+};
+
+/**
+ * dp_parser_get() - get the DP's device tree parser module
+ *
+ * @pdev: platform data of the client
+ * return: pointer to dp_parser structure.
+ *
+ * This function provides client capability to parse the
+ * device tree and populate the data structures. The data
+ * related to clock, regulators, pin-control and other
+ * can be parsed using this module.
+ */
+struct dp_parser *dp_parser_get(struct platform_device *pdev);
+
+/**
+ * dp_parser_put() - cleans the dp_parser module
+ *
+ * @parser: pointer to the parser's data.
+ */
+void dp_parser_put(struct dp_parser *parser);
+#endif
diff --git a/drivers/gpu/drm/msm/dp/dp_power.c b/drivers/gpu/drm/msm/dp/dp_power.c
new file mode 100644
index 0000000..54d4a10
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_power.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
+
+#include <linux/clk.h>
+#include "dp_power.h"
+
+struct dp_power_private {
+ struct dp_parser *parser;
+ struct platform_device *pdev;
+ struct clk *pixel_clk_rcg;
+ struct clk *pixel_parent;
+
+ struct dp_power dp_power;
+
+ bool core_clks_on;
+ bool link_clks_on;
+};
+
+static int dp_power_regulator_init(struct dp_power_private *power)
+{
+ int rc = 0, i = 0, j = 0;
+ struct platform_device *pdev;
+ struct dp_parser *parser;
+
+ parser = power->parser;
+ pdev = power->pdev;
+
+ for (i = DP_CORE_PM; !rc && (i < DP_MAX_PM); i++) {
+ rc = msm_dss_config_vreg(&pdev->dev,
+ parser->mp[i].vreg_config,
+ parser->mp[i].num_vreg, 1);
+ if (rc) {
+ pr_err("failed to init vregs for %s\n",
+ dp_parser_pm_name(i));
+ for (j = i - 1; j >= DP_CORE_PM; j--) {
+ msm_dss_config_vreg(&pdev->dev,
+ parser->mp[j].vreg_config,
+ parser->mp[j].num_vreg, 0);
+ }
+
+ goto error;
+ }
+ }
+error:
+ return rc;
+}
+
+static int dp_power_regulator_ctrl(struct dp_power_private *power, bool enable)
+{
+ int rc = 0, i = 0, j = 0;
+ struct dp_parser *parser;
+
+ parser = power->parser;
+
+ for (i = DP_CORE_PM; i < DP_MAX_PM; i++) {
+ rc = msm_dss_enable_vreg(
+ parser->mp[i].vreg_config,
+ parser->mp[i].num_vreg, enable);
+ if (rc) {
+ pr_err("failed to '%s' vregs for %s\n",
+ enable ? "enable" : "disable",
+ dp_parser_pm_name(i));
+ if (enable) {
+ for (j = i-1; j >= DP_CORE_PM; j--) {
+ msm_dss_enable_vreg(
+ parser->mp[j].vreg_config,
+ parser->mp[j].num_vreg, 0);
+ }
+ }
+ goto error;
+ }
+ }
+error:
+ return rc;
+}
+
+static int dp_power_pinctrl_set(struct dp_power_private *power, bool active)
+{
+ int rc = -EFAULT;
+ struct pinctrl_state *pin_state;
+ struct dp_parser *parser;
+
+ parser = power->parser;
+
+ if (IS_ERR_OR_NULL(parser->pinctrl.pin))
+ return PTR_ERR(parser->pinctrl.pin);
+
+ pin_state = active ? parser->pinctrl.state_active
+ : parser->pinctrl.state_suspend;
+ if (!IS_ERR_OR_NULL(pin_state)) {
+ rc = pinctrl_select_state(parser->pinctrl.pin,
+ pin_state);
+ if (rc)
+ pr_err("can not set %s pins\n",
+ active ? "dp_active"
+ : "dp_sleep");
+ } else {
+ pr_err("invalid '%s' pinstate\n",
+ active ? "dp_active"
+ : "dp_sleep");
+ }
+
+ return rc;
+}
+
+static int dp_power_clk_init(struct dp_power_private *power, bool enable)
+{
+ int rc = 0;
+ struct dss_module_power *core, *ctrl;
+ struct device *dev;
+
+ core = &power->parser->mp[DP_CORE_PM];
+ ctrl = &power->parser->mp[DP_CTRL_PM];
+
+ dev = &power->pdev->dev;
+
+ if (!core || !ctrl) {
+ pr_err("invalid power_data\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (enable) {
+ rc = msm_dss_get_clk(dev, core->clk_config, core->num_clk);
+ if (rc) {
+ pr_err("failed to get %s clk. err=%d\n",
+ dp_parser_pm_name(DP_CORE_PM), rc);
+ goto exit;
+ }
+
+ rc = msm_dss_get_clk(dev, ctrl->clk_config, ctrl->num_clk);
+ if (rc) {
+ pr_err("failed to get %s clk. err=%d\n",
+ dp_parser_pm_name(DP_CTRL_PM), rc);
+ goto ctrl_get_error;
+ }
+
+ power->pixel_clk_rcg = devm_clk_get(dev, "pixel_clk_rcg");
+ if (IS_ERR(power->pixel_clk_rcg)) {
+ pr_debug("Unable to get DP pixel clk RCG\n");
+ power->pixel_clk_rcg = NULL;
+ }
+
+ power->pixel_parent = devm_clk_get(dev, "pixel_parent");
+ if (IS_ERR(power->pixel_parent)) {
+ pr_debug("Unable to get DP pixel RCG parent\n");
+ power->pixel_parent = NULL;
+ }
+ } else {
+ if (power->pixel_parent)
+ devm_clk_put(dev, power->pixel_parent);
+
+ if (power->pixel_clk_rcg)
+ devm_clk_put(dev, power->pixel_clk_rcg);
+
+ msm_dss_put_clk(ctrl->clk_config, ctrl->num_clk);
+ msm_dss_put_clk(core->clk_config, core->num_clk);
+ }
+
+ return rc;
+
+ctrl_get_error:
+ msm_dss_put_clk(core->clk_config, core->num_clk);
+exit:
+ return rc;
+}
+
+static int dp_power_clk_set_rate(struct dp_power_private *power,
+ enum dp_pm_type module, bool enable)
+{
+ int rc = 0;
+ struct dss_module_power *mp;
+
+ if (!power) {
+ pr_err("invalid power data\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ mp = &power->parser->mp[module];
+
+ if (enable) {
+ rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
+ if (rc) {
+ pr_err("failed to set clks rate.\n");
+ goto exit;
+ }
+
+ rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, 1);
+ if (rc) {
+ pr_err("failed to enable clks\n");
+ goto exit;
+ }
+ } else {
+ rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, 0);
+ if (rc) {
+ pr_err("failed to disable clks\n");
+ goto exit;
+ }
+ }
+exit:
+ return rc;
+}
+
+static int dp_power_clk_enable(struct dp_power *dp_power,
+ enum dp_pm_type pm_type, bool enable)
+{
+ int rc = 0;
+ struct dss_module_power *mp;
+ struct dp_power_private *power;
+
+ if (!dp_power) {
+ pr_err("invalid power data\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ power = container_of(dp_power, struct dp_power_private, dp_power);
+
+ mp = &power->parser->mp[pm_type];
+
+ if ((pm_type != DP_CORE_PM) && (pm_type != DP_CTRL_PM)) {
+ pr_err("unsupported power module: %s\n",
+ dp_parser_pm_name(pm_type));
+ return -EINVAL;
+ }
+
+ if (enable) {
+ if ((pm_type == DP_CORE_PM)
+ && (power->core_clks_on)) {
+ pr_debug("core clks already enabled\n");
+ return 0;
+ }
+
+ if ((pm_type == DP_CTRL_PM)
+ && (power->link_clks_on)) {
+ pr_debug("links clks already enabled\n");
+ return 0;
+ }
+
+ if ((pm_type == DP_CTRL_PM) && (!power->core_clks_on)) {
+ pr_debug("Need to enable core clks before link clks\n");
+
+ rc = dp_power_clk_set_rate(power, pm_type, enable);
+ if (rc) {
+ pr_err("failed to enable clks: %s. err=%d\n",
+ dp_parser_pm_name(DP_CORE_PM), rc);
+ goto error;
+ } else {
+ power->core_clks_on = true;
+ }
+ }
+ }
+
+ rc = dp_power_clk_set_rate(power, pm_type, enable);
+ if (rc) {
+ pr_err("failed to '%s' clks for: %s. err=%d\n",
+ enable ? "enable" : "disable",
+ dp_parser_pm_name(pm_type), rc);
+ goto error;
+ }
+
+ if (pm_type == DP_CORE_PM)
+ power->core_clks_on = enable;
+ else
+ power->link_clks_on = enable;
+
+ pr_debug("%s clocks for %s\n",
+ enable ? "enable" : "disable",
+ dp_parser_pm_name(pm_type));
+ pr_debug("link_clks:%s core_clks:%s\n",
+ power->link_clks_on ? "on" : "off",
+ power->core_clks_on ? "on" : "off");
+error:
+ return rc;
+}
+
+static int dp_power_request_gpios(struct dp_power_private *power)
+{
+ int rc = 0, i;
+ struct device *dev;
+ struct dss_module_power *mp;
+ static const char * const gpio_names[] = {
+ "aux_enable", "aux_sel", "usbplug_cc",
+ };
+
+ if (!power) {
+ pr_err("invalid power data\n");
+ return -EINVAL;
+ }
+
+ dev = &power->pdev->dev;
+ mp = &power->parser->mp[DP_CORE_PM];
+
+ for (i = 0; i < ARRAY_SIZE(gpio_names); i++) {
+ unsigned int gpio = mp->gpio_config[i].gpio;
+
+ if (gpio_is_valid(gpio)) {
+ rc = devm_gpio_request(dev, gpio, gpio_names[i]);
+ if (rc) {
+ pr_err("request %s gpio failed, rc=%d\n",
+ gpio_names[i], rc);
+ goto error;
+ }
+ }
+ }
+ return 0;
+error:
+ for (i = 0; i < ARRAY_SIZE(gpio_names); i++) {
+ unsigned int gpio = mp->gpio_config[i].gpio;
+
+ if (gpio_is_valid(gpio))
+ gpio_free(gpio);
+ }
+ return rc;
+}
+
+static bool dp_power_find_gpio(const char *gpio1, const char *gpio2)
+{
+ return !!strnstr(gpio1, gpio2, strlen(gpio1));
+}
+
+static void dp_power_set_gpio(struct dp_power_private *power, bool flip)
+{
+ int i;
+ struct dss_module_power *mp = &power->parser->mp[DP_CORE_PM];
+ struct dss_gpio *config = mp->gpio_config;
+
+ for (i = 0; i < mp->num_gpio; i++) {
+ if (dp_power_find_gpio(config->gpio_name, "aux-sel"))
+ config->value = flip;
+
+ if (gpio_is_valid(config->gpio)) {
+ pr_debug("gpio %s, value %d\n", config->gpio_name,
+ config->value);
+
+ if (dp_power_find_gpio(config->gpio_name, "aux-en") ||
+ dp_power_find_gpio(config->gpio_name, "aux-sel"))
+ gpio_direction_output(config->gpio,
+ config->value);
+ else
+ gpio_set_value(config->gpio, config->value);
+
+ }
+ config++;
+ }
+}
+
+static int dp_power_config_gpios(struct dp_power_private *power, bool flip,
+ bool enable)
+{
+ int rc = 0, i;
+ struct dss_module_power *mp;
+ struct dss_gpio *config;
+
+ mp = &power->parser->mp[DP_CORE_PM];
+ config = mp->gpio_config;
+
+ if (enable) {
+ rc = dp_power_request_gpios(power);
+ if (rc) {
+ pr_err("gpio request failed\n");
+ return rc;
+ }
+
+ dp_power_set_gpio(power, flip);
+ } else {
+ for (i = 0; i < mp->num_gpio; i++) {
+ gpio_set_value(config[i].gpio, 0);
+ gpio_free(config[i].gpio);
+ }
+ }
+
+ return 0;
+}
+
+static int dp_power_set_pixel_clk_parent(struct dp_power *dp_power)
+{
+ int rc = 0;
+ struct dp_power_private *power;
+
+ if (!dp_power) {
+ pr_err("invalid power data\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ power = container_of(dp_power, struct dp_power_private, dp_power);
+
+ if (power->pixel_clk_rcg && power->pixel_parent)
+ clk_set_parent(power->pixel_clk_rcg, power->pixel_parent);
+exit:
+ return rc;
+}
+
+static int dp_power_init(struct dp_power *dp_power, bool flip)
+{
+ int rc = 0;
+ struct dp_power_private *power;
+
+ if (!dp_power) {
+ pr_err("invalid power data\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ power = container_of(dp_power, struct dp_power_private, dp_power);
+
+ rc = dp_power_regulator_ctrl(power, true);
+ if (rc) {
+ pr_err("failed to enable regulators\n");
+ goto exit;
+ }
+
+ rc = dp_power_pinctrl_set(power, true);
+ if (rc) {
+ pr_err("failed to set pinctrl state\n");
+ goto err_pinctrl;
+ }
+
+ rc = dp_power_config_gpios(power, flip, true);
+ if (rc) {
+ pr_err("failed to enable gpios\n");
+ goto err_gpio;
+ }
+
+ rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
+ if (rc) {
+ pr_err("failed to enable DP core clocks\n");
+ goto err_clk;
+ }
+
+ return 0;
+
+err_clk:
+ dp_power_config_gpios(power, flip, false);
+err_gpio:
+ dp_power_pinctrl_set(power, false);
+err_pinctrl:
+ dp_power_regulator_ctrl(power, false);
+exit:
+ return rc;
+}
+
+static int dp_power_deinit(struct dp_power *dp_power)
+{
+ int rc = 0;
+ struct dp_power_private *power;
+
+ if (!dp_power) {
+ pr_err("invalid power data\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ power = container_of(dp_power, struct dp_power_private, dp_power);
+
+ dp_power_clk_enable(dp_power, DP_CORE_PM, false);
+ dp_power_config_gpios(power, false, false);
+ dp_power_pinctrl_set(power, false);
+ dp_power_regulator_ctrl(power, false);
+exit:
+ return rc;
+}
+
+struct dp_power *dp_power_get(struct dp_parser *parser)
+{
+ int rc = 0;
+ struct dp_power_private *power;
+ struct dp_power *dp_power;
+
+ if (!parser) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL);
+ if (!power) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ power->parser = parser;
+ power->pdev = parser->pdev;
+
+ dp_power = &power->dp_power;
+
+ dp_power->init = dp_power_init;
+ dp_power->deinit = dp_power_deinit;
+ dp_power->clk_enable = dp_power_clk_enable;
+ dp_power->set_pixel_clk_parent = dp_power_set_pixel_clk_parent;
+
+ rc = dp_power_regulator_init(power);
+ if (rc) {
+ pr_err("failed to init regulators\n");
+ goto error;
+ }
+
+ rc = dp_power_clk_init(power, true);
+ if (rc) {
+ pr_err("failed to init clocks\n");
+ goto error;
+ }
+
+ return dp_power;
+error:
+ return ERR_PTR(rc);
+}
+
+void dp_power_put(struct dp_power *dp_power)
+{
+ struct dp_power_private *power = container_of(dp_power,
+ struct dp_power_private, dp_power);
+
+ (void)dp_power_clk_init(power, false);
+ devm_kfree(&power->pdev->dev, power);
+}
diff --git a/drivers/gpu/drm/msm/dp/dp_power.h b/drivers/gpu/drm/msm/dp/dp_power.h
new file mode 100644
index 0000000..3d71695
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_power.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 _DP_POWER_H_
+#define _DP_POWER_H_
+
+#include "dp_parser.h"
+
+/**
+ * sruct dp_power - DisplayPort's power related data
+ *
+ * @init: initializes the regulators/core clocks/GPIOs/pinctrl
+ * @deinit: turns off the regulators/core clocks/GPIOs/pinctrl
+ * @clk_enable: enable/disable the DP clocks
+ * @set_pixel_clk_parent: set the parent of DP pixel clock
+ */
+struct dp_power {
+ int (*init)(struct dp_power *power, bool flip);
+ int (*deinit)(struct dp_power *power);
+ int (*clk_enable)(struct dp_power *power, enum dp_pm_type pm_type,
+ bool enable);
+ int (*set_pixel_clk_parent)(struct dp_power *power);
+};
+
+/**
+ * dp_power_get() - configure and get the DisplayPort power module data
+ *
+ * @parser: instance of parser module
+ * return: pointer to allocated power module data
+ *
+ * This API will configure the DisplayPort's power module and provides
+ * methods to be called by the client to configure the power related
+ * modueles.
+ */
+struct dp_power *dp_power_get(struct dp_parser *parser);
+
+/**
+ * dp_power_put() - release the power related resources
+ *
+ * @power: pointer to the power module's data
+ */
+void dp_power_put(struct dp_power *power);
+#endif /* _DP_POWER_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index 5dcdf46..2d7b174 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -142,7 +142,8 @@
void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl,
struct dsi_mode_info *mode,
u32 h_stride,
- u32 vc_id);
+ u32 vc_id,
+ struct dsi_rect *roi);
void dsi_ctrl_hw_cmn_phy_sw_reset(struct dsi_ctrl_hw *ctrl);
void dsi_ctrl_hw_cmn_soft_reset(struct dsi_ctrl_hw *ctrl);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index f187ad1..39b797e 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -1558,7 +1558,6 @@
int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl)
{
- struct dsi_mode_info video_timing;
int rc = 0;
if (!dsi_ctrl) {
@@ -1568,12 +1567,6 @@
mutex_lock(&dsi_ctrl->ctrl_lock);
- /* replace video mode width with actual roi width */
- memcpy(&video_timing, &dsi_ctrl->host_config.video_timing,
- sizeof(video_timing));
- video_timing.h_active = dsi_ctrl->roi.w;
- video_timing.v_active = dsi_ctrl->roi.h;
-
dsi_ctrl->hw.ops.setup_lane_map(&dsi_ctrl->hw,
&dsi_ctrl->host_config.lane_map);
@@ -1586,9 +1579,10 @@
&dsi_ctrl->host_config.u.cmd_engine);
dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
- &video_timing,
- video_timing.h_active * 3,
- 0x0);
+ &dsi_ctrl->host_config.video_timing,
+ dsi_ctrl->host_config.video_timing.h_active * 3,
+ 0x0,
+ &dsi_ctrl->roi);
dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, true);
} else {
dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw,
@@ -1690,7 +1684,8 @@
dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
&dsi_ctrl->host_config.video_timing,
dsi_ctrl->host_config.video_timing.h_active * 3,
- 0x0);
+ 0x0,
+ NULL);
} else {
dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw,
&dsi_ctrl->host_config.common_config,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index 859d707..bb72807 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -319,7 +319,8 @@
void (*setup_cmd_stream)(struct dsi_ctrl_hw *ctrl,
struct dsi_mode_info *mode,
u32 h_stride,
- u32 vc_id);
+ u32 vc_id,
+ struct dsi_rect *roi);
/**
* ctrl_en() - enable DSI controller engine
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
index 48c2370..a024c43 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
@@ -19,6 +19,7 @@
#include "dsi_ctrl_hw.h"
#include "dsi_ctrl_reg.h"
#include "dsi_hw.h"
+#include "dsi_panel.h"
#define MMSS_MISC_CLAMP_REG_OFF 0x0014
#define DSI_CTRL_DYNAMIC_FORCE_ON (0x23F|BIT(8)|BIT(9)|BIT(11)|BIT(21))
@@ -234,21 +235,36 @@
void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl,
struct dsi_mode_info *mode,
u32 h_stride,
- u32 vc_id)
+ u32 vc_id,
+ struct dsi_rect *roi)
{
- u32 reg = 0;
u32 width_final, stride_final;
+ u32 height_final;
+ u32 stream_total = 0, stream_ctrl = 0;
+ u32 reg_ctrl = 0, reg_ctrl2 = 0;
+
+ if (roi && (!roi->w || !roi->h))
+ return;
if (mode->dsc_enabled && mode->dsc) {
+ u32 reg = 0;
u32 offset = 0;
- u32 reg_ctrl, reg_ctrl2;
+ int pic_width, this_frame_slices, intf_ip_w;
+ struct msm_display_dsc_info dsc;
+
+ memcpy(&dsc, mode->dsc, sizeof(dsc));
+ pic_width = roi ? roi->w : mode->h_active;
+ this_frame_slices = pic_width / dsc.slice_width;
+ intf_ip_w = this_frame_slices * dsc.slice_width;
+ dsi_dsc_pclk_param_calc(&dsc, intf_ip_w);
if (vc_id != 0)
offset = 16;
reg_ctrl = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL);
reg_ctrl2 = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2);
- width_final = mode->dsc->pclk_per_line;
- stride_final = mode->dsc->bytes_per_pkt;
+ width_final = dsc.pclk_per_line;
+ stride_final = dsc.bytes_per_pkt;
+ height_final = roi ? roi->h : mode->v_active;
reg = 0x39 << 8;
/*
@@ -258,34 +274,45 @@
* 2 == 4 pkt
* 3 pkt is not support
*/
- if (mode->dsc->pkt_per_line == 4)
- reg |= (mode->dsc->pkt_per_line - 2) << 6;
+ if (dsc.pkt_per_line == 4)
+ reg |= (dsc.pkt_per_line - 2) << 6;
else
- reg |= (mode->dsc->pkt_per_line - 1) << 6;
- reg |= mode->dsc->eol_byte_num << 4;
+ reg |= (dsc.pkt_per_line - 1) << 6;
+ reg |= dsc.eol_byte_num << 4;
reg |= 1;
reg_ctrl &= ~(0xFFFF << offset);
reg_ctrl |= (reg << offset);
reg_ctrl2 &= ~(0xFFFF << offset);
- reg_ctrl2 |= (mode->dsc->bytes_in_slice << offset);
+ reg_ctrl2 |= (dsc.bytes_in_slice << offset);
DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl);
DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2);
+
+ pr_debug("ctrl %d reg_ctrl 0x%x reg_ctrl2 0x%x\n", ctrl->index,
+ reg_ctrl, reg_ctrl2);
+ } else if (roi) {
+ width_final = roi->w;
+ stride_final = roi->w * 3;
+ height_final = roi->h;
} else {
width_final = mode->h_active;
stride_final = h_stride;
+ height_final = mode->v_active;
}
- reg = (stride_final + 1) << 16;
- reg |= (vc_id & 0x3) << 8;
- reg |= 0x39; /* packet data type */
+ stream_ctrl = (stride_final + 1) << 16;
+ stream_ctrl |= (vc_id & 0x3) << 8;
+ stream_ctrl |= 0x39; /* packet data type */
- DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_CTRL, reg);
- DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_CTRL, reg);
+ DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_CTRL, stream_ctrl);
+ DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_CTRL, stream_ctrl);
- reg = (mode->v_active << 16) | width_final;
- DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_TOTAL, reg);
- DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_TOTAL, reg);
+ stream_total = (height_final << 16) | width_final;
+ DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_TOTAL, stream_total);
+ DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_TOTAL, stream_total);
+
+ pr_debug("ctrl %d stream_ctrl 0x%x stream_total 0x%x\n", ctrl->index,
+ stream_ctrl, stream_total);
}
/**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 4c9fbbe..f254af5 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -249,4 +249,6 @@
int dsi_panel_send_roi_dcs(struct dsi_panel *panel, int ctrl_idx,
struct dsi_rect *roi);
+void dsi_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, int intf_width);
+
#endif /* _DSI_PANEL_H_ */
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 4e0b678..a3a9142 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -1271,22 +1271,20 @@
return ret;
}
-void msm_send_crtc_notification(struct drm_crtc *crtc,
- struct drm_event *event, u8 *payload)
+void msm_mode_object_event_nofity(struct drm_mode_object *obj,
+ struct drm_device *dev, struct drm_event *event, u8 *payload)
{
- struct drm_device *dev = NULL;
struct msm_drm_private *priv = NULL;
unsigned long flags;
struct msm_drm_event *notify, *node;
int len = 0, ret;
- if (!crtc || !event || !event->length || !payload) {
- DRM_ERROR("err param crtc %pK event %pK len %d payload %pK\n",
- crtc, event, ((event) ? (event->length) : -1),
+ if (!obj || !event || !event->length || !payload) {
+ DRM_ERROR("err param obj %pK event %pK len %d payload %pK\n",
+ obj, event, ((event) ? (event->length) : -1),
payload);
return;
}
- dev = crtc->dev;
priv = (dev) ? dev->dev_private : NULL;
if (!dev || !priv) {
DRM_ERROR("invalid dev %pK priv %pK\n", dev, priv);
@@ -1296,7 +1294,7 @@
spin_lock_irqsave(&dev->event_lock, flags);
list_for_each_entry(node, &priv->client_event_list, base.link) {
if (node->event.type != event->type ||
- crtc->base.id != node->info.object_id)
+ obj->id != node->info.object_id)
continue;
len = event->length + sizeof(struct drm_msm_event_resp);
if (node->base.file_priv->event_space < len) {
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index d50a185..f596989 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -710,13 +710,14 @@
};
/* *
- * msm_send_crtc_notification - notify user-space clients of crtc events.
- * @crtc: crtc that is generating the event.
+ * msm_mode_object_event_notify - notify user-space clients of drm object
+ * events.
+ * @obj: mode object (crtc/connector) that is generating the event.
* @event: event that needs to be notified.
* @payload: payload for the event.
*/
-void msm_send_crtc_notification(struct drm_crtc *crtc,
- struct drm_event *event, u8 *payload);
+void msm_mode_object_event_nofity(struct drm_mode_object *obj,
+ struct drm_device *dev, struct drm_event *event, u8 *payload);
#ifdef CONFIG_DRM_MSM_DSI
void __init msm_dsi_register(void);
void __exit msm_dsi_unregister(void);
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c
index d5207b9..b410302 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.c
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c
@@ -180,7 +180,7 @@
struct drm_property_blob *blob = prop_node->blob_ptr;
if (!blob)
- return -EINVAL;
+ return 0;
drm_property_unreference_blob(blob);
prop_node->blob_ptr = NULL;
return 0;
@@ -1357,7 +1357,8 @@
hw_dspp->ops.ad_read_intr_resp(hw_dspp, AD4_BACKLIGHT, &bl);
event.length = sizeof(u32);
event.type = DRM_EVENT_AD_BACKLIGHT;
- msm_send_crtc_notification(&crtc->base, &event, (u8 *)&bl);
+ msm_mode_object_event_nofity(&crtc_drm->base, crtc_drm->dev,
+ &event, (u8 *)&bl);
}
int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en,
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 6593b47..f13c6c9 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -59,6 +59,7 @@
struct dsi_display *display;
struct sde_connector *c_conn;
int bl_lvl;
+ struct drm_event event;
brightness = bd->props.brightness;
@@ -79,8 +80,13 @@
if (!bl_lvl && brightness)
bl_lvl = 1;
- if (c_conn->ops.set_backlight)
+ if (c_conn->ops.set_backlight) {
+ event.type = DRM_EVENT_SYS_BACKLIGHT;
+ event.length = sizeof(u32);
+ msm_mode_object_event_nofity(&c_conn->base.base,
+ c_conn->base.dev, &event, (u8 *)&brightness);
c_conn->ops.set_backlight(c_conn->display, bl_lvl);
+ }
return 0;
}
@@ -1165,5 +1171,14 @@
int sde_connector_register_custom_event(struct sde_kms *kms,
struct drm_connector *conn_drm, u32 event, bool val)
{
- return -EINVAL;
+ int ret = -EINVAL;
+
+ switch (event) {
+ case DRM_EVENT_SYS_BACKLIGHT:
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+ return ret;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index dcf3c08..79fcfb7 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -51,8 +51,12 @@
struct sde_irq_callback *irq);
};
+static int sde_crtc_power_interrupt_handler(struct drm_crtc *crtc_drm,
+ bool en, struct sde_irq_callback *ad_irq);
+
static struct sde_crtc_custom_events custom_events[] = {
- {DRM_EVENT_AD_BACKLIGHT, sde_cp_ad_interrupt}
+ {DRM_EVENT_AD_BACKLIGHT, sde_cp_ad_interrupt},
+ {DRM_EVENT_CRTC_POWER, sde_crtc_power_interrupt_handler}
};
/* default input fence timeout, in ms */
@@ -608,12 +612,15 @@
int i;
if (!dim_layer->rect.w || !dim_layer->rect.h) {
- SDE_DEBUG("empty dim layer\n");
+ SDE_DEBUG("empty dim_layer\n");
return;
}
cstate = to_sde_crtc_state(crtc->state);
+ SDE_DEBUG("dim_layer - flags:%d, stage:%d\n",
+ dim_layer->flags, dim_layer->stage);
+
split_dim_layer.stage = dim_layer->stage;
split_dim_layer.color_fill = dim_layer->color_fill;
@@ -647,9 +654,13 @@
} else {
split_dim_layer.rect.x =
split_dim_layer.rect.x -
- cstate->lm_bounds[i].w;
+ cstate->lm_bounds[i].x;
}
+ SDE_DEBUG("split_dim_layer - LM:%d, rect:{%d,%d,%d,%d}}\n",
+ i, split_dim_layer.rect.x, split_dim_layer.rect.y,
+ split_dim_layer.rect.w, split_dim_layer.rect.h);
+
lm = mixer[i].hw_lm;
mixer[i].mixer_op_mode |= 1 << split_dim_layer.stage;
lm->ops.setup_dim_layer(lm, &split_dim_layer);
@@ -854,9 +865,24 @@
sde_crtc = to_sde_crtc(crtc);
crtc_state = to_sde_crtc_state(state);
- for (i = 0; i < sde_crtc->num_mixers; i++) {
- if (!sde_kms_rect_is_null(&crtc_state->lm_roi[i]))
- disp_bitmask |= BIT(i);
+ /* pingpong split: one ROI, one LM, two physical displays */
+ if (crtc_state->is_ppsplit) {
+ u32 lm_split_width = crtc_state->lm_bounds[0].w / 2;
+ struct sde_rect *roi = &crtc_state->lm_roi[0];
+
+ if (sde_kms_rect_is_null(roi))
+ disp_bitmask = 0;
+ else if ((u32)roi->x + (u32)roi->w <= lm_split_width)
+ disp_bitmask = BIT(0); /* left only */
+ else if (roi->x >= lm_split_width)
+ disp_bitmask = BIT(1); /* right only */
+ else
+ disp_bitmask = BIT(0) | BIT(1); /* left and right */
+ } else {
+ for (i = 0; i < sde_crtc->num_mixers; i++) {
+ if (!sde_kms_rect_is_null(&crtc_state->lm_roi[i]))
+ disp_bitmask |= BIT(i);
+ }
}
SDE_DEBUG("affected displays 0x%x\n", disp_bitmask);
@@ -877,9 +903,6 @@
sde_crtc = to_sde_crtc(crtc);
crtc_state = to_sde_crtc_state(state);
- if (sde_crtc->num_mixers == 1)
- return 0;
-
if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) {
SDE_ERROR("%s: unsupported number of mixers: %d\n",
sde_crtc->name, sde_crtc->num_mixers);
@@ -887,9 +910,41 @@
}
/*
- * On certain HW, ROIs must be centered on the split between LMs,
- * and be of equal width.
+ * If using pingpong split: one ROI, one LM, two physical displays
+ * then the ROI must be centered on the panel split boundary and
+ * be of equal width across the split.
*/
+ if (crtc_state->is_ppsplit) {
+ u16 panel_split_width;
+ u32 display_mask;
+
+ roi[0] = &crtc_state->lm_roi[0];
+
+ if (sde_kms_rect_is_null(roi[0]))
+ return 0;
+
+ display_mask = _sde_crtc_get_displays_affected(crtc, state);
+ if (display_mask != (BIT(0) | BIT(1)))
+ return 0;
+
+ panel_split_width = crtc_state->lm_bounds[0].w / 2;
+ if (roi[0]->x + roi[0]->w / 2 != panel_split_width) {
+ SDE_ERROR("%s: roi x %d w %d split %d\n",
+ sde_crtc->name, roi[0]->x, roi[0]->w,
+ panel_split_width);
+ return -EINVAL;
+ }
+
+ return 0;
+ }
+
+ /*
+ * On certain HW, if using 2 LM, ROIs must be split evenly between the
+ * LMs and be of equal width.
+ */
+ if (sde_crtc->num_mixers == 1)
+ return 0;
+
roi[0] = &crtc_state->lm_roi[0];
roi[1] = &crtc_state->lm_roi[1];
@@ -1177,6 +1232,69 @@
_sde_crtc_program_lm_output_roi(crtc);
}
+static void _sde_crtc_swap_mixers_for_right_partial_update(
+ struct drm_crtc *crtc)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *cstate;
+ struct drm_encoder *drm_enc;
+ bool is_right_only;
+ bool encoder_in_dsc_merge = false;
+
+ if (!crtc || !crtc->state)
+ return;
+
+ sde_crtc = to_sde_crtc(crtc);
+ cstate = to_sde_crtc_state(crtc->state);
+
+ if (sde_crtc->num_mixers != CRTC_DUAL_MIXERS)
+ return;
+
+ drm_for_each_encoder(drm_enc, crtc->dev) {
+ if (drm_enc->crtc == crtc &&
+ sde_encoder_is_dsc_merge(drm_enc)) {
+ encoder_in_dsc_merge = true;
+ break;
+ }
+ }
+
+ /**
+ * For right-only partial update with DSC merge, we swap LM0 & LM1.
+ * This is due to two reasons:
+ * - On 8996, there is a DSC HW requirement that in DSC Merge Mode,
+ * the left DSC must be used, right DSC cannot be used alone.
+ * For right-only partial update, this means swap layer mixers to map
+ * Left LM to Right INTF. On later HW this was relaxed.
+ * - In DSC Merge mode, the physical encoder has already registered
+ * PP0 as the master, to switch to right-only we would have to
+ * reprogram to be driven by PP1 instead.
+ * To support both cases, we prefer to support the mixer swap solution.
+ */
+ if (!encoder_in_dsc_merge)
+ return;
+
+ is_right_only = sde_kms_rect_is_null(&cstate->lm_roi[0]) &&
+ !sde_kms_rect_is_null(&cstate->lm_roi[1]);
+
+ if (is_right_only && !sde_crtc->mixers_swapped) {
+ /* right-only update swap mixers */
+ swap(sde_crtc->mixers[0], sde_crtc->mixers[1]);
+ sde_crtc->mixers_swapped = true;
+ } else if (!is_right_only && sde_crtc->mixers_swapped) {
+ /* left-only or full update, swap back */
+ swap(sde_crtc->mixers[0], sde_crtc->mixers[1]);
+ sde_crtc->mixers_swapped = false;
+ }
+
+ SDE_DEBUG("%s: right_only %d swapped %d, mix0->lm%d, mix1->lm%d\n",
+ sde_crtc->name, is_right_only, sde_crtc->mixers_swapped,
+ sde_crtc->mixers[0].hw_lm->idx - LM_0,
+ sde_crtc->mixers[1].hw_lm->idx - LM_0);
+ SDE_EVT32(DRMID(crtc), is_right_only, sde_crtc->mixers_swapped,
+ sde_crtc->mixers[0].hw_lm->idx - LM_0,
+ sde_crtc->mixers[1].hw_lm->idx - LM_0);
+}
+
/**
* _sde_crtc_blend_setup - configure crtc mixers
* @crtc: Pointer to drm crtc structure
@@ -1222,6 +1340,8 @@
lm->ops.clear_dim_layer(lm);
}
+ _sde_crtc_swap_mixers_for_right_partial_update(crtc);
+
/* initialize stage cfg */
memset(&sde_crtc->stage_cfg, 0, sizeof(struct sde_hw_stage_cfg));
@@ -1530,26 +1650,28 @@
{
struct sde_drm_dim_layer_v1 dim_layer_v1;
struct sde_drm_dim_layer_cfg *user_cfg;
+ struct sde_hw_dim_layer *dim_layer;
u32 count, i;
if (!cstate) {
SDE_ERROR("invalid cstate\n");
return;
}
+ dim_layer = cstate->dim_layer;
if (!usr_ptr) {
- SDE_DEBUG("dim layer data removed\n");
+ SDE_DEBUG("dim_layer data removed\n");
return;
}
if (copy_from_user(&dim_layer_v1, usr_ptr, sizeof(dim_layer_v1))) {
- SDE_ERROR("failed to copy dim layer data\n");
+ SDE_ERROR("failed to copy dim_layer data\n");
return;
}
count = dim_layer_v1.num_layers;
- if (!count || (count > SDE_MAX_DIM_LAYERS)) {
- SDE_ERROR("invalid number of Dim Layers:%d", count);
+ if (count > SDE_MAX_DIM_LAYERS) {
+ SDE_ERROR("invalid number of dim_layers:%d", count);
return;
}
@@ -1557,22 +1679,31 @@
cstate->num_dim_layers = count;
for (i = 0; i < count; i++) {
user_cfg = &dim_layer_v1.layer_cfg[i];
- cstate->dim_layer[i].flags = user_cfg->flags;
- cstate->dim_layer[i].stage = user_cfg->stage + SDE_STAGE_0;
- cstate->dim_layer[i].rect.x = user_cfg->rect.x1;
- cstate->dim_layer[i].rect.y = user_cfg->rect.y1;
- cstate->dim_layer[i].rect.w = user_cfg->rect.x2 -
- user_cfg->rect.x1 + 1;
- cstate->dim_layer[i].rect.h = user_cfg->rect.y2 -
- user_cfg->rect.y1 + 1;
+ dim_layer[i].flags = user_cfg->flags;
+ dim_layer[i].stage = user_cfg->stage + SDE_STAGE_0;
- cstate->dim_layer[i].color_fill = (struct sde_mdss_color) {
+ dim_layer[i].rect.x = user_cfg->rect.x1;
+ dim_layer[i].rect.y = user_cfg->rect.y1;
+ dim_layer[i].rect.w = user_cfg->rect.x2 - user_cfg->rect.x1;
+ dim_layer[i].rect.h = user_cfg->rect.y2 - user_cfg->rect.y1;
+
+ dim_layer[i].color_fill = (struct sde_mdss_color) {
user_cfg->color_fill.color_0,
user_cfg->color_fill.color_1,
user_cfg->color_fill.color_2,
user_cfg->color_fill.color_3,
};
+
+ SDE_DEBUG("dim_layer[%d] - flags:%d, stage:%d\n",
+ i, dim_layer[i].flags, dim_layer[i].stage);
+ SDE_DEBUG(" rect:{%d,%d,%d,%d}, color:{%d,%d,%d,%d}\n",
+ dim_layer[i].rect.x, dim_layer[i].rect.y,
+ dim_layer[i].rect.w, dim_layer[i].rect.h,
+ dim_layer[i].color_fill.color_0,
+ dim_layer[i].color_fill.color_1,
+ dim_layer[i].color_fill.color_2,
+ dim_layer[i].color_fill.color_3);
}
}
@@ -1696,6 +1827,23 @@
mutex_unlock(&sde_crtc->crtc_lock);
}
+static void _sde_crtc_setup_is_ppsplit(struct drm_crtc_state *state)
+{
+ int i;
+ struct sde_crtc_state *cstate;
+
+ cstate = to_sde_crtc_state(state);
+
+ cstate->is_ppsplit = false;
+ for (i = 0; i < cstate->num_connectors; i++) {
+ struct drm_connector *conn = cstate->connectors[i];
+
+ if (sde_connector_get_topology_name(conn) ==
+ SDE_RM_TOPOLOGY_PPSPLIT)
+ cstate->is_ppsplit = true;
+ }
+}
+
static void _sde_crtc_setup_lm_bounds(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
@@ -1760,6 +1908,7 @@
if (!sde_crtc->num_mixers) {
_sde_crtc_setup_mixers(crtc);
+ _sde_crtc_setup_is_ppsplit(crtc->state);
_sde_crtc_setup_lm_bounds(crtc, crtc->state);
}
@@ -2022,6 +2171,8 @@
struct sde_crtc *sde_crtc;
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
+ struct drm_event event;
+ u32 power_on;
if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
SDE_ERROR("invalid crtc\n");
@@ -2040,13 +2191,18 @@
mutex_lock(&sde_crtc->crtc_lock);
+ event.type = DRM_EVENT_CRTC_POWER;
+ event.length = sizeof(u32);
/*
* Update CP on suspend/resume transitions
*/
- if (enable && !sde_crtc->suspend)
+ if (enable && !sde_crtc->suspend) {
sde_cp_crtc_suspend(crtc);
- else if (!enable && sde_crtc->suspend)
+ power_on = 0;
+ } else if (!enable && sde_crtc->suspend) {
sde_cp_crtc_resume(crtc);
+ power_on = 1;
+ }
/*
* If the vblank refcount != 0, release a power reference on suspend
@@ -2059,7 +2215,8 @@
_sde_crtc_vblank_enable_nolock(sde_crtc, !enable);
sde_crtc->suspend = enable;
-
+ msm_mode_object_event_nofity(&crtc->base, crtc->dev, &event,
+ (u8 *)&power_on);
mutex_unlock(&sde_crtc->crtc_lock);
}
@@ -2474,6 +2631,7 @@
mixer_width = sde_crtc_mixer_width(sde_crtc, mode);
+ _sde_crtc_setup_is_ppsplit(state);
_sde_crtc_setup_lm_bounds(crtc, state);
/* get plane state for all drm planes associated with crtc state */
@@ -2496,9 +2654,10 @@
/* check dim layer stage with every plane */
for (i = 0; i < cstate->num_dim_layers; i++) {
if (pstates[cnt].stage == cstate->dim_layer[i].stage) {
- SDE_ERROR("plane%d/dimlayer in same stage:%d\n",
- plane->base.id,
- cstate->dim_layer[i].stage);
+ SDE_ERROR(
+ "plane:%d/dim_layer:%i-same stage:%d\n",
+ plane->base.id, i,
+ cstate->dim_layer[i].stage);
rc = -EINVAL;
goto end;
}
@@ -2769,16 +2928,18 @@
msm_property_install_blob(&sde_crtc->property_info, "capabilities",
DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO);
- if (catalog->has_dim_layer) {
- msm_property_install_volatile_range(&sde_crtc->property_info,
- "dim_layer_v1", 0x0, 0, ~0, 0, CRTC_PROP_DIM_LAYER_V1);
- }
-
msm_property_install_volatile_range(&sde_crtc->property_info,
"sde_drm_roi_v1", 0x0, 0, ~0, 0, CRTC_PROP_ROI_V1);
sde_kms_info_reset(info);
+ if (catalog->has_dim_layer) {
+ msm_property_install_volatile_range(&sde_crtc->property_info,
+ "dim_layer_v1", 0x0, 0, ~0, 0, CRTC_PROP_DIM_LAYER_V1);
+ sde_kms_info_add_keyint(info, "dim_layer_v1_max_layers",
+ SDE_MAX_DIM_LAYERS);
+ }
+
sde_kms_info_add_keyint(info, "hw_version", catalog->hwversion);
sde_kms_info_add_keyint(info, "max_linewidth",
catalog->max_mixer_width);
@@ -2978,6 +3139,7 @@
struct drm_display_mode *mode;
struct drm_framebuffer *fb;
struct drm_plane_state *state;
+ struct sde_crtc_state *cstate;
int i, out_width;
@@ -2986,6 +3148,7 @@
sde_crtc = s->private;
crtc = &sde_crtc->base;
+ cstate = to_sde_crtc_state(crtc->state);
mutex_lock(&sde_crtc->crtc_lock);
mode = &crtc->state->adjusted_mode;
@@ -3010,6 +3173,23 @@
seq_puts(s, "\n");
+ for (i = 0; i < cstate->num_dim_layers; i++) {
+ struct sde_hw_dim_layer *dim_layer = &cstate->dim_layer[i];
+
+ seq_printf(s, "\tdim_layer:%d] stage:%d flags:%d\n",
+ i, dim_layer->stage, dim_layer->flags);
+ seq_printf(s, "\tdst_x:%d dst_y:%d dst_w:%d dst_h:%d\n",
+ dim_layer->rect.x, dim_layer->rect.y,
+ dim_layer->rect.w, dim_layer->rect.h);
+ seq_printf(s,
+ "\tcolor_0:%d color_1:%d color_2:%d color_3:%d\n",
+ dim_layer->color_fill.color_0,
+ dim_layer->color_fill.color_1,
+ dim_layer->color_fill.color_2,
+ dim_layer->color_fill.color_3);
+ seq_puts(s, "\n");
+ }
+
drm_atomic_crtc_for_each_plane(plane, crtc) {
pstate = to_sde_plane_state(plane->state);
state = plane->state;
@@ -3054,6 +3234,11 @@
state->crtc_h);
seq_printf(s, "\tmultirect: mode: %d index: %d\n",
pstate->multirect_mode, pstate->multirect_index);
+
+ seq_printf(s, "\texcl_rect: x:%4d y:%4d w:%4d h:%4d\n",
+ pstate->excl_rect.x, pstate->excl_rect.y,
+ pstate->excl_rect.w, pstate->excl_rect.h);
+
seq_puts(s, "\n");
}
@@ -3615,3 +3800,9 @@
return ret;
}
+
+static int sde_crtc_power_interrupt_handler(struct drm_crtc *crtc_drm,
+ bool en, struct sde_irq_callback *irq)
+{
+ return 0;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 6a22115..9ef6f25 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -108,6 +108,8 @@
* @name : ASCII description of this crtc
* @num_ctls : Number of ctl paths in use
* @num_mixers : Number of mixers in use
+ * @mixers_swapped: Whether the mixers have been swapped for left/right update
+ * especially in the case of DSC Merge.
* @mixers : List of active mixers
* @event : Pointer to last received drm vblank event. If there is a
* pending vblank event, this will be non-null.
@@ -147,6 +149,7 @@
/* HW Resources reserved for the crtc */
u32 num_ctls;
u32 num_mixers;
+ bool mixers_swapped;
struct sde_crtc_mixer mixers[CRTC_DUAL_MIXERS];
struct drm_pending_vblank_event *event;
@@ -251,6 +254,7 @@
* @num_connectors: Number of associated drm connectors
* @intf_mode : Interface mode of the primary connector
* @rsc_client : sde rsc client when mode is valid
+ * @is_ppsplit : Whether current topology requires PPSplit special handling
* @crtc_roi : Current CRTC ROI. Possibly sub-rectangle of mode.
* Origin top left of CRTC.
* @lm_bounds : LM boundaries based on current mode full resolution, no ROI.
@@ -277,6 +281,7 @@
struct sde_rsc_client *rsc_client;
bool rsc_update;
+ bool is_ppsplit;
struct sde_rect crtc_roi;
struct sde_rect lm_bounds[CRTC_DUAL_MIXERS];
struct sde_rect lm_roi[CRTC_DUAL_MIXERS];
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index f11ba51..e3ad960 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -123,8 +123,11 @@
* @cur_master: Pointer to the current master in this mode. Optimization
* Only valid after enable. Cleared as disable.
* @hw_pp Handle to the pingpong blocks used for the display. No.
- * pingpong blocks can be different than num_phys_encs.
+ * pingpong blocks can be different than num_phys_encs.
* @hw_dsc: Array of DSC block handles used for the display.
+ * @intfs_swapped Whether or not the phys_enc interfaces have been swapped
+ * for partial update right-only cases, such as pingpong
+ * split where virtual pingpong does not generate IRQs
* @crtc_vblank_cb: Callback into the upper layer / CRTC for
* notification of the VBLANK
* @crtc_vblank_cb_data: Data from upper layer for VBLANK notification
@@ -155,6 +158,8 @@
* @topology: topology of the display
* @mode_set_complete: flag to indicate modeset completion
* @rsc_cfg: rsc configuration
+ * @cur_conn_roi: current connector roi
+ * @prv_conn_roi: previous connector roi to optimize if unchanged
*/
struct sde_encoder_virt {
struct drm_encoder base;
@@ -169,6 +174,8 @@
struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
+ bool intfs_swapped;
+
void (*crtc_vblank_cb)(void *);
void *crtc_vblank_cb_data;
@@ -195,17 +202,51 @@
bool mode_set_complete;
struct sde_encoder_rsc_config rsc_cfg;
+ struct sde_rect cur_conn_roi;
+ struct sde_rect prv_conn_roi;
};
#define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
-inline bool _sde_is_dsc_enabled(struct sde_encoder_virt *sde_enc)
+bool sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc)
+
{
- struct msm_compression_info *comp_info = &sde_enc->disp_info.comp_info;
+ struct sde_encoder_virt *sde_enc;
+ struct msm_compression_info *comp_info;
+
+ if (!drm_enc)
+ return false;
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+ comp_info = &sde_enc->disp_info.comp_info;
return (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC);
}
+bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc)
+{
+ enum sde_rm_topology_name topology;
+ struct sde_encoder_virt *sde_enc;
+ struct drm_connector *drm_conn;
+
+ if (!drm_enc)
+ return false;
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+ if (!sde_enc->cur_master)
+ return false;
+
+ drm_conn = sde_enc->cur_master->connector;
+ if (!drm_conn)
+ return false;
+
+ topology = sde_connector_get_topology_name(drm_conn);
+ if (topology == SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE)
+ return true;
+
+ return false;
+}
+
static inline int _sde_encoder_power_enable(struct sde_encoder_virt *sde_enc,
bool enable)
{
@@ -320,7 +361,22 @@
sde_enc = to_sde_encoder_virt(phys_enc->parent);
hw_mdptop = phys_enc->hw_mdptop;
- cfg.en = phys_enc->split_role != ENC_ROLE_SOLO;
+
+ /**
+ * disable split modes since encoder will be operating in as the only
+ * encoder, either for the entire use case in the case of, for example,
+ * single DSI, or for this frame in the case of left/right only partial
+ * update.
+ */
+ if (phys_enc->split_role == ENC_ROLE_SOLO) {
+ if (hw_mdptop->ops.setup_split_pipe)
+ hw_mdptop->ops.setup_split_pipe(hw_mdptop, &cfg);
+ if (hw_mdptop->ops.setup_pp_split)
+ hw_mdptop->ops.setup_pp_split(hw_mdptop, &cfg);
+ return;
+ }
+
+ cfg.en = true;
cfg.mode = phys_enc->intf_mode;
cfg.intf = interface;
@@ -334,8 +390,7 @@
else
cfg.pp_split_slave = INTF_MAX;
- if (phys_enc->split_role != ENC_ROLE_SLAVE) {
- /* master/solo encoder */
+ if (phys_enc->split_role == ENC_ROLE_MASTER) {
SDE_DEBUG_ENC(sde_enc, "enable %d\n", cfg.en);
if (hw_mdptop->ops.setup_split_pipe)
@@ -555,8 +610,14 @@
static void _sde_encoder_dsc_pipe_cfg(struct sde_hw_dsc *hw_dsc,
struct sde_hw_pingpong *hw_pp, struct msm_display_dsc_info *dsc,
- u32 common_mode, bool ich_reset)
+ u32 common_mode, bool ich_reset, bool enable)
{
+ if (!enable) {
+ if (hw_pp->ops.disable_dsc)
+ hw_pp->ops.disable_dsc(hw_pp);
+ return;
+ }
+
if (hw_dsc->ops.dsc_config)
hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, ich_reset);
@@ -570,9 +631,27 @@
hw_pp->ops.enable_dsc(hw_pp);
}
+static void _sde_encoder_get_connector_roi(
+ struct sde_encoder_virt *sde_enc,
+ struct sde_rect *merged_conn_roi)
+{
+ struct drm_connector *drm_conn;
+ struct sde_connector_state *c_state;
+
+ if (!sde_enc || !merged_conn_roi)
+ return;
+
+ drm_conn = sde_enc->phys_encs[0]->connector;
+
+ if (!drm_conn || !drm_conn->state)
+ return;
+
+ c_state = to_sde_connector_state(drm_conn->state);
+ sde_kms_rect_merge_rectangles(&c_state->rois, merged_conn_roi);
+}
+
static int _sde_encoder_dsc_1_lm_1_enc_1_intf(struct sde_encoder_virt *sde_enc)
{
- int pic_width, pic_height;
int this_frame_slices;
int intf_ip_w, enc_ip_w;
int ich_res, dsc_common_mode = 0;
@@ -580,22 +659,18 @@
struct sde_hw_pingpong *hw_pp = sde_enc->hw_pp[0];
struct sde_hw_dsc *hw_dsc = sde_enc->hw_dsc[0];
struct sde_encoder_phys *enc_master = sde_enc->cur_master;
- struct sde_hw_mdp *hw_mdp_top = enc_master->hw_mdptop;
+ const struct sde_rect *roi = &sde_enc->cur_conn_roi;
struct msm_display_dsc_info *dsc =
&sde_enc->disp_info.comp_info.dsc_info;
- if (dsc == NULL || hw_dsc == NULL || hw_pp == NULL ||
- hw_mdp_top == NULL) {
+ if (dsc == NULL || hw_dsc == NULL || hw_pp == NULL || !enc_master) {
SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
return -EINVAL;
}
- pic_width = dsc->pic_width;
- pic_height = dsc->pic_height;
+ _sde_encoder_dsc_update_pic_dim(dsc, roi->w, roi->h);
- _sde_encoder_dsc_update_pic_dim(dsc, pic_width, pic_height);
-
- this_frame_slices = pic_width / dsc->slice_width;
+ this_frame_slices = roi->w / dsc->slice_width;
intf_ip_w = this_frame_slices * dsc->slice_width;
_sde_encoder_dsc_pclk_param_calc(dsc, intf_ip_w);
@@ -608,132 +683,208 @@
dsc_common_mode = DSC_MODE_VIDEO;
SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n",
- pic_width, pic_height, dsc_common_mode);
- SDE_EVT32(DRMID(&sde_enc->base), pic_width, pic_height,
- dsc_common_mode);
+ roi->w, roi->h, dsc_common_mode);
+ SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h, dsc_common_mode);
_sde_encoder_dsc_pipe_cfg(hw_dsc, hw_pp, dsc, dsc_common_mode,
- ich_res);
+ ich_res, true);
return 0;
}
-static int _sde_encoder_dsc_2_lm_2_enc_2_intf(struct sde_encoder_virt *sde_enc)
+static int _sde_encoder_dsc_2_lm_2_enc_2_intf(struct sde_encoder_virt *sde_enc,
+ struct sde_encoder_kickoff_params *params)
{
- int pic_width, pic_height;
int this_frame_slices;
int intf_ip_w, enc_ip_w;
int ich_res, dsc_common_mode;
struct sde_encoder_phys *enc_master = sde_enc->cur_master;
- struct sde_hw_dsc *l_hw_dsc = sde_enc->hw_dsc[0];
- struct sde_hw_dsc *r_hw_dsc = sde_enc->hw_dsc[1];
- struct sde_hw_pingpong *l_hw_pp = sde_enc->hw_pp[0];
- struct sde_hw_pingpong *r_hw_pp = sde_enc->hw_pp[1];
- struct sde_hw_mdp *hw_mdp_top = enc_master->hw_mdptop;
- struct msm_display_dsc_info *dsc =
- &sde_enc->disp_info.comp_info.dsc_info;
+ const struct sde_rect *roi = &sde_enc->cur_conn_roi;
+ struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
+ struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
+ struct msm_display_dsc_info dsc[MAX_CHANNELS_PER_ENC];
+ bool half_panel_partial_update;
+ int i;
- if (l_hw_dsc == NULL || r_hw_dsc == NULL || hw_mdp_top == NULL ||
- l_hw_pp == NULL || r_hw_pp == NULL) {
- SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
- return -EINVAL;
+ for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
+ hw_pp[i] = sde_enc->hw_pp[i];
+ hw_dsc[i] = sde_enc->hw_dsc[i];
+
+ if (!hw_pp[i] || !hw_dsc[i]) {
+ SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
+ return -EINVAL;
+ }
}
- pic_width = dsc->pic_width * sde_enc->display_num_of_h_tiles;
- pic_height = dsc->pic_height;
+ half_panel_partial_update =
+ hweight_long(params->affected_displays) == 1;
- _sde_encoder_dsc_update_pic_dim(dsc, pic_width, pic_height);
-
- this_frame_slices = pic_width / dsc->slice_width;
- intf_ip_w = this_frame_slices * dsc->slice_width;
-
- intf_ip_w /= 2;
- _sde_encoder_dsc_pclk_param_calc(dsc, intf_ip_w);
-
- enc_ip_w = intf_ip_w;
- _sde_encoder_dsc_initial_line_calc(dsc, enc_ip_w);
-
- ich_res = _sde_encoder_dsc_ich_reset_override_needed(false, dsc);
-
- dsc_common_mode = DSC_MODE_SPLIT_PANEL;
+ dsc_common_mode = 0;
+ if (!half_panel_partial_update)
+ dsc_common_mode |= DSC_MODE_SPLIT_PANEL;
if (enc_master->intf_mode == INTF_MODE_VIDEO)
dsc_common_mode |= DSC_MODE_VIDEO;
- SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n",
- pic_width, pic_height, dsc_common_mode);
- SDE_EVT32(DRMID(&sde_enc->base), pic_width, pic_height,
- dsc_common_mode);
+ memcpy(&dsc[0], &sde_enc->disp_info.comp_info.dsc_info, sizeof(dsc[0]));
+ memcpy(&dsc[1], &sde_enc->disp_info.comp_info.dsc_info, sizeof(dsc[1]));
- _sde_encoder_dsc_pipe_cfg(l_hw_dsc, l_hw_pp, dsc, dsc_common_mode,
- ich_res);
- _sde_encoder_dsc_pipe_cfg(r_hw_dsc, r_hw_pp, dsc, dsc_common_mode,
- ich_res);
+ /*
+ * Since both DSC use same pic dimension, set same pic dimension
+ * to both DSC structures.
+ */
+ _sde_encoder_dsc_update_pic_dim(&dsc[0], roi->w, roi->h);
+ _sde_encoder_dsc_update_pic_dim(&dsc[1], roi->w, roi->h);
+
+ this_frame_slices = roi->w / dsc[0].slice_width;
+ intf_ip_w = this_frame_slices * dsc[0].slice_width;
+
+ if (!half_panel_partial_update)
+ intf_ip_w /= 2;
+
+ /*
+ * In this topology when both interfaces are active, they have same
+ * load so intf_ip_w will be same.
+ */
+ _sde_encoder_dsc_pclk_param_calc(&dsc[0], intf_ip_w);
+ _sde_encoder_dsc_pclk_param_calc(&dsc[1], intf_ip_w);
+
+ /*
+ * In this topology, since there is no dsc_merge, uncompressed input
+ * to encoder and interface is same.
+ */
+ enc_ip_w = intf_ip_w;
+ _sde_encoder_dsc_initial_line_calc(&dsc[0], enc_ip_w);
+ _sde_encoder_dsc_initial_line_calc(&dsc[1], enc_ip_w);
+
+ /*
+ * __is_ich_reset_override_needed should be called only after
+ * updating pic dimension, mdss_panel_dsc_update_pic_dim.
+ */
+ ich_res = _sde_encoder_dsc_ich_reset_override_needed(
+ half_panel_partial_update, &dsc[0]);
+
+ SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n",
+ roi->w, roi->h, dsc_common_mode);
+
+ for (i = 0; i < sde_enc->num_phys_encs; i++) {
+ bool active = !!((1 << i) & params->affected_displays);
+
+ SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h,
+ dsc_common_mode, i, active);
+ _sde_encoder_dsc_pipe_cfg(hw_dsc[i], hw_pp[i], &dsc[i],
+ dsc_common_mode, ich_res, active);
+ }
return 0;
}
-static int _sde_encoder_dsc_2_lm_2_enc_1_intf(struct sde_encoder_virt *sde_enc)
+static int _sde_encoder_dsc_2_lm_2_enc_1_intf(struct sde_encoder_virt *sde_enc,
+ struct sde_encoder_kickoff_params *params)
{
- int pic_width, pic_height;
int this_frame_slices;
int intf_ip_w, enc_ip_w;
int ich_res, dsc_common_mode;
struct sde_encoder_phys *enc_master = sde_enc->cur_master;
- struct sde_hw_dsc *l_hw_dsc = sde_enc->hw_dsc[0];
- struct sde_hw_dsc *r_hw_dsc = sde_enc->hw_dsc[1];
- struct sde_hw_pingpong *l_hw_pp = sde_enc->hw_pp[0];
- struct sde_hw_pingpong *r_hw_pp = sde_enc->hw_pp[1];
- struct sde_hw_mdp *hw_mdp_top = enc_master->hw_mdptop;
+ const struct sde_rect *roi = &sde_enc->cur_conn_roi;
+ struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
+ struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
struct msm_display_dsc_info *dsc =
&sde_enc->disp_info.comp_info.dsc_info;
+ bool half_panel_partial_update;
+ int i;
- if (l_hw_dsc == NULL || r_hw_dsc == NULL || hw_mdp_top == NULL ||
- l_hw_pp == NULL || r_hw_pp == NULL) {
- SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
- return -EINVAL;
+ for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
+ hw_pp[i] = sde_enc->hw_pp[i];
+ hw_dsc[i] = sde_enc->hw_dsc[i];
+
+ if (!hw_pp[i] || !hw_dsc[i]) {
+ SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
+ return -EINVAL;
+ }
}
- pic_width = dsc->pic_width;
- pic_height = dsc->pic_height;
- _sde_encoder_dsc_update_pic_dim(dsc, pic_width, pic_height);
+ half_panel_partial_update =
+ hweight_long(params->affected_displays) == 1;
- this_frame_slices = pic_width / dsc->slice_width;
+ dsc_common_mode = 0;
+ if (!half_panel_partial_update)
+ dsc_common_mode |= DSC_MODE_SPLIT_PANEL | DSC_MODE_MULTIPLEX;
+ if (enc_master->intf_mode == INTF_MODE_VIDEO)
+ dsc_common_mode |= DSC_MODE_VIDEO;
+
+ _sde_encoder_dsc_update_pic_dim(dsc, roi->w, roi->h);
+
+ this_frame_slices = roi->w / dsc->slice_width;
intf_ip_w = this_frame_slices * dsc->slice_width;
_sde_encoder_dsc_pclk_param_calc(dsc, intf_ip_w);
/*
- * when using 2 encoders for the same stream, no. of slices
- * need to be same on both the encoders.
+ * dsc merge case: when using 2 encoders for the same stream,
+ * no. of slices need to be same on both the encoders.
*/
enc_ip_w = intf_ip_w / 2;
_sde_encoder_dsc_initial_line_calc(dsc, enc_ip_w);
- ich_res = _sde_encoder_dsc_ich_reset_override_needed(false, dsc);
-
- dsc_common_mode = DSC_MODE_MULTIPLEX | DSC_MODE_SPLIT_PANEL;
- if (enc_master->intf_mode == INTF_MODE_VIDEO)
- dsc_common_mode |= DSC_MODE_VIDEO;
+ ich_res = _sde_encoder_dsc_ich_reset_override_needed(
+ half_panel_partial_update, dsc);
SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n",
- pic_width, pic_height, dsc_common_mode);
- SDE_EVT32(DRMID(&sde_enc->base), pic_width, pic_height,
- dsc_common_mode);
+ roi->w, roi->h, dsc_common_mode);
+ SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h,
+ dsc_common_mode, i, params->affected_displays);
- _sde_encoder_dsc_pipe_cfg(l_hw_dsc, l_hw_pp, dsc, dsc_common_mode,
- ich_res);
- _sde_encoder_dsc_pipe_cfg(r_hw_dsc, r_hw_pp, dsc, dsc_common_mode,
- ich_res);
+ _sde_encoder_dsc_pipe_cfg(hw_dsc[0], hw_pp[0], dsc, dsc_common_mode,
+ ich_res, true);
+ _sde_encoder_dsc_pipe_cfg(hw_dsc[1], hw_pp[1], dsc, dsc_common_mode,
+ ich_res, !half_panel_partial_update);
return 0;
}
-static int _sde_encoder_dsc_setup(struct sde_encoder_virt *sde_enc)
+static int _sde_encoder_update_roi(struct drm_encoder *drm_enc)
+{
+ struct sde_encoder_virt *sde_enc;
+ struct drm_connector *drm_conn;
+ struct drm_display_mode *adj_mode;
+ struct sde_rect roi;
+
+ if (!drm_enc || !drm_enc->crtc || !drm_enc->crtc->state)
+ return -EINVAL;
+ sde_enc = to_sde_encoder_virt(drm_enc);
+
+ if (!sde_enc->cur_master)
+ return -EINVAL;
+
+ adj_mode = &sde_enc->base.crtc->state->adjusted_mode;
+ drm_conn = sde_enc->cur_master->connector;
+
+ _sde_encoder_get_connector_roi(sde_enc, &roi);
+ if (sde_kms_rect_is_null(&roi)) {
+ roi.w = adj_mode->hdisplay;
+ roi.h = adj_mode->vdisplay;
+ }
+
+ memcpy(&sde_enc->prv_conn_roi, &sde_enc->cur_conn_roi,
+ sizeof(sde_enc->prv_conn_roi));
+ memcpy(&sde_enc->cur_conn_roi, &roi, sizeof(sde_enc->cur_conn_roi));
+
+ return 0;
+}
+
+static int _sde_encoder_dsc_setup(struct sde_encoder_virt *sde_enc,
+ struct sde_encoder_kickoff_params *params)
{
enum sde_rm_topology_name topology;
- struct drm_connector *drm_conn = sde_enc->phys_encs[0]->connector;
+ struct drm_connector *drm_conn;
int ret = 0;
+ if (!sde_enc || !params || !sde_enc->phys_encs[0] ||
+ !sde_enc->phys_encs[0]->connector)
+ return -EINVAL;
+
+ drm_conn = sde_enc->phys_encs[0]->connector;
+
topology = sde_connector_get_topology_name(drm_conn);
if (topology == SDE_RM_TOPOLOGY_NONE) {
SDE_ERROR_ENC(sde_enc, "topology not set yet\n");
@@ -743,15 +894,19 @@
SDE_DEBUG_ENC(sde_enc, "\n");
SDE_EVT32(DRMID(&sde_enc->base));
+ if (sde_kms_rect_is_equal(&sde_enc->cur_conn_roi,
+ &sde_enc->prv_conn_roi))
+ return ret;
+
switch (topology) {
case SDE_RM_TOPOLOGY_SINGLEPIPE_DSC:
ret = _sde_encoder_dsc_1_lm_1_enc_1_intf(sde_enc);
break;
case SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE:
- ret = _sde_encoder_dsc_2_lm_2_enc_1_intf(sde_enc);
+ ret = _sde_encoder_dsc_2_lm_2_enc_1_intf(sde_enc, params);
break;
case SDE_RM_TOPOLOGY_DUALPIPE_DSC:
- ret = _sde_encoder_dsc_2_lm_2_enc_2_intf(sde_enc);
+ ret = _sde_encoder_dsc_2_lm_2_enc_2_intf(sde_enc, params);
break;
default:
SDE_ERROR_ENC(sde_enc, "No DSC support for topology %d",
@@ -1217,7 +1372,6 @@
struct sde_kms *sde_kms;
struct sde_hw_mdp *hw_mdptop;
int i = 0;
- int ret = 0;
struct sde_watchdog_te_status te_cfg = { 0 };
if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) {
@@ -1252,12 +1406,6 @@
sde_enc->cur_master->hw_mdptop,
sde_kms->catalog);
- if (_sde_is_dsc_enabled(sde_enc)) {
- ret = _sde_encoder_dsc_setup(sde_enc);
- if (ret)
- SDE_ERROR_ENC(sde_enc, "failed to setup DSC:%d\n", ret);
- }
-
if (hw_mdptop->ops.setup_vsync_sel) {
for (i = 0; i < sde_enc->num_phys_encs; i++)
te_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx;
@@ -1763,6 +1911,65 @@
spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags);
}
+static void _sde_encoder_ppsplit_swap_intf_for_right_only_update(
+ struct drm_encoder *drm_enc,
+ unsigned long *affected_displays,
+ int num_active_phys)
+{
+ struct sde_encoder_virt *sde_enc;
+ struct sde_encoder_phys *master;
+ enum sde_rm_topology_name topology;
+ bool is_right_only;
+
+ if (!drm_enc || !affected_displays)
+ return;
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+ master = sde_enc->cur_master;
+ if (!master || !master->connector)
+ return;
+
+ topology = sde_connector_get_topology_name(master->connector);
+ if (topology != SDE_RM_TOPOLOGY_PPSPLIT)
+ return;
+
+ /*
+ * For pingpong split, the slave pingpong won't generate IRQs. For
+ * right-only updates, we can't swap pingpongs, or simply swap the
+ * master/slave assignment, we actually have to swap the interfaces
+ * so that the master physical encoder will use a pingpong/interface
+ * that generates irqs on which to wait.
+ */
+ is_right_only = !test_bit(0, affected_displays) &&
+ test_bit(1, affected_displays);
+
+ if (is_right_only && !sde_enc->intfs_swapped) {
+ /* right-only update swap interfaces */
+ swap(sde_enc->phys_encs[0]->intf_idx,
+ sde_enc->phys_encs[1]->intf_idx);
+ sde_enc->intfs_swapped = true;
+ } else if (!is_right_only && sde_enc->intfs_swapped) {
+ /* left-only or full update, swap back */
+ swap(sde_enc->phys_encs[0]->intf_idx,
+ sde_enc->phys_encs[1]->intf_idx);
+ sde_enc->intfs_swapped = false;
+ }
+
+ SDE_DEBUG_ENC(sde_enc,
+ "right_only %d swapped %d phys0->intf%d, phys1->intf%d\n",
+ is_right_only, sde_enc->intfs_swapped,
+ sde_enc->phys_encs[0]->intf_idx - INTF_0,
+ sde_enc->phys_encs[1]->intf_idx - INTF_0);
+ SDE_EVT32(DRMID(drm_enc), is_right_only, sde_enc->intfs_swapped,
+ sde_enc->phys_encs[0]->intf_idx - INTF_0,
+ sde_enc->phys_encs[1]->intf_idx - INTF_0,
+ *affected_displays);
+
+ /* ppsplit always uses master since ppslave invalid for irqs*/
+ if (num_active_phys == 1)
+ *affected_displays = BIT(0);
+}
+
static void _sde_encoder_update_master(struct drm_encoder *drm_enc,
struct sde_encoder_kickoff_params *params)
{
@@ -1785,6 +1992,10 @@
SDE_DEBUG_ENC(sde_enc, "affected_displays 0x%lx num_active_phys %d\n",
params->affected_displays, num_active_phys);
+ /* for left/right only update, ppsplit master switches interface */
+ _sde_encoder_ppsplit_swap_intf_for_right_only_update(drm_enc,
+ ¶ms->affected_displays, num_active_phys);
+
for (i = 0; i < sde_enc->num_phys_encs; i++) {
enum sde_enc_split_role prv_role, new_role;
bool active;
@@ -1814,6 +2025,9 @@
SDE_DEBUG_ENC(sde_enc, "pp %d role prv %d new %d active %d\n",
phys->hw_pp->idx - PINGPONG_0, prv_role,
phys->split_role, active);
+ SDE_EVT32(DRMID(drm_enc), params->affected_displays,
+ phys->hw_pp->idx - PINGPONG_0, prv_role,
+ phys->split_role, active, num_active_phys);
}
}
@@ -1892,6 +2106,8 @@
_sde_encoder_update_master(drm_enc, params);
+ _sde_encoder_update_roi(drm_enc);
+
if (sde_enc->cur_master && sde_enc->cur_master->connector) {
rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector);
if (rc)
@@ -1899,6 +2115,12 @@
sde_enc->cur_master->connector->base.id,
rc);
}
+
+ if (sde_encoder_is_dsc_enabled(drm_enc)) {
+ rc = _sde_encoder_dsc_setup(sde_enc, params);
+ if (rc)
+ SDE_ERROR_ENC(sde_enc, "failed to setup DSC: %d\n", rc);
+ }
}
void sde_encoder_kickoff(struct drm_encoder *drm_enc)
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index 7292a12..6ef245b 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -149,6 +149,20 @@
void sde_encoder_virt_restore(struct drm_encoder *encoder);
/**
+ * sde_encoder_is_dsc_enabled - check if encoder is in DSC mode
+ * @drm_enc: Pointer to drm encoder object
+ * @Return: true if encoder is in DSC mode
+ */
+bool sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc);
+
+/**
+ * sde_encoder_is_dsc_merge - check if encoder is in DSC merge mode
+ * @drm_enc: Pointer to drm encoder object
+ * @Return: true if encoder is in DSC merge mode
+ */
+bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc);
+
+/**
* sde_encoder_init - initialize virtual encoder object
* @dev: Pointer to drm device structure
* @disp_info: Pointer to display information structure
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 572bd9e..53f5b89 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -615,7 +615,8 @@
phys_enc->hw_pp->idx - PINGPONG_0);
drm_mode_debug_printmodeline(&phys_enc->cached_mode);
- _sde_encoder_phys_cmd_update_intf_cfg(phys_enc);
+ if (!_sde_encoder_phys_is_ppsplit_slave(phys_enc))
+ _sde_encoder_phys_cmd_update_intf_cfg(phys_enc);
sde_encoder_phys_cmd_tearcheck_config(phys_enc);
}
@@ -832,15 +833,28 @@
struct sde_encoder_phys *phys_enc,
enum sde_enc_split_role role)
{
- struct sde_encoder_phys_cmd *cmd_enc =
- to_sde_encoder_phys_cmd(phys_enc);
- enum sde_enc_split_role old_role = phys_enc->split_role;
+ struct sde_encoder_phys_cmd *cmd_enc;
+ enum sde_enc_split_role old_role;
+ bool is_ppsplit;
+
+ if (!phys_enc)
+ return;
+
+ cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
+ old_role = phys_enc->split_role;
+ is_ppsplit = _sde_encoder_phys_is_ppsplit(phys_enc);
+
+ phys_enc->split_role = role;
SDE_DEBUG_CMDENC(cmd_enc, "old role %d new role %d\n",
old_role, role);
- phys_enc->split_role = role;
- if (role == ENC_ROLE_SKIP || role == old_role)
+ /*
+ * ppsplit solo needs to reprogram because intf may have swapped without
+ * role changing on left-only, right-only back-to-back commits
+ */
+ if (!(is_ppsplit && role == ENC_ROLE_SOLO) &&
+ (role == old_role || role == ENC_ROLE_SKIP))
return;
sde_encoder_helper_split_config(phys_enc, phys_enc->intf_idx);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
index 28479ab..8f7764d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
@@ -21,6 +21,7 @@
#define GAMUT_MAP_EN BIT(1)
#define GAMUT_EN BIT(0)
#define GAMUT_MODE_13B_OFF 640
+#define GAMUT_MODE_5_OFF 1248
enum {
gamut_mode_17 = 0,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
index 5719c51..0dcbb7e 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
@@ -347,10 +347,9 @@
break;
case GAMUT_3D_MODE_5:
*tbl_len = GAMUT_3D_MODE5_TBL_SZ * sizeof(u32) * 2;
- *tbl_off = 0;
+ *tbl_off = GAMUT_MODE_5_OFF;
*scale_off = GAMUT_SCALEB_OFFSET_OFF;
*opcode = gamut_mode_5 << 2;
- *opcode |= GAMUT_MAP_EN;
break;
case GAMUT_3D_MODE_13:
*tbl_len = GAMUT_3D_MODE13_TBL_SZ * sizeof(u32) * 2;
@@ -364,7 +363,6 @@
*scale_off = (*opcode == gamut_mode_13a) ?
GAMUT_SCALEA_OFFSET_OFF : GAMUT_SCALEB_OFFSET_OFF;
*opcode <<= 2;
- *opcode |= GAMUT_MAP_EN;
break;
default:
rc = -EINVAL;
@@ -377,6 +375,45 @@
return rc;
}
+static void dspp_3d_gamutv4_off(struct sde_hw_dspp *ctx, void *cfg)
+{
+ struct sde_reg_dma_kickoff_cfg kick_off;
+ struct sde_hw_cp_cfg *hw_cfg = cfg;
+ u32 op_mode;
+ struct sde_hw_reg_dma_ops *dma_ops;
+ struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
+ int rc;
+
+ dma_ops = sde_reg_dma_get_ops();
+ dma_ops->reset_reg_dma_buf(dspp_buf[GAMUT][ctx->idx]);
+
+ REG_DMA_INIT_OPS(dma_write_cfg, dspp_mapping[ctx->idx], GAMUT,
+ dspp_buf[GAMUT][ctx->idx]);
+
+ REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("write decode select failed ret %d\n", rc);
+ return;
+ }
+
+ REG_DMA_SETUP_OPS(dma_write_cfg,
+ ctx->cap->sblk->gamut.base,
+ &op_mode, sizeof(op_mode), REG_SINGLE_WRITE, 0, 0);
+ rc = dma_ops->setup_payload(&dma_write_cfg);
+ if (rc) {
+ DRM_ERROR("opmode write single reg failed ret %d\n", rc);
+ return;
+ }
+
+ REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[GAMUT][ctx->idx],
+ REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE);
+ kick_off.last_command = hw_cfg->last_feature;
+ rc = dma_ops->kick_off(&kick_off);
+ if (rc)
+ DRM_ERROR("failed to kick off ret %d\n", rc);
+}
+
void reg_dmav1_setup_dspp_3d_gamutv4(struct sde_hw_dspp *ctx, void *cfg)
{
struct drm_msm_3d_gamut *payload;
@@ -394,7 +431,7 @@
op_mode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->gamut.base);
if (!hw_cfg->payload) {
DRM_DEBUG_DRIVER("disable gamut feature\n");
- SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->gamut.base, 0);
+ dspp_3d_gamutv4_off(ctx, cfg);
return;
}
@@ -436,7 +473,7 @@
}
REG_DMA_SETUP_OPS(dma_write_cfg,
ctx->cap->sblk->gamut.base + GAMUT_LOWER_COLOR_OFF,
- &payload->col[i][0].c0, tbl_len,
+ &payload->col[i][0].c2_c1, tbl_len,
REG_BLK_WRITE_MULTIPLE, 2, 0);
rc = dma_ops->setup_payload(&dma_write_cfg);
if (rc) {
diff --git a/drivers/gpu/drm/msm/sde/sde_kms_utils.c b/drivers/gpu/drm/msm/sde/sde_kms_utils.c
index dcc0bd5..b77d64d 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms_utils.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms_utils.c
@@ -166,7 +166,7 @@
r = min((r1->x + r1->w), (r2->x + r2->w));
b = min((r1->y + r1->h), (r2->y + r2->h));
- if (r < l || b < t) {
+ if (r <= l || b <= t) {
memset(result, 0, sizeof(*result));
} else {
result->x = l;
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index ed16a0d..1721c67 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -2464,7 +2464,7 @@
pstate->excl_rect.h != old_pstate->excl_rect.h ||
pstate->excl_rect.x != old_pstate->excl_rect.x ||
pstate->excl_rect.y != old_pstate->excl_rect.y) {
- SDE_DEBUG_PLANE(psde, "excl rect updated\n");
+ SDE_DEBUG_PLANE(psde, "excl_rect updated\n");
pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
}
@@ -2677,6 +2677,9 @@
(char *)&fmt->base.pixel_format);
ret = -EINVAL;
}
+ SDE_DEBUG_PLANE(psde, "excl_rect: {%d,%d,%d,%d}\n",
+ pstate->excl_rect.x, pstate->excl_rect.y,
+ pstate->excl_rect.w, pstate->excl_rect.h);
}
modeset_update:
@@ -3502,20 +3505,24 @@
}
if (!usr_ptr) {
- SDE_DEBUG_PLANE(psde, "excl rect data removed\n");
+ SDE_DEBUG_PLANE(psde, "invalid excl_rect user data\n");
return;
}
if (copy_from_user(&excl_rect_v1, usr_ptr, sizeof(excl_rect_v1))) {
- SDE_ERROR_PLANE(psde, "failed to copy excl rect data\n");
+ SDE_ERROR_PLANE(psde, "failed to copy excl_rect data\n");
return;
}
/* populate from user space */
pstate->excl_rect.x = excl_rect_v1.x1;
pstate->excl_rect.y = excl_rect_v1.y1;
- pstate->excl_rect.w = excl_rect_v1.x2 - excl_rect_v1.x1 + 1;
- pstate->excl_rect.h = excl_rect_v1.y2 - excl_rect_v1.y1 + 1;
+ pstate->excl_rect.w = excl_rect_v1.x2 - excl_rect_v1.x1;
+ pstate->excl_rect.h = excl_rect_v1.y2 - excl_rect_v1.y1;
+
+ SDE_DEBUG_PLANE(psde, "excl_rect: {%d,%d,%d,%d}\n",
+ pstate->excl_rect.x, pstate->excl_rect.y,
+ pstate->excl_rect.w, pstate->excl_rect.h);
}
static int sde_plane_atomic_set_property(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/msm/sde_power_handle.h b/drivers/gpu/drm/msm/sde_power_handle.h
index da68139..38bf21f 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.h
+++ b/drivers/gpu/drm/msm/sde_power_handle.h
@@ -16,9 +16,9 @@
#define MAX_CLIENT_NAME_LEN 128
-#define SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA 2000000
+#define SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA 6000000000
#define SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA 0
-#define SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA 2000000
+#define SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA 6000000000
#define SDE_POWER_HANDLE_DISABLE_BUS_IB_QUOTA 0
#include <linux/sde_io_util.h>
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index bf3a91a..2e92335 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1509,8 +1509,7 @@
PERFCOUNTER_FLAG_KERNEL);
if (ret) {
- KGSL_DRV_ERR(device,
- "Unable to get the perf counters for DCVS\n");
+ WARN_ONCE(1, "Unable to get perf counters for DCVS\n");
adreno_dev->perfctr_pwr_lo = 0;
}
}
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index d04ddb0..e157e7b 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -813,12 +813,12 @@
t = jiffies + msecs_to_jiffies(timeout);
- while (!time_after(jiffies, t)) {
+ do {
kgsl_gmu_regread(device, offset, &value);
if ((value & mask) == expected_ret)
return 0;
cpu_relax();
- }
+ } while (!time_after(jiffies, t));
return -EINVAL;
}
@@ -952,7 +952,7 @@
int ret = 0;
if (!kgsl_gmu_isenabled(device))
- return -ENODEV;
+ return 0;
kgsl_gmu_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, set_mask);
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index 63dbde0..17ee6e6 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -640,6 +640,9 @@
unsigned int *data = (unsigned int *)(buf + sizeof(*header));
int i, j;
+ if (!device->snapshot_legacy)
+ return 0;
+
if (remain < sizeof(*header)) {
SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
return 0;
@@ -748,6 +751,9 @@
unsigned int read_sel;
int i, j;
+ if (!device->snapshot_legacy)
+ return 0;
+
/* Figure out how many registers we are going to dump */
for (i = 0; i < regs->num_sets; i++) {
int start = regs->regs[i * 2];
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 876b668..be379e3 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -291,6 +291,8 @@
/* Use CP Crash dumper to get GPU snapshot*/
bool snapshot_crashdumper;
+ /* Use HOST side register reads to get GPU snapshot*/
+ bool snapshot_legacy;
struct kobject snapshot_kobj;
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 54659fc..8de1a7e 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1438,7 +1438,7 @@
if (hfi->hfi_interrupt_num) {
devm_free_irq(&gmu->pdev->dev,
- hfi->hfi_interrupt_num, gmu);
+ hfi->hfi_interrupt_num, hfi);
hfi->hfi_interrupt_num = 0;
}
diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c
index 30e1d7c..b05e18d 100644
--- a/drivers/gpu/msm/kgsl_hfi.c
+++ b/drivers/gpu/msm/kgsl_hfi.c
@@ -573,44 +573,41 @@
if (result)
return result;
- if (boot_state == GMU_COLD_BOOT) {
- major = adreno_dev->gpucore->gpmu_major;
- minor = adreno_dev->gpucore->gpmu_minor;
+ major = adreno_dev->gpucore->gpmu_major;
+ minor = adreno_dev->gpucore->gpmu_minor;
+ result = hfi_get_fw_version(gmu,
+ FW_VERSION(major, minor), &ver);
+ if (result)
+ dev_err(dev, "Failed to get FW version via HFI\n");
- result = hfi_get_fw_version(gmu,
- FW_VERSION(major, minor), &ver);
- if (result)
- dev_err(dev, "Failed to get FW version via HFI\n");
+ gmu->ver = ver;
+ if (major != FW_VER_MAJOR(ver))
+ dev_err(dev, "FW version major %d error (expect %d)\n",
+ FW_VER_MAJOR(ver),
+ adreno_dev->gpucore->gpmu_major);
- gmu->ver = ver;
- if (major != FW_VER_MAJOR(ver))
- dev_err(dev, "FW version major %d error (expect %d)\n",
- FW_VER_MAJOR(ver),
- adreno_dev->gpucore->gpmu_major);
+ if (minor > FW_VER_MINOR(ver))
+ dev_err(dev, "FW version minor %d error (expect %d)\n",
+ FW_VER_MINOR(ver),
+ adreno_dev->gpucore->gpmu_minor);
- if (minor > FW_VER_MINOR(ver))
- dev_err(dev, "FW version minor %d error (expect %d)\n",
- FW_VER_MINOR(ver),
- adreno_dev->gpucore->gpmu_minor);
+ result = hfi_send_perftbl(gmu);
+ if (result)
+ return result;
- result = hfi_send_perftbl(gmu);
- if (result)
- return result;
+ result = hfi_send_bwtbl(gmu);
+ if (result)
+ return result;
- result = hfi_send_bwtbl(gmu);
- if (result)
- return result;
-
- /*
- * FW is not ready for LM configuration
- * without powering on GPU.
- */
- /*
- * result = hfi_send_lmconfig(gmu);
- * if (result)
- * return result;
- */
- }
+ /*
+ * FW is not ready for LM configuration
+ * without powering on GPU.
+ */
+ /*
+ * result = hfi_send_lmconfig(gmu);
+ * if (result)
+ * return result;
+ */
set_bit(GMU_HFI_ON, &gmu->flags);
return 0;
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 40d239c..7cbda72 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -875,6 +875,25 @@
return snprintf(buf, PAGE_SIZE, "%lu\n", timestamp);
}
+static ssize_t snapshot_legacy_show(struct kgsl_device *device, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", device->snapshot_legacy);
+}
+
+static ssize_t snapshot_legacy_store(struct kgsl_device *device,
+ const char *buf, size_t count)
+{
+ unsigned int val = 0;
+ int ret;
+
+ ret = kgsl_sysfs_store(buf, &val);
+
+ if (!ret && device)
+ device->snapshot_legacy = (bool)val;
+
+ return (ssize_t) ret < 0 ? ret : count;
+}
+
static struct bin_attribute snapshot_attr = {
.attr.name = "dump",
.attr.mode = 0444,
@@ -894,6 +913,8 @@
static SNAPSHOT_ATTR(force_panic, 0644, force_panic_show, force_panic_store);
static SNAPSHOT_ATTR(snapshot_crashdumper, 0644, snapshot_crashdumper_show,
snapshot_crashdumper_store);
+static SNAPSHOT_ATTR(snapshot_legacy, 0644, snapshot_legacy_show,
+ snapshot_legacy_store);
static ssize_t snapshot_sysfs_show(struct kobject *kobj,
struct attribute *attr, char *buf)
@@ -975,6 +996,7 @@
device->snapshot_faultcount = 0;
device->force_panic = 0;
device->snapshot_crashdumper = 1;
+ device->snapshot_legacy = 0;
ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot,
&device->dev->kobj, "snapshot");
@@ -1000,6 +1022,12 @@
ret = sysfs_create_file(&device->snapshot_kobj,
&attr_snapshot_crashdumper.attr);
+ if (ret)
+ goto done;
+
+ ret = sysfs_create_file(&device->snapshot_kobj,
+ &attr_snapshot_legacy.attr);
+
done:
return ret;
}
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 622ccbc..989af91 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -23,6 +23,7 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
#include <linux/qcom-geni-se.h>
#define SE_I2C_TX_TRANS_LEN (0x26C)
@@ -87,17 +88,31 @@
u32 m_stat = readl_relaxed(gi2c->base + SE_GENI_M_IRQ_STATUS);
u32 tx_stat = readl_relaxed(gi2c->base + SE_GENI_TX_FIFO_STATUS);
u32 rx_stat = readl_relaxed(gi2c->base + SE_GENI_RX_FIFO_STATUS);
+ u32 dm_tx_st = readl_relaxed(gi2c->base + SE_DMA_TX_IRQ_STAT);
+ u32 dm_rx_st = readl_relaxed(gi2c->base + SE_DMA_RX_IRQ_STAT);
+ u32 dma = readl_relaxed(gi2c->base + SE_GENI_DMA_MODE_EN);
struct i2c_msg *cur = gi2c->cur;
dev_dbg(gi2c->dev,
"got i2c irq:%d, stat:0x%x, tx stat:0x%x, rx stat:0x%x\n",
irq, m_stat, tx_stat, rx_stat);
- if (!cur || m_stat & SE_I2C_ERR) {
- dev_err(gi2c->dev, "i2c txn err");
- writel_relaxed(0, (gi2c->base + SE_GENI_TX_WATERMARK_REG));
+ if (!cur || (m_stat & SE_I2C_ERR) || (dm_tx_st & TX_SBE) ||
+ (dm_rx_st & RX_SBE)) {
+ dev_err(gi2c->dev, "i2c err:st:0x%x, dm_t: 0x%x, dm_r: 0x%x\n",
+ m_stat, dm_tx_st, dm_tx_st);
+ if (!dma)
+ writel_relaxed(0, (gi2c->base +
+ SE_GENI_TX_WATERMARK_REG));
gi2c->err = -EIO;
goto irqret;
}
+
+ if (dma) {
+ dev_dbg(gi2c->dev, "i2c dma tx:0x%x, dma rx:0x%x\n", dm_tx_st,
+ dm_rx_st);
+ goto irqret;
+ }
+
if (((m_stat & M_RX_FIFO_WATERMARK_EN) ||
(m_stat & M_RX_FIFO_LAST_EN)) && (cur->flags & I2C_M_RD)) {
u32 rxcnt = rx_stat & RX_FIFO_WC_MSK;
@@ -112,10 +127,11 @@
cur->buf[i] = (u8) ((temp >> (p * 8)) & 0xff);
gi2c->cur_rd = i;
if (gi2c->cur_rd == cur->len) {
- dev_dbg(gi2c->dev, "i:%d,read 0x%x\n", i, temp);
+ dev_dbg(gi2c->dev, "FIFO i:%d,read 0x%x\n",
+ i, temp);
break;
}
- dev_dbg(gi2c->dev, "i: %d, read 0x%x\n", i, temp);
+ dev_dbg(gi2c->dev, "FIFO i: %d, read 0x%x\n", i, temp);
}
} else if ((m_stat & M_TX_FIFO_WATERMARK_EN) &&
!(cur->flags & I2C_M_RD)) {
@@ -128,9 +144,9 @@
temp |= (((u32)(cur->buf[i]) << (p * 8)));
writel_relaxed(temp, gi2c->base + SE_GENI_TX_FIFOn);
gi2c->cur_wr = i;
- dev_dbg(gi2c->dev, "i:%d,wrote 0x%x\n", i, temp);
+ dev_dbg(gi2c->dev, "FIFO i:%d,wrote 0x%x\n", i, temp);
if (gi2c->cur_wr == cur->len) {
- dev_dbg(gi2c->dev, "i2c bytes done writing\n");
+ dev_dbg(gi2c->dev, "FIFO i2c bytes done writing\n");
writel_relaxed(0,
(gi2c->base + SE_GENI_TX_WATERMARK_REG));
break;
@@ -138,15 +154,25 @@
}
}
irqret:
- writel_relaxed(m_stat, gi2c->base + SE_GENI_M_IRQ_CLEAR);
- /* Ensure all writes are done before returning from ISR. */
- wmb();
- /* if this is err with done-bit not set, handle that thr' timeout. */
- if (m_stat & M_CMD_DONE_EN) {
- dev_dbg(gi2c->dev, "i2c irq: err:%d, stat:0x%x\n",
- gi2c->err, m_stat);
- complete(&gi2c->xfer);
+ if (m_stat)
+ writel_relaxed(m_stat, gi2c->base + SE_GENI_M_IRQ_CLEAR);
+
+ if (dma) {
+ if (dm_tx_st)
+ writel_relaxed(dm_tx_st, gi2c->base +
+ SE_DMA_TX_IRQ_CLR);
+ if (dm_rx_st)
+ writel_relaxed(dm_rx_st, gi2c->base +
+ SE_DMA_RX_IRQ_CLR);
+ /* Ensure all writes are done before returning from ISR. */
+ wmb();
}
+ /* if this is err with done-bit not set, handle that thr' timeout. */
+ if (m_stat & M_CMD_DONE_EN)
+ complete(&gi2c->xfer);
+ else if ((dm_tx_st & TX_DMA_DONE) || (dm_rx_st & RX_DMA_DONE))
+ complete(&gi2c->xfer);
+
return IRQ_HANDLED;
}
@@ -175,11 +201,21 @@
int stretch = (i < (num - 1));
u32 m_param = 0;
u32 m_cmd = 0;
+ dma_addr_t tx_dma = 0;
+ dma_addr_t rx_dma = 0;
+ enum se_xfer_mode mode = FIFO_MODE;
m_param |= (stretch ? STOP_STRETCH : 0);
m_param |= ((msgs[i].addr & 0x7F) << SLV_ADDR_SHFT);
gi2c->cur = &msgs[i];
+ mode = msgs[i].len > 32 ? SE_DMA : FIFO_MODE;
+ ret = geni_se_select_mode(gi2c->base, mode);
+ if (ret) {
+ dev_err(gi2c->dev, "%s: Error mode init %d:%d:%d\n",
+ __func__, mode, i, msgs[i].len);
+ break;
+ }
if (msgs[i].flags & I2C_M_RD) {
dev_dbg(gi2c->dev,
"READ,n:%d,i:%d len:%d, stretch:%d\n",
@@ -188,22 +224,41 @@
gi2c->base, SE_I2C_RX_TRANS_LEN);
m_cmd = I2C_READ;
geni_setup_m_cmd(gi2c->base, m_cmd, m_param);
+ if (mode == SE_DMA) {
+ ret = geni_se_rx_dma_prep(gi2c->wrapper_dev,
+ gi2c->base, msgs[i].buf,
+ msgs[i].len, &rx_dma);
+ if (ret)
+ mode = FIFO_MODE;
+ }
+ if (mode == FIFO_MODE)
+ geni_se_select_mode(gi2c->base, mode);
} else {
dev_dbg(gi2c->dev,
- "WRITE:n:%d,i%d len:%d, stretch:%d\n",
- num, i, msgs[i].len, stretch);
+ "WRITE:n:%d,i:%d len:%d, stretch:%d, m_param:0x%x\n",
+ num, i, msgs[i].len, stretch, m_param);
geni_write_reg(msgs[i].len, gi2c->base,
SE_I2C_TX_TRANS_LEN);
m_cmd = I2C_WRITE;
geni_setup_m_cmd(gi2c->base, m_cmd, m_param);
- /* Get FIFO IRQ */
- geni_write_reg(1, gi2c->base, SE_GENI_TX_WATERMARK_REG);
+ if (mode == SE_DMA) {
+ ret = geni_se_tx_dma_prep(gi2c->wrapper_dev,
+ gi2c->base, msgs[i].buf,
+ msgs[i].len, &tx_dma);
+ if (ret)
+ mode = FIFO_MODE;
+ }
+ if (mode == FIFO_MODE) {
+ geni_se_select_mode(gi2c->base, mode);
+ /* Get FIFO IRQ */
+ geni_write_reg(1, gi2c->base,
+ SE_GENI_TX_WATERMARK_REG);
+ }
}
/* Ensure FIFO write go through before waiting for Done evet */
mb();
timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
if (!timeout) {
- dev_err(gi2c->dev, "Timed out\n");
gi2c->err = -ETIMEDOUT;
gi2c->cur = NULL;
geni_abort_m_cmd(gi2c->base);
@@ -211,9 +266,24 @@
}
gi2c->cur_wr = 0;
gi2c->cur_rd = 0;
+ if (mode == SE_DMA) {
+ if (gi2c->err) {
+ if (msgs[i].flags != I2C_M_RD)
+ writel_relaxed(1, gi2c->base +
+ SE_DMA_TX_FSM_RST);
+ else
+ writel_relaxed(1, gi2c->base +
+ SE_DMA_RX_FSM_RST);
+ wait_for_completion_timeout(&gi2c->xfer, HZ);
+ }
+ geni_se_rx_dma_unprep(gi2c->wrapper_dev, rx_dma,
+ msgs[i].len);
+ geni_se_tx_dma_unprep(gi2c->wrapper_dev, tx_dma,
+ msgs[i].len);
+ }
+ ret = gi2c->err;
if (gi2c->err) {
dev_err(gi2c->dev, "i2c error :%d\n", gi2c->err);
- ret = gi2c->err;
break;
}
}
@@ -352,6 +422,7 @@
pm_runtime_enable(gi2c->dev);
i2c_add_adapter(&gi2c->adap);
+ dev_dbg(gi2c->dev, "I2C probed\n");
return 0;
}
@@ -393,7 +464,6 @@
gi2c->tx_wm = gi2c_tx_depth - 1;
geni_se_init(gi2c->base, gi2c->tx_wm, gi2c_tx_depth);
- geni_se_select_mode(gi2c->base, FIFO_MODE);
se_config_packing(gi2c->base, 8, 4, true);
}
enable_irq(gi2c->irq);
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index c1fb545..42de5f2 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -1301,7 +1301,7 @@
free_port_list_attributes(device);
err_unregister:
- device_unregister(class_dev);
+ device_del(class_dev);
err:
return ret;
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 8368764..0e64b52 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -1516,7 +1516,9 @@
if (!qp->device->attach_mcast)
return -ENOSYS;
- if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
+ if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD ||
+ lid < be16_to_cpu(IB_MULTICAST_LID_BASE) ||
+ lid == be16_to_cpu(IB_LID_PERMISSIVE))
return -EINVAL;
ret = qp->device->attach_mcast(qp, gid, lid);
@@ -1532,7 +1534,9 @@
if (!qp->device->detach_mcast)
return -ENOSYS;
- if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
+ if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD ||
+ lid < be16_to_cpu(IB_MULTICAST_LID_BASE) ||
+ lid == be16_to_cpu(IB_LID_PERMISSIVE))
return -EINVAL;
ret = qp->device->detach_mcast(qp, gid, lid);
diff --git a/drivers/infiniband/hw/hfi1/ruc.c b/drivers/infiniband/hw/hfi1/ruc.c
index a1576ae..9f768b4 100644
--- a/drivers/infiniband/hw/hfi1/ruc.c
+++ b/drivers/infiniband/hw/hfi1/ruc.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2015, 2016 Intel Corporation.
+ * Copyright(c) 2015 - 2017 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -833,23 +833,29 @@
/* when sending, force a reschedule every one of these periods */
#define SEND_RESCHED_TIMEOUT (5 * HZ) /* 5s in jiffies */
+void hfi1_do_send_from_rvt(struct rvt_qp *qp)
+{
+ hfi1_do_send(qp, false);
+}
+
void _hfi1_do_send(struct work_struct *work)
{
struct iowait *wait = container_of(work, struct iowait, iowork);
struct rvt_qp *qp = iowait_to_qp(wait);
- hfi1_do_send(qp);
+ hfi1_do_send(qp, true);
}
/**
* hfi1_do_send - perform a send on a QP
* @work: contains a pointer to the QP
+ * @in_thread: true if in a workqueue thread
*
* Process entries in the send work queue until credit or queue is
* exhausted. Only allow one CPU to send a packet per QP.
* Otherwise, two threads could send packets out of order.
*/
-void hfi1_do_send(struct rvt_qp *qp)
+void hfi1_do_send(struct rvt_qp *qp, bool in_thread)
{
struct hfi1_pkt_state ps;
struct hfi1_qp_priv *priv = qp->priv;
@@ -917,8 +923,10 @@
qp->s_hdrwords = 0;
/* allow other tasks to run */
if (unlikely(time_after(jiffies, timeout))) {
- if (workqueue_congested(cpu,
- ps.ppd->hfi1_wq)) {
+ if (!in_thread ||
+ workqueue_congested(
+ cpu,
+ ps.ppd->hfi1_wq)) {
spin_lock_irqsave(
&qp->s_lock,
ps.flags);
@@ -931,11 +939,9 @@
*ps.ppd->dd->send_schedule);
return;
}
- if (!irqs_disabled()) {
- cond_resched();
- this_cpu_inc(
- *ps.ppd->dd->send_schedule);
- }
+ cond_resched();
+ this_cpu_inc(
+ *ps.ppd->dd->send_schedule);
timeout = jiffies + (timeout_int) / 8;
}
spin_lock_irqsave(&qp->s_lock, ps.flags);
diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c
index 4b7a16c..01a380e 100644
--- a/drivers/infiniband/hw/hfi1/verbs.c
+++ b/drivers/infiniband/hw/hfi1/verbs.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2015, 2016 Intel Corporation.
+ * Copyright(c) 2015 - 2017 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -1697,7 +1697,7 @@
dd->verbs_dev.rdi.driver_f.qp_priv_free = qp_priv_free;
dd->verbs_dev.rdi.driver_f.free_all_qps = free_all_qps;
dd->verbs_dev.rdi.driver_f.notify_qp_reset = notify_qp_reset;
- dd->verbs_dev.rdi.driver_f.do_send = hfi1_do_send;
+ dd->verbs_dev.rdi.driver_f.do_send = hfi1_do_send_from_rvt;
dd->verbs_dev.rdi.driver_f.schedule_send = hfi1_schedule_send;
dd->verbs_dev.rdi.driver_f.schedule_send_no_lock = _hfi1_schedule_send;
dd->verbs_dev.rdi.driver_f.get_pmtu_from_attr = get_pmtu_from_attr;
diff --git a/drivers/infiniband/hw/hfi1/verbs.h b/drivers/infiniband/hw/hfi1/verbs.h
index 1c3815d..bac84f8 100644
--- a/drivers/infiniband/hw/hfi1/verbs.h
+++ b/drivers/infiniband/hw/hfi1/verbs.h
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2015, 2016 Intel Corporation.
+ * Copyright(c) 2015 - 2017 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -372,7 +372,9 @@
void _hfi1_do_send(struct work_struct *work);
-void hfi1_do_send(struct rvt_qp *qp);
+void hfi1_do_send_from_rvt(struct rvt_qp *qp);
+
+void hfi1_do_send(struct rvt_qp *qp, bool in_thread);
void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe,
enum ib_wc_status status);
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 46ad995..f2a885e 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -2926,6 +2926,7 @@
mlx4_ib_delete_counters_table(ibdev, &ibdev->counters_table[i]);
err_map:
+ mlx4_ib_free_eqs(dev, ibdev);
iounmap(ibdev->uar_map);
err_uar:
diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c
index a21d37f..e6ea81c 100644
--- a/drivers/infiniband/hw/mlx4/mcg.c
+++ b/drivers/infiniband/hw/mlx4/mcg.c
@@ -1102,7 +1102,8 @@
while ((p = rb_first(&ctx->mcg_table)) != NULL) {
group = rb_entry(p, struct mcast_group, node);
if (atomic_read(&group->refcount))
- mcg_warn_group(group, "group refcount %d!!! (pointer %p)\n", atomic_read(&group->refcount), group);
+ mcg_debug_group(group, "group refcount %d!!! (pointer %p)\n",
+ atomic_read(&group->refcount), group);
force_clean_group(group);
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
index 6bd5740..09396bd 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
@@ -281,8 +281,11 @@
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
+ WARN_ONCE(!priv->mcg_dentry, "null mcg debug file\n");
+ WARN_ONCE(!priv->path_dentry, "null path debug file\n");
debugfs_remove(priv->mcg_dentry);
debugfs_remove(priv->path_dentry);
+ priv->mcg_dentry = priv->path_dentry = NULL;
}
int ipoib_register_debugfs(void)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 3ef7b8f..08c4b02 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -108,6 +108,33 @@
.get_net_dev_by_params = ipoib_get_net_dev_by_params,
};
+#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
+static int ipoib_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct netdev_notifier_info *ni = ptr;
+ struct net_device *dev = ni->dev;
+
+ if (dev->netdev_ops->ndo_open != ipoib_open)
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case NETDEV_REGISTER:
+ ipoib_create_debug_files(dev);
+ break;
+ case NETDEV_CHANGENAME:
+ ipoib_delete_debug_files(dev);
+ ipoib_create_debug_files(dev);
+ break;
+ case NETDEV_UNREGISTER:
+ ipoib_delete_debug_files(dev);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+#endif
+
int ipoib_open(struct net_device *dev)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -1655,8 +1682,6 @@
ASSERT_RTNL();
- ipoib_delete_debug_files(dev);
-
/* Delete any child interfaces first */
list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) {
/* Stop GC on child */
@@ -2074,8 +2099,6 @@
goto register_failed;
}
- ipoib_create_debug_files(priv->dev);
-
if (ipoib_cm_add_mode_attr(priv->dev))
goto sysfs_failed;
if (ipoib_add_pkey_attr(priv->dev))
@@ -2090,7 +2113,6 @@
return priv->dev;
sysfs_failed:
- ipoib_delete_debug_files(priv->dev);
unregister_netdev(priv->dev);
register_failed:
@@ -2175,6 +2197,12 @@
kfree(dev_list);
}
+#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
+static struct notifier_block ipoib_netdev_notifier = {
+ .notifier_call = ipoib_netdev_event,
+};
+#endif
+
static int __init ipoib_init_module(void)
{
int ret;
@@ -2227,6 +2255,9 @@
if (ret)
goto err_client;
+#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
+ register_netdevice_notifier(&ipoib_netdev_notifier);
+#endif
return 0;
err_client:
@@ -2244,6 +2275,9 @@
static void __exit ipoib_cleanup_module(void)
{
+#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
+ unregister_netdevice_notifier(&ipoib_netdev_notifier);
+#endif
ipoib_netlink_fini();
ib_unregister_client(&ipoib_client);
ib_sa_unregister_client(&ipoib_sa_client);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index a2f9f29..57eadd2 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -87,8 +87,6 @@
goto register_failed;
}
- ipoib_create_debug_files(priv->dev);
-
/* RTNL childs don't need proprietary sysfs entries */
if (type == IPOIB_LEGACY_CHILD) {
if (ipoib_cm_add_mode_attr(priv->dev))
@@ -109,7 +107,6 @@
sysfs_failed:
result = -ENOMEM;
- ipoib_delete_debug_files(priv->dev);
unregister_netdevice(priv->dev);
register_failed:
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 41515bb..ee50a61 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -299,3 +299,5 @@
config STM32_EXTI
bool
select IRQ_DOMAIN
+
+source "drivers/irqchip/qcom/Kconfig"
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 987bd89..450059c 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -75,3 +75,4 @@
obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
+obj-$(CONFIG_QTI_PDC) += qcom/
diff --git a/drivers/irqchip/qcom/Kconfig b/drivers/irqchip/qcom/Kconfig
new file mode 100644
index 0000000..e4a7a88
--- /dev/null
+++ b/drivers/irqchip/qcom/Kconfig
@@ -0,0 +1,15 @@
+config QTI_PDC
+ bool "QTI PDC"
+ depends on ARCH_QCOM
+ select IRQ_DOMAIN
+ select IRQ_DOMAIN_HIERARCHY
+ help
+ QTI Power Domain Controller driver to manage and configure wakeup
+ IRQs
+
+config QTI_PDC_SDM845
+ bool "QTI PDC SDM845"
+ select QTI_PDC
+ default y if ARCH_SDM845
+ help
+ QTI Power Domain Controller for SDM845
diff --git a/drivers/irqchip/qcom/Makefile b/drivers/irqchip/qcom/Makefile
new file mode 100644
index 0000000..1b7856d
--- /dev/null
+++ b/drivers/irqchip/qcom/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_QTI_PDC) += pdc.o
+obj-$(CONFIG_QTI_PDC_SDM845) += pdc-sdm845.o
diff --git a/drivers/irqchip/qcom/pdc-sdm845.c b/drivers/irqchip/qcom/pdc-sdm845.c
new file mode 100644
index 0000000..178cf1f0
--- /dev/null
+++ b/drivers/irqchip/qcom/pdc-sdm845.c
@@ -0,0 +1,139 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/irqchip.h>
+#include "pdc.h"
+
+static struct pdc_pin sdm845_data[] = {
+ {0, 512}, /* rpmh_wake */
+ {1, 513}, /* ee0_apps_hlos_spmi_periph_irq */
+ {2, 514}, /* ee1_apps_trustzone_spmi_periph_irq */
+ {3, 515}, /* secure_wdog_expired */
+ {4, 516}, /* secure_wdog_bark_irq */
+ {5, 517}, /* aop_wdog_expired_irq */
+ {6, 518}, /* qmp_usb3_lfps_rxterm_irq */
+ {7, 519}, /* qmp_usb3_lfps_rxterm_irq */
+ {8, 520}, /* eud_p0_dmse_int_mx */
+ {9, 521}, /* eud_p0_dpse_int_mx */
+ {10, 522}, /* eud_p1_dmse_int_mx */
+ {11, 523}, /* eud_p1_dpse_int_mx */
+ {12, 524}, /* eud_int_mx[1] */
+ {13, 525}, /* ssc_xpu_irq_summary */
+ {14, 526}, /* wd_bite_apps */
+ {15, 527}, /* ssc_vmidmt_irq_summary */
+ {16, 528}, /* q6ss_irq_out_apps_ipc[4] */
+ {17, 529}, /* not-connected */
+ {18, 530}, /* aoss_pmic_arb_mpu_xpu_summary_irq */
+ {19, 531}, /* apps_pdc_irq_in_19 */
+ {20, 532}, /* apps_pdc_irq_in_20 */
+ {21, 533}, /* apps_pdc_irq_in_21 */
+ {22, 534}, /* pdc_apps_epcb_timeout_summary_irq */
+ {23, 535}, /* spmi_protocol_irq */
+ {24, 536}, /* tsense0_tsense_max_min_int */
+ {25, 537}, /* tsense1_tsense_max_min_int */
+ {26, 538}, /* tsense0_upper_lower_intr */
+ {27, 539}, /* tsense1_upper_lower_intr */
+ {28, 540}, /* tsense0_critical_intr */
+ {29, 541}, /* tsense1_critical_intr */
+ {30, 542}, /* core_bi_px_gpio_1 */
+ {31, 543}, /* core_bi_px_gpio_3 */
+ {32, 544}, /* core_bi_px_gpio_5 */
+ {33, 545}, /* core_bi_px_gpio_10 */
+ {34, 546}, /* core_bi_px_gpio_11 */
+ {35, 547}, /* core_bi_px_gpio_20 */
+ {36, 548}, /* core_bi_px_gpio_22 */
+ {37, 549}, /* core_bi_px_gpio_24 */
+ {38, 550}, /* core_bi_px_gpio_26 */
+ {39, 551}, /* core_bi_px_gpio_30 */
+ {41, 553}, /* core_bi_px_gpio_32 */
+ {42, 554}, /* core_bi_px_gpio_34 */
+ {43, 555}, /* core_bi_px_gpio_36 */
+ {44, 556}, /* core_bi_px_gpio_37 */
+ {45, 557}, /* core_bi_px_gpio_38 */
+ {46, 558}, /* core_bi_px_gpio_39 */
+ {47, 559}, /* core_bi_px_gpio_40 */
+ {49, 561}, /* core_bi_px_gpio_43 */
+ {50, 562}, /* core_bi_px_gpio_44 */
+ {51, 563}, /* core_bi_px_gpio_46 */
+ {52, 564}, /* core_bi_px_gpio_48 */
+ {54, 566}, /* core_bi_px_gpio_52 */
+ {55, 567}, /* core_bi_px_gpio_53 */
+ {56, 568}, /* core_bi_px_gpio_54 */
+ {57, 569}, /* core_bi_px_gpio_56 */
+ {58, 570}, /* core_bi_px_gpio_57 */
+ {59, 571}, /* core_bi_px_gpio_58 */
+ {60, 572}, /* core_bi_px_gpio_59 */
+ {61, 573}, /* core_bi_px_gpio_60 */
+ {62, 574}, /* core_bi_px_gpio_61 */
+ {63, 575}, /* core_bi_px_gpio_62 */
+ {64, 576}, /* core_bi_px_gpio_63 */
+ {65, 577}, /* core_bi_px_gpio_64 */
+ {66, 578}, /* core_bi_px_gpio_66 */
+ {67, 579}, /* core_bi_px_gpio_68 */
+ {68, 580}, /* core_bi_px_gpio_71 */
+ {69, 581}, /* core_bi_px_gpio_73 */
+ {70, 582}, /* core_bi_px_gpio_77 */
+ {71, 583}, /* core_bi_px_gpio_78 */
+ {72, 584}, /* core_bi_px_gpio_79 */
+ {73, 585}, /* core_bi_px_gpio_80 */
+ {74, 586}, /* core_bi_px_gpio_84 */
+ {75, 587}, /* core_bi_px_gpio_85 */
+ {76, 588}, /* core_bi_px_gpio_86 */
+ {77, 589}, /* core_bi_px_gpio_88 */
+ {79, 591}, /* core_bi_px_gpio_91 */
+ {80, 592}, /* core_bi_px_gpio_92 */
+ {81, 593}, /* core_bi_px_gpio_95 */
+ {82, 594}, /* core_bi_px_gpio_96 */
+ {83, 595}, /* core_bi_px_gpio_97 */
+ {84, 596}, /* core_bi_px_gpio_101 */
+ {85, 597}, /* core_bi_px_gpio_103 */
+ {86, 598}, /* core_bi_px_gpio_104 */
+ {87, 599}, /* core_bi_px_to_mpm[6] */
+ {88, 600}, /* core_bi_px_to_mpm[0] */
+ {89, 601}, /* core_bi_px_to_mpm[1] */
+ {90, 602}, /* core_bi_px_gpio_115 */
+ {91, 603}, /* core_bi_px_gpio_116 */
+ {92, 604}, /* core_bi_px_gpio_117 */
+ {93, 605}, /* core_bi_px_gpio_118 */
+ {94, 641}, /* core_bi_px_gpio_119 */
+ {95, 642}, /* core_bi_px_gpio_120 */
+ {96, 643}, /* core_bi_px_gpio_121 */
+ {97, 644}, /* core_bi_px_gpio_122 */
+ {98, 645}, /* core_bi_px_gpio_123 */
+ {99, 646}, /* core_bi_px_gpio_124 */
+ {100, 647}, /* core_bi_px_gpio_125 */
+ {101, 648}, /* core_bi_px_to_mpm[5] */
+ {102, 649}, /* core_bi_px_gpio_127 */
+ {103, 650}, /* core_bi_px_gpio_128 */
+ {104, 651}, /* core_bi_px_gpio_129 */
+ {105, 652}, /* core_bi_px_gpio_130 */
+ {106, 653}, /* core_bi_px_gpio_132 */
+ {107, 654}, /* core_bi_px_gpio_133 */
+ {108, 655}, /* core_bi_px_gpio_145 */
+ {119, 666}, /* core_bi_px_to_mpm[2] */
+ {120, 667}, /* core_bi_px_to_mpm[3] */
+ {121, 668}, /* core_bi_px_to_mpm[4] */
+ {122, 669}, /* core_bi_px_gpio_41 */
+ {123, 670}, /* core_bi_px_gpio_89 */
+ {124, 671}, /* core_bi_px_gpio_31 */
+ {125, 672}, /* core_bi_px_gpio_49 */
+ {-1}
+};
+
+static int __init qcom_pdc_gic_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return qcom_pdc_init(node, parent, sdm845_data);
+}
+
+IRQCHIP_DECLARE(pdc_sdm845, "qcom,pdc-sdm845", qcom_pdc_gic_init);
diff --git a/drivers/irqchip/qcom/pdc.c b/drivers/irqchip/qcom/pdc.c
new file mode 100644
index 0000000..923552f
--- /dev/null
+++ b/drivers/irqchip/qcom/pdc.c
@@ -0,0 +1,299 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include "pdc.h"
+#define CREATE_TRACE_POINTS
+#include "trace/events/pdc.h"
+
+#define MAX_IRQS 126
+#define CLEAR_INTR(reg, intr) (reg & ~(1 << intr))
+#define ENABLE_INTR(reg, intr) (reg | (1 << intr))
+
+enum pdc_register_offsets {
+ IRQ_ENABLE_BANK = 0x10,
+ IRQ_i_CFG = 0x110,
+};
+
+static DEFINE_SPINLOCK(pdc_lock);
+static void __iomem *pdc_base;
+
+static int get_pdc_pin(irq_hw_number_t hwirq, void *data)
+{
+ int i;
+ struct pdc_pin *pdc_data = (struct pdc_pin *) data;
+
+ for (i = 0; pdc_data[i].pin >= 0; i++) {
+ if (pdc_data[i].hwirq == hwirq)
+ return pdc_data[i].pin;
+ }
+
+ return -EINVAL;
+}
+
+static inline int pdc_enable_intr(struct irq_data *d, bool on)
+{
+ int pin_out = get_pdc_pin(d->hwirq, d->chip_data);
+ unsigned int index, mask;
+ u32 enable, r_enable;
+ unsigned long flags;
+
+ if (pin_out < 0)
+ return 0;
+
+ index = pin_out / 32;
+ mask = pin_out % 32;
+ spin_lock_irqsave(&pdc_lock, flags);
+
+ enable = readl_relaxed(pdc_base + IRQ_ENABLE_BANK + (index *
+ sizeof(uint32_t)));
+ if (on)
+ enable = ENABLE_INTR(enable, mask);
+ else
+ enable = CLEAR_INTR(enable, mask);
+
+ writel_relaxed(enable, pdc_base + IRQ_ENABLE_BANK + (index *
+ sizeof(uint32_t)));
+
+ do {
+ r_enable = readl_relaxed(pdc_base + IRQ_ENABLE_BANK +
+ (index * sizeof(uint32_t)));
+ if (r_enable == enable)
+ break;
+ udelay(5);
+ } while (1);
+
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ trace_irq_pin_config("enable", (u32)pin_out, (u32)d->hwirq,
+ 0, on);
+
+ return 0;
+}
+
+static void qcom_pdc_gic_mask(struct irq_data *d)
+{
+ pdc_enable_intr(d, false);
+ irq_chip_mask_parent(d);
+}
+
+static void qcom_pdc_gic_unmask(struct irq_data *d)
+{
+ pdc_enable_intr(d, true);
+ irq_chip_unmask_parent(d);
+}
+
+static void qcom_pdc_gic_enable(struct irq_data *d)
+{
+ pdc_enable_intr(d, true);
+ irq_chip_enable_parent(d);
+}
+
+static void qcom_pdc_gic_disable(struct irq_data *d)
+{
+ pdc_enable_intr(d, false);
+ irq_chip_disable_parent(d);
+}
+
+/*
+ * GIC does not handle falling edge or active low. To allow falling edge and
+ * active low interrupts to be handled at GIC, PDC has an inverter that inverts
+ * falling edge into a rising edge and active low into an active high.
+ * For the inverter to work, the polarity bit in the IRQ_CONFIG register has to
+ * set as per the table below.
+ * (polarity, falling edge, rising edge ) ORIG POL CONV POLARITY
+ * 3'b0 00 Level sensitive active low (~~~|_____) (___|~~~~~) LOW
+ * 3'b0 01 Rising edge sensitive (___|~~|__) (~~~|__|~~) NOT USED
+ * 3'b0 10 Falling edge sensitive (~~~|__|~~) (___|~~|__) LOW
+ * 3'b0 11 Dual Edge sensitive NOT USED
+ * 3'b1 00 Level senstive active High (___|~~~~~) (___|~~~~~) HIGH
+ * 3'b1 01 Falling Edge sensitive (~~~|__|~~) (~~~|__|~~) NOT USED
+ * 3'b1 10 Rising edge sensitive (___|~~|__) (___|~~|__) HIGH
+ * 3'b1 11 Dual Edge sensitive HIGH
+ */
+enum pdc_irq_config_bits {
+ POLARITY_LOW = 0, //0 00
+ FALLING_EDGE = 2, //0 10
+ POLARITY_HIGH = 4,//1 00
+ RISING_EDGE = 6, //1 10
+ DUAL_EDGE = 7, //1 11
+};
+
+static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
+{
+ int pin_out = get_pdc_pin(d->hwirq, d->chip_data);
+ u32 pdc_type = 0, config;
+
+ if (pin_out < 0)
+ goto fwd_to_parent;
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ pdc_type = RISING_EDGE;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ pdc_type = FALLING_EDGE;
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ pdc_type = DUAL_EDGE;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ pdc_type = POLARITY_HIGH;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ pdc_type = POLARITY_LOW;
+ break;
+ default:
+ pdc_type = POLARITY_HIGH;
+ break;
+ }
+ writel_relaxed(pdc_type, pdc_base + IRQ_i_CFG +
+ (pin_out * sizeof(uint32_t)));
+
+ do {
+ config = readl_relaxed(pdc_base + IRQ_i_CFG +
+ (pin_out * sizeof(uint32_t)));
+ if (config == pdc_type)
+ break;
+ udelay(5);
+ } while (1);
+
+ trace_irq_pin_config("type_config", (u32)pin_out, (u32)d->hwirq,
+ pdc_type, 0);
+
+ /*
+ * If type is edge triggered, forward that as Rising edge as PDC
+ * takes care of converting falling edge to rising edge signal
+ */
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ type = IRQ_TYPE_EDGE_RISING;
+
+ /*
+ * If type is level, then forward that as level high as PDC
+ * takes care of converting falling edge to rising edge signal
+ */
+ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+ type = IRQ_TYPE_LEVEL_HIGH;
+
+fwd_to_parent:
+
+ return irq_chip_set_type_parent(d, type);
+}
+
+static struct irq_chip qcom_pdc_gic_chip = {
+ .name = "PDC-GIC",
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_mask = qcom_pdc_gic_mask,
+ .irq_enable = qcom_pdc_gic_enable,
+ .irq_unmask = qcom_pdc_gic_unmask,
+ .irq_disable = qcom_pdc_gic_disable,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_set_type = qcom_pdc_gic_set_type,
+ .flags = IRQCHIP_MASK_ON_SUSPEND |
+ IRQCHIP_SET_TYPE_MASKED |
+ IRQCHIP_SKIP_SET_WAKE,
+ .irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+#endif
+};
+
+static int qcom_pdc_translate(struct irq_domain *d,
+ struct irq_fwspec *fwspec, unsigned long *hwirq, unsigned int *type)
+{
+ return d->parent->ops->translate(d->parent, fwspec, hwirq, type);
+}
+
+static int qcom_pdc_alloc(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs, void *data)
+{
+ struct irq_fwspec *fwspec = data;
+ struct irq_fwspec parent_fwspec;
+ irq_hw_number_t hwirq;
+ int i;
+ unsigned int type;
+ int ret;
+
+ ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type);
+ if (ret)
+ return -EINVAL;
+
+ for (i = 0; i < nr_irqs; i++)
+ irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+ &qcom_pdc_gic_chip, domain->host_data);
+
+ parent_fwspec = *fwspec;
+ parent_fwspec.fwnode = domain->parent->fwnode;
+
+ return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
+ &parent_fwspec);
+}
+
+static const struct irq_domain_ops qcom_pdc_ops = {
+ .translate = qcom_pdc_translate,
+ .alloc = qcom_pdc_alloc,
+ .free = irq_domain_free_irqs_common,
+};
+
+int qcom_pdc_init(struct device_node *node,
+ struct device_node *parent, void *data)
+{
+ struct irq_domain *parent_domain;
+ int ret;
+ struct irq_domain *pdc_domain;
+
+ pdc_base = of_iomap(node, 0);
+ if (!pdc_base) {
+ pr_err("%s(): unable to map PDC registers\n", node->full_name);
+ return -ENXIO;
+ }
+
+ parent_domain = irq_find_host(parent);
+ if (!parent_domain) {
+ pr_err("unable to obtain PDC parent domain\n");
+ ret = -ENXIO;
+ goto failure;
+ }
+
+ pdc_domain = irq_domain_add_hierarchy(parent_domain, 0, MAX_IRQS,
+ node, &qcom_pdc_ops, data);
+ if (!pdc_domain) {
+ pr_err("GIC domain add failed\n");
+ ret = -ENOMEM;
+ goto failure;
+ }
+
+ pdc_domain->name = "qcom,pdc";
+
+ return 0;
+
+failure:
+ iounmap(pdc_base);
+
+ return ret;
+}
+EXPORT_SYMBOL(qcom_pdc_init);
diff --git a/drivers/irqchip/qcom/pdc.h b/drivers/irqchip/qcom/pdc.h
new file mode 100644
index 0000000..7c4d89c
--- /dev/null
+++ b/drivers/irqchip/qcom/pdc.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/device.h>
+
+struct pdc_pin {
+ int pin;
+ irq_hw_number_t hwirq;
+};
+
+int qcom_pdc_init(struct device_node *node,
+ struct device_node *parent, void *data);
diff --git a/drivers/md/dm-era-target.c b/drivers/md/dm-era-target.c
index bf2b267..80e3df1 100644
--- a/drivers/md/dm-era-target.c
+++ b/drivers/md/dm-era-target.c
@@ -961,18 +961,18 @@
}
}
- r = save_sm_root(md);
- if (r) {
- DMERR("%s: save_sm_root failed", __func__);
- return r;
- }
-
r = dm_tm_pre_commit(md->tm);
if (r) {
DMERR("%s: pre commit failed", __func__);
return r;
}
+ r = save_sm_root(md);
+ if (r) {
+ DMERR("%s: save_sm_root failed", __func__);
+ return r;
+ }
+
r = superblock_lock(md, &sblock);
if (r) {
DMERR("%s: superblock lock failed", __func__);
diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c
index 2c96542..ba7c4c6 100644
--- a/drivers/md/dm-rq.c
+++ b/drivers/md/dm-rq.c
@@ -997,10 +997,14 @@
dm_init_md_queue(md);
/* backfill 'mq' sysfs registration normally done in blk_register_queue */
- blk_mq_register_dev(disk_to_dev(md->disk), q);
+ err = blk_mq_register_dev(disk_to_dev(md->disk), q);
+ if (err)
+ goto out_cleanup_queue;
return 0;
+out_cleanup_queue:
+ blk_cleanup_queue(q);
out_tag_set:
blk_mq_free_tag_set(md->tag_set);
out_kfree_tag_set:
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index d1c05c1..be869a9 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -1070,6 +1070,7 @@
* to unmap (we ignore err).
*/
queue_passdown_pt2(bio->bi_private);
+ bio_put(bio);
}
static void process_prepared_discard_passdown_pt1(struct dm_thin_new_mapping *m)
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index 76dd1f3..5a4e6e9 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -59,15 +59,22 @@
}
if (!bubble_state) {
- CDBG("%s: Sync success: fd 0x%x\n", __func__,
+ CDBG("%s: Sync with success: fd 0x%x\n", __func__,
req_isp->fence_map_out[j].sync_id);
- cam_sync_signal(req_isp->fence_map_out[j].sync_id,
+ rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id,
CAM_SYNC_STATE_SIGNALED_SUCCESS);
+ if (rc)
+ pr_err("%s: Sync failed with rc = %d\n",
+ __func__, rc);
+
} else if (!req_isp->bubble_report) {
- CDBG("%s: Sync failure: fd 0x%x\n", __func__,
+ CDBG("%s: Sync with failure: fd 0x%x\n", __func__,
req_isp->fence_map_out[j].sync_id);
- cam_sync_signal(req_isp->fence_map_out[j].sync_id,
+ rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id,
CAM_SYNC_STATE_SIGNALED_ERROR);
+ if (rc)
+ pr_err("%s: Sync failed with rc = %d\n",
+ __func__, rc);
} else {
/*
* Ignore the buffer done if bubble detect is on
@@ -277,7 +284,7 @@
ctx_isp->frame_id++;
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
- pr_err("%s: next substate %d\n", __func__,
+ CDBG("%s: next substate %d\n", __func__,
ctx_isp->substate_activated);
return rc;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index 259e773..49085d7 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -1493,19 +1493,6 @@
if (i == ctx->num_base)
master_base_idx = ctx->base[0].idx;
- /* Stop the master CIDs first */
- cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
- master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
-
- /* stop rest of the CIDs */
- for (i = 0; i < ctx->num_base; i++) {
- if (i == master_base_idx)
- continue;
- cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
- ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
- }
-
-
/* Stop the master CSID path first */
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
@@ -1519,6 +1506,18 @@
ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
}
+ /* Stop the master CIDs first */
+ cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
+ master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+
+ /* stop rest of the CIDs */
+ for (i = 0; i < ctx->num_base; i++) {
+ if (i == master_base_idx)
+ continue;
+ cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
+ ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+ }
+
if (cam_cdm_stream_off(ctx->cdm_handle))
pr_err("%s%d: CDM stream off failed %d\n",
__func__, __LINE__, ctx->cdm_handle);
@@ -2884,7 +2883,7 @@
int i, j;
struct cam_iommu_handle cdm_handles;
- pr_info("%s: Enter\n", __func__);
+ CDBG("%s: Enter\n", __func__);
memset(&g_ife_hw_mgr, 0, sizeof(g_ife_hw_mgr));
@@ -3037,7 +3036,7 @@
hw_mgr_intf->hw_prepare_update = cam_ife_mgr_prepare_hw_update;
hw_mgr_intf->hw_config = cam_ife_mgr_config_hw;
- pr_info("%s: Exit\n", __func__);
+ CDBG("%s: Exit\n", __func__);
return 0;
end:
if (rc) {
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index 6306df3..3ec9aa6 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -1133,7 +1133,7 @@
if (rc)
return rc;
- /**
+ /*
* configure the IPP and enable the time stamp capture.
* enable the HW measrurement blocks
*/
@@ -1417,7 +1417,7 @@
if (rc)
return rc;
- /**
+ /*
* RDI path config and enable the time stamp capture
* Enable the measurement blocks
*/
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
index 34243e6..15b8a2d 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
@@ -227,9 +227,10 @@
{
struct sde_rot_data_type *mdata = sde_rot_get_mdata();
u32 ot_lim;
- u32 reg_off_vbif_lim_conf = (params->xin_id / 4) * 4 +
- params->reg_off_vbif_lim_conf;
- u32 bit_off_vbif_lim_conf = (params->xin_id % 4) * 8;
+ u32 reg_off_vbif_lim_conf = ((params->xin_id / mdata->npriority_lvl)
+ * mdata->npriority_lvl)
+ + params->reg_off_vbif_lim_conf;
+ u32 bit_off_vbif_lim_conf = (params->xin_id % mdata->npriority_lvl) * 8;
u32 reg_val;
u32 sts;
bool forced_on;
@@ -420,6 +421,136 @@
}
}
+static void sde_mdp_parse_cdp_setting(struct platform_device *pdev,
+ struct sde_rot_data_type *mdata)
+{
+ int rc;
+ u32 len, data[SDE_ROT_OP_MAX] = {0};
+
+ len = sde_mdp_parse_dt_prop_len(pdev,
+ "qcom,mdss-rot-cdp-setting");
+ if (len == SDE_ROT_OP_MAX) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-rot-cdp-setting", data, len);
+ if (rc) {
+ SDEROT_ERR("invalid CDP setting\n");
+ goto end;
+ }
+
+ set_bit(SDE_QOS_CDP, mdata->sde_qos_map);
+ mdata->enable_cdp[SDE_ROT_RD] = data[SDE_ROT_RD];
+ mdata->enable_cdp[SDE_ROT_WR] = data[SDE_ROT_WR];
+ return;
+ }
+end:
+ clear_bit(SDE_QOS_CDP, mdata->sde_qos_map);
+}
+
+static void sde_mdp_parse_rot_lut_setting(struct platform_device *pdev,
+ struct sde_rot_data_type *mdata)
+{
+ int rc;
+ u32 len, data[4];
+
+ len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-rot-qos-lut");
+ if (len == 4) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-rot-qos-lut", data, len);
+ if (!rc) {
+ mdata->lut_cfg[SDE_ROT_RD].creq_lut_0 = data[0];
+ mdata->lut_cfg[SDE_ROT_RD].creq_lut_1 = data[1];
+ mdata->lut_cfg[SDE_ROT_WR].creq_lut_0 = data[2];
+ mdata->lut_cfg[SDE_ROT_WR].creq_lut_1 = data[3];
+ set_bit(SDE_QOS_LUT, mdata->sde_qos_map);
+ } else {
+ SDEROT_DBG("qos lut setting not found\n");
+ }
+ }
+
+ len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-rot-danger-lut");
+ if (len == SDE_ROT_OP_MAX) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-rot-danger-lut", data, len);
+ if (!rc) {
+ mdata->lut_cfg[SDE_ROT_RD].danger_lut
+ = data[SDE_ROT_RD];
+ mdata->lut_cfg[SDE_ROT_WR].danger_lut
+ = data[SDE_ROT_WR];
+ set_bit(SDE_QOS_DANGER_LUT, mdata->sde_qos_map);
+ } else {
+ SDEROT_DBG("danger lut setting not found\n");
+ }
+ }
+
+ len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-rot-safe-lut");
+ if (len == SDE_ROT_OP_MAX) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-rot-safe-lut", data, len);
+ if (!rc) {
+ mdata->lut_cfg[SDE_ROT_RD].safe_lut = data[SDE_ROT_RD];
+ mdata->lut_cfg[SDE_ROT_WR].safe_lut = data[SDE_ROT_WR];
+ set_bit(SDE_QOS_SAFE_LUT, mdata->sde_qos_map);
+ } else {
+ SDEROT_DBG("safe lut setting not found\n");
+ }
+ }
+}
+
+static void sde_mdp_parse_inline_rot_lut_setting(struct platform_device *pdev,
+ struct sde_rot_data_type *mdata)
+{
+ int rc;
+ u32 len, data[4];
+
+ len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-inline-rot-qos-lut");
+ if (len == 4) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-inline-rot-qos-lut", data, len);
+ if (!rc) {
+ mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_0 = data[0];
+ mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_1 = data[1];
+ mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_0 = data[2];
+ mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_1 = data[3];
+ set_bit(SDE_INLINE_QOS_LUT, mdata->sde_inline_qos_map);
+ } else {
+ SDEROT_DBG("inline qos lut setting not found\n");
+ }
+ }
+
+ len = sde_mdp_parse_dt_prop_len(pdev,
+ "qcom,mdss-inline-rot-danger-lut");
+ if (len == SDE_ROT_OP_MAX) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-inline-rot-danger-lut", data, len);
+ if (!rc) {
+ mdata->inline_lut_cfg[SDE_ROT_RD].danger_lut
+ = data[SDE_ROT_RD];
+ mdata->inline_lut_cfg[SDE_ROT_WR].danger_lut
+ = data[SDE_ROT_WR];
+ set_bit(SDE_INLINE_QOS_DANGER_LUT,
+ mdata->sde_inline_qos_map);
+ } else {
+ SDEROT_DBG("inline danger lut setting not found\n");
+ }
+ }
+
+ len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-inline-rot-safe-lut");
+ if (len == SDE_ROT_OP_MAX) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-inline-rot-safe-lut", data, len);
+ if (!rc) {
+ mdata->inline_lut_cfg[SDE_ROT_RD].safe_lut
+ = data[SDE_ROT_RD];
+ mdata->inline_lut_cfg[SDE_ROT_WR].safe_lut
+ = data[SDE_ROT_WR];
+ set_bit(SDE_INLINE_QOS_SAFE_LUT,
+ mdata->sde_inline_qos_map);
+ } else {
+ SDEROT_DBG("inline safe lut setting not found\n");
+ }
+ }
+}
+
static int sde_mdp_parse_dt_misc(struct platform_device *pdev,
struct sde_rot_data_type *mdata)
{
@@ -444,8 +575,14 @@
SDEROT_DBG(
"Could not read optional property: highest bank bit\n");
+ sde_mdp_parse_cdp_setting(pdev, mdata);
+
sde_mdp_parse_vbif_qos(pdev, mdata);
+ sde_mdp_parse_rot_lut_setting(pdev, mdata);
+
+ sde_mdp_parse_inline_rot_lut_setting(pdev, mdata);
+
mdata->mdp_base = mdata->sde_io.base + SDE_MDP_OFFSET;
return 0;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
index 5c64bee..313c709 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -40,6 +40,9 @@
#define SDE_MDP_HW_REV_301 SDE_MDP_REV(3, 0, 1) /* 8998 v1.1 */
#define SDE_MDP_HW_REV_400 SDE_MDP_REV(4, 0, 0) /* sdm845 v1.0 */
+#define SDE_MDP_VBIF_4_LEVEL_REMAPPER 4
+#define SDE_MDP_VBIF_8_LEVEL_REMAPPER 8
+
struct sde_mult_factor {
uint32_t numer;
uint32_t denom;
@@ -77,9 +80,19 @@
SDE_QOS_PER_PIPE_LUT,
SDE_QOS_SIMPLIFIED_PREFILL,
SDE_QOS_VBLANK_PANIC_CTRL,
+ SDE_QOS_LUT,
+ SDE_QOS_DANGER_LUT,
+ SDE_QOS_SAFE_LUT,
SDE_QOS_MAX,
};
+enum sde_inline_qos_settings {
+ SDE_INLINE_QOS_LUT,
+ SDE_INLINE_QOS_DANGER_LUT,
+ SDE_INLINE_QOS_SAFE_LUT,
+ SDE_INLINE_QOS_MAX,
+};
+
/**
* enum sde_rot_type: SDE rotator HW version
* @SDE_ROT_TYPE_V1_0: V1.0 HW version
@@ -117,6 +130,12 @@
SDE_MAX_BUS_CLIENTS
};
+enum sde_rot_op {
+ SDE_ROT_RD,
+ SDE_ROT_WR,
+ SDE_ROT_OP_MAX
+};
+
enum sde_rot_regdump_access {
SDE_ROT_REGDUMP_READ,
SDE_ROT_REGDUMP_WRITE,
@@ -167,6 +186,13 @@
enum sde_rot_regdump_access access;
};
+struct sde_rot_lut_cfg {
+ u32 creq_lut_0;
+ u32 creq_lut_1;
+ u32 danger_lut;
+ u32 safe_lut;
+};
+
struct sde_rot_data_type {
u32 mdss_version;
@@ -179,6 +205,7 @@
/* bitmap to track qos applicable settings */
DECLARE_BITMAP(sde_qos_map, SDE_QOS_MAX);
+ DECLARE_BITMAP(sde_inline_qos_map, SDE_QOS_MAX);
/* bitmap to track capability settings */
DECLARE_BITMAP(sde_caps_map, SDE_CAPS_MAX);
@@ -212,6 +239,11 @@
void *sde_rot_hw;
int sec_cam_en;
+ u32 enable_cdp[SDE_ROT_OP_MAX];
+
+ struct sde_rot_lut_cfg lut_cfg[SDE_ROT_OP_MAX];
+ struct sde_rot_lut_cfg inline_lut_cfg[SDE_ROT_OP_MAX];
+
struct ion_client *iclient;
bool clk_always_on;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
index 051db78..de448a4 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -65,6 +65,8 @@
#define MMSS_VBIF_NRT_VBIF_IN_WR_LIM_CONF2 0x00C8
#define MMSS_VBIF_NRT_VBIF_OUT_RD_LIM_CONF0 0x00D0
#define MMSS_VBIF_NRT_VBIF_OUT_WR_LIM_CONF0 0x00D4
+#define MMSS_VBIF_NRT_VBIF_QOS_RP_REMAP_000 0x0550
+#define MMSS_VBIF_NRT_VBIF_QOS_LVL_REMAP_000 0x0590
#define SDE_MDP_REG_TRAFFIC_SHAPER_EN BIT(31)
#define SDE_MDP_REG_TRAFFIC_SHAPER_RD_CLIENT(num) (0x030 + (num * 4))
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index f25077e..6ebfc1a 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -493,6 +493,12 @@
SDE_ROT_REGDUMP_VBIF },
};
+struct sde_rot_cdp_params {
+ bool enable;
+ struct sde_mdp_format_params *fmt;
+ u32 offset;
+};
+
/* Invalid software timestamp value for initialization */
#define SDE_REGDMA_SWTS_INVALID (~0)
@@ -741,6 +747,76 @@
}
/*
+ * sde_hw_rotator_vbif_setting - helper function to set vbif QoS remapper
+ * levels, enable write gather enable and avoid clk gating setting for
+ * debug purpose.
+ *
+ * @rot: Pointer to rotator hw
+ */
+static void sde_hw_rotator_vbif_setting(struct sde_hw_rotator *rot)
+{
+ u32 i, mask, vbif_qos, reg_val = 0;
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+
+ /* VBIF_ROT QoS remapper setting */
+ switch (mdata->npriority_lvl) {
+
+ case SDE_MDP_VBIF_4_LEVEL_REMAPPER:
+ for (i = 0; i < mdata->npriority_lvl; i++) {
+ reg_val = SDE_VBIF_READ(mdata,
+ MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4);
+ mask = 0x3 << (XIN_SSPP * 2);
+ vbif_qos = mdata->vbif_nrt_qos[i];
+ reg_val |= vbif_qos << (XIN_SSPP * 2);
+ /* ensure write is issued after the read operation */
+ mb();
+ SDE_VBIF_WRITE(mdata,
+ MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4,
+ reg_val);
+ }
+ break;
+
+ case SDE_MDP_VBIF_8_LEVEL_REMAPPER:
+ mask = mdata->npriority_lvl - 1;
+ for (i = 0; i < mdata->npriority_lvl; i++) {
+ /* RD and WR client */
+ reg_val |= (mdata->vbif_nrt_qos[i] & mask)
+ << (XIN_SSPP * 4);
+ reg_val |= (mdata->vbif_nrt_qos[i] & mask)
+ << (XIN_WRITEBACK * 4);
+
+ SDE_VBIF_WRITE(mdata,
+ MMSS_VBIF_NRT_VBIF_QOS_RP_REMAP_000 + i*8,
+ reg_val);
+ SDE_VBIF_WRITE(mdata,
+ MMSS_VBIF_NRT_VBIF_QOS_LVL_REMAP_000 + i*8,
+ reg_val);
+ }
+ break;
+
+ default:
+ SDEROT_DBG("invalid vbif remapper levels\n");
+ }
+
+ /* Enable write gather for writeback to remove write gaps, which
+ * may hang AXI/BIMC/SDE.
+ */
+ SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN,
+ BIT(XIN_WRITEBACK));
+
+ /*
+ * For debug purpose, disable clock gating, i.e. Clocks always on
+ */
+ if (mdata->clk_always_on) {
+ SDE_VBIF_WRITE(mdata, MMSS_VBIF_CLKON, 0x3);
+ SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0, 0x3);
+ SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL1,
+ 0xFFFF);
+ SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_CLK_CTRL, 1);
+ }
+}
+
+/*
* sde_hw_rotator_setup_timestamp_packet - setup timestamp writeback command
* @ctx: Pointer to rotator context
* @mask: Bit mask location of the timestamp
@@ -796,6 +872,156 @@
}
/*
+ * sde_hw_rotator_cdp_configs - configures the CDP registers
+ * @ctx: Pointer to rotator context
+ * @params: Pointer to parameters needed for CDP configs
+ */
+static void sde_hw_rotator_cdp_configs(struct sde_hw_rotator_context *ctx,
+ struct sde_rot_cdp_params *params)
+{
+ int reg_val;
+ u32 *wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
+ if (!params->enable) {
+ SDE_REGDMA_WRITE(wrptr, params->offset, 0x0);
+ goto end;
+ }
+
+ reg_val = BIT(0); /* enable cdp */
+
+ if (sde_mdp_is_ubwc_format(params->fmt))
+ reg_val |= BIT(1); /* enable UBWC meta cdp */
+
+ if (sde_mdp_is_ubwc_format(params->fmt)
+ || sde_mdp_is_tilea4x_format(params->fmt)
+ || sde_mdp_is_tilea5x_format(params->fmt))
+ reg_val |= BIT(2); /* enable tile amortize */
+
+ reg_val |= BIT(3); /* enable preload addr ahead cnt 64 */
+
+ SDE_REGDMA_WRITE(wrptr, params->offset, reg_val);
+
+end:
+ sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+}
+
+/*
+ * sde_hw_rotator_setup_qos_lut_wr - Set QoS LUT/Danger LUT/Safe LUT configs
+ * for the WRITEBACK rotator for inline and offline rotation.
+ *
+ * @ctx: Pointer to rotator context
+ */
+static void sde_hw_rotator_setup_qos_lut_wr(struct sde_hw_rotator_context *ctx)
+{
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+ u32 *wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
+ /* Offline rotation setting */
+ if (!ctx->sbuf_mode) {
+ /* QOS LUT WR setting */
+ if (test_bit(SDE_QOS_LUT, mdata->sde_qos_map)) {
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_0,
+ mdata->lut_cfg[SDE_ROT_WR].creq_lut_0);
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_1,
+ mdata->lut_cfg[SDE_ROT_WR].creq_lut_1);
+ }
+
+ /* Danger LUT WR setting */
+ if (test_bit(SDE_QOS_DANGER_LUT, mdata->sde_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_DANGER_LUT,
+ mdata->lut_cfg[SDE_ROT_WR].danger_lut);
+
+ /* Safe LUT WR setting */
+ if (test_bit(SDE_QOS_SAFE_LUT, mdata->sde_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_SAFE_LUT,
+ mdata->lut_cfg[SDE_ROT_WR].safe_lut);
+
+ /* Inline rotation setting */
+ } else {
+ /* QOS LUT WR setting */
+ if (test_bit(SDE_INLINE_QOS_LUT, mdata->sde_inline_qos_map)) {
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_0,
+ mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_0);
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_1,
+ mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_1);
+ }
+
+ /* Danger LUT WR setting */
+ if (test_bit(SDE_INLINE_QOS_DANGER_LUT,
+ mdata->sde_inline_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_DANGER_LUT,
+ mdata->inline_lut_cfg[SDE_ROT_WR].danger_lut);
+
+ /* Safe LUT WR setting */
+ if (test_bit(SDE_INLINE_QOS_SAFE_LUT,
+ mdata->sde_inline_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_SAFE_LUT,
+ mdata->inline_lut_cfg[SDE_ROT_WR].safe_lut);
+ }
+
+ /* Update command queue write ptr */
+ sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+}
+
+/*
+ * sde_hw_rotator_setup_qos_lut_rd - Set QoS LUT/Danger LUT/Safe LUT configs
+ * for the SSPP rotator for inline and offline rotation.
+ *
+ * @ctx: Pointer to rotator context
+ */
+static void sde_hw_rotator_setup_qos_lut_rd(struct sde_hw_rotator_context *ctx)
+{
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+ u32 *wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
+ /* Offline rotation setting */
+ if (!ctx->sbuf_mode) {
+ /* QOS LUT RD setting */
+ if (test_bit(SDE_QOS_LUT, mdata->sde_qos_map)) {
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_0,
+ mdata->lut_cfg[SDE_ROT_RD].creq_lut_0);
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_1,
+ mdata->lut_cfg[SDE_ROT_RD].creq_lut_1);
+ }
+
+ /* Danger LUT RD setting */
+ if (test_bit(SDE_QOS_DANGER_LUT, mdata->sde_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_DANGER_LUT,
+ mdata->lut_cfg[SDE_ROT_RD].danger_lut);
+
+ /* Safe LUT RD setting */
+ if (test_bit(SDE_QOS_SAFE_LUT, mdata->sde_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SAFE_LUT,
+ mdata->lut_cfg[SDE_ROT_RD].safe_lut);
+
+ /* inline rotation setting */
+ } else {
+ /* QOS LUT RD setting */
+ if (test_bit(SDE_INLINE_QOS_LUT, mdata->sde_inline_qos_map)) {
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_0,
+ mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_0);
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_1,
+ mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_1);
+ }
+
+ /* Danger LUT RD setting */
+ if (test_bit(SDE_INLINE_QOS_DANGER_LUT,
+ mdata->sde_inline_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_DANGER_LUT,
+ mdata->inline_lut_cfg[SDE_ROT_RD].danger_lut);
+
+ /* Safe LUT RD setting */
+ if (test_bit(SDE_INLINE_QOS_SAFE_LUT,
+ mdata->sde_inline_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SAFE_LUT,
+ mdata->inline_lut_cfg[SDE_ROT_RD].safe_lut);
+ }
+
+ /* Update command queue write ptr */
+ sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+}
+
+/*
* sde_hw_rotator_setup_fetchengine - setup fetch engine
* @ctx: Pointer to rotator context
* @queue_id: Priority queue identifier
@@ -814,6 +1040,7 @@
struct sde_hw_rotator *rot = ctx->rot;
struct sde_mdp_format_params *fmt;
struct sde_mdp_data *data;
+ struct sde_rot_cdp_params cdp_params = {0};
struct sde_rot_data_type *mdata = sde_rot_get_mdata();
u32 *wrptr;
u32 opmode = 0;
@@ -985,13 +1212,29 @@
ctx->is_secure = false;
}
+ /* Update command queue write ptr */
+ sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+
+ /* CDP register RD setting */
+ cdp_params.enable = test_bit(SDE_QOS_CDP, mdata->sde_qos_map) ?
+ mdata->enable_cdp[SDE_ROT_RD] : false;
+ cdp_params.fmt = fmt;
+ cdp_params.offset = ROT_SSPP_CDP_CNTL;
+ sde_hw_rotator_cdp_configs(ctx, &cdp_params);
+
+ /* QOS LUT/ Danger LUT/ Safe Lut WR setting */
+ sde_hw_rotator_setup_qos_lut_rd(ctx);
+
+ wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
/*
* Determine if traffic shaping is required. Only enable traffic
* shaping when content is 4k@30fps. The actual traffic shaping
* bandwidth calculation is done in output setup.
*/
- if (((cfg->src_rect->w * cfg->src_rect->h) >= RES_UHD) &&
- (cfg->fps <= 30)) {
+ if (((!ctx->sbuf_mode)
+ && (cfg->src_rect->w * cfg->src_rect->h) >= RES_UHD)
+ && (cfg->fps <= 30)) {
SDEROT_DBG("Enable Traffic Shaper\n");
ctx->is_traffic_shaping = true;
} else {
@@ -1017,6 +1260,7 @@
{
struct sde_rot_data_type *mdata = sde_rot_get_mdata();
struct sde_mdp_format_params *fmt;
+ struct sde_rot_cdp_params cdp_params = {0};
u32 *wrptr;
u32 pack = 0;
u32 dst_format = 0;
@@ -1126,8 +1370,23 @@
SDE_REGDMA_WRITE(wrptr, ROTTOP_OP_MODE, ctx->op_mode |
(flags & SDE_ROT_FLAG_ROT_90 ? BIT(1) : 0) | BIT(0));
+ sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+
+ /* CDP register WR setting */
+ cdp_params.enable = test_bit(SDE_QOS_CDP, mdata->sde_qos_map) ?
+ mdata->enable_cdp[SDE_ROT_WR] : false;
+ cdp_params.fmt = fmt;
+ cdp_params.offset = ROT_WB_CDP_CNTL;
+ sde_hw_rotator_cdp_configs(ctx, &cdp_params);
+
+ /* QOS LUT/ Danger LUT/ Safe LUT WR setting */
+ sde_hw_rotator_setup_qos_lut_wr(ctx);
+
+ wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
/* setup traffic shaper for 4k 30fps content or if prefill_bw is set */
- if (ctx->is_traffic_shaping || cfg->prefill_bw) {
+ if (!ctx->sbuf_mode &&
+ (ctx->is_traffic_shaping || cfg->prefill_bw)) {
u32 bw;
/*
@@ -2142,7 +2401,7 @@
item->input.format, item->output.format,
entry->perf->config.frame_rate);
- if (mdata->default_ot_rd_limit) {
+ if (!ctx->sbuf_mode && mdata->default_ot_rd_limit) {
struct sde_mdp_set_ot_params ot_params;
memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params));
@@ -2164,7 +2423,7 @@
sde_mdp_set_ot_limit(&ot_params);
}
- if (mdata->default_ot_wr_limit) {
+ if (!ctx->sbuf_mode && mdata->default_ot_wr_limit) {
struct sde_mdp_set_ot_params ot_params;
memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params));
@@ -2195,46 +2454,9 @@
SDE_ROTREG_WRITE(rot->mdss_base, ROT_SSPP_CREQ_LUT, qos_lut);
}
- /* Set CDP control registers to 0 if CDP is disabled */
- if (!test_bit(SDE_QOS_CDP, mdata->sde_qos_map)) {
- SDE_ROTREG_WRITE(rot->mdss_base, ROT_SSPP_CDP_CNTL, 0x0);
- SDE_ROTREG_WRITE(rot->mdss_base, ROT_WB_CDP_CNTL, 0x0);
- }
-
- if (mdata->npriority_lvl > 0) {
- u32 mask, reg_val, i, vbif_qos;
-
- for (i = 0; i < mdata->npriority_lvl; i++) {
- reg_val = SDE_VBIF_READ(mdata,
- MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4);
- mask = 0x3 << (XIN_SSPP * 2);
- reg_val &= ~(mask);
- vbif_qos = mdata->vbif_nrt_qos[i];
- reg_val |= vbif_qos << (XIN_SSPP * 2);
- /* ensure write is issued after the read operation */
- mb();
- SDE_VBIF_WRITE(mdata,
- MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4,
- reg_val);
- }
- }
-
- /* Enable write gather for writeback to remove write gaps, which
- * may hang AXI/BIMC/SDE.
- */
- SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN,
- BIT(XIN_WRITEBACK));
-
- /*
- * For debug purpose, disable clock gating, i.e. Clocks always on
- */
- if (mdata->clk_always_on) {
- SDE_VBIF_WRITE(mdata, MMSS_VBIF_CLKON, 0x3);
- SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0, 0x3);
- SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL1,
- 0xFFFF);
- SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_CLK_CTRL, 1);
- }
+ /* VBIF QoS and other settings */
+ if (!ctx->sbuf_mode)
+ sde_hw_rotator_vbif_setting(rot);
return 0;
@@ -2343,7 +2565,6 @@
clear_bit(SDE_QOS_PER_PIPE_IB, mdata->sde_qos_map);
set_bit(SDE_QOS_OVERHEAD_FACTOR, mdata->sde_qos_map);
- clear_bit(SDE_QOS_CDP, mdata->sde_qos_map);
set_bit(SDE_QOS_OTLIM, mdata->sde_qos_map);
set_bit(SDE_QOS_PER_PIPE_LUT, mdata->sde_qos_map);
clear_bit(SDE_QOS_SIMPLIFIED_PREFILL, mdata->sde_qos_map);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
index aa762dd..d2b81d5 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
@@ -81,6 +81,8 @@
#define ROT_SSPP_CREQ_LUT (SDE_ROT_SSPP_OFFSET+0x68)
#define ROT_SSPP_QOS_CTRL (SDE_ROT_SSPP_OFFSET+0x6C)
#define ROT_SSPP_SRC_ADDR_SW_STATUS (SDE_ROT_SSPP_OFFSET+0x70)
+#define ROT_SSPP_CREQ_LUT_0 (SDE_ROT_SSPP_OFFSET+0x74)
+#define ROT_SSPP_CREQ_LUT_1 (SDE_ROT_SSPP_OFFSET+0x78)
#define ROT_SSPP_CURRENT_SRC0_ADDR (SDE_ROT_SSPP_OFFSET+0xA4)
#define ROT_SSPP_CURRENT_SRC1_ADDR (SDE_ROT_SSPP_OFFSET+0xA8)
#define ROT_SSPP_CURRENT_SRC2_ADDR (SDE_ROT_SSPP_OFFSET+0xAC)
@@ -167,6 +169,8 @@
#define ROT_WB_CREQ_LUT (SDE_ROT_WB_OFFSET+0x08C)
#define ROT_WB_QOS_CTRL (SDE_ROT_WB_OFFSET+0x090)
#define ROT_WB_SYS_CACHE_MODE (SDE_ROT_WB_OFFSET+0x094)
+#define ROT_WB_CREQ_LUT_0 (SDE_ROT_WB_OFFSET+0x098)
+#define ROT_WB_CREQ_LUT_1 (SDE_ROT_WB_OFFSET+0x09C)
#define ROT_WB_UBWC_STATIC_CTRL (SDE_ROT_WB_OFFSET+0x144)
#define ROT_WB_SBUF_STATUS_PLANE0 (SDE_ROT_WB_OFFSET+0x148)
#define ROT_WB_SBUF_STATUS_PLANE1 (SDE_ROT_WB_OFFSET+0x14C)
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index a477340..e7e9278 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -515,13 +515,13 @@
buffer = HFI_BUFFER_EXTRADATA_OUTPUT2;
break;
case HAL_BUFFER_INTERNAL_SCRATCH:
- buffer = HFI_BUFFER_INTERNAL_SCRATCH;
+ buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH;
break;
case HAL_BUFFER_INTERNAL_SCRATCH_1:
- buffer = HFI_BUFFER_INTERNAL_SCRATCH_1;
+ buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH_1;
break;
case HAL_BUFFER_INTERNAL_SCRATCH_2:
- buffer = HFI_BUFFER_INTERNAL_SCRATCH_2;
+ buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2;
break;
case HAL_BUFFER_INTERNAL_PERSIST:
buffer = HFI_BUFFER_INTERNAL_PERSIST;
@@ -1863,14 +1863,6 @@
pkt->size += sizeof(u32) + sizeof(*work_mode);
break;
}
- case HAL_PARAM_USE_SYS_CACHE:
- {
- create_pkt_enable(pkt->rg_property_data,
- HFI_PROPERTY_PARAM_USE_SYS_CACHE,
- (((struct hal_enable *) pdata)->enable));
- pkt->size += sizeof(u32) * 2;
- break;
- }
/* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */
case HAL_CONFIG_BUFFER_REQUIREMENTS:
case HAL_CONFIG_PRIORITY:
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index b424fbb..89e8356 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1082,19 +1082,19 @@
buffreq->buffer[5].buffer_type =
HAL_BUFFER_EXTRADATA_OUTPUT2;
break;
- case HFI_BUFFER_INTERNAL_SCRATCH:
+ case HFI_BUFFER_COMMON_INTERNAL_SCRATCH:
memcpy(&buffreq->buffer[6], hfi_buf_req,
sizeof(struct hfi_buffer_requirements));
buffreq->buffer[6].buffer_type =
HAL_BUFFER_INTERNAL_SCRATCH;
break;
- case HFI_BUFFER_INTERNAL_SCRATCH_1:
+ case HFI_BUFFER_COMMON_INTERNAL_SCRATCH_1:
memcpy(&buffreq->buffer[7], hfi_buf_req,
sizeof(struct hfi_buffer_requirements));
buffreq->buffer[7].buffer_type =
HAL_BUFFER_INTERNAL_SCRATCH_1;
break;
- case HFI_BUFFER_INTERNAL_SCRATCH_2:
+ case HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2:
memcpy(&buffreq->buffer[8], hfi_buf_req,
sizeof(struct hfi_buffer_requirements));
buffreq->buffer[8].buffer_type =
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 3d3d567..074ea4fa 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -94,10 +94,17 @@
trace_msm_smem_buffer_iommu_op_start("MAP", 0, 0,
align, *iova, *buffer_size);
- /* Map a scatterlist into an SMMU with system cacheability */
- rc = msm_dma_map_sg_attrs(cb->dev, table->sgl,
- table->nents, DMA_BIDIRECTIONAL,
- buf, DMA_ATTR_IOMMU_USE_UPSTREAM_HINT);
+ /* Map a scatterlist into SMMU */
+ if (smem_client->res->sys_cache_present) {
+ /* with sys cache attribute & delayed unmap */
+ rc = msm_dma_map_sg_attrs(cb->dev, table->sgl,
+ table->nents, DMA_BIDIRECTIONAL,
+ buf, DMA_ATTR_IOMMU_USE_UPSTREAM_HINT);
+ } else {
+ /* with delayed unmap */
+ rc = msm_dma_map_sg_lazy(cb->dev, table->sgl,
+ table->nents, DMA_BIDIRECTIONAL, buf);
+ }
if (rc != table->nents) {
dprintk(VIDC_ERR,
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 8906027..14eb3ab 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -86,7 +86,6 @@
};
static const char *const hevc_tier_level[] = {
- "Level unknown"
"Main Tier Level 1",
"Main Tier Level 2",
"Main Tier Level 2.1",
@@ -113,6 +112,7 @@
"High Tier Level 6",
"High Tier Level 6.1",
"High Tier Level 6.2",
+ "Level unknown",
};
static const char *const hevc_profile[] = {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 2289b23..04876d2 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1267,10 +1267,9 @@
return -EINVAL;
}
if (*num_buffers < bufreq->buffer_count_min_host) {
- dprintk(VIDC_ERR,
- "Invalid parameters : Req = %d Act = %d\n",
+ dprintk(VIDC_DBG,
+ "Client passed num buffers %d less than the min_host count %d\n",
*num_buffers, bufreq->buffer_count_min_host);
- return -EINVAL;
}
*num_planes = inst->bufq[OUTPUT_PORT].num_planes;
if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
@@ -1299,11 +1298,10 @@
if (inst->session_type != MSM_VIDC_DECODER &&
inst->state > MSM_VIDC_LOAD_RESOURCES_DONE) {
if (*num_buffers < bufreq->buffer_count_min_host) {
- dprintk(VIDC_ERR,
- "Invalid parameters : Req = %d Act = %d\n",
+ dprintk(VIDC_DBG,
+ "Client passed num buffers %d less than the min_host count %d\n",
*num_buffers,
bufreq->buffer_count_min_host);
- return -EINVAL;
}
}
*num_planes = inst->bufq[CAPTURE_PORT].num_planes;
@@ -1449,8 +1447,6 @@
}
}
- msm_comm_set_use_sys_cache(inst);
-
/*
* For seq_changed_insufficient, driver should set session_continue
* to firmware after the following sequence
@@ -1890,16 +1886,30 @@
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
- case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
+ ctrl->val = msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ inst->profile);
+ break;
case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
- ctrl->val = inst->profile;
+ ctrl->val = msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE,
+ inst->profile);
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ ctrl->val = msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ inst->level);
+ break;
case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
- case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
+ ctrl->val = msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+ inst->level);
+ break;
case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
- ctrl->val = inst->level;
+ ctrl->val = msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL,
+ inst->level);
break;
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index c0bbfbb..b1a8e8b 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -199,6 +199,8 @@
return V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
case HAL_H264_LEVEL_51:
return V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
+ case HAL_H264_LEVEL_52:
+ return V4L2_MPEG_VIDEO_H264_LEVEL_5_2;
default:
goto unknown_value;
}
@@ -212,7 +214,91 @@
default:
goto unknown_value;
}
+ case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
+ switch (value) {
+ case HAL_HEVC_PROFILE_MAIN:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN;
+ case HAL_HEVC_PROFILE_MAIN10:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10;
+ case HAL_HEVC_PROFILE_MAIN_STILL_PIC:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
+ switch (value) {
+ case HAL_HEVC_MAIN_TIER_LEVEL_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1;
+ case HAL_HEVC_MAIN_TIER_LEVEL_2:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2;
+ case HAL_HEVC_MAIN_TIER_LEVEL_2_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1;
+ case HAL_HEVC_MAIN_TIER_LEVEL_3:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3;
+ case HAL_HEVC_MAIN_TIER_LEVEL_3_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1;
+ case HAL_HEVC_MAIN_TIER_LEVEL_4:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4;
+ case HAL_HEVC_MAIN_TIER_LEVEL_4_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1;
+ case HAL_HEVC_MAIN_TIER_LEVEL_5:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5;
+ case HAL_HEVC_MAIN_TIER_LEVEL_5_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1;
+ case HAL_HEVC_MAIN_TIER_LEVEL_5_2:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2;
+ case HAL_HEVC_MAIN_TIER_LEVEL_6:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6;
+ case HAL_HEVC_MAIN_TIER_LEVEL_6_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1;
+ case HAL_HEVC_MAIN_TIER_LEVEL_6_2:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_2;
+ case HAL_HEVC_HIGH_TIER_LEVEL_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1;
+ case HAL_HEVC_HIGH_TIER_LEVEL_2:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2;
+ case HAL_HEVC_HIGH_TIER_LEVEL_2_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1;
+ case HAL_HEVC_HIGH_TIER_LEVEL_3:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3;
+ case HAL_HEVC_HIGH_TIER_LEVEL_3_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1;
+ case HAL_HEVC_HIGH_TIER_LEVEL_4:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4;
+ case HAL_HEVC_HIGH_TIER_LEVEL_4_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1;
+ case HAL_HEVC_HIGH_TIER_LEVEL_5:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5;
+ case HAL_HEVC_HIGH_TIER_LEVEL_5_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1;
+ case HAL_HEVC_HIGH_TIER_LEVEL_5_2:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2;
+ case HAL_HEVC_HIGH_TIER_LEVEL_6:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6;
+ case HAL_HEVC_HIGH_TIER_LEVEL_6_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1;
+ case HAL_HEVC_HIGH_TIER_LEVEL_6_2:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_2;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_UNKNOWN:
+ return HAL_HEVC_TIER_LEVEL_UNKNOWN;
+ default:
+ goto unknown_value;
+ }
case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+ switch (value) {
+ case HAL_VPX_LEVEL_VERSION_0:
+ return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0;
+ case HAL_VPX_LEVEL_VERSION_1:
+ return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1;
+ case HAL_VPX_LEVEL_VERSION_2:
+ return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2;
+ case HAL_VPX_LEVEL_VERSION_3:
+ return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3;
+ case HAL_VPX_LEVEL_UNUSED:
+ return V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED;
+ default:
+ goto unknown_value;
+ }
case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
/*
@@ -396,6 +482,8 @@
return HAL_HEVC_HIGH_TIER_LEVEL_6;
case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1:
return HAL_HEVC_HIGH_TIER_LEVEL_6_1;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_2:
+ return HAL_HEVC_HIGH_TIER_LEVEL_6_2;
case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_UNKNOWN:
return HAL_HEVC_TIER_LEVEL_UNKNOWN;
default:
@@ -1463,15 +1551,9 @@
* ptr[4] = colour space
*/
- inst->entropy_mode = msm_comm_hal_to_v4l2(
- V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
- event_notify->entropy_mode);
- inst->profile = msm_comm_hal_to_v4l2(
- V4L2_CID_MPEG_VIDEO_H264_PROFILE,
- event_notify->profile);
- inst->level = msm_comm_hal_to_v4l2(
- V4L2_CID_MPEG_VIDEO_H264_LEVEL,
- event_notify->level);
+ inst->entropy_mode = event_notify->entropy_mode;
+ inst->profile = event_notify->profile;
+ inst->level = event_notify->level;
ptr = (u32 *)seq_changed_event.u.data;
ptr[0] = event_notify->height;
@@ -2342,7 +2424,7 @@
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
vbuf->flags |= V4L2_QCOM_BUF_FLAG_EOS;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
- vbuf->flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+ vbuf->flags |= V4L2_QCOM_BUF_FLAG_CODECCONFIG;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
vbuf->flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
@@ -5554,40 +5636,3 @@
return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height);
}
-void msm_comm_set_use_sys_cache(struct msm_vidc_inst *inst)
-{
- struct hal_enable syscache_use;
- int rc = 0;
-
-
- if (!inst->core->resources.sys_cache_enabled)
- goto exit;
-
- syscache_use.enable = false;
- inst->clk_data.use_sys_cache = false;
-
- if (inst->flags & VIDC_REALTIME)
- syscache_use.enable = true;
-
- if (inst->flags & VIDC_THUMBNAIL)
- syscache_use.enable = false;
-
- dprintk(VIDC_DBG,
- "set_use_sys_cache: enable = %d inst = %pK flags =%d\n",
- syscache_use.enable, inst, inst->flags);
- rc = msm_comm_try_set_prop(inst, HAL_PARAM_USE_SYS_CACHE,
- &syscache_use);
- if (rc) {
- dprintk(VIDC_ERR, "set_use_sys_cache: failed!!\n");
- inst->clk_data.use_sys_cache = false;
- goto exit;
- }
-
- inst->clk_data.use_sys_cache = syscache_use.enable;
-
- return;
-
-exit:
- return;
-}
-
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index f62c132..a8f776f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -31,6 +31,7 @@
bool msm_vidc_thermal_mitigation_disabled = !true;
bool msm_vidc_clock_scaling = true;
bool msm_vidc_debug_timeout = !true;
+bool msm_vidc_syscache_disable = true;
#define MAX_DBG_BUF_SIZE 4096
@@ -186,6 +187,8 @@
&msm_vidc_clock_scaling) &&
__debugfs_create(bool, "debug_timeout",
&msm_vidc_debug_timeout);
+ __debugfs_create(bool, "disable_video_syscache",
+ &msm_vidc_syscache_disable);
#undef __debugfs_create
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index f5c8e5a..c23ff82 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -64,6 +64,7 @@
extern bool msm_vidc_thermal_mitigation_disabled;
extern bool msm_vidc_clock_scaling;
extern bool msm_vidc_debug_timeout;
+extern bool msm_vidc_syscache_disable;
#define VIDC_MSG_PRIO2STRING(__level) ({ \
char *__str; \
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 17c3045..37bccbd 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -224,7 +224,6 @@
u32 core_id;
enum hal_work_mode work_mode;
bool low_latency_mode;
- bool use_sys_cache;
};
struct profile_data {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index 5cf4628..d259072 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -275,12 +275,12 @@
"cache-slice-names", c, &vsc->name);
}
- res->sys_cache_enabled = true;
+ res->sys_cache_present = true;
return 0;
err_load_subcache_table_fail:
- res->sys_cache_enabled = false;
+ res->sys_cache_present = false;
subcaches->count = 0;
subcaches->subcache_tbl = NULL;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index d76985e..b07785a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -159,6 +159,7 @@
struct dcvs_table *dcvs_tbl;
uint32_t dcvs_tbl_size;
struct dcvs_limit *dcvs_limit;
+ bool sys_cache_present;
bool sys_cache_enabled;
struct subcache_set subcache_set;
struct reg_set reg_set;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 5a8dd26..8968764 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -120,6 +120,11 @@
return device->state != VENUS_STATE_DEINIT;
}
+static inline bool is_sys_cache_present(struct venus_hfi_device *device)
+{
+ return device->res->sys_cache_present;
+}
+
static void __dump_packet(u8 *packet, enum vidc_msg_prio log_level)
{
u32 c = 0, packet_size = *(u32 *)packet;
@@ -3492,7 +3497,7 @@
goto exit;
}
- if (!device->res->sys_cache_enabled)
+ if (!is_sys_cache_present(device))
goto exit;
venus_hfi_for_each_subcache_reverse(device, sinfo) {
@@ -3519,7 +3524,7 @@
return -EINVAL;
}
- if (!device->res->sys_cache_enabled)
+ if (!is_sys_cache_present(device))
return 0;
venus_hfi_for_each_subcache(device, sinfo) {
@@ -3764,7 +3769,7 @@
struct hfi_resource_subcache_type *sc_res;
struct vidc_resource_hdr rhdr;
- if (!device->res->sys_cache_enabled)
+ if (msm_vidc_syscache_disable || !is_sys_cache_present(device))
return 0;
memset((void *)resource, 0x0, (sizeof(u32) * VIDC_MAX_SUBCACHE_SIZE));
@@ -3812,6 +3817,8 @@
dprintk(VIDC_DBG, "Activated & Set Subcaches to Venus\n");
+ device->res->sys_cache_enabled = true;
+
return 0;
err_fail_set_subacaches:
@@ -3830,7 +3837,7 @@
struct hfi_resource_subcache_type *sc_res;
struct vidc_resource_hdr rhdr;
- if (!device->res->sys_cache_enabled)
+ if (msm_vidc_syscache_disable || !is_sys_cache_present(device))
return 0;
dprintk(VIDC_DBG, "Disabling Subcaches\n");
@@ -3877,6 +3884,8 @@
}
}
+ device->res->sys_cache_enabled = false;
+
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 48a6f17..5601f1b 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -56,13 +56,6 @@
#define HFI_ERR_SESSION_START_CODE_NOT_FOUND \
(HFI_OX_BASE + 0x1004)
-#define HFI_BUFFER_INTERNAL_SCRATCH (HFI_OX_BASE + 0x1)
-#define HFI_BUFFER_EXTRADATA_INPUT (HFI_OX_BASE + 0x2)
-#define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_OX_BASE + 0x3)
-#define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_OX_BASE + 0x4)
-#define HFI_BUFFER_INTERNAL_SCRATCH_1 (HFI_OX_BASE + 0x5)
-#define HFI_BUFFER_INTERNAL_SCRATCH_2 (HFI_OX_BASE + 0x6)
-#define HFI_BUFFER_INTERNAL_RECON (HFI_OX_BASE + 0x9)
#define HFI_BUFFER_MODE_DYNAMIC (HFI_OX_BASE + 0x3)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index bcc29c0..cc35bb3 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -224,7 +224,6 @@
HAL_PARAM_VIDEO_CORES_USAGE,
HAL_PARAM_VIDEO_WORK_MODE,
HAL_PARAM_SECURE,
- HAL_PARAM_USE_SYS_CACHE,
};
enum hal_domain {
@@ -377,11 +376,11 @@
};
enum hal_vpx_level {
+ HAL_VPX_LEVEL_UNUSED = 0x00000000,
HAL_VPX_LEVEL_VERSION_0 = 0x00000001,
HAL_VPX_LEVEL_VERSION_1 = 0x00000002,
HAL_VPX_LEVEL_VERSION_2 = 0x00000004,
HAL_VPX_LEVEL_VERSION_3 = 0x00000008,
- HAL_VPX_LEVEL_UNUSED = 0x10000000,
};
struct hal_frame_rate {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index fc638f0..0df4812 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -155,6 +155,13 @@
#define HFI_BUFFER_OUTPUT2 (HFI_COMMON_BASE + 0x3)
#define HFI_BUFFER_INTERNAL_PERSIST (HFI_COMMON_BASE + 0x4)
#define HFI_BUFFER_INTERNAL_PERSIST_1 (HFI_COMMON_BASE + 0x5)
+#define HFI_BUFFER_COMMON_INTERNAL_SCRATCH (HFI_COMMON_BASE + 0x6)
+#define HFI_BUFFER_COMMON_INTERNAL_SCRATCH_1 (HFI_COMMON_BASE + 0x7)
+#define HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2 (HFI_COMMON_BASE + 0x8)
+#define HFI_BUFFER_COMMON_INTERNAL_RECON (HFI_COMMON_BASE + 0x9)
+#define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_COMMON_BASE + 0xA)
+#define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_COMMON_BASE + 0xB)
+#define HFI_BUFFER_EXTRADATA_INPUT (HFI_COMMON_BASE + 0xC)
#define HFI_BITDEPTH_8 (HFI_COMMON_BASE + 0x0)
#define HFI_BITDEPTH_9 (HFI_COMMON_BASE + 0x1)
@@ -220,8 +227,6 @@
(HFI_PROPERTY_PARAM_COMMON_START + 0x010)
#define HFI_PROPERTY_PARAM_SECURE_SESSION \
(HFI_PROPERTY_PARAM_COMMON_START + 0x011)
-#define HFI_PROPERTY_PARAM_USE_SYS_CACHE \
- (HFI_PROPERTY_PARAM_COMMON_START + 0x012)
#define HFI_PROPERTY_PARAM_WORK_MODE \
(HFI_PROPERTY_PARAM_COMMON_START + 0x015)
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index 6c033c9..78cb3e2 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -538,7 +538,8 @@
nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
altmap = NULL;
} else if (nd_pfn->mode == PFN_MODE_PMEM) {
- nd_pfn->npfns = (resource_size(res) - offset) / PAGE_SIZE;
+ nd_pfn->npfns = PFN_SECTION_ALIGN_UP((resource_size(res)
+ - offset) / PAGE_SIZE);
if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
dev_info(&nd_pfn->dev,
"number of pfns truncated from %lld to %ld\n",
@@ -625,7 +626,8 @@
*/
start += start_pad;
size = resource_size(&nsio->res);
- npfns = (size - start_pad - end_trunc - SZ_8K) / SZ_4K;
+ npfns = PFN_SECTION_ALIGN_UP((size - start_pad - end_trunc - SZ_8K)
+ / PAGE_SIZE);
if (nd_pfn->mode == PFN_MODE_PMEM) {
/*
* vmemmap_populate_hugepages() allocates the memmap array in
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 2461843..b480859 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -383,12 +383,12 @@
static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
{
- struct pmem_device *pmem = dev_get_drvdata(dev);
- struct nd_region *nd_region = to_region(pmem);
+ struct nd_region *nd_region;
resource_size_t offset = 0, end_trunc = 0;
struct nd_namespace_common *ndns;
struct nd_namespace_io *nsio;
struct resource res;
+ struct badblocks *bb;
if (event != NVDIMM_REVALIDATE_POISON)
return;
@@ -397,20 +397,33 @@
struct nd_btt *nd_btt = to_nd_btt(dev);
ndns = nd_btt->ndns;
- } else if (is_nd_pfn(dev)) {
- struct nd_pfn *nd_pfn = to_nd_pfn(dev);
- struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
+ nd_region = to_nd_region(ndns->dev.parent);
+ nsio = to_nd_namespace_io(&ndns->dev);
+ bb = &nsio->bb;
+ } else {
+ struct pmem_device *pmem = dev_get_drvdata(dev);
- ndns = nd_pfn->ndns;
- offset = pmem->data_offset + __le32_to_cpu(pfn_sb->start_pad);
- end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
- } else
- ndns = to_ndns(dev);
+ nd_region = to_region(pmem);
+ bb = &pmem->bb;
- nsio = to_nd_namespace_io(&ndns->dev);
+ if (is_nd_pfn(dev)) {
+ struct nd_pfn *nd_pfn = to_nd_pfn(dev);
+ struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
+
+ ndns = nd_pfn->ndns;
+ offset = pmem->data_offset +
+ __le32_to_cpu(pfn_sb->start_pad);
+ end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
+ } else {
+ ndns = to_ndns(dev);
+ }
+
+ nsio = to_nd_namespace_io(&ndns->dev);
+ }
+
res.start = nsio->res.start + offset;
res.end = nsio->res.end - end_trunc;
- nvdimm_badblocks_populate(nd_region, &pmem->bb, &res);
+ nvdimm_badblocks_populate(nd_region, bb, &res);
}
MODULE_ALIAS("pmem");
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index 9cf6f1a..f623062 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -968,17 +968,20 @@
*/
int nvdimm_has_flush(struct nd_region *nd_region)
{
- struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev);
int i;
/* no nvdimm == flushing capability unknown */
if (nd_region->ndr_mappings == 0)
return -ENXIO;
- for (i = 0; i < nd_region->ndr_mappings; i++)
- /* flush hints present, flushing required */
- if (ndrd_get_flush_wpq(ndrd, i, 0))
+ for (i = 0; i < nd_region->ndr_mappings; i++) {
+ struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+ struct nvdimm *nvdimm = nd_mapping->nvdimm;
+
+ /* flush hints present / available */
+ if (nvdimm->num_flush)
return 1;
+ }
/*
* The platform defines dimm devices without hints, assume
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 2a1367e..9520166 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -17,6 +17,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinctrl.h>
@@ -31,7 +32,7 @@
#include <linux/reboot.h>
#include <linux/pm.h>
#include <linux/log2.h>
-
+#include <linux/irq.h>
#include "../core.h"
#include "../pinconf.h"
#include "pinctrl-msm.h"
@@ -749,6 +750,91 @@
.irq_set_wake = msm_gpio_irq_set_wake,
};
+static void msm_dirconn_irq_mask(struct irq_data *d)
+{
+ struct irq_desc *desc = irq_data_to_desc(d);
+ struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
+
+ if (parent_data->chip->irq_mask)
+ parent_data->chip->irq_mask(parent_data);
+}
+
+static void msm_dirconn_irq_unmask(struct irq_data *d)
+{
+ struct irq_desc *desc = irq_data_to_desc(d);
+ struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
+
+ if (parent_data->chip->irq_unmask)
+ parent_data->chip->irq_unmask(parent_data);
+}
+
+static void msm_dirconn_irq_ack(struct irq_data *d)
+{
+ struct irq_desc *desc = irq_data_to_desc(d);
+ struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
+
+ if (parent_data->chip->irq_ack)
+ parent_data->chip->irq_ack(parent_data);
+}
+
+static void msm_dirconn_irq_eoi(struct irq_data *d)
+{
+ struct irq_desc *desc = irq_data_to_desc(d);
+ struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
+
+ if (parent_data->chip->irq_eoi)
+ parent_data->chip->irq_eoi(parent_data);
+}
+
+static int msm_dirconn_irq_set_affinity(struct irq_data *d,
+ const struct cpumask *maskval, bool force)
+{
+ struct irq_desc *desc = irq_data_to_desc(d);
+ struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
+
+ if (parent_data->chip->irq_set_affinity)
+ return parent_data->chip->irq_set_affinity(parent_data,
+ maskval, force);
+ return 0;
+}
+
+static int msm_dirconn_irq_set_vcpu_affinity(struct irq_data *d,
+ void *vcpu_info)
+{
+ struct irq_desc *desc = irq_data_to_desc(d);
+ struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
+
+ if (parent_data->chip->irq_set_vcpu_affinity)
+ return parent_data->chip->irq_set_vcpu_affinity(parent_data,
+ vcpu_info);
+ return 0;
+}
+
+static int msm_dirconn_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ struct irq_desc *desc = irq_data_to_desc(d);
+ struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
+
+ if (parent_data->chip->irq_set_type)
+ return parent_data->chip->irq_set_type(parent_data, type);
+
+ return 0;
+}
+
+static struct irq_chip msm_dirconn_irq_chip = {
+ .name = "msmgpio-dc",
+ .irq_mask = msm_dirconn_irq_mask,
+ .irq_unmask = msm_dirconn_irq_unmask,
+ .irq_eoi = msm_dirconn_irq_eoi,
+ .irq_ack = msm_dirconn_irq_ack,
+ .irq_set_type = msm_dirconn_irq_set_type,
+ .irq_set_affinity = msm_dirconn_irq_set_affinity,
+ .irq_set_vcpu_affinity = msm_dirconn_irq_set_vcpu_affinity,
+ .flags = IRQCHIP_SKIP_SET_WAKE
+ | IRQCHIP_MASK_ON_SUSPEND
+ | IRQCHIP_SET_TYPE_MASKED,
+};
+
static void msm_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
@@ -783,6 +869,55 @@
chained_irq_exit(chip, desc);
}
+static void msm_gpio_dirconn_handler(struct irq_desc *desc)
+{
+ struct irq_data *irqd = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(chip, desc);
+ generic_handle_irq(irqd->irq);
+ chained_irq_exit(chip, desc);
+}
+
+static void msm_gpio_setup_dir_connects(struct msm_pinctrl *pctrl)
+{
+ struct device_node *parent_node;
+ struct irq_domain *parent_domain;
+ struct irq_fwspec fwspec;
+ unsigned int i;
+
+ parent_node = of_irq_find_parent(pctrl->dev->of_node);
+
+ if (!parent_node)
+ return;
+
+ parent_domain = irq_find_host(parent_node);
+ if (!parent_domain)
+ return;
+
+ fwspec.fwnode = parent_domain->fwnode;
+ for (i = 0; i < pctrl->soc->n_dir_conns; i++) {
+ const struct msm_dir_conn *dirconn = &pctrl->soc->dir_conn[i];
+ unsigned int parent_irq;
+ int irq;
+
+ fwspec.param[0] = 0; /* SPI */
+ fwspec.param[1] = dirconn->hwirq;
+ fwspec.param[2] = IRQ_TYPE_NONE;
+ fwspec.param_count = 3;
+ parent_irq = irq_create_fwspec_mapping(&fwspec);
+
+ irq = irq_find_mapping(pctrl->chip.irqdomain, dirconn->gpio);
+
+ irq_set_parent(irq, parent_irq);
+ irq_set_chip(irq, &msm_dirconn_irq_chip);
+ irq_set_chip_data(irq, irq_get_irq_data(parent_irq));
+ __irq_set_handler(parent_irq, msm_gpio_dirconn_handler,
+ false, NULL);
+ irq_set_handler_data(parent_irq, irq_get_irq_data(irq));
+ }
+}
+
static int msm_gpio_init(struct msm_pinctrl *pctrl)
{
struct gpio_chip *chip;
@@ -827,6 +962,7 @@
gpiochip_set_chained_irqchip(chip, &msm_gpio_irq_chip, pctrl->irq,
msm_gpio_irq_handler);
+ msm_gpio_setup_dir_connects(pctrl);
return 0;
}
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
index e986fda..0e223e0 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -95,6 +95,16 @@
unsigned intr_polarity_bit:5;
unsigned intr_detection_bit:5;
unsigned intr_detection_width:5;
+}
+
+/**
+ * struct msm_dir_conn - Direct GPIO connect configuration
+ * @gpio: GPIO pin number
+ * @hwirq: The GIC interrupt that the pin is connected to
+ */;
+struct msm_dir_conn {
+ unsigned int gpio;
+ irq_hw_number_t hwirq;
};
/**
@@ -106,6 +116,8 @@
* @groups: An array describing all pin groups the pin SoC supports.
* @ngroups: The numbmer of entries in @groups.
* @ngpio: The number of pingroups the driver should expose as GPIOs.
+ * @dir_conn: An array describing all the pins directly connected to GIC.
+ * @ndirconns: The number of pins directly connected to GIC
*/
struct msm_pinctrl_soc_data {
const struct pinctrl_pin_desc *pins;
@@ -115,6 +127,8 @@
const struct msm_pingroup *groups;
unsigned ngroups;
unsigned ngpios;
+ const struct msm_dir_conn *dir_conn;
+ unsigned int n_dir_conns;
};
int msm_pinctrl_probe(struct platform_device *pdev,
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index 30c31a8..7d125eb 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -2377,6 +2377,84 @@
UFS_RESET(ufs_reset, 0x99f000),
};
+static const struct msm_dir_conn sdm845_dir_conn[] = {
+ {1, 510},
+ {3, 511},
+ {5, 512},
+ {10, 513},
+ {11, 514},
+ {20, 515},
+ {22, 516},
+ {24, 517},
+ {26, 518},
+ {30, 519},
+ {31, 639},
+ {32, 521},
+ {34, 522},
+ {36, 523},
+ {37, 524},
+ {38, 525},
+ {39, 526},
+ {40, 527},
+ {41, 637},
+ {43, 529},
+ {44, 530},
+ {46, 531},
+ {48, 532},
+ {49, 640},
+ {52, 534},
+ {53, 535},
+ {54, 536},
+ {56, 537},
+ {57, 538},
+ {58, 539},
+ {59, 540},
+ {60, 541},
+ {61, 542},
+ {62, 543},
+ {63, 544},
+ {64, 545},
+ {66, 546},
+ {68, 547},
+ {71, 548},
+ {73, 549},
+ {77, 550},
+ {78, 551},
+ {79, 552},
+ {80, 553},
+ {84, 554},
+ {85, 555},
+ {86, 556},
+ {88, 557},
+ {89, 638},
+ {91, 559},
+ {92, 560},
+ {95, 561},
+ {96, 562},
+ {97, 563},
+ {101, 564},
+ {103, 565},
+ {104, 566},
+ {115, 570},
+ {116, 571},
+ {117, 572},
+ {118, 573},
+ {119, 609},
+ {120, 610},
+ {121, 611},
+ {122, 612},
+ {123, 613},
+ {124, 614},
+ {125, 615},
+ {127, 617},
+ {128, 618},
+ {129, 619},
+ {130, 620},
+ {132, 621},
+ {133, 622},
+ {145, 623},
+};
+
static const struct msm_pinctrl_soc_data sdm845_pinctrl = {
.pins = sdm845_pins,
.npins = ARRAY_SIZE(sdm845_pins),
@@ -2385,6 +2463,8 @@
.groups = sdm845_groups,
.ngroups = ARRAY_SIZE(sdm845_groups),
.ngpios = 150,
+ .dir_conn = sdm845_dir_conn,
+ .n_dir_conns = ARRAY_SIZE(sdm845_dir_conn),
};
static int sdm845_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index 6c597f0..38264d9 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -101,76 +101,76 @@
const char *ipa_clients_strings[IPA_CLIENT_MAX] = {
__stringify(IPA_CLIENT_HSIC1_PROD),
- __stringify(IPA_CLIENT_WLAN1_PROD),
- __stringify(IPA_CLIENT_HSIC2_PROD),
- __stringify(IPA_CLIENT_USB2_PROD),
- __stringify(IPA_CLIENT_HSIC3_PROD),
- __stringify(IPA_CLIENT_USB3_PROD),
- __stringify(IPA_CLIENT_HSIC4_PROD),
- __stringify(IPA_CLIENT_USB4_PROD),
- __stringify(IPA_CLIENT_HSIC5_PROD),
- __stringify(IPA_CLIENT_USB_PROD),
- __stringify(IPA_CLIENT_A5_WLAN_AMPDU_PROD),
- __stringify(IPA_CLIENT_A2_EMBEDDED_PROD),
- __stringify(IPA_CLIENT_A2_TETHERED_PROD),
- __stringify(IPA_CLIENT_APPS_LAN_PROD),
- __stringify(IPA_CLIENT_APPS_WAN_PROD),
- __stringify(IPA_CLIENT_APPS_CMD_PROD),
- __stringify(IPA_CLIENT_ODU_PROD),
- __stringify(IPA_CLIENT_MHI_PROD),
- __stringify(IPA_CLIENT_Q6_LAN_PROD),
- __stringify(IPA_CLIENT_Q6_WAN_PROD),
- __stringify(IPA_CLIENT_Q6_CMD_PROD),
- __stringify(IPA_CLIENT_MEMCPY_DMA_SYNC_PROD),
- __stringify(IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD),
- __stringify(IPA_CLIENT_Q6_DECOMP_PROD),
- __stringify(IPA_CLIENT_Q6_DECOMP2_PROD),
- __stringify(IPA_CLIENT_UC_USB_PROD),
- __stringify(IPA_CLIENT_ETHERNET_PROD),
-
- /* Below PROD client type is only for test purpose */
- __stringify(IPA_CLIENT_TEST_PROD),
- __stringify(IPA_CLIENT_TEST1_PROD),
- __stringify(IPA_CLIENT_TEST2_PROD),
- __stringify(IPA_CLIENT_TEST3_PROD),
- __stringify(IPA_CLIENT_TEST4_PROD),
-
__stringify(IPA_CLIENT_HSIC1_CONS),
- __stringify(IPA_CLIENT_WLAN1_CONS),
+ __stringify(IPA_CLIENT_HSIC2_PROD),
__stringify(IPA_CLIENT_HSIC2_CONS),
- __stringify(IPA_CLIENT_USB2_CONS),
- __stringify(IPA_CLIENT_WLAN2_CONS),
+ __stringify(IPA_CLIENT_HSIC3_PROD),
__stringify(IPA_CLIENT_HSIC3_CONS),
- __stringify(IPA_CLIENT_USB3_CONS),
- __stringify(IPA_CLIENT_WLAN3_CONS),
+ __stringify(IPA_CLIENT_HSIC4_PROD),
__stringify(IPA_CLIENT_HSIC4_CONS),
- __stringify(IPA_CLIENT_USB4_CONS),
- __stringify(IPA_CLIENT_WLAN4_CONS),
+ __stringify(IPA_CLIENT_HSIC5_PROD),
__stringify(IPA_CLIENT_HSIC5_CONS),
+ __stringify(IPA_CLIENT_WLAN1_PROD),
+ __stringify(IPA_CLIENT_WLAN1_CONS),
+ __stringify(IPA_CLIENT_A5_WLAN_AMPDU_PROD),
+ __stringify(IPA_CLIENT_WLAN2_CONS),
+ __stringify(RESERVERD_PROD_14),
+ __stringify(IPA_CLIENT_WLAN3_CONS),
+ __stringify(RESERVERD_PROD_16),
+ __stringify(IPA_CLIENT_WLAN4_CONS),
+ __stringify(IPA_CLIENT_USB_PROD),
__stringify(IPA_CLIENT_USB_CONS),
+ __stringify(IPA_CLIENT_USB2_PROD),
+ __stringify(IPA_CLIENT_USB2_CONS),
+ __stringify(IPA_CLIENT_USB3_PROD),
+ __stringify(IPA_CLIENT_USB3_CONS),
+ __stringify(IPA_CLIENT_USB4_PROD),
+ __stringify(IPA_CLIENT_USB4_CONS),
+ __stringify(IPA_CLIENT_UC_USB_PROD),
__stringify(IPA_CLIENT_USB_DPL_CONS),
+ __stringify(IPA_CLIENT_A2_EMBEDDED_PROD),
__stringify(IPA_CLIENT_A2_EMBEDDED_CONS),
+ __stringify(IPA_CLIENT_A2_TETHERED_PROD),
__stringify(IPA_CLIENT_A2_TETHERED_CONS),
- __stringify(IPA_CLIENT_A5_LAN_WAN_CONS),
+ __stringify(IPA_CLIENT_APPS_LAN_PROD),
__stringify(IPA_CLIENT_APPS_LAN_CONS),
+ __stringify(IPA_CLIENT_APPS_WAN_PROD),
__stringify(IPA_CLIENT_APPS_WAN_CONS),
+ __stringify(IPA_CLIENT_APPS_CMD_PROD),
+ __stringify(IPA_CLIENT_A5_LAN_WAN_CONS),
+ __stringify(IPA_CLIENT_ODU_PROD),
__stringify(IPA_CLIENT_ODU_EMB_CONS),
+ __stringify(RESERVERD_PROD_40),
__stringify(IPA_CLIENT_ODU_TETH_CONS),
+ __stringify(IPA_CLIENT_MHI_PROD),
__stringify(IPA_CLIENT_MHI_CONS),
- __stringify(IPA_CLIENT_Q6_LAN_CONS),
- __stringify(IPA_CLIENT_Q6_WAN_CONS),
- __stringify(IPA_CLIENT_Q6_DUN_CONS),
+ __stringify(IPA_CLIENT_MEMCPY_DMA_SYNC_PROD),
__stringify(IPA_CLIENT_MEMCPY_DMA_SYNC_CONS),
+ __stringify(IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD),
__stringify(IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS),
- __stringify(IPA_CLIENT_Q6_DECOMP_CONS),
- __stringify(IPA_CLIENT_Q6_DECOMP2_CONS),
- __stringify(IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS),
+ __stringify(IPA_CLIENT_ETHERNET_PROD),
__stringify(IPA_CLIENT_ETHERNET_CONS),
- /* Below CONS client type is only for test purpose */
+ __stringify(IPA_CLIENT_Q6_LAN_PROD),
+ __stringify(IPA_CLIENT_Q6_LAN_CONS),
+ __stringify(IPA_CLIENT_Q6_WAN_PROD),
+ __stringify(IPA_CLIENT_Q6_WAN_CONS),
+ __stringify(IPA_CLIENT_Q6_CMD_PROD),
+ __stringify(IPA_CLIENT_Q6_DUN_CONS),
+ __stringify(IPA_CLIENT_Q6_DECOMP_PROD),
+ __stringify(IPA_CLIENT_Q6_DECOMP_CONS),
+ __stringify(IPA_CLIENT_Q6_DECOMP2_PROD),
+ __stringify(IPA_CLIENT_Q6_DECOMP2_CONS),
+ __stringify(RESERVERD_PROD_60),
+ __stringify(IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS),
+ __stringify(IPA_CLIENT_TEST_PROD),
__stringify(IPA_CLIENT_TEST_CONS),
+ __stringify(IPA_CLIENT_TEST1_PROD),
__stringify(IPA_CLIENT_TEST1_CONS),
+ __stringify(IPA_CLIENT_TEST2_PROD),
__stringify(IPA_CLIENT_TEST2_CONS),
+ __stringify(IPA_CLIENT_TEST3_PROD),
__stringify(IPA_CLIENT_TEST3_CONS),
+ __stringify(IPA_CLIENT_TEST4_PROD),
__stringify(IPA_CLIENT_TEST4_CONS),
};
diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h
index 981129e..50804ee 100644
--- a/drivers/platform/msm/ipa/ipa_common_i.h
+++ b/drivers/platform/msm/ipa/ipa_common_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -108,8 +108,10 @@
ipa_assert();\
} while (0)
-#define IPA_CLIENT_IS_PROD(x) (x >= IPA_CLIENT_PROD && x < IPA_CLIENT_CONS)
-#define IPA_CLIENT_IS_CONS(x) (x >= IPA_CLIENT_CONS && x < IPA_CLIENT_MAX)
+#define IPA_CLIENT_IS_PROD(x) \
+ (x < IPA_CLIENT_MAX && (x & 0x1) == 0)
+#define IPA_CLIENT_IS_CONS(x) \
+ (x < IPA_CLIENT_MAX && (x & 0x1) == 1)
#define IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC (1000)
#define IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC (2000)
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index ea91b13..914028c 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -19,32 +19,33 @@
static const char *resource_name_to_str[IPA_RM_RESOURCE_MAX] = {
__stringify(IPA_RM_RESOURCE_Q6_PROD),
- __stringify(IPA_RM_RESOURCE_USB_PROD),
- __stringify(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD),
- __stringify(IPA_RM_RESOURCE_HSIC_PROD),
- __stringify(IPA_RM_RESOURCE_STD_ECM_PROD),
- __stringify(IPA_RM_RESOURCE_RNDIS_PROD),
- __stringify(IPA_RM_RESOURCE_WWAN_0_PROD),
- __stringify(IPA_RM_RESOURCE_WLAN_PROD),
- __stringify(IPA_RM_RESOURCE_ODU_ADAPT_PROD),
- __stringify(IPA_RM_RESOURCE_MHI_PROD),
- __stringify(IPA_RM_RESOURCE_ETHERNET_PROD),
__stringify(IPA_RM_RESOURCE_Q6_CONS),
+ __stringify(IPA_RM_RESOURCE_USB_PROD),
__stringify(IPA_RM_RESOURCE_USB_CONS),
+ __stringify(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD),
__stringify(IPA_RM_RESOURCE_USB_DPL_CONS),
+ __stringify(IPA_RM_RESOURCE_HSIC_PROD),
__stringify(IPA_RM_RESOURCE_HSIC_CONS),
- __stringify(IPA_RM_RESOURCE_WLAN_CONS),
+ __stringify(IPA_RM_RESOURCE_STD_ECM_PROD),
__stringify(IPA_RM_RESOURCE_APPS_CONS),
+ __stringify(IPA_RM_RESOURCE_RNDIS_PROD),
+ __stringify(RESERVED_CONS_11),
+ __stringify(IPA_RM_RESOURCE_WWAN_0_PROD),
+ __stringify(RESERVED_CONS_13),
+ __stringify(IPA_RM_RESOURCE_WLAN_PROD),
+ __stringify(IPA_RM_RESOURCE_WLAN_CONS),
+ __stringify(IPA_RM_RESOURCE_ODU_ADAPT_PROD),
__stringify(IPA_RM_RESOURCE_ODU_ADAPT_CONS),
+ __stringify(IPA_RM_RESOURCE_MHI_PROD),
__stringify(IPA_RM_RESOURCE_MHI_CONS),
+ __stringify(IPA_RM_RESOURCE_ETHERNET_PROD),
__stringify(IPA_RM_RESOURCE_ETHERNET_CONS),
};
struct ipa_rm_profile_vote_type {
enum ipa_voltage_level volt[IPA_RM_RESOURCE_MAX];
enum ipa_voltage_level curr_volt;
- u32 bw_prods[IPA_RM_RESOURCE_PROD_MAX];
- u32 bw_cons[IPA_RM_RESOURCE_CONS_MAX];
+ u32 bw_resources[IPA_RM_RESOURCE_MAX];
u32 curr_bw;
};
@@ -999,7 +1000,9 @@
return result;
spin_lock_irqsave(&ipa_rm_ctx->ipa_rm_lock, flags);
- for (i = 0; i < IPA_RM_RESOURCE_PROD_MAX; ++i) {
+ for (i = 0; i < IPA_RM_RESOURCE_MAX; ++i) {
+ if (!IPA_RM_RESORCE_IS_PROD(i))
+ continue;
result = ipa_rm_dep_graph_get_resource(
ipa_rm_ctx->dep_graph,
i,
@@ -1014,11 +1017,12 @@
}
}
- for (i = 0; i < IPA_RM_RESOURCE_PROD_MAX; i++)
- sum_bw_prod += ipa_rm_ctx->prof_vote.bw_prods[i];
-
- for (i = 0; i < IPA_RM_RESOURCE_CONS_MAX; i++)
- sum_bw_cons += ipa_rm_ctx->prof_vote.bw_cons[i];
+ for (i = 0; i < IPA_RM_RESOURCE_MAX; i++) {
+ if (IPA_RM_RESORCE_IS_PROD(i))
+ sum_bw_prod += ipa_rm_ctx->prof_vote.bw_resources[i];
+ else
+ sum_bw_cons += ipa_rm_ctx->prof_vote.bw_resources[i];
+ }
result = scnprintf(buf + cnt, size - cnt,
"All prod bandwidth: %d, All cons bandwidth: %d\n",
@@ -1118,15 +1122,7 @@
old_volt = ipa_rm_ctx->prof_vote.curr_volt;
old_bw = ipa_rm_ctx->prof_vote.curr_bw;
- if (IPA_RM_RESORCE_IS_PROD(resource_name)) {
- bw_ptr = &ipa_rm_ctx->prof_vote.bw_prods[resource_name];
- } else if (IPA_RM_RESORCE_IS_CONS(resource_name)) {
- bw_ptr = &ipa_rm_ctx->prof_vote.bw_cons[
- resource_name - IPA_RM_RESOURCE_PROD_MAX];
- } else {
- IPA_RM_ERR("Invalid resource_name\n");
- return;
- }
+ bw_ptr = &ipa_rm_ctx->prof_vote.bw_resources[resource_name];
switch (resource->state) {
case IPA_RM_GRANTED:
@@ -1161,11 +1157,12 @@
}
}
- for (i = 0; i < IPA_RM_RESOURCE_PROD_MAX; i++)
- sum_bw_prod += ipa_rm_ctx->prof_vote.bw_prods[i];
-
- for (i = 0; i < IPA_RM_RESOURCE_CONS_MAX; i++)
- sum_bw_cons += ipa_rm_ctx->prof_vote.bw_cons[i];
+ for (i = 0; i < IPA_RM_RESOURCE_MAX; i++) {
+ if (IPA_RM_RESORCE_IS_PROD(i))
+ sum_bw_prod += ipa_rm_ctx->prof_vote.bw_resources[i];
+ else
+ sum_bw_cons += ipa_rm_ctx->prof_vote.bw_resources[i];
+ }
IPA_RM_DBG_LOW("all prod bandwidth: %d all cons bandwidth: %d\n",
sum_bw_prod, sum_bw_cons);
diff --git a/drivers/platform/msm/ipa/ipa_rm_i.h b/drivers/platform/msm/ipa/ipa_rm_i.h
index 1610bb1..c0e3ce2 100644
--- a/drivers/platform/msm/ipa/ipa_rm_i.h
+++ b/drivers/platform/msm/ipa/ipa_rm_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -47,12 +47,10 @@
IPA_RM_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
-#define IPA_RM_RESOURCE_CONS_MAX \
- (IPA_RM_RESOURCE_MAX - IPA_RM_RESOURCE_PROD_MAX)
#define IPA_RM_RESORCE_IS_PROD(x) \
- (x >= IPA_RM_RESOURCE_PROD && x < IPA_RM_RESOURCE_PROD_MAX)
+ (x < IPA_RM_RESOURCE_MAX && (x & 0x1) == 0)
#define IPA_RM_RESORCE_IS_CONS(x) \
- (x >= IPA_RM_RESOURCE_PROD_MAX && x < IPA_RM_RESOURCE_MAX)
+ (x < IPA_RM_RESOURCE_MAX && (x & 0x1) == 1)
#define IPA_RM_INDEX_INVALID (-1)
#define IPA_RM_RELEASE_DELAY_IN_MSEC 1000
diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.c b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
index fe8e781..8365120 100644
--- a/drivers/platform/msm/ipa/ipa_rm_peers_list.c
+++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -32,9 +32,6 @@
resource_index = ipa_rm_prod_index(resource_name);
else if (IPA_RM_RESORCE_IS_CONS(resource_name)) {
resource_index = ipa_rm_cons_index(resource_name);
- if (resource_index != IPA_RM_INDEX_INVALID)
- resource_index =
- resource_index - IPA_RM_RESOURCE_PROD_MAX;
}
return resource_index;
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 9e74a3f..991208f 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -328,7 +328,7 @@
(*resource) = (struct ipa_rm_resource *) (*producer);
(*resource)->type = IPA_RM_PRODUCER;
- *max_peers = IPA_RM_RESOURCE_CONS_MAX;
+ *max_peers = IPA_RM_RESOURCE_MAX;
goto bail;
register_fail:
kfree(*producer);
@@ -371,7 +371,7 @@
(*resource) = (struct ipa_rm_resource *) (*consumer);
(*resource)->type = IPA_RM_CONSUMER;
init_completion(&((*consumer)->request_consumer_in_progress));
- *max_peers = IPA_RM_RESOURCE_PROD_MAX;
+ *max_peers = IPA_RM_RESOURCE_MAX;
bail:
return result;
}
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index f5d8227..947a54c 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -3713,7 +3713,7 @@
resource = ipa2_get_rm_resource_from_ep(i);
res = ipa_rm_request_resource_with_timer(
resource);
- if (res == -EPERM &&
+ if ((res == -EPERM) &&
IPA_CLIENT_IS_CONS(
ipa_ctx->ep[i].client)) {
holb_cfg.en = 1;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
index a822f66..0196815 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
@@ -953,7 +953,7 @@
IPADBG("\n");
- for (client_num = IPA_CLIENT_CONS;
+ for (client_num = 0;
client_num < IPA_CLIENT_MAX; client_num++) {
if (!IPA_CLIENT_IS_APPS_CONS(client_num))
continue;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index a50665c..da62b77 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -72,209 +72,124 @@
#define INVALID_EP_MAPPING_INDEX (-1)
-static const int ep_mapping[3][IPA_CLIENT_MAX] = {
- [IPA_1_1][IPA_CLIENT_HSIC1_PROD] = 19,
- [IPA_1_1][IPA_CLIENT_WLAN1_PROD] = -1,
- [IPA_1_1][IPA_CLIENT_HSIC2_PROD] = 12,
- [IPA_1_1][IPA_CLIENT_USB2_PROD] = 12,
- [IPA_1_1][IPA_CLIENT_HSIC3_PROD] = 13,
- [IPA_1_1][IPA_CLIENT_USB3_PROD] = 13,
- [IPA_1_1][IPA_CLIENT_HSIC4_PROD] = 0,
- [IPA_1_1][IPA_CLIENT_USB4_PROD] = 0,
- [IPA_1_1][IPA_CLIENT_HSIC5_PROD] = -1,
- [IPA_1_1][IPA_CLIENT_USB_PROD] = 11,
- [IPA_1_1][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = 15,
- [IPA_1_1][IPA_CLIENT_A2_EMBEDDED_PROD] = 8,
- [IPA_1_1][IPA_CLIENT_A2_TETHERED_PROD] = 6,
- [IPA_1_1][IPA_CLIENT_APPS_LAN_PROD] = -1,
- [IPA_1_1][IPA_CLIENT_APPS_LAN_WAN_PROD] = 2,
- [IPA_1_1][IPA_CLIENT_APPS_CMD_PROD] = 1,
- [IPA_1_1][IPA_CLIENT_ODU_PROD] = -1,
- [IPA_1_1][IPA_CLIENT_MHI_PROD] = -1,
- [IPA_1_1][IPA_CLIENT_Q6_LAN_PROD] = 5,
- [IPA_1_1][IPA_CLIENT_Q6_WAN_PROD] = -1,
- [IPA_1_1][IPA_CLIENT_Q6_CMD_PROD] = -1,
- [IPA_1_1][IPA_CLIENT_ETHERNET_PROD] = -1,
+struct ipa_ep_confing {
+ bool valid;
+ int pipe_num;
+};
- [IPA_1_1][IPA_CLIENT_HSIC1_CONS] = 14,
- [IPA_1_1][IPA_CLIENT_WLAN1_CONS] = -1,
- [IPA_1_1][IPA_CLIENT_HSIC2_CONS] = 16,
- [IPA_1_1][IPA_CLIENT_USB2_CONS] = 16,
- [IPA_1_1][IPA_CLIENT_WLAN2_CONS] = -1,
- [IPA_1_1][IPA_CLIENT_HSIC3_CONS] = 17,
- [IPA_1_1][IPA_CLIENT_USB3_CONS] = 17,
- [IPA_1_1][IPA_CLIENT_WLAN3_CONS] = -1,
- [IPA_1_1][IPA_CLIENT_HSIC4_CONS] = 18,
- [IPA_1_1][IPA_CLIENT_USB4_CONS] = 18,
- [IPA_1_1][IPA_CLIENT_WLAN4_CONS] = -1,
- [IPA_1_1][IPA_CLIENT_HSIC5_CONS] = -1,
- [IPA_1_1][IPA_CLIENT_USB_CONS] = 10,
- [IPA_1_1][IPA_CLIENT_USB_DPL_CONS] = -1,
- [IPA_1_1][IPA_CLIENT_A2_EMBEDDED_CONS] = 9,
- [IPA_1_1][IPA_CLIENT_A2_TETHERED_CONS] = 7,
- [IPA_1_1][IPA_CLIENT_A5_LAN_WAN_CONS] = 3,
- [IPA_1_1][IPA_CLIENT_APPS_LAN_CONS] = -1,
- [IPA_1_1][IPA_CLIENT_APPS_WAN_CONS] = -1,
- [IPA_1_1][IPA_CLIENT_ODU_EMB_CONS] = -1,
- [IPA_1_1][IPA_CLIENT_ODU_TETH_CONS] = -1,
- [IPA_1_1][IPA_CLIENT_MHI_CONS] = -1,
- [IPA_1_1][IPA_CLIENT_Q6_LAN_CONS] = 4,
- [IPA_1_1][IPA_CLIENT_Q6_WAN_CONS] = -1,
- [IPA_1_1][IPA_CLIENT_ETHERNET_CONS] = -1,
+static const struct ipa_ep_confing ep_mapping[3][IPA_CLIENT_MAX] = {
+ [IPA_1_1][IPA_CLIENT_HSIC1_PROD] = {true, 19},
+ [IPA_1_1][IPA_CLIENT_HSIC2_PROD] = {true, 12},
+ [IPA_1_1][IPA_CLIENT_USB2_PROD] = {true, 12},
+ [IPA_1_1][IPA_CLIENT_HSIC3_PROD] = {true, 13},
+ [IPA_1_1][IPA_CLIENT_USB3_PROD] = {true, 13},
+ [IPA_1_1][IPA_CLIENT_HSIC4_PROD] = {true, 0},
+ [IPA_1_1][IPA_CLIENT_USB4_PROD] = {true, 0},
+ [IPA_1_1][IPA_CLIENT_USB_PROD] = {true, 11},
+ [IPA_1_1][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = {true, 15},
+ [IPA_1_1][IPA_CLIENT_A2_EMBEDDED_PROD] = {true, 8},
+ [IPA_1_1][IPA_CLIENT_A2_TETHERED_PROD] = {true, 6},
+ [IPA_1_1][IPA_CLIENT_APPS_LAN_WAN_PROD] = {true, 2},
+ [IPA_1_1][IPA_CLIENT_APPS_CMD_PROD] = {true, 1},
+ [IPA_1_1][IPA_CLIENT_Q6_LAN_PROD] = {true, 5},
+
+ [IPA_1_1][IPA_CLIENT_HSIC1_CONS] = {true, 14},
+ [IPA_1_1][IPA_CLIENT_HSIC2_CONS] = {true, 16},
+ [IPA_1_1][IPA_CLIENT_USB2_CONS] = {true, 16},
+ [IPA_1_1][IPA_CLIENT_HSIC3_CONS] = {true, 17},
+ [IPA_1_1][IPA_CLIENT_USB3_CONS] = {true, 17},
+ [IPA_1_1][IPA_CLIENT_HSIC4_CONS] = {true, 18},
+ [IPA_1_1][IPA_CLIENT_USB4_CONS] = {true, 18},
+ [IPA_1_1][IPA_CLIENT_USB_CONS] = {true, 10},
+ [IPA_1_1][IPA_CLIENT_A2_EMBEDDED_CONS] = {true, 9},
+ [IPA_1_1][IPA_CLIENT_A2_TETHERED_CONS] = {true, 7},
+ [IPA_1_1][IPA_CLIENT_A5_LAN_WAN_CONS] = {true, 3},
+ [IPA_1_1][IPA_CLIENT_Q6_LAN_CONS] = {true, 4},
- [IPA_2_0][IPA_CLIENT_HSIC1_PROD] = 12,
- [IPA_2_0][IPA_CLIENT_WLAN1_PROD] = 18,
- [IPA_2_0][IPA_CLIENT_HSIC2_PROD] = -1,
- [IPA_2_0][IPA_CLIENT_USB2_PROD] = 12,
- [IPA_2_0][IPA_CLIENT_HSIC3_PROD] = -1,
- [IPA_2_0][IPA_CLIENT_USB3_PROD] = 13,
- [IPA_2_0][IPA_CLIENT_HSIC4_PROD] = -1,
- [IPA_2_0][IPA_CLIENT_USB4_PROD] = 0,
- [IPA_2_0][IPA_CLIENT_HSIC5_PROD] = -1,
- [IPA_2_0][IPA_CLIENT_USB_PROD] = 11,
- [IPA_2_0][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = -1,
- [IPA_2_0][IPA_CLIENT_A2_EMBEDDED_PROD] = -1,
- [IPA_2_0][IPA_CLIENT_A2_TETHERED_PROD] = -1,
- [IPA_2_0][IPA_CLIENT_APPS_LAN_PROD] = -1,
- [IPA_2_0][IPA_CLIENT_APPS_LAN_WAN_PROD] = 4,
- [IPA_2_0][IPA_CLIENT_APPS_CMD_PROD] = 3,
- [IPA_2_0][IPA_CLIENT_ODU_PROD] = 12,
- [IPA_2_0][IPA_CLIENT_MHI_PROD] = 18,
- [IPA_2_0][IPA_CLIENT_Q6_LAN_PROD] = 6,
- [IPA_2_0][IPA_CLIENT_Q6_WAN_PROD] = -1,
- [IPA_2_0][IPA_CLIENT_Q6_CMD_PROD] = 7,
- [IPA_2_0][IPA_CLIENT_Q6_DECOMP_PROD] = -1,
- [IPA_2_0][IPA_CLIENT_Q6_DECOMP2_PROD] = -1,
+ [IPA_2_0][IPA_CLIENT_HSIC1_PROD] = {true, 12},
+ [IPA_2_0][IPA_CLIENT_WLAN1_PROD] = {true, 18},
+ [IPA_2_0][IPA_CLIENT_USB2_PROD] = {true, 12},
+ [IPA_2_0][IPA_CLIENT_USB3_PROD] = {true, 13},
+ [IPA_2_0][IPA_CLIENT_USB4_PROD] = {true, 0},
+ [IPA_2_0][IPA_CLIENT_USB_PROD] = {true, 11},
+ [IPA_2_0][IPA_CLIENT_APPS_LAN_WAN_PROD] = {true, 4},
+ [IPA_2_0][IPA_CLIENT_APPS_CMD_PROD] = {true, 3},
+ [IPA_2_0][IPA_CLIENT_ODU_PROD] = {true, 12},
+ [IPA_2_0][IPA_CLIENT_MHI_PROD] = {true, 18},
+ [IPA_2_0][IPA_CLIENT_Q6_LAN_PROD] = {true, 6},
+ [IPA_2_0][IPA_CLIENT_Q6_CMD_PROD] = {true, 7},
[IPA_2_0][IPA_CLIENT_MEMCPY_DMA_SYNC_PROD]
- = 12,
+ = {true, 12},
[IPA_2_0][IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD]
- = 19,
- [IPA_2_0][IPA_CLIENT_ETHERNET_PROD] = 12,
+ = {true, 19},
+ [IPA_2_0][IPA_CLIENT_ETHERNET_PROD] = {true, 12},
/* Only for test purpose */
- [IPA_2_0][IPA_CLIENT_TEST_PROD] = 19,
- [IPA_2_0][IPA_CLIENT_TEST1_PROD] = 19,
- [IPA_2_0][IPA_CLIENT_TEST2_PROD] = 12,
- [IPA_2_0][IPA_CLIENT_TEST3_PROD] = 11,
- [IPA_2_0][IPA_CLIENT_TEST4_PROD] = 0,
+ [IPA_2_0][IPA_CLIENT_TEST_PROD] = {true, 19},
+ [IPA_2_0][IPA_CLIENT_TEST1_PROD] = {true, 19},
+ [IPA_2_0][IPA_CLIENT_TEST2_PROD] = {true, 12},
+ [IPA_2_0][IPA_CLIENT_TEST3_PROD] = {true, 11},
+ [IPA_2_0][IPA_CLIENT_TEST4_PROD] = {true, 0},
- [IPA_2_0][IPA_CLIENT_HSIC1_CONS] = 13,
- [IPA_2_0][IPA_CLIENT_WLAN1_CONS] = 17,
- [IPA_2_0][IPA_CLIENT_HSIC2_CONS] = -1,
- [IPA_2_0][IPA_CLIENT_USB2_CONS] = -1,
- [IPA_2_0][IPA_CLIENT_WLAN2_CONS] = 16,
- [IPA_2_0][IPA_CLIENT_HSIC3_CONS] = -1,
- [IPA_2_0][IPA_CLIENT_USB3_CONS] = -1,
- [IPA_2_0][IPA_CLIENT_WLAN3_CONS] = 14,
- [IPA_2_0][IPA_CLIENT_HSIC4_CONS] = -1,
- [IPA_2_0][IPA_CLIENT_USB4_CONS] = -1,
- [IPA_2_0][IPA_CLIENT_WLAN4_CONS] = 19,
- [IPA_2_0][IPA_CLIENT_HSIC5_CONS] = -1,
- [IPA_2_0][IPA_CLIENT_USB_CONS] = 15,
- [IPA_2_0][IPA_CLIENT_USB_DPL_CONS] = 0,
- [IPA_2_0][IPA_CLIENT_A2_EMBEDDED_CONS] = -1,
- [IPA_2_0][IPA_CLIENT_A2_TETHERED_CONS] = -1,
- [IPA_2_0][IPA_CLIENT_A5_LAN_WAN_CONS] = -1,
- [IPA_2_0][IPA_CLIENT_APPS_LAN_CONS] = 2,
- [IPA_2_0][IPA_CLIENT_APPS_WAN_CONS] = 5,
- [IPA_2_0][IPA_CLIENT_ODU_EMB_CONS] = 13,
- [IPA_2_0][IPA_CLIENT_ODU_TETH_CONS] = 1,
- [IPA_2_0][IPA_CLIENT_MHI_CONS] = 17,
- [IPA_2_0][IPA_CLIENT_Q6_LAN_CONS] = 8,
- [IPA_2_0][IPA_CLIENT_Q6_WAN_CONS] = 9,
- [IPA_2_0][IPA_CLIENT_Q6_DUN_CONS] = -1,
- [IPA_2_0][IPA_CLIENT_Q6_DECOMP_CONS] = -1,
- [IPA_2_0][IPA_CLIENT_Q6_DECOMP2_CONS] = -1,
+ [IPA_2_0][IPA_CLIENT_HSIC1_CONS] = {true, 13},
+ [IPA_2_0][IPA_CLIENT_WLAN1_CONS] = {true, 17},
+ [IPA_2_0][IPA_CLIENT_WLAN2_CONS] = {true, 16},
+ [IPA_2_0][IPA_CLIENT_WLAN3_CONS] = {true, 14},
+ [IPA_2_0][IPA_CLIENT_WLAN4_CONS] = {true, 19},
+ [IPA_2_0][IPA_CLIENT_USB_CONS] = {true, 15},
+ [IPA_2_0][IPA_CLIENT_USB_DPL_CONS] = {true, 0},
+ [IPA_2_0][IPA_CLIENT_APPS_LAN_CONS] = {true, 2},
+ [IPA_2_0][IPA_CLIENT_APPS_WAN_CONS] = {true, 5},
+ [IPA_2_0][IPA_CLIENT_ODU_EMB_CONS] = {true, 13},
+ [IPA_2_0][IPA_CLIENT_ODU_TETH_CONS] = {true, 1},
+ [IPA_2_0][IPA_CLIENT_MHI_CONS] = {true, 17},
+ [IPA_2_0][IPA_CLIENT_Q6_LAN_CONS] = {true, 8},
+ [IPA_2_0][IPA_CLIENT_Q6_WAN_CONS] = {true, 9},
[IPA_2_0][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS]
- = 13,
+ = {true, 13},
[IPA_2_0][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS]
- = 16,
+ = {true, 16},
[IPA_2_0][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS]
- = 10,
- [IPA_2_0][IPA_CLIENT_ETHERNET_CONS] = 1,
+ = {true, 10},
+ [IPA_2_0][IPA_CLIENT_ETHERNET_CONS] = {true, 1},
+
/* Only for test purpose */
- [IPA_2_0][IPA_CLIENT_TEST_CONS] = 1,
- [IPA_2_0][IPA_CLIENT_TEST1_CONS] = 1,
- [IPA_2_0][IPA_CLIENT_TEST2_CONS] = 16,
- [IPA_2_0][IPA_CLIENT_TEST3_CONS] = 13,
- [IPA_2_0][IPA_CLIENT_TEST4_CONS] = 15,
+ [IPA_2_0][IPA_CLIENT_TEST_CONS] = {true, 1},
+ [IPA_2_0][IPA_CLIENT_TEST1_CONS] = {true, 1},
+ [IPA_2_0][IPA_CLIENT_TEST2_CONS] = {true, 16},
+ [IPA_2_0][IPA_CLIENT_TEST3_CONS] = {true, 13},
+ [IPA_2_0][IPA_CLIENT_TEST4_CONS] = {true, 15},
- [IPA_2_6L][IPA_CLIENT_HSIC1_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_WLAN1_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_HSIC2_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_USB2_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_HSIC3_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_USB3_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_HSIC4_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_USB4_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_HSIC5_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_USB_PROD] = 1,
- [IPA_2_6L][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_A2_EMBEDDED_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_A2_TETHERED_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_APPS_LAN_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_APPS_LAN_WAN_PROD] = 4,
- [IPA_2_6L][IPA_CLIENT_APPS_CMD_PROD] = 3,
- [IPA_2_6L][IPA_CLIENT_ODU_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_MHI_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_Q6_LAN_PROD] = 6,
- [IPA_2_6L][IPA_CLIENT_Q6_WAN_PROD] = -1,
- [IPA_2_6L][IPA_CLIENT_Q6_CMD_PROD] = 7,
- [IPA_2_6L][IPA_CLIENT_Q6_DECOMP_PROD] = 11,
- [IPA_2_6L][IPA_CLIENT_Q6_DECOMP2_PROD] = 13,
- [IPA_2_6L][IPA_CLIENT_MEMCPY_DMA_SYNC_PROD]
- = -1,
- [IPA_2_6L][IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD]
- = -1,
- [IPA_2_6L][IPA_CLIENT_ETHERNET_PROD] = -1,
- /* Only for test purpose */
- [IPA_2_6L][IPA_CLIENT_TEST_PROD] = 11,
- [IPA_2_6L][IPA_CLIENT_TEST1_PROD] = 11,
- [IPA_2_6L][IPA_CLIENT_TEST2_PROD] = 12,
- [IPA_2_6L][IPA_CLIENT_TEST3_PROD] = 13,
- [IPA_2_6L][IPA_CLIENT_TEST4_PROD] = 14,
+ [IPA_2_6L][IPA_CLIENT_APPS_LAN_WAN_PROD] = {true, 4},
+ [IPA_2_6L][IPA_CLIENT_APPS_CMD_PROD] = {true, 3},
+ [IPA_2_6L][IPA_CLIENT_Q6_LAN_PROD] = {true, 6},
+ [IPA_2_6L][IPA_CLIENT_Q6_CMD_PROD] = {true, 7},
+ [IPA_2_6L][IPA_CLIENT_Q6_DECOMP_PROD] = {true, 11},
+ [IPA_2_6L][IPA_CLIENT_Q6_DECOMP2_PROD] = {true, 13},
- [IPA_2_6L][IPA_CLIENT_HSIC1_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_WLAN1_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_HSIC2_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_USB2_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_WLAN2_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_HSIC3_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_USB3_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_WLAN3_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_HSIC4_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_USB4_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_WLAN4_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_HSIC5_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_USB_CONS] = 0,
- [IPA_2_6L][IPA_CLIENT_USB_DPL_CONS] = 10,
- [IPA_2_6L][IPA_CLIENT_A2_EMBEDDED_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_A2_TETHERED_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_A5_LAN_WAN_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_APPS_LAN_CONS] = 2,
- [IPA_2_6L][IPA_CLIENT_APPS_WAN_CONS] = 5,
- [IPA_2_6L][IPA_CLIENT_ODU_EMB_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_ODU_TETH_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_MHI_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_Q6_LAN_CONS] = 8,
- [IPA_2_6L][IPA_CLIENT_Q6_WAN_CONS] = 9,
- [IPA_2_6L][IPA_CLIENT_Q6_DUN_CONS] = -1,
- [IPA_2_6L][IPA_CLIENT_Q6_DECOMP_CONS] = 12,
- [IPA_2_6L][IPA_CLIENT_Q6_DECOMP2_CONS] = 14,
- [IPA_2_6L][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS]
- = -1,
- [IPA_2_6L][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS]
- = -1,
- [IPA_2_6L][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS]
- = -1,
- [IPA_2_6L][IPA_CLIENT_ETHERNET_CONS] = -1,
/* Only for test purpose */
- [IPA_2_6L][IPA_CLIENT_TEST_CONS] = 15,
- [IPA_2_6L][IPA_CLIENT_TEST1_CONS] = 15,
- [IPA_2_6L][IPA_CLIENT_TEST2_CONS] = 0,
- [IPA_2_6L][IPA_CLIENT_TEST3_CONS] = 1,
- [IPA_2_6L][IPA_CLIENT_TEST4_CONS] = 10,
+ [IPA_2_6L][IPA_CLIENT_TEST_PROD] = {true, 11},
+ [IPA_2_6L][IPA_CLIENT_TEST1_PROD] = {true, 11},
+ [IPA_2_6L][IPA_CLIENT_TEST2_PROD] = {true, 12},
+ [IPA_2_6L][IPA_CLIENT_TEST3_PROD] = {true, 13},
+ [IPA_2_6L][IPA_CLIENT_TEST4_PROD] = {true, 14},
+
+ [IPA_2_6L][IPA_CLIENT_USB_CONS] = {true, 0},
+ [IPA_2_6L][IPA_CLIENT_USB_DPL_CONS] = {true, 10},
+ [IPA_2_6L][IPA_CLIENT_APPS_LAN_CONS] = {true, 2},
+ [IPA_2_6L][IPA_CLIENT_APPS_WAN_CONS] = {true, 5},
+ [IPA_2_6L][IPA_CLIENT_Q6_LAN_CONS] = {true, 8},
+ [IPA_2_6L][IPA_CLIENT_Q6_WAN_CONS] = {true, 9},
+ [IPA_2_6L][IPA_CLIENT_Q6_DECOMP_CONS] = {true, 12},
+ [IPA_2_6L][IPA_CLIENT_Q6_DECOMP2_CONS] = {true, 14},
+
+ /* Only for test purpose */
+ [IPA_2_6L][IPA_CLIENT_TEST_CONS] = {true, 15},
+ [IPA_2_6L][IPA_CLIENT_TEST1_CONS] = {true, 15},
+ [IPA_2_6L][IPA_CLIENT_TEST2_CONS] = {true, 0},
+ [IPA_2_6L][IPA_CLIENT_TEST3_CONS] = {true, 1},
+ [IPA_2_6L][IPA_CLIENT_TEST4_CONS] = {true, 10},
};
static struct msm_bus_vectors ipa_init_vectors_v1_1[] = {
@@ -949,7 +864,10 @@
break;
}
- return ep_mapping[hw_type_index][client];
+ if (!ep_mapping[hw_type_index][client].valid)
+ return INVALID_EP_MAPPING_INDEX;
+
+ return ep_mapping[hw_type_index][client].pipe_num;
}
/* ipa2_set_client() - provide client mapping
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index bf13ac5..04d807f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -3659,7 +3659,6 @@
struct ipa_mem_buffer mem_info = {0};
static int total_cnt;
- IPADBG("\n");
if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
ipa3_ctx->ep[clnt_hdl].valid == 0) {
IPAERR("bad parm 0x%x\n", clnt_hdl);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 73a405f..86442b1 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -139,9 +139,6 @@
#define IPA_LAN_RX_HDR_NAME "ipa_lan_hdr"
#define IPA_INVALID_L4_PROTOCOL 0xFF
-#define IPA_CLIENT_IS_PROD(x) (x >= IPA_CLIENT_PROD && x < IPA_CLIENT_CONS)
-#define IPA_CLIENT_IS_CONS(x) (x >= IPA_CLIENT_CONS && x < IPA_CLIENT_MAX)
-
#define IPA_HDR_PROC_CTX_TABLE_ALIGNMENT_BYTE 8
#define IPA_HDR_PROC_CTX_TABLE_ALIGNMENT(start_ofst) \
(((start_ofst) + IPA_HDR_PROC_CTX_TABLE_ALIGNMENT_BYTE - 1) & \
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index f8b4d7d..23c8241 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -93,11 +93,6 @@
#define QMB_MASTER_SELECT_DDR (0)
#define QMB_MASTER_SELECT_PCIE (1)
-#define IPA_CLIENT_NOT_USED \
- { IPA_EP_NOT_ALLOCATED, IPA_EP_NOT_ALLOCATED, false, \
- IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, \
- { -1, -1, -1, -1, -1 } }
-
/* Resource Group index*/
#define IPA_v3_0_GROUP_UL (0)
#define IPA_v3_0_GROUP_DL (1)
@@ -406,7 +401,7 @@
};
struct ipa_ep_configuration {
- int pipe_num;
+ bool valid;
int group_num;
bool support_flt;
int sequencer_type;
@@ -414,506 +409,424 @@
struct ipa_gsi_ep_config ipa_gsi_ep_info;
};
+/* clients not included in the list below are considered as invalid */
static const struct ipa_ep_configuration ipa3_ep_mapping
[IPA_VER_MAX][IPA_CLIENT_MAX] = {
- [IPA_3_0][IPA_CLIENT_HSIC1_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_0][IPA_CLIENT_WLAN1_PROD] = {
- 10, IPA_v3_0_GROUP_UL, true,
+ true, IPA_v3_0_GROUP_UL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 10, 1, 8, 16, IPA_EE_UC } },
- [IPA_3_0][IPA_CLIENT_HSIC2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_USB2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_HSIC3_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_USB3_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_HSIC4_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_USB4_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_HSIC5_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_0][IPA_CLIENT_USB_PROD] = {
- 1, IPA_v3_0_GROUP_UL, true,
+ true, IPA_v3_0_GROUP_UL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 1, 3, 8, 16, IPA_EE_AP } },
- [IPA_3_0][IPA_CLIENT_UC_USB_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_A2_EMBEDDED_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_A2_TETHERED_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_0][IPA_CLIENT_APPS_LAN_PROD] = {
- 14, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 14, 11, 8, 16, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_APPS_WAN_PROD] = {
- 3, IPA_v3_0_GROUP_UL, true,
+ true, IPA_v3_0_GROUP_UL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 3, 5, 16, 32, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_APPS_CMD_PROD] = {
- 22, IPA_v3_0_GROUP_IMM_CMD, false,
+ true, IPA_v3_0_GROUP_IMM_CMD, false,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_DDR,
{ 22, 6, 18, 28, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_ODU_PROD] = {
- 12, IPA_v3_0_GROUP_UL, true,
+ true, IPA_v3_0_GROUP_UL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 12, 9, 8, 16, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_MHI_PROD] = {
- 0, IPA_v3_0_GROUP_UL, true,
+ true, IPA_v3_0_GROUP_UL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_PCIE,
{ 0, 0, 8, 16, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_Q6_LAN_PROD] = {
- 9, IPA_v3_0_GROUP_UL, false,
+ true, IPA_v3_0_GROUP_UL, false,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 9, 4, 8, 12, IPA_EE_Q6 } },
[IPA_3_0][IPA_CLIENT_Q6_WAN_PROD] = {
- 5, IPA_v3_0_GROUP_DL, true,
+ true, IPA_v3_0_GROUP_DL, true,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 5, 0, 16, 32, IPA_EE_Q6 } },
[IPA_3_0][IPA_CLIENT_Q6_CMD_PROD] = {
- 6, IPA_v3_0_GROUP_IMM_CMD, false,
+ true, IPA_v3_0_GROUP_IMM_CMD, false,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 6, 1, 18, 28, IPA_EE_Q6 } },
[IPA_3_0][IPA_CLIENT_Q6_DECOMP_PROD] = {
- 7, IPA_v3_0_GROUP_Q6ZIP,
+ true, IPA_v3_0_GROUP_Q6ZIP,
false, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 7, 2, 0, 0, IPA_EE_Q6 } },
[IPA_3_0][IPA_CLIENT_Q6_DECOMP2_PROD] = {
- 8, IPA_v3_0_GROUP_Q6ZIP,
+ true, IPA_v3_0_GROUP_Q6ZIP,
false, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 8, 3, 0, 0, IPA_EE_Q6 } },
[IPA_3_0][IPA_CLIENT_MEMCPY_DMA_SYNC_PROD] = {
- 12, IPA_v3_0_GROUP_DMA, false,
+ true, IPA_v3_0_GROUP_DMA, false,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_PCIE,
{ 12, 9, 8, 16, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD] = {
- 13, IPA_v3_0_GROUP_DMA, false,
+ true, IPA_v3_0_GROUP_DMA, false,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_PCIE,
{ 13, 10, 8, 16, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_ETHERNET_PROD] = {
- 2, IPA_v3_0_GROUP_UL, true,
+ true, IPA_v3_0_GROUP_UL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{2, 0, 8, 16, IPA_EE_UC} },
/* Only for test purpose */
[IPA_3_0][IPA_CLIENT_TEST_PROD] = {
- 1, IPA_v3_0_GROUP_UL, true,
+ true, IPA_v3_0_GROUP_UL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 1, 3, 8, 16, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_TEST1_PROD] = {
- 1, IPA_v3_0_GROUP_UL, true,
+ true, IPA_v3_0_GROUP_UL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 1, 3, 8, 16, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_TEST2_PROD] = {
- 3, IPA_v3_0_GROUP_UL, true,
+ true, IPA_v3_0_GROUP_UL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 3, 5, 16, 32, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_TEST3_PROD] = {
- 12, IPA_v3_0_GROUP_UL, true,
+ true, IPA_v3_0_GROUP_UL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 12, 9, 8, 16, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_TEST4_PROD] = {
- 13, IPA_v3_0_GROUP_UL, true,
+ true, IPA_v3_0_GROUP_UL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 13, 10, 8, 16, IPA_EE_AP } },
- [IPA_3_0][IPA_CLIENT_HSIC1_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_0][IPA_CLIENT_WLAN1_CONS] = {
- 25, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 25, 4, 8, 8, IPA_EE_UC } },
- [IPA_3_0][IPA_CLIENT_HSIC2_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_USB2_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_0][IPA_CLIENT_WLAN2_CONS] = {
- 27, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 27, 4, 8, 8, IPA_EE_AP } },
- [IPA_3_0][IPA_CLIENT_HSIC3_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_USB3_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_0][IPA_CLIENT_WLAN3_CONS] = {
- 28, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 28, 13, 8, 8, IPA_EE_AP } },
- [IPA_3_0][IPA_CLIENT_HSIC4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_USB4_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_0][IPA_CLIENT_WLAN4_CONS] = {
- 29, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 29, 14, 8, 8, IPA_EE_AP } },
- [IPA_3_0][IPA_CLIENT_HSIC5_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_0][IPA_CLIENT_USB_CONS] = {
- 26, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 26, 12, 8, 8, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_USB_DPL_CONS] = {
- 17, IPA_v3_0_GROUP_DPL, false,
+ true, IPA_v3_0_GROUP_DPL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 17, 2, 8, 12, IPA_EE_AP } },
- [IPA_3_0][IPA_CLIENT_A2_EMBEDDED_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_A2_TETHERED_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_A5_LAN_WAN_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_0][IPA_CLIENT_APPS_LAN_CONS] = {
- 15, IPA_v3_0_GROUP_UL, false,
+ true, IPA_v3_0_GROUP_UL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 15, 7, 8, 12, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_APPS_WAN_CONS] = {
- 16, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 16, 8, 8, 12, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_ODU_EMB_CONS] = {
- 23, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 23, 1, 8, 8, IPA_EE_AP } },
- [IPA_3_0][IPA_CLIENT_ODU_TETH_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_0][IPA_CLIENT_MHI_CONS] = {
- 23, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 23, 1, 8, 8, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_Q6_LAN_CONS] = {
- 19, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 19, 6, 8, 12, IPA_EE_Q6 } },
[IPA_3_0][IPA_CLIENT_Q6_WAN_CONS] = {
- 18, IPA_v3_0_GROUP_UL, false,
+ true, IPA_v3_0_GROUP_UL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 18, 5, 8, 12, IPA_EE_Q6 } },
[IPA_3_0][IPA_CLIENT_Q6_DUN_CONS] = {
- 30, IPA_v3_0_GROUP_DIAG, false,
+ true, IPA_v3_0_GROUP_DIAG, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 30, 7, 4, 4, IPA_EE_Q6 } },
[IPA_3_0][IPA_CLIENT_Q6_DECOMP_CONS] = {
- 21, IPA_v3_0_GROUP_Q6ZIP, false,
+ true, IPA_v3_0_GROUP_Q6ZIP, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 21, 8, 4, 4, IPA_EE_Q6 } },
[IPA_3_0][IPA_CLIENT_Q6_DECOMP2_CONS] = {
- 4, IPA_v3_0_GROUP_Q6ZIP, false,
+ true, IPA_v3_0_GROUP_Q6ZIP, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 4, 9, 4, 4, IPA_EE_Q6 } },
[IPA_3_0][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS] = {
- 28, IPA_v3_0_GROUP_DMA, false,
+ true, IPA_v3_0_GROUP_DMA, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 28, 13, 8, 8, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS] = {
- 29, IPA_v3_0_GROUP_DMA, false,
+ true, IPA_v3_0_GROUP_DMA, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 29, 14, 8, 8, IPA_EE_AP } },
- [IPA_3_0][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_0][IPA_CLIENT_ETHERNET_CONS] = {
- 24, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{24, 3, 8, 8, IPA_EE_UC} },
/* Only for test purpose */
[IPA_3_0][IPA_CLIENT_TEST_CONS] = {
- 26, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 26, 12, 8, 8, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_TEST1_CONS] = {
- 26, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 26, 12, 8, 8, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_TEST2_CONS] = {
- 27, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 27, 4, 8, 8, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_TEST3_CONS] = {
- 28, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 28, 13, 8, 8, IPA_EE_AP } },
[IPA_3_0][IPA_CLIENT_TEST4_CONS] = {
- 29, IPA_v3_0_GROUP_DL, false,
+ true, IPA_v3_0_GROUP_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 29, 14, 8, 8, IPA_EE_AP } },
/* IPA_3_5 */
- [IPA_3_5][IPA_CLIENT_HSIC1_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5][IPA_CLIENT_WLAN1_PROD] = {
- 6, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 6, 1, 8, 16, IPA_EE_UC } },
- [IPA_3_5][IPA_CLIENT_HSIC2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_USB2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_HSIC3_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_USB3_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_HSIC4_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_USB4_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_HSIC5_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5][IPA_CLIENT_USB_PROD] = {
- 0, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 0, 7, 8, 16, IPA_EE_AP } },
- [IPA_3_5][IPA_CLIENT_UC_USB_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_A2_EMBEDDED_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_A2_TETHERED_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5][IPA_CLIENT_APPS_LAN_PROD] = {
- 8, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 8, 9, 8, 16, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_APPS_WAN_PROD] = {
- 2, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 2, 3, 16, 32, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_APPS_CMD_PROD] = {
- 5, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_DDR,
{ 5, 4, 20, 23, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_ODU_PROD] = {
- 1, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 1, 0, 8, 16, IPA_EE_UC } },
- [IPA_3_5][IPA_CLIENT_MHI_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5][IPA_CLIENT_Q6_LAN_PROD] = {
- 3, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 3, 0, 16, 32, IPA_EE_Q6 } },
- [IPA_3_5][IPA_CLIENT_Q6_WAN_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5][IPA_CLIENT_Q6_CMD_PROD] = {
- 4, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 4, 1, 20, 23, IPA_EE_Q6 } },
- [IPA_3_5][IPA_CLIENT_Q6_DECOMP_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_Q6_DECOMP2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_MEMCPY_DMA_SYNC_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_ETHERNET_PROD] = IPA_CLIENT_NOT_USED,
/* Only for test purpose */
[IPA_3_5][IPA_CLIENT_TEST_PROD] = {
- 0, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{0, 7, 8, 16, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_TEST1_PROD] = {
- 0, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{0, 7, 8, 16, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_TEST2_PROD] = {
- 1, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 1, 0, 8, 16, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_TEST3_PROD] = {
- 7, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{7, 8, 8, 16, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_TEST4_PROD] = {
- 8, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 8, 9, 8, 16, IPA_EE_AP } },
- [IPA_3_5][IPA_CLIENT_HSIC1_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5][IPA_CLIENT_WLAN1_CONS] = {
- 16, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 16, 3, 8, 8, IPA_EE_UC } },
- [IPA_3_5][IPA_CLIENT_HSIC2_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_USB2_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5][IPA_CLIENT_WLAN2_CONS] = {
- 18, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 18, 12, 8, 8, IPA_EE_AP } },
- [IPA_3_5][IPA_CLIENT_HSIC3_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_USB3_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5][IPA_CLIENT_WLAN3_CONS] = {
- 19, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 19, 13, 8, 8, IPA_EE_AP } },
- [IPA_3_5][IPA_CLIENT_HSIC4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_USB4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_WLAN4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_HSIC5_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5][IPA_CLIENT_USB_CONS] = {
- 17, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 17, 11, 8, 8, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_USB_DPL_CONS] = {
- 14, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 14, 10, 4, 6, IPA_EE_AP } },
- [IPA_3_5][IPA_CLIENT_A2_EMBEDDED_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_A2_TETHERED_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_A5_LAN_WAN_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5][IPA_CLIENT_APPS_LAN_CONS] = {
- 9, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 9, 5, 8, 12, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_APPS_WAN_CONS] = {
- 10, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 10, 6, 8, 12, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_ODU_EMB_CONS] = {
- 15, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 15, 1, 8, 8, IPA_EE_AP } },
- [IPA_3_5][IPA_CLIENT_ODU_TETH_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_MHI_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5][IPA_CLIENT_Q6_LAN_CONS] = {
- 13, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 13, 3, 8, 12, IPA_EE_Q6 } },
[IPA_3_5][IPA_CLIENT_Q6_WAN_CONS] = {
- 12, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 12, 2, 8, 12, IPA_EE_Q6 } },
- [IPA_3_5][IPA_CLIENT_Q6_DUN_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_Q6_DECOMP_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_Q6_DECOMP2_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5][IPA_CLIENT_ETHERNET_CONS] = IPA_CLIENT_NOT_USED,
/* Only for test purpose */
/* MBIM aggregation test pipes should have the same QMB as USB_CONS */
[IPA_3_5][IPA_CLIENT_TEST_CONS] = {
- 15, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 15, 1, 8, 8, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_TEST1_CONS] = {
- 15, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 15, 1, 8, 8, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_TEST2_CONS] = {
- 17, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 17, 11, 8, 8, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_TEST3_CONS] = {
- 18, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 18, 12, 8, 8, IPA_EE_AP } },
[IPA_3_5][IPA_CLIENT_TEST4_CONS] = {
- 19, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 19, 13, 8, 8, IPA_EE_AP } },
/* IPA_3_5_MHI */
- [IPA_3_5_MHI][IPA_CLIENT_HSIC1_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_WLAN1_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_HSIC2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_USB2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_HSIC3_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_USB3_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_HSIC4_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_USB4_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_HSIC5_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5_MHI][IPA_CLIENT_USB_PROD] = {
- 0, IPA_v3_5_MHI_GROUP_DDR, true,
+ true, IPA_v3_5_MHI_GROUP_DDR, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 0, 7, 8, 16, IPA_EE_AP } },
- [IPA_3_5_MHI][IPA_CLIENT_UC_USB_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_A2_EMBEDDED_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_A2_TETHERED_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_APPS_LAN_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5_MHI][IPA_CLIENT_APPS_WAN_PROD] = {
- 2, IPA_v3_5_MHI_GROUP_DDR, true,
+ true, IPA_v3_5_MHI_GROUP_DDR, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 2, 3, 16, 32, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_APPS_CMD_PROD] = {
- 5, IPA_v3_5_MHI_GROUP_DDR, false,
+ true, IPA_v3_5_MHI_GROUP_DDR, false,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_DDR,
{ 5, 4, 20, 23, IPA_EE_AP } },
- [IPA_3_5_MHI][IPA_CLIENT_ODU_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5_MHI][IPA_CLIENT_MHI_PROD] = {
- 1, IPA_v3_5_MHI_GROUP_PCIE, true,
+ true, IPA_v3_5_MHI_GROUP_PCIE, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_PCIE,
{ 1, 0, 8, 16, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_Q6_LAN_PROD] = {
- 3, IPA_v3_5_MHI_GROUP_DDR, true,
+ true, IPA_v3_5_MHI_GROUP_DDR, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 3, 0, 16, 32, IPA_EE_Q6 } },
[IPA_3_5_MHI][IPA_CLIENT_Q6_WAN_PROD] = {
- 6, IPA_v3_5_MHI_GROUP_DDR, true,
+ true, IPA_v3_5_MHI_GROUP_DDR, true,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 6, 4, 10, 30, IPA_EE_Q6 } },
[IPA_3_5_MHI][IPA_CLIENT_Q6_CMD_PROD] = {
- 4, IPA_v3_5_MHI_GROUP_PCIE, false,
+ true, IPA_v3_5_MHI_GROUP_PCIE, false,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 4, 1, 20, 23, IPA_EE_Q6 } },
- [IPA_3_5_MHI][IPA_CLIENT_Q6_DECOMP_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_Q6_DECOMP2_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5_MHI][IPA_CLIENT_MEMCPY_DMA_SYNC_PROD] = {
- 7, IPA_v3_5_MHI_GROUP_DMA, false,
+ true, IPA_v3_5_MHI_GROUP_DMA, false,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_DDR,
{ 7, 8, 8, 16, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD] = {
- 8, IPA_v3_5_MHI_GROUP_DMA, false,
+ true, IPA_v3_5_MHI_GROUP_DMA, false,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_DDR,
{ 8, 9, 8, 16, IPA_EE_AP } },
- [IPA_3_5_MHI][IPA_CLIENT_ETHERNET_PROD] = IPA_CLIENT_NOT_USED,
/* Only for test purpose */
[IPA_3_5_MHI][IPA_CLIENT_TEST_PROD] = {
- 0, IPA_v3_5_MHI_GROUP_DDR, true,
+ true, IPA_v3_5_MHI_GROUP_DDR, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{0, 7, 8, 16, IPA_EE_AP } },
@@ -923,300 +836,238 @@
QMB_MASTER_SELECT_DDR,
{0, 7, 8, 16, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_TEST2_PROD] = {
- 1, IPA_v3_5_MHI_GROUP_PCIE, true,
+ true, IPA_v3_5_MHI_GROUP_PCIE, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_PCIE,
{ 1, 0, 8, 16, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_TEST3_PROD] = {
- 7, IPA_v3_5_MHI_GROUP_DMA, true,
+ true, IPA_v3_5_MHI_GROUP_DMA, true,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_DDR,
{7, 8, 8, 16, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_TEST4_PROD] = {
- 8, IPA_v3_5_MHI_GROUP_DMA, true,
+ true, IPA_v3_5_MHI_GROUP_DMA, true,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_DDR,
{ 8, 9, 8, 16, IPA_EE_AP } },
- [IPA_3_5_MHI][IPA_CLIENT_HSIC1_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5_MHI][IPA_CLIENT_WLAN1_CONS] = {
- 16, IPA_v3_5_MHI_GROUP_DDR, false,
+ true, IPA_v3_5_MHI_GROUP_DDR, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 16, 3, 8, 8, IPA_EE_UC } },
- [IPA_3_5_MHI][IPA_CLIENT_HSIC2_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_USB2_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_WLAN2_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_HSIC3_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_USB3_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_WLAN3_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_HSIC4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_USB4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_WLAN4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_HSIC5_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5_MHI][IPA_CLIENT_USB_CONS] = {
- 17, IPA_v3_5_MHI_GROUP_DDR, false,
+ true, IPA_v3_5_MHI_GROUP_DDR, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 17, 11, 8, 8, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_USB_DPL_CONS] = {
- 14, IPA_v3_5_MHI_GROUP_DDR, false,
+ true, IPA_v3_5_MHI_GROUP_DDR, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 14, 10, 4, 6, IPA_EE_AP } },
- [IPA_3_5_MHI][IPA_CLIENT_A2_EMBEDDED_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_A2_TETHERED_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_A5_LAN_WAN_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5_MHI][IPA_CLIENT_APPS_LAN_CONS] = {
- 9, IPA_v3_5_MHI_GROUP_DDR, false,
+ true, IPA_v3_5_MHI_GROUP_DDR, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 9, 5, 8, 12, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_APPS_WAN_CONS] = {
- 10, IPA_v3_5_MHI_GROUP_DDR, false,
+ true, IPA_v3_5_MHI_GROUP_DDR, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 10, 6, 8, 12, IPA_EE_AP } },
- [IPA_3_5_MHI][IPA_CLIENT_ODU_EMB_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_ODU_TETH_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5_MHI][IPA_CLIENT_MHI_CONS] = {
- 15, IPA_v3_5_MHI_GROUP_PCIE, false,
+ true, IPA_v3_5_MHI_GROUP_PCIE, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 15, 1, 8, 8, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_Q6_LAN_CONS] = {
- 13, IPA_v3_5_MHI_GROUP_DDR, false,
+ true, IPA_v3_5_MHI_GROUP_DDR, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 13, 3, 8, 12, IPA_EE_Q6 } },
[IPA_3_5_MHI][IPA_CLIENT_Q6_WAN_CONS] = {
- 12, IPA_v3_5_MHI_GROUP_DDR, false,
+ true, IPA_v3_5_MHI_GROUP_DDR, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 12, 2, 8, 12, IPA_EE_Q6 } },
- [IPA_3_5_MHI][IPA_CLIENT_Q6_DUN_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_Q6_DECOMP_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_Q6_DECOMP2_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5_MHI][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS] = {
- 18, IPA_v3_5_MHI_GROUP_DMA, false,
+ true, IPA_v3_5_MHI_GROUP_DMA, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 18, 12, 8, 8, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS] = {
- 19, IPA_v3_5_MHI_GROUP_DMA, false,
+ true, IPA_v3_5_MHI_GROUP_DMA, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 19, 13, 8, 8, IPA_EE_AP } },
- [IPA_3_5_MHI][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_MHI][IPA_CLIENT_ETHERNET_CONS] = IPA_CLIENT_NOT_USED,
/* Only for test purpose */
[IPA_3_5_MHI][IPA_CLIENT_TEST_CONS] = {
- 15, IPA_v3_5_MHI_GROUP_PCIE, false,
+ true, IPA_v3_5_MHI_GROUP_PCIE, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 15, 1, 8, 8, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_TEST1_CONS] = {
- 15, IPA_v3_5_MHI_GROUP_PCIE, false,
+ true, IPA_v3_5_MHI_GROUP_PCIE, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 15, 1, 8, 8, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_TEST2_CONS] = {
- 17, IPA_v3_5_MHI_GROUP_DDR, false,
+ true, IPA_v3_5_MHI_GROUP_DDR, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 17, 11, 8, 8, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_TEST3_CONS] = {
- 18, IPA_v3_5_MHI_GROUP_DMA, false,
+ true, IPA_v3_5_MHI_GROUP_DMA, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 18, 12, 8, 8, IPA_EE_AP } },
[IPA_3_5_MHI][IPA_CLIENT_TEST4_CONS] = {
- 19, IPA_v3_5_MHI_GROUP_DMA, false,
+ true, IPA_v3_5_MHI_GROUP_DMA, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 19, 13, 8, 8, IPA_EE_AP } },
/* IPA_3_5_1 */
- [IPA_3_5_1][IPA_CLIENT_HSIC1_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5_1][IPA_CLIENT_WLAN1_PROD] = {
- 7, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 7, 1, 8, 16, IPA_EE_UC } },
- [IPA_3_5_1][IPA_CLIENT_HSIC2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_USB2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_HSIC3_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_USB3_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_HSIC4_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_USB4_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_HSIC5_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5_1][IPA_CLIENT_USB_PROD] = {
- 0, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 0, 0, 8, 16, IPA_EE_AP } },
- [IPA_3_5_1][IPA_CLIENT_UC_USB_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_A2_EMBEDDED_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_A2_TETHERED_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5_1][IPA_CLIENT_APPS_LAN_PROD] = {
- 8, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 8, 7, 8, 16, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_APPS_WAN_PROD] = {
- 2, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 2, 3, 16, 32, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_APPS_CMD_PROD] = {
- 5, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_DDR,
{ 5, 4, 20, 23, IPA_EE_AP } },
- [IPA_3_5_1][IPA_CLIENT_ODU_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_MHI_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_5_1][IPA_CLIENT_Q6_LAN_PROD] = {
- 3, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 3, 0, 16, 32, IPA_EE_Q6 } },
[IPA_3_5_1][IPA_CLIENT_Q6_WAN_PROD] = {
- 6, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 6, 4, 12, 30, IPA_EE_Q6 } },
[IPA_3_5_1][IPA_CLIENT_Q6_CMD_PROD] = {
- 4, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 4, 1, 20, 23, IPA_EE_Q6 } },
- [IPA_3_5_1][IPA_CLIENT_Q6_DECOMP_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_Q6_DECOMP2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_MEMCPY_DMA_SYNC_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_ETHERNET_PROD] = IPA_CLIENT_NOT_USED,
/* Only for test purpose */
[IPA_3_5_1][IPA_CLIENT_TEST_PROD] = {
- 0, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 0, 0, 8, 16, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_TEST1_PROD] = {
- 0, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 0, 0, 8, 16, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_TEST2_PROD] = {
- 2, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 2, 3, 16, 32, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_TEST3_PROD] = {
- 4, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 4, 1, 20, 23, IPA_EE_Q6 } },
[IPA_3_5_1][IPA_CLIENT_TEST4_PROD] = {
- 1, IPA_v3_5_GROUP_UL_DL, true,
+ true, IPA_v3_5_GROUP_UL_DL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 1, 0, 8, 16, IPA_EE_UC } },
- [IPA_3_5_1][IPA_CLIENT_HSIC1_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5_1][IPA_CLIENT_WLAN1_CONS] = {
- 16, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 16, 3, 8, 8, IPA_EE_UC } },
- [IPA_3_5_1][IPA_CLIENT_HSIC2_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_USB2_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5_1][IPA_CLIENT_WLAN2_CONS] = {
- 18, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 18, 9, 8, 8, IPA_EE_AP } },
- [IPA_3_5_1][IPA_CLIENT_HSIC3_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_USB3_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5_1][IPA_CLIENT_WLAN3_CONS] = {
- 19, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 19, 10, 8, 8, IPA_EE_AP } },
- [IPA_3_5_1][IPA_CLIENT_HSIC4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_USB4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_WLAN4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_HSIC5_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5_1][IPA_CLIENT_USB_CONS] = {
- 17, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 17, 8, 8, 8, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_USB_DPL_CONS] = {
- 11, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 11, 2, 4, 6, IPA_EE_AP } },
- [IPA_3_5_1][IPA_CLIENT_A2_EMBEDDED_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_A2_TETHERED_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_A5_LAN_WAN_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5_1][IPA_CLIENT_APPS_LAN_CONS] = {
- 9, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 9, 5, 8, 12, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_APPS_WAN_CONS] = {
- 10, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 10, 6, 8, 12, IPA_EE_AP } },
- [IPA_3_5_1][IPA_CLIENT_ODU_EMB_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_ODU_TETH_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_MHI_CONS] = IPA_CLIENT_NOT_USED,
[IPA_3_5_1][IPA_CLIENT_Q6_LAN_CONS] = {
- 13, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 13, 3, 8, 12, IPA_EE_Q6 } },
[IPA_3_5_1][IPA_CLIENT_Q6_WAN_CONS] = {
- 12, IPA_v3_5_GROUP_UL_DL, false,
+ true, IPA_v3_5_GROUP_UL_DL, false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 12, 2, 8, 12, IPA_EE_Q6 } },
- [IPA_3_5_1][IPA_CLIENT_Q6_DUN_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_Q6_DECOMP_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_Q6_DECOMP2_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_3_5_1][IPA_CLIENT_ETHERNET_CONS] = IPA_CLIENT_NOT_USED,
/* Only for test purpose */
[IPA_3_5_1][IPA_CLIENT_TEST_CONS] = {
- 17, IPA_v3_5_GROUP_UL_DL,
+ true, IPA_v3_5_GROUP_UL_DL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 17, 8, 8, 8, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_TEST1_CONS] = {
- 17, IPA_v3_5_GROUP_UL_DL,
+ true, IPA_v3_5_GROUP_UL_DL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 17, 8, 8, 8, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_TEST2_CONS] = {
- 18, IPA_v3_5_GROUP_UL_DL,
+ true, IPA_v3_5_GROUP_UL_DL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 18, 9, 8, 8, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_TEST3_CONS] = {
- 19, IPA_v3_5_GROUP_UL_DL,
+ true, IPA_v3_5_GROUP_UL_DL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 19, 10, 8, 8, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_TEST4_CONS] = {
- 11, IPA_v3_5_GROUP_UL_DL,
+ true, IPA_v3_5_GROUP_UL_DL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
@@ -1224,391 +1075,379 @@
/* IPA_4_0 */
- [IPA_4_0][IPA_CLIENT_HSIC1_PROD] = IPA_CLIENT_NOT_USED,
[IPA_4_0][IPA_CLIENT_WLAN1_PROD] = {
- 7, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 7, 9, 8, 16, IPA_EE_AP } },
- [IPA_4_0][IPA_CLIENT_HSIC2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_USB2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_HSIC3_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_USB3_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_HSIC4_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_USB4_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_HSIC5_PROD] = IPA_CLIENT_NOT_USED,
[IPA_4_0][IPA_CLIENT_USB_PROD] = {
- 0, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 0, 8, 8, 16, IPA_EE_AP } },
- [IPA_4_0][IPA_CLIENT_UC_USB_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_A2_EMBEDDED_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_A2_TETHERED_PROD] = IPA_CLIENT_NOT_USED,
[IPA_4_0][IPA_CLIENT_APPS_LAN_PROD] = {
- 8, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 8, 10, 8, 16, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_APPS_WAN_PROD] = {
- 2, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 2, 3, 16, 32, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_APPS_CMD_PROD] = {
- 5, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_DDR,
{ 5, 4, 20, 24, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_ODU_PROD] = {
- 0, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_DDR,
{ 0, 1, 8, 16, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_ETHERNET_PROD] = {
- 9, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 9, 0, 8, 16, IPA_EE_UC } },
- [IPA_4_0][IPA_CLIENT_MHI_PROD] = IPA_CLIENT_NOT_USED,
[IPA_4_0][IPA_CLIENT_Q6_LAN_PROD] = {
- 6, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 6, 2, 12, 24, IPA_EE_Q6 } },
[IPA_4_0][IPA_CLIENT_Q6_WAN_PROD] = {
- 3, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 3, 0, 16, 32, IPA_EE_Q6 } },
[IPA_4_0][IPA_CLIENT_Q6_CMD_PROD] = {
- 4, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 4, 1, 20, 24, IPA_EE_Q6 } },
- [IPA_4_0][IPA_CLIENT_Q6_DECOMP_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_Q6_DECOMP2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_MEMCPY_DMA_SYNC_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD] = IPA_CLIENT_NOT_USED,
/* Only for test purpose */
[IPA_4_0][IPA_CLIENT_TEST_PROD] = {
- 0, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{0, 8, 8, 16, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_TEST1_PROD] = {
- 0, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{0, 8, 8, 16, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_TEST2_PROD] = {
- 1, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 1, 0, 8, 16, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_TEST3_PROD] = {
- 7, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{7, 9, 8, 16, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_TEST4_PROD] = {
- 8, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 8, 10, 8, 16, IPA_EE_AP } },
- [IPA_4_0][IPA_CLIENT_HSIC1_CONS] = IPA_CLIENT_NOT_USED,
[IPA_4_0][IPA_CLIENT_WLAN1_CONS] = {
- 18, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 18, 12, 6, 9, IPA_EE_AP } },
- [IPA_4_0][IPA_CLIENT_HSIC2_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_USB2_CONS] = IPA_CLIENT_NOT_USED,
[IPA_4_0][IPA_CLIENT_WLAN2_CONS] = {
- 20, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 20, 14, 9, 9, IPA_EE_AP } },
- [IPA_4_0][IPA_CLIENT_HSIC3_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_USB3_CONS] = IPA_CLIENT_NOT_USED,
[IPA_4_0][IPA_CLIENT_WLAN3_CONS] = {
- 21, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 21, 15, 9, 9, IPA_EE_AP } },
- [IPA_4_0][IPA_CLIENT_HSIC4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_USB4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_WLAN4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_HSIC5_CONS] = IPA_CLIENT_NOT_USED,
[IPA_4_0][IPA_CLIENT_USB_CONS] = {
- 19, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 19, 13, 9, 9, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_USB_DPL_CONS] = {
- 15, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 15, 7, 5, 5, IPA_EE_AP } },
- [IPA_4_0][IPA_CLIENT_A2_EMBEDDED_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_A2_TETHERED_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_A5_LAN_WAN_CONS] = IPA_CLIENT_NOT_USED,
[IPA_4_0][IPA_CLIENT_APPS_LAN_CONS] = {
- 10, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 10, 5, 9, 9, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_APPS_WAN_CONS] = {
- 11, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 11, 6, 9, 9, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_ODU_EMB_CONS] = {
- 17, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 17, 1, 17, 17, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_ETHERNET_CONS] = {
- 22, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 22, 1, 17, 17, IPA_EE_UC } },
- [IPA_4_0][IPA_CLIENT_ODU_TETH_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_MHI_CONS] = IPA_CLIENT_NOT_USED,
[IPA_4_0][IPA_CLIENT_Q6_LAN_CONS] = {
- 14, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 14, 4, 9, 9, IPA_EE_Q6 } },
[IPA_4_0][IPA_CLIENT_Q6_WAN_CONS] = {
- 13, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 13, 3, 9, 9, IPA_EE_Q6 } },
- [IPA_4_0][IPA_CLIENT_Q6_DUN_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_Q6_DECOMP_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_Q6_DECOMP2_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS] = IPA_CLIENT_NOT_USED,
[IPA_4_0][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = {
- 16, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 16, 5, 9, 9, IPA_EE_Q6 } },
/* Only for test purpose */
/* MBIM aggregation test pipes should have the same QMB as USB_CONS */
[IPA_4_0][IPA_CLIENT_TEST_CONS] = {
- 12, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 12, 2, 5, 5, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_TEST1_CONS] = {
- 12, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 12, 2, 5, 5, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_TEST2_CONS] = {
- 18, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 18, 12, 6, 9, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_TEST3_CONS] = {
- 20, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 20, 14, 9, 9, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_TEST4_CONS] = {
- 21, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 21, 15, 9, 9, IPA_EE_AP } },
/* IPA_4_0_MHI */
- [IPA_4_0_MHI][IPA_CLIENT_HSIC1_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_WLAN1_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_HSIC2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_USB2_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_HSIC3_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_USB3_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_HSIC4_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_USB4_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_HSIC5_PROD] = IPA_CLIENT_NOT_USED,
[IPA_4_0_MHI][IPA_CLIENT_USB_PROD] = {
- 0, IPA_v4_0_MHI_GROUP_DDR, true,
+ true, IPA_v4_0_MHI_GROUP_DDR,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 0, 8, 8, 16, IPA_EE_AP } },
- [IPA_4_0_MHI][IPA_CLIENT_UC_USB_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_A2_EMBEDDED_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_A2_TETHERED_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_APPS_LAN_PROD] = IPA_CLIENT_NOT_USED,
[IPA_4_0_MHI][IPA_CLIENT_APPS_WAN_PROD] = {
- 2, IPA_v4_0_MHI_GROUP_DDR, true,
+ true, IPA_v4_0_MHI_GROUP_DDR,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 2, 3, 16, 32, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_APPS_CMD_PROD] = {
- 5, IPA_v4_0_MHI_GROUP_DDR, false,
+ true, IPA_v4_0_MHI_GROUP_DDR,
+ false,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_DDR,
{ 5, 4, 20, 24, IPA_EE_AP } },
- [IPA_4_0_MHI][IPA_CLIENT_ODU_PROD] = IPA_CLIENT_NOT_USED,
[IPA_4_0_MHI][IPA_CLIENT_MHI_PROD] = {
- 1, IPA_v4_0_MHI_GROUP_PCIE, true,
+ true, IPA_v4_0_MHI_GROUP_PCIE,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_PCIE,
{ 1, 0, 8, 16, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_Q6_LAN_PROD] = {
- 3, IPA_v4_0_MHI_GROUP_DDR, true,
+ true, IPA_v4_0_MHI_GROUP_DDR,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 3, 0, 16, 32, IPA_EE_Q6 } },
[IPA_4_0_MHI][IPA_CLIENT_Q6_WAN_PROD] = {
- 6, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 6, 2, 12, 24, IPA_EE_Q6 } },
[IPA_4_0_MHI][IPA_CLIENT_Q6_CMD_PROD] = {
- 4, IPA_v4_0_MHI_GROUP_PCIE, false,
+ true, IPA_v4_0_MHI_GROUP_PCIE,
+ false,
IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 4, 1, 20, 24, IPA_EE_Q6 } },
- [IPA_4_0_MHI][IPA_CLIENT_Q6_DECOMP_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_Q6_DECOMP2_PROD] = IPA_CLIENT_NOT_USED,
[IPA_4_0_MHI][IPA_CLIENT_MEMCPY_DMA_SYNC_PROD] = {
- 7, IPA_v4_0_MHI_GROUP_DMA, false,
+ true, IPA_v4_0_MHI_GROUP_DMA,
+ false,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_DDR,
{ 7, 9, 8, 16, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD] = {
- 8, IPA_v4_0_MHI_GROUP_DMA, false,
+ true, IPA_v4_0_MHI_GROUP_DMA,
+ false,
IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY,
QMB_MASTER_SELECT_DDR,
{ 8, 10, 8, 16, IPA_EE_AP } },
/* Only for test purpose */
[IPA_4_0_MHI][IPA_CLIENT_TEST_PROD] = {
- 0, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{0, 8, 8, 16, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_TEST1_PROD] = {
- 0, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{0, 8, 8, 16, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_TEST2_PROD] = {
- 1, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 1, 0, 8, 16, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_TEST3_PROD] = {
- 7, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{7, 9, 8, 16, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_TEST4_PROD] = {
- 8, IPA_v4_0_GROUP_UL_DL, true,
+ true, IPA_v4_0_GROUP_UL_DL,
+ true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR,
{ 8, 10, 8, 16, IPA_EE_AP } },
- [IPA_4_0_MHI][IPA_CLIENT_HSIC1_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_WLAN1_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_HSIC2_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_USB2_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_WLAN2_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_HSIC3_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_USB3_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_WLAN3_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_HSIC4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_USB4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_WLAN4_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_HSIC5_CONS] = IPA_CLIENT_NOT_USED,
[IPA_4_0_MHI][IPA_CLIENT_USB_CONS] = {
- 19, IPA_v4_0_MHI_GROUP_DDR, false,
+ true, IPA_v4_0_MHI_GROUP_DDR,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 19, 13, 9, 9, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_USB_DPL_CONS] = {
- 15, IPA_v4_0_MHI_GROUP_DDR, false,
+ true, IPA_v4_0_MHI_GROUP_DDR,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 15, 7, 5, 5, IPA_EE_AP } },
- [IPA_4_0_MHI][IPA_CLIENT_A2_EMBEDDED_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_A2_TETHERED_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_A5_LAN_WAN_CONS] = IPA_CLIENT_NOT_USED,
[IPA_4_0_MHI][IPA_CLIENT_APPS_LAN_CONS] = {
- 10, IPA_v4_0_MHI_GROUP_DDR, false,
+ true, IPA_v4_0_MHI_GROUP_DDR,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 10, 5, 9, 9, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_APPS_WAN_CONS] = {
- 11, IPA_v4_0_MHI_GROUP_DDR, false,
+ true, IPA_v4_0_MHI_GROUP_DDR,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 11, 6, 9, 9, IPA_EE_AP } },
- [IPA_4_0_MHI][IPA_CLIENT_ODU_EMB_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_ODU_TETH_CONS] = IPA_CLIENT_NOT_USED,
[IPA_4_0_MHI][IPA_CLIENT_MHI_CONS] = {
- 17, IPA_v4_0_MHI_GROUP_PCIE, false,
+ true, IPA_v4_0_MHI_GROUP_PCIE,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 17, 1, 17, 17, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_Q6_LAN_CONS] = {
- 14, IPA_v4_0_MHI_GROUP_DDR, false,
+ true, IPA_v4_0_MHI_GROUP_DDR,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 14, 4, 9, 9, IPA_EE_Q6 } },
[IPA_4_0_MHI][IPA_CLIENT_Q6_WAN_CONS] = {
- 13, IPA_v4_0_MHI_GROUP_DDR, false,
+ true, IPA_v4_0_MHI_GROUP_DDR,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 13, 3, 9, 9, IPA_EE_Q6 } },
- [IPA_4_0_MHI][IPA_CLIENT_Q6_DUN_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_Q6_DECOMP_CONS] = IPA_CLIENT_NOT_USED,
- [IPA_4_0_MHI][IPA_CLIENT_Q6_DECOMP2_CONS] = IPA_CLIENT_NOT_USED,
[IPA_4_0_MHI][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS] = {
- 20, IPA_v4_0_MHI_GROUP_DMA, false,
+ true, IPA_v4_0_MHI_GROUP_DMA,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 20, 14, 9, 9, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS] = {
- 21, IPA_v4_0_MHI_GROUP_DMA, false,
+ true, IPA_v4_0_MHI_GROUP_DMA,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 21, 15, 9, 9, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = {
- 16, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 16, 5, 9, 9, IPA_EE_Q6 } },
/* Only for test purpose */
[IPA_4_0_MHI][IPA_CLIENT_TEST_CONS] = {
- 12, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 12, 2, 5, 5, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_TEST1_CONS] = {
- 12, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 12, 2, 5, 5, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_TEST2_CONS] = {
- 18, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 18, 12, 6, 9, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_TEST3_CONS] = {
- 20, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 20, 14, 9, 9, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_TEST4_CONS] = {
- 21, IPA_v4_0_GROUP_UL_DL, false,
+ true, IPA_v4_0_GROUP_UL_DL,
+ false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
{ 21, 15, 9, 9, IPA_EE_AP } },
@@ -2204,7 +2043,11 @@
return IPA_EP_NOT_ALLOCATED;
}
- ipa_ep_idx = ipa3_ep_mapping[ipa3_get_hw_type_index()][client].pipe_num;
+ if (!ipa3_ep_mapping[ipa3_get_hw_type_index()][client].valid)
+ return IPA_EP_NOT_ALLOCATED;
+
+ ipa_ep_idx = ipa3_ep_mapping[ipa3_get_hw_type_index()][client].
+ ipa_gsi_ep_info.ipa_ep_num;
if (ipa_ep_idx < 0 || ipa_ep_idx >= IPA3_MAX_NUM_PIPES)
return IPA_EP_NOT_ALLOCATED;
@@ -2226,6 +2069,9 @@
if (ep_idx == IPA_EP_NOT_ALLOCATED)
return NULL;
+ if (!ipa3_ep_mapping[ipa3_get_hw_type_index()][client].valid)
+ return NULL;
+
return &(ipa3_ep_mapping[ipa3_get_hw_type_index()]
[client].ipa_gsi_ep_info);
}
@@ -2243,6 +2089,9 @@
return -EINVAL;
}
+ if (!ipa3_ep_mapping[ipa3_get_hw_type_index()][client].valid)
+ return -EINVAL;
+
return ipa3_ep_mapping[ipa3_get_hw_type_index()][client].group_num;
}
@@ -2259,6 +2108,9 @@
return -EINVAL;
}
+ if (!ipa3_ep_mapping[ipa3_get_hw_type_index()][client].valid)
+ return -EINVAL;
+
return ipa3_ep_mapping[ipa3_get_hw_type_index()]
[client].qmb_master_sel;
}
@@ -2404,6 +2256,7 @@
enum ipa_client_type cl;
u8 hw_type_idx = ipa3_get_hw_type_index();
u32 bitmap;
+ u32 pipe_num;
bitmap = 0;
@@ -2411,8 +2264,9 @@
for (cl = 0; cl < IPA_CLIENT_MAX ; cl++) {
if (ipa3_ep_mapping[hw_type_idx][cl].support_flt) {
- bitmap |=
- (1U<<ipa3_ep_mapping[hw_type_idx][cl].pipe_num);
+ pipe_num = ipa3_ep_mapping[hw_type_idx][cl].
+ ipa_gsi_ep_info.ipa_ep_num;
+ bitmap |= (1U << pipe_num);
if (bitmap != ipa3_ctx->ep_flt_bitmap) {
ipa3_ctx->ep_flt_bitmap = bitmap;
ipa3_ctx->ep_flt_num++;
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 46dc148..cd76ca2 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -119,7 +119,8 @@
else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
return scnprintf(buf, PAGE_SIZE, "%s\n",
capacity_level_text[value.intval]);
- else if (off == POWER_SUPPLY_PROP_TYPE)
+ else if (off == POWER_SUPPLY_PROP_TYPE ||
+ off == POWER_SUPPLY_PROP_REAL_TYPE)
return scnprintf(buf, PAGE_SIZE, "%s\n",
type_text[value.intval]);
else if (off == POWER_SUPPLY_PROP_SCOPE)
@@ -308,6 +309,7 @@
POWER_SUPPLY_ATTR(connector_health),
POWER_SUPPLY_ATTR(ctm_current_max),
POWER_SUPPLY_ATTR(hw_current_max),
+ POWER_SUPPLY_ATTR(real_type),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 54bef52..4ecf9a5 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -26,6 +26,7 @@
#include <linux/pm_wakeup.h>
#include <linux/slab.h>
#include <linux/pmic-voter.h>
+#include "battery.h"
#define DRV_MAJOR_VERSION 1
#define DRV_MINOR_VERSION 0
@@ -410,19 +411,6 @@
if (!chip->main_psy)
return 0;
- if (chip->batt_psy) {
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CURRENT_QNOVO,
- &pval);
- if (rc < 0) {
- pr_err("Couldn't get qnovo fcc, rc=%d\n", rc);
- return rc;
- }
-
- if (pval.intval != -EINVAL)
- total_fcc_ua = pval.intval;
- }
-
if (chip->pl_mode == POWER_SUPPLY_PL_NONE
|| get_effective_result_locked(chip->pl_disable_votable)) {
pval.intval = total_fcc_ua;
@@ -473,7 +461,6 @@
struct pl_data *chip = data;
union power_supply_propval pval = {0, };
int rc = 0;
- int effective_fv_uv = fv_uv;
if (fv_uv < 0)
return 0;
@@ -481,20 +468,7 @@
if (!chip->main_psy)
return 0;
- if (chip->batt_psy) {
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_VOLTAGE_QNOVO,
- &pval);
- if (rc < 0) {
- pr_err("Couldn't get qnovo fv, rc=%d\n", rc);
- return rc;
- }
-
- if (pval.intval != -EINVAL)
- effective_fv_uv = pval.intval;
- }
-
- pval.intval = effective_fv_uv;
+ pval.intval = fv_uv;
rc = power_supply_set_property(chip->main_psy,
POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
@@ -930,11 +904,17 @@
}
#define DEFAULT_RESTRICTED_CURRENT_UA 1000000
-static int pl_init(void)
+int qcom_batt_init(void)
{
struct pl_data *chip;
int rc = 0;
+ /* initialize just once */
+ if (the_chip) {
+ pr_err("was initialized earlier. Failing now\n");
+ return -EINVAL;
+ }
+
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
@@ -1014,7 +994,9 @@
goto unreg_notifier;
}
- return rc;
+ the_chip = chip;
+
+ return 0;
unreg_notifier:
power_supply_unreg_notifier(&chip->nb);
@@ -1031,21 +1013,23 @@
return rc;
}
-static void pl_deinit(void)
+void qcom_batt_deinit(void)
{
struct pl_data *chip = the_chip;
+ if (chip == NULL)
+ return;
+
+ cancel_work_sync(&chip->status_change_work);
+ cancel_delayed_work_sync(&chip->pl_taper_work);
+ cancel_work_sync(&chip->pl_disable_forever_work);
+
power_supply_unreg_notifier(&chip->nb);
destroy_votable(chip->pl_awake_votable);
destroy_votable(chip->pl_disable_votable);
destroy_votable(chip->fv_votable);
destroy_votable(chip->fcc_votable);
wakeup_source_unregister(chip->pl_ws);
+ the_chip = NULL;
kfree(chip);
}
-
-module_init(pl_init);
-module_exit(pl_deinit)
-
-MODULE_DESCRIPTION("");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/qcom/battery.h b/drivers/power/supply/qcom/battery.h
new file mode 100644
index 0000000..38626e7
--- /dev/null
+++ b/drivers/power/supply/qcom/battery.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __BATTERY_H
+#define __BATTERY_H
+int qcom_batt_init(void);
+void qcom_batt_deinit(void);
+#endif /* __BATTERY_H */
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 64e1f43..2266a2a 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -238,11 +238,9 @@
#define STEP_CHARGING_MAX_STEPS 5
struct smb_dt_props {
- int fcc_ua;
int usb_icl_ua;
int dc_icl_ua;
int boost_threshold_ua;
- int fv_uv;
int wipower_max_uw;
int min_freq_khz;
int max_freq_khz;
@@ -310,14 +308,14 @@
"qcom,external-vconn");
rc = of_property_read_u32(node,
- "qcom,fcc-max-ua", &chip->dt.fcc_ua);
+ "qcom,fcc-max-ua", &chg->batt_profile_fcc_ua);
if (rc < 0)
- chip->dt.fcc_ua = -EINVAL;
+ chg->batt_profile_fcc_ua = -EINVAL;
rc = of_property_read_u32(node,
- "qcom,fv-max-uv", &chip->dt.fv_uv);
+ "qcom,fv-max-uv", &chg->batt_profile_fv_uv);
if (rc < 0)
- chip->dt.fv_uv = -EINVAL;
+ chg->batt_profile_fv_uv = -EINVAL;
rc = of_property_read_u32(node,
"qcom,usb-icl-ua", &chip->dt.usb_icl_ua);
@@ -429,6 +427,7 @@
POWER_SUPPLY_PROP_PE_START,
POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
POWER_SUPPLY_PROP_HW_CURRENT_MAX,
+ POWER_SUPPLY_PROP_REAL_TYPE,
};
static int smb2_usb_get_prop(struct power_supply *psy,
@@ -448,6 +447,16 @@
break;
case POWER_SUPPLY_PROP_ONLINE:
rc = smblib_get_prop_usb_online(chg, val);
+ if (!val->intval)
+ break;
+
+ rc = smblib_get_prop_typec_mode(chg, val);
+ if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
+ chg->micro_usb_mode) &&
+ chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+ val->intval = 0;
+ else
+ val->intval = 1;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
val->intval = chg->voltage_min_uv;
@@ -465,10 +474,13 @@
rc = smblib_get_prop_usb_current_max(chg, val);
break;
case POWER_SUPPLY_PROP_TYPE:
+ val->intval = POWER_SUPPLY_TYPE_USB_PD;
+ break;
+ case POWER_SUPPLY_PROP_REAL_TYPE:
if (chip->bad_part)
- val->intval = POWER_SUPPLY_TYPE_USB;
+ val->intval = POWER_SUPPLY_TYPE_USB_PD;
else
- val->intval = chg->usb_psy_desc.type;
+ val->intval = chg->real_charger_type;
break;
case POWER_SUPPLY_PROP_TYPEC_MODE:
if (chg->micro_usb_mode)
@@ -610,7 +622,7 @@
struct smb_charger *chg = &chip->chg;
chg->usb_psy_desc.name = "usb";
- chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
+ chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD;
chg->usb_psy_desc.properties = smb2_usb_props;
chg->usb_psy_desc.num_properties = ARRAY_SIZE(smb2_usb_props);
chg->usb_psy_desc.get_property = smb2_usb_get_prop;
@@ -619,7 +631,7 @@
usb_cfg.drv_data = chip;
usb_cfg.of_node = chg->dev->of_node;
- chg->usb_psy = devm_power_supply_register(chg->dev,
+ chg->usb_psy = power_supply_register(chg->dev,
&chg->usb_psy_desc,
&usb_cfg);
if (IS_ERR(chg->usb_psy)) {
@@ -630,6 +642,97 @@
return 0;
}
+/********************************
+ * USB PC_PORT PSY REGISTRATION *
+ ********************************/
+static enum power_supply_property smb2_usb_port_props[] = {
+ POWER_SUPPLY_PROP_TYPE,
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static int smb2_usb_port_get_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct smb2 *chip = power_supply_get_drvdata(psy);
+ struct smb_charger *chg = &chip->chg;
+ int rc = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_TYPE:
+ val->intval = POWER_SUPPLY_TYPE_USB;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ rc = smblib_get_prop_usb_online(chg, val);
+ if (!val->intval)
+ break;
+
+ rc = smblib_get_prop_typec_mode(chg, val);
+ if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
+ chg->micro_usb_mode) &&
+ chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+ val->intval = 1;
+ else
+ val->intval = 0;
+ break;
+ default:
+ pr_err_ratelimited("Get prop %d is not supported in pc_port\n",
+ psp);
+ return -EINVAL;
+ }
+
+ if (rc < 0) {
+ pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+ return -ENODATA;
+ }
+
+ return 0;
+}
+
+static int smb2_usb_port_set_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ int rc = 0;
+
+ switch (psp) {
+ default:
+ pr_err_ratelimited("Set prop %d is not supported in pc_port\n",
+ psp);
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+static const struct power_supply_desc usb_port_psy_desc = {
+ .name = "pc_port",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .properties = smb2_usb_port_props,
+ .num_properties = ARRAY_SIZE(smb2_usb_port_props),
+ .get_property = smb2_usb_port_get_prop,
+ .set_property = smb2_usb_port_set_prop,
+};
+
+static int smb2_init_usb_port_psy(struct smb2 *chip)
+{
+ struct power_supply_config usb_port_cfg = {};
+ struct smb_charger *chg = &chip->chg;
+
+ usb_port_cfg.drv_data = chip;
+ usb_port_cfg.of_node = chg->dev->of_node;
+ chg->usb_port_psy = power_supply_register(chg->dev,
+ &usb_port_psy_desc,
+ &usb_port_cfg);
+ if (IS_ERR(chg->usb_port_psy)) {
+ pr_err("Couldn't register USB pc_port power supply\n");
+ return PTR_ERR(chg->usb_port_psy);
+ }
+
+ return 0;
+}
+
/*****************************
* USB MAIN PSY REGISTRATION *
*****************************/
@@ -734,7 +837,7 @@
usb_main_cfg.drv_data = chip;
usb_main_cfg.of_node = chg->dev->of_node;
- chg->usb_main_psy = devm_power_supply_register(chg->dev,
+ chg->usb_main_psy = power_supply_register(chg->dev,
&usb_main_psy_desc,
&usb_main_cfg);
if (IS_ERR(chg->usb_main_psy)) {
@@ -836,7 +939,7 @@
dc_cfg.drv_data = chip;
dc_cfg.of_node = chg->dev->of_node;
- chg->dc_psy = devm_power_supply_register(chg->dev,
+ chg->dc_psy = power_supply_register(chg->dev,
&dc_psy_desc,
&dc_cfg);
if (IS_ERR(chg->dc_psy)) {
@@ -946,13 +1049,15 @@
rc = smblib_get_prop_charge_qnovo_enable(chg, val);
break;
case POWER_SUPPLY_PROP_VOLTAGE_QNOVO:
- val->intval = chg->qnovo_fv_uv;
+ val->intval = get_client_vote_locked(chg->fv_votable,
+ QNOVO_VOTER);
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
rc = smblib_get_prop_batt_current_now(chg, val);
break;
case POWER_SUPPLY_PROP_CURRENT_QNOVO:
- val->intval = chg->qnovo_fcc_ua;
+ val->intval = get_client_vote_locked(chg->fcc_votable,
+ QNOVO_VOTER);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
val->intval = get_client_vote(chg->fcc_votable,
@@ -1018,23 +1123,37 @@
vote(chg->pl_disable_votable, USER_VOTER, (bool)val->intval, 0);
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
- vote(chg->fv_votable, DEFAULT_VOTER, true, val->intval);
+ chg->batt_profile_fv_uv = val->intval;
+ vote(chg->fv_votable, BATT_PROFILE_VOTER, true, val->intval);
break;
case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE:
rc = smblib_set_prop_charge_qnovo_enable(chg, val);
break;
case POWER_SUPPLY_PROP_VOLTAGE_QNOVO:
- chg->qnovo_fv_uv = val->intval;
- rc = rerun_election(chg->fv_votable);
+ if (val->intval == -EINVAL) {
+ vote(chg->fv_votable, BATT_PROFILE_VOTER,
+ true, chg->batt_profile_fv_uv);
+ vote(chg->fv_votable, QNOVO_VOTER, false, 0);
+ } else {
+ vote(chg->fv_votable, QNOVO_VOTER, true, val->intval);
+ vote(chg->fv_votable, BATT_PROFILE_VOTER, false, 0);
+ }
break;
case POWER_SUPPLY_PROP_CURRENT_QNOVO:
- chg->qnovo_fcc_ua = val->intval;
vote(chg->pl_disable_votable, PL_QNOVO_VOTER,
val->intval != -EINVAL && val->intval < 2000000, 0);
- rc = rerun_election(chg->fcc_votable);
+ if (val->intval == -EINVAL) {
+ vote(chg->fcc_votable, BATT_PROFILE_VOTER,
+ true, chg->batt_profile_fcc_ua);
+ vote(chg->fcc_votable, QNOVO_VOTER, false, 0);
+ } else {
+ vote(chg->fcc_votable, QNOVO_VOTER, true, val->intval);
+ vote(chg->fcc_votable, BATT_PROFILE_VOTER, false, 0);
+ }
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
- vote(chg->fcc_votable, DEFAULT_VOTER, true, val->intval);
+ chg->batt_profile_fcc_ua = val->intval;
+ vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval);
break;
case POWER_SUPPLY_PROP_SET_SHIP_MODE:
/* Not in ship mode as long as the device is active */
@@ -1051,6 +1170,9 @@
case POWER_SUPPLY_PROP_DP_DM:
rc = smblib_dp_dm(chg, val->intval);
break;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
+ rc = smblib_set_prop_input_current_limited(chg, val);
+ break;
default:
rc = -EINVAL;
}
@@ -1068,6 +1190,7 @@
case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
case POWER_SUPPLY_PROP_DP_DM:
case POWER_SUPPLY_PROP_RERUN_AICL:
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
return 1;
default:
break;
@@ -1094,7 +1217,7 @@
batt_cfg.drv_data = chg;
batt_cfg.of_node = chg->dev->of_node;
- chg->batt_psy = devm_power_supply_register(chg->dev,
+ chg->batt_psy = power_supply_register(chg->dev,
&batt_psy_desc,
&batt_cfg);
if (IS_ERR(chg->batt_psy)) {
@@ -1451,11 +1574,13 @@
if (chip->dt.no_battery)
chg->fake_capacity = 50;
- if (chip->dt.fcc_ua < 0)
- smblib_get_charge_param(chg, &chg->param.fcc, &chip->dt.fcc_ua);
+ if (chg->batt_profile_fcc_ua < 0)
+ smblib_get_charge_param(chg, &chg->param.fcc,
+ &chg->batt_profile_fcc_ua);
- if (chip->dt.fv_uv < 0)
- smblib_get_charge_param(chg, &chg->param.fv, &chip->dt.fv_uv);
+ if (chg->batt_profile_fv_uv < 0)
+ smblib_get_charge_param(chg, &chg->param.fv,
+ &chg->batt_profile_fv_uv);
smblib_get_charge_param(chg, &chg->param.usb_icl,
&chg->default_icl_ua);
@@ -1516,9 +1641,9 @@
vote(chg->dc_suspend_votable,
DEFAULT_VOTER, chip->dt.no_battery, 0);
vote(chg->fcc_votable,
- DEFAULT_VOTER, true, chip->dt.fcc_ua);
+ BATT_PROFILE_VOTER, true, chg->batt_profile_fcc_ua);
vote(chg->fv_votable,
- DEFAULT_VOTER, true, chip->dt.fv_uv);
+ BATT_PROFILE_VOTER, true, chg->batt_profile_fv_uv);
vote(chg->dc_icl_votable,
DEFAULT_VOTER, true, chip->dt.dc_icl_ua);
vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
@@ -2062,6 +2187,21 @@
return rc;
}
+static void smb2_free_interrupts(struct smb_charger *chg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(smb2_irqs); i++) {
+ if (smb2_irqs[i].irq > 0) {
+ if (smb2_irqs[i].wake)
+ disable_irq_wake(smb2_irqs[i].irq);
+
+ devm_free_irq(chg->dev, smb2_irqs[i].irq,
+ smb2_irqs[i].irq_data);
+ }
+ }
+}
+
static void smb2_disable_interrupts(struct smb_charger *chg)
{
int i;
@@ -2239,7 +2379,13 @@
rc = smb2_init_usb_main_psy(chip);
if (rc < 0) {
- pr_err("Couldn't initialize usb psy rc=%d\n", rc);
+ pr_err("Couldn't initialize usb main psy rc=%d\n", rc);
+ goto cleanup;
+ }
+
+ rc = smb2_init_usb_port_psy(chip);
+ if (rc < 0) {
+ pr_err("Couldn't initialize usb pc_port psy rc=%d\n", rc);
goto cleanup;
}
@@ -2297,20 +2443,29 @@
device_init_wakeup(chg->dev, true);
pr_info("QPNP SMB2 probed successfully usb:present=%d type=%d batt:present = %d health = %d charge = %d\n",
- usb_present, chg->usb_psy_desc.type,
+ usb_present, chg->real_charger_type,
batt_present, batt_health, batt_charge_type);
return rc;
cleanup:
- smblib_deinit(chg);
- if (chg->usb_psy)
- power_supply_unregister(chg->usb_psy);
+ smb2_free_interrupts(chg);
if (chg->batt_psy)
power_supply_unregister(chg->batt_psy);
+ if (chg->usb_main_psy)
+ power_supply_unregister(chg->usb_main_psy);
+ if (chg->usb_psy)
+ power_supply_unregister(chg->usb_psy);
+ if (chg->usb_port_psy)
+ power_supply_unregister(chg->usb_port_psy);
+ if (chg->dc_psy)
+ power_supply_unregister(chg->dc_psy);
if (chg->vconn_vreg && chg->vconn_vreg->rdev)
- regulator_unregister(chg->vconn_vreg->rdev);
+ devm_regulator_unregister(chg->dev, chg->vconn_vreg->rdev);
if (chg->vbus_vreg && chg->vbus_vreg->rdev)
- regulator_unregister(chg->vbus_vreg->rdev);
+ devm_regulator_unregister(chg->dev, chg->vbus_vreg->rdev);
+
+ smblib_deinit(chg);
+
platform_set_drvdata(pdev, NULL);
return rc;
}
@@ -2322,6 +2477,7 @@
power_supply_unregister(chg->batt_psy);
power_supply_unregister(chg->usb_psy);
+ power_supply_unregister(chg->usb_port_psy);
regulator_unregister(chg->vconn_vreg->rdev);
regulator_unregister(chg->vbus_vreg->rdev);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 6eb7009..b1070e8 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -18,10 +18,11 @@
#include <linux/regulator/driver.h>
#include <linux/qpnp/qpnp-revid.h>
#include <linux/irq.h>
+#include <linux/pmic-voter.h>
#include "smb-lib.h"
#include "smb-reg.h"
+#include "battery.h"
#include "storm-watch.h"
-#include <linux/pmic-voter.h>
#define smblib_err(chg, fmt, ...) \
pr_err("%s: %s: " fmt, chg->name, \
@@ -548,9 +549,9 @@
/* if PD is active, APSD is disabled so won't have a valid result */
if (chg->pd_active)
- chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD;
+ chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
else
- chg->usb_psy_desc.type = apsd_result->pst;
+ chg->real_charger_type = apsd_result->pst;
smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n",
apsd_result->name, chg->pd_active);
@@ -856,7 +857,7 @@
/* configure current */
if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
- && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
+ && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
rc = set_sdp_current(chg, icl_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
@@ -877,10 +878,10 @@
/* remove override if no voters - hw defaults is desired */
override = false;
} else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
- if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)
+ if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
/* For std cable with type = SDP never override */
override = false;
- else if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_CDP
+ else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
&& icl_ua == 1500000)
/*
* For std cable with type = CDP override only if
@@ -1712,6 +1713,11 @@
u8 stat;
int rc;
+ if (chg->fake_input_current_limited >= 0) {
+ val->intval = chg->fake_input_current_limited;
+ return 0;
+ }
+
rc = smblib_read(chg, AICL_STATUS_REG, &stat);
if (rc < 0) {
smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
@@ -1903,6 +1909,13 @@
return rc;
}
+int smblib_set_prop_input_current_limited(struct smb_charger *chg,
+ const union power_supply_propval *val)
+{
+ chg->fake_input_current_limited = val->intval;
+ return 0;
+}
+
int smblib_rerun_aicl(struct smb_charger *chg)
{
int rc, settled_icl_ua;
@@ -3319,7 +3332,7 @@
int pulses;
power_supply_changed(chg->usb_main_psy);
- if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP) {
+ if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
if (rc < 0) {
smblib_err(chg,
@@ -3347,7 +3360,7 @@
}
}
- if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
+ if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, &stat);
if (rc < 0) {
smblib_err(chg,
@@ -4278,26 +4291,30 @@
int rc = 0;
chg->fcc_votable = find_votable("FCC");
- if (!chg->fcc_votable) {
- rc = -EPROBE_DEFER;
+ if (chg->fcc_votable == NULL) {
+ rc = -EINVAL;
+ smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
return rc;
}
chg->fv_votable = find_votable("FV");
- if (!chg->fv_votable) {
- rc = -EPROBE_DEFER;
+ if (chg->fv_votable == NULL) {
+ rc = -EINVAL;
+ smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
return rc;
}
chg->usb_icl_votable = find_votable("USB_ICL");
if (!chg->usb_icl_votable) {
- rc = -EPROBE_DEFER;
+ rc = -EINVAL;
+ smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
return rc;
}
chg->pl_disable_votable = find_votable("PL_DISABLE");
- if (!chg->pl_disable_votable) {
- rc = -EPROBE_DEFER;
+ if (chg->pl_disable_votable == NULL) {
+ rc = -EINVAL;
+ smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
return rc;
}
vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
@@ -4476,11 +4493,17 @@
INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
chg->fake_capacity = -EINVAL;
+ chg->fake_input_current_limited = -EINVAL;
switch (chg->mode) {
case PARALLEL_MASTER:
- chg->qnovo_fcc_ua = -EINVAL;
- chg->qnovo_fv_uv = -EINVAL;
+ rc = qcom_batt_init();
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
+ rc);
+ return rc;
+ }
+
rc = smblib_create_votables(chg);
if (rc < 0) {
smblib_err(chg, "Couldn't create votables rc=%d\n",
@@ -4512,8 +4535,20 @@
{
switch (chg->mode) {
case PARALLEL_MASTER:
+ cancel_work_sync(&chg->bms_update_work);
+ cancel_work_sync(&chg->rdstd_cc2_detach_work);
+ cancel_delayed_work_sync(&chg->hvdcp_detect_work);
+ cancel_delayed_work_sync(&chg->step_soc_req_work);
+ cancel_delayed_work_sync(&chg->clear_hdc_work);
+ cancel_work_sync(&chg->otg_oc_work);
+ cancel_work_sync(&chg->vconn_oc_work);
+ cancel_delayed_work_sync(&chg->otg_ss_done_work);
+ cancel_delayed_work_sync(&chg->icl_change_work);
+ cancel_delayed_work_sync(&chg->pl_enable_work);
+ cancel_work_sync(&chg->legacy_detection_work);
power_supply_unreg_notifier(&chg->nb);
smblib_destroy_votables(chg);
+ qcom_batt_deinit();
break;
case PARALLEL_SLAVE:
break;
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index e4679f4..42b357e 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -62,6 +62,8 @@
#define AICL_RERUN_VOTER "AICL_RERUN_VOTER"
#define LEGACY_UNKNOWN_VOTER "LEGACY_UNKNOWN_VOTER"
#define CC2_WA_VOTER "CC2_WA_VOTER"
+#define QNOVO_VOTER "QNOVO_VOTER"
+#define BATT_PROFILE_VOTER "BATT_PROFILE_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
@@ -242,6 +244,8 @@
struct power_supply *bms_psy;
struct power_supply_desc usb_psy_desc;
struct power_supply *usb_main_psy;
+ struct power_supply *usb_port_psy;
+ enum power_supply_type real_charger_type;
/* notifiers */
struct notifier_block nb;
@@ -314,6 +318,7 @@
bool typec_present;
u8 typec_status[5];
bool typec_legacy_valid;
+ int fake_input_current_limited;
/* workaround flag */
u32 wa_flags;
@@ -325,9 +330,11 @@
/* extcon for VBUS / ID notification to USB for uUSB */
struct extcon_dev *extcon;
+ /* battery profile */
+ int batt_profile_fcc_ua;
+ int batt_profile_fv_uv;
+
/* qnovo */
- int qnovo_fcc_ua;
- int qnovo_fv_uv;
int usb_icl_delta_ua;
int pulse_cnt;
};
@@ -417,6 +424,8 @@
const union power_supply_propval *val);
int smblib_set_prop_system_temp_level(struct smb_charger *chg,
const union power_supply_propval *val);
+int smblib_set_prop_input_current_limited(struct smb_charger *chg,
+ const union power_supply_propval *val);
int smblib_get_prop_dc_present(struct smb_charger *chg,
union power_supply_propval *val);
diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h
index 3f260a4..167666a 100644
--- a/drivers/power/supply/qcom/smb-reg.h
+++ b/drivers/power/supply/qcom/smb-reg.h
@@ -1025,14 +1025,4 @@
/* CHGR FREQ Peripheral registers */
#define FREQ_CLK_DIV_REG (CHGR_FREQ_BASE + 0x50)
-/* SMB1355 specific registers */
-#define SMB1355_TEMP_COMP_STATUS_REG (MISC_BASE + 0x07)
-#define SKIN_TEMP_RST_HOT_BIT BIT(6)
-#define SKIN_TEMP_UB_HOT_BIT BIT(5)
-#define SKIN_TEMP_LB_HOT_BIT BIT(4)
-#define DIE_TEMP_TSD_HOT_BIT BIT(3)
-#define DIE_TEMP_RST_HOT_BIT BIT(2)
-#define DIE_TEMP_UB_HOT_BIT BIT(1)
-#define DIE_TEMP_LB_HOT_BIT BIT(0)
-
#endif /* __SMB2_CHARGER_REG_H */
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index 8725590..83374bb 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -104,8 +104,6 @@
struct smb_dt_props dt;
struct power_supply *parallel_psy;
u32 wa_flags;
- struct pmic_revid_data *pmic_rev_id;
- char *name;
};
static int __debug_mask;
@@ -169,14 +167,6 @@
if (rc < 0)
chip->dt.pl_mode = POWER_SUPPLY_PL_USBMID_USBMID;
- /* check that smb1355 is configured to run in mid-mid mode */
- if (chip->pmic_rev_id->pmic_subtype == SMB1355_SUBTYPE
- && chip->dt.pl_mode != POWER_SUPPLY_PL_USBMID_USBMID) {
- pr_err("Smb1355 can only run in MID-MID mode, saw = %d mode\n",
- chip->dt.pl_mode);
- return -EINVAL;
- }
-
chip->dt.suspend_input = of_property_read_bool(node,
"qcom,suspend-input");
@@ -489,30 +479,6 @@
* PARALLEL PSY REGISTRATION *
*****************************/
-static int smb1355_get_prop_connector_health(struct smb138x *chip)
-{
- struct smb_charger *chg = &chip->chg;
- u8 temp;
- int rc;
-
- rc = smblib_read(chg, SMB1355_TEMP_COMP_STATUS_REG, &temp);
- if (rc < 0) {
- pr_err("Couldn't read comp stat reg rc = %d\n", rc);
- return POWER_SUPPLY_HEALTH_UNKNOWN;
- }
-
- if (temp & SKIN_TEMP_RST_HOT_BIT)
- return POWER_SUPPLY_HEALTH_OVERHEAT;
-
- if (temp & SKIN_TEMP_UB_HOT_BIT)
- return POWER_SUPPLY_HEALTH_HOT;
-
- if (temp & SKIN_TEMP_LB_HOT_BIT)
- return POWER_SUPPLY_HEALTH_WARM;
-
- return POWER_SUPPLY_HEALTH_COOL;
-}
-
static int smb138x_get_prop_connector_health(struct smb138x *chip)
{
struct smb_charger *chg = &chip->chg;
@@ -570,54 +536,18 @@
POWER_SUPPLY_PROP_PIN_ENABLED,
POWER_SUPPLY_PROP_INPUT_SUSPEND,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
- POWER_SUPPLY_PROP_VOLTAGE_MAX,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
- POWER_SUPPLY_PROP_MODEL_NAME,
- POWER_SUPPLY_PROP_PARALLEL_MODE,
- POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
- POWER_SUPPLY_PROP_SET_SHIP_MODE,
- POWER_SUPPLY_PROP_CHARGER_TEMP,
- POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
- POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_MAX,
-};
-
-static enum power_supply_property smb1355_parallel_props[] = {
- POWER_SUPPLY_PROP_CHARGE_TYPE,
- POWER_SUPPLY_PROP_CHARGING_ENABLED,
- POWER_SUPPLY_PROP_PIN_ENABLED,
- POWER_SUPPLY_PROP_INPUT_SUSPEND,
- POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CHARGER_TEMP,
+ POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_PARALLEL_MODE,
POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
POWER_SUPPLY_PROP_SET_SHIP_MODE,
- POWER_SUPPLY_PROP_CHARGER_TEMP,
- POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
};
-static int smb138x_get_parallel_charging(struct smb138x *chip, int *disabled)
-{
- struct smb_charger *chg = &chip->chg;
- int rc = 0;
- u8 cfg2;
-
- rc = smblib_read(chg, CHGR_CFG2_REG, &cfg2);
- if (rc < 0) {
- pr_err("Couldn't read en_cmg_reg rc=%d\n", rc);
- return rc;
- }
-
- if (cfg2 & CHG_EN_SRC_BIT)
- *disabled = 0;
- else
- *disabled = 1;
-
- return 0;
-}
-
static int smb138x_parallel_get_prop(struct power_supply *psy,
enum power_supply_property prop,
union power_supply_propval *val)
@@ -644,7 +574,7 @@
val->intval = !(temp & DISABLE_CHARGING_BIT);
break;
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
- rc = smb138x_get_parallel_charging(chip, &val->intval);
+ rc = smblib_get_usb_suspend(chg, &val->intval);
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
@@ -653,6 +583,14 @@
else
val->intval = 0;
break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
+ rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
+ &val->intval);
+ else
+ val->intval = 0;
+ break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
break;
@@ -660,46 +598,28 @@
rc = smblib_get_charge_param(chg, &chg->param.fcc,
&val->intval);
break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ rc = smblib_get_prop_slave_current_now(chg, val);
+ break;
+ case POWER_SUPPLY_PROP_CHARGER_TEMP:
+ rc = smb138x_get_prop_charger_temp(chip, val);
+ break;
+ case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
+ rc = smblib_get_prop_charger_temp_max(chg, val);
+ break;
case POWER_SUPPLY_PROP_MODEL_NAME:
- val->strval = chip->name;
+ val->strval = "smb138x";
break;
case POWER_SUPPLY_PROP_PARALLEL_MODE:
val->intval = chip->dt.pl_mode;
break;
case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
- if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
- val->intval = smb138x_get_prop_connector_health(chip);
- else
- val->intval = smb1355_get_prop_connector_health(chip);
+ val->intval = smb138x_get_prop_connector_health(chip);
break;
case POWER_SUPPLY_PROP_SET_SHIP_MODE:
/* Not in ship mode as long as device is active */
val->intval = 0;
break;
- case POWER_SUPPLY_PROP_CHARGER_TEMP:
- if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
- rc = smb138x_get_prop_charger_temp(chip, val);
- else
- rc = smblib_get_prop_charger_temp(chg, val);
- break;
- case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
- rc = smblib_get_prop_charger_temp_max(chg, val);
- break;
- case POWER_SUPPLY_PROP_CURRENT_NOW:
- if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
- rc = smblib_get_prop_slave_current_now(chg, val);
- else
- rc = -ENODATA;
- break;
- case POWER_SUPPLY_PROP_CURRENT_MAX:
- if ((chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
- && ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
- || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)))
- rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
- &val->intval);
- else
- rc = -ENODATA;
- break;
default:
pr_err("parallel power supply get prop %d not supported\n",
prop);
@@ -714,33 +634,28 @@
return rc;
}
-static int smb138x_set_parallel_charging(struct smb138x *chip, bool disable)
+static int smb138x_set_parallel_suspend(struct smb138x *chip, bool suspend)
{
struct smb_charger *chg = &chip->chg;
int rc = 0;
rc = smblib_masked_write(chg, WD_CFG_REG, WDOG_TIMER_EN_BIT,
- disable ? 0 : WDOG_TIMER_EN_BIT);
+ suspend ? 0 : WDOG_TIMER_EN_BIT);
if (rc < 0) {
pr_err("Couldn't %s watchdog rc=%d\n",
- disable ? "disable" : "enable", rc);
- disable = true;
+ suspend ? "disable" : "enable", rc);
+ suspend = true;
}
- /*
- * Configure charge enable for high polarity and
- * When disabling charging set it to cmd register control(cmd bit=0)
- * When enabling charging set it to pin control
- */
- rc = smblib_masked_write(chg, CHGR_CFG2_REG,
- CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT,
- disable ? 0 : CHG_EN_SRC_BIT);
+ rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
+ suspend ? USBIN_SUSPEND_BIT : 0);
if (rc < 0) {
- pr_err("Couldn't configure charge enable source rc=%d\n", rc);
+ pr_err("Couldn't %s parallel charger rc=%d\n",
+ suspend ? "suspend" : "resume", rc);
return rc;
}
- return 0;
+ return rc;
}
static int smb138x_parallel_set_prop(struct power_supply *psy,
@@ -753,7 +668,7 @@
switch (prop) {
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
- rc = smb138x_set_parallel_charging(chip, (bool)val->intval);
+ rc = smb138x_set_parallel_suspend(chip, (bool)val->intval);
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
@@ -788,7 +703,7 @@
return 0;
}
-static struct power_supply_desc parallel_psy_desc = {
+static const struct power_supply_desc parallel_psy_desc = {
.name = "parallel",
.type = POWER_SUPPLY_TYPE_PARALLEL,
.properties = smb138x_parallel_props,
@@ -816,28 +731,6 @@
return 0;
}
-static int smb1355_init_parallel_psy(struct smb138x *chip)
-{
- struct power_supply_config parallel_cfg = {};
- struct smb_charger *chg = &chip->chg;
-
- parallel_cfg.drv_data = chip;
- parallel_cfg.of_node = chg->dev->of_node;
-
- /* change to smb1355's property list */
- parallel_psy_desc.properties = smb1355_parallel_props;
- parallel_psy_desc.num_properties = ARRAY_SIZE(smb1355_parallel_props);
- chip->parallel_psy = devm_power_supply_register(chg->dev,
- ¶llel_psy_desc,
- ¶llel_cfg);
- if (IS_ERR(chip->parallel_psy)) {
- pr_err("Couldn't register parallel power supply\n");
- return PTR_ERR(chip->parallel_psy);
- }
-
- return 0;
-}
-
/******************************
* VBUS REGULATOR REGISTRATION *
******************************/
@@ -971,25 +864,10 @@
return rc;
}
- /* disable the charging path when under s/w control */
- rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
- CHARGING_ENABLE_CMD_BIT, 0);
+ /* suspend parallel charging */
+ rc = smb138x_set_parallel_suspend(chip, true);
if (rc < 0) {
- pr_err("Couldn't disable charging rc=%d\n", rc);
- return rc;
- }
-
- /* disable parallel charging path */
- rc = smb138x_set_parallel_charging(chip, true);
- if (rc < 0) {
- pr_err("Couldn't disable parallel path rc=%d\n", rc);
- return rc;
- }
-
- /* unsuspend parallel charging */
- rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT, 0);
- if (rc < 0) {
- pr_err("Couldn't unsuspend parallel charging rc=%d\n", rc);
+ pr_err("Couldn't suspend parallel charging rc=%d\n", rc);
return rc;
}
@@ -1000,6 +878,24 @@
return rc;
}
+ /* enable the charging path */
+ rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
+ CHARGING_ENABLE_CMD_BIT,
+ CHARGING_ENABLE_CMD_BIT);
+ if (rc < 0) {
+ pr_err("Couldn't enable charging rc=%d\n", rc);
+ return rc;
+ }
+
+ /* configure charge enable for software control; active high */
+ rc = smblib_masked_write(chg, CHGR_CFG2_REG,
+ CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT, 0);
+ if (rc < 0) {
+ pr_err("Couldn't configure charge enable source rc=%d\n",
+ rc);
+ return rc;
+ }
+
/* enable parallel current sensing */
rc = smblib_masked_write(chg, CFG_REG,
VCHG_EN_CFG_BIT, VCHG_EN_CFG_BIT);
@@ -1154,6 +1050,7 @@
static int smb138x_setup_wa_flags(struct smb138x *chip)
{
+ struct pmic_revid_data *pmic_rev_id;
struct device_node *revid_dev_node;
revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
@@ -1163,8 +1060,8 @@
return -EINVAL;
}
- chip->pmic_rev_id = get_revid_data(revid_dev_node);
- if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
+ pmic_rev_id = get_revid_data(revid_dev_node);
+ if (IS_ERR_OR_NULL(pmic_rev_id)) {
/*
* the revid peripheral must be registered, any failure
* here only indicates that the rev-id module has not
@@ -1173,14 +1070,14 @@
return -EPROBE_DEFER;
}
- switch (chip->pmic_rev_id->pmic_subtype) {
+ switch (pmic_rev_id->pmic_subtype) {
case SMB1381_SUBTYPE:
- if (chip->pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */
+ if (pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */
chip->wa_flags |= OOB_COMP_WA_BIT;
break;
default:
pr_err("PMIC subtype %d not supported\n",
- chip->pmic_rev_id->pmic_subtype);
+ pmic_rev_id->pmic_subtype);
return -EINVAL;
}
@@ -1478,7 +1375,6 @@
chg->param = v1_params;
- chip->name = "smb1381";
rc = smblib_init(chg);
if (rc < 0) {
pr_err("Couldn't initialize smblib rc=%d\n", rc);
@@ -1539,7 +1435,7 @@
return rc;
}
-static int smb1355_slave_probe(struct smb138x *chip)
+static int smb138x_slave_probe(struct smb138x *chip)
{
struct smb_charger *chg = &chip->chg;
int rc = 0;
@@ -1552,55 +1448,6 @@
goto cleanup;
}
- rc = smb138x_parse_dt(chip);
- if (rc < 0) {
- pr_err("Couldn't parse device tree rc=%d\n", rc);
- goto cleanup;
- }
-
- rc = smb138x_init_slave_hw(chip);
- if (rc < 0) {
- pr_err("Couldn't initialize hardware rc=%d\n", rc);
- goto cleanup;
- }
-
- rc = smb1355_init_parallel_psy(chip);
- if (rc < 0) {
- pr_err("Couldn't initialize parallel psy rc=%d\n", rc);
- goto cleanup;
- }
-
- rc = smb138x_determine_initial_slave_status(chip);
- if (rc < 0) {
- pr_err("Couldn't determine initial status rc=%d\n", rc);
- goto cleanup;
- }
-
- rc = smb138x_request_interrupts(chip);
- if (rc < 0) {
- pr_err("Couldn't request interrupts rc=%d\n", rc);
- goto cleanup;
- }
-
- return 0;
-
-cleanup:
- smblib_deinit(chg);
- return rc;
-}
-
-static int smb1381_slave_probe(struct smb138x *chip)
-{
- struct smb_charger *chg = &chip->chg;
- int rc = 0;
-
- chg->param = v1_params;
-
- rc = smblib_init(chg);
- if (rc < 0) {
- pr_err("Couldn't initialize smblib rc=%d\n", rc);
- goto cleanup;
- }
chg->iio.temp_max_chan = iio_channel_get(chg->dev, "charger_temp_max");
if (IS_ERR(chg->iio.temp_max_chan)) {
rc = PTR_ERR(chg->iio.temp_max_chan);
@@ -1668,71 +1515,25 @@
goto cleanup;
}
- return 0;
+ return rc;
cleanup:
smblib_deinit(chg);
+ if (chip->parallel_psy)
+ power_supply_unregister(chip->parallel_psy);
+ if (chg->vbus_vreg && chg->vbus_vreg->rdev)
+ regulator_unregister(chg->vbus_vreg->rdev);
return rc;
}
-static int slave_probe(struct smb138x *chip)
-{
- struct device_node *revid_dev_node;
- int rc = 0;
-
- revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
- "qcom,pmic-revid", 0);
- if (!revid_dev_node) {
- pr_err("Missing qcom,pmic-revid property\n");
- return -EINVAL;
- }
-
- chip->pmic_rev_id = get_revid_data(revid_dev_node);
- if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
- /*
- * the revid peripheral must be registered, any failure
- * here only indicates that the rev-id module has not
- * probed yet.
- */
- return -EPROBE_DEFER;
- }
-
- switch (chip->pmic_rev_id->pmic_subtype) {
- case SMB1355_SUBTYPE:
- chip->name = "smb1355";
- rc = smb1355_slave_probe(chip);
- break;
- case SMB1381_SUBTYPE:
- chip->name = "smb1381";
- rc = smb1381_slave_probe(chip);
- break;
- default:
- pr_err("Unsupported pmic subtype = 0x%02x\n",
- chip->pmic_rev_id->pmic_subtype);
- rc = -EINVAL;
- }
-
- if (rc < 0) {
- if (rc != -EPROBE_DEFER)
- pr_err("Couldn't probe SMB138X rc=%d\n", rc);
- return rc;
- }
-
- return 0;
-}
-
static const struct of_device_id match_table[] = {
{
- .compatible = "qcom,smb138x-charger",
- .data = (void *) PARALLEL_MASTER,
+ .compatible = "qcom,smb138x-charger",
+ .data = (void *) PARALLEL_MASTER
},
{
- .compatible = "qcom,smb138x-parallel-slave",
- .data = (void *) PARALLEL_SLAVE,
- },
- {
- .compatible = "qcom,smb1355-parallel-slave",
- .data = (void *) PARALLEL_SLAVE,
+ .compatible = "qcom,smb138x-parallel-slave",
+ .data = (void *) PARALLEL_SLAVE
},
{ },
};
@@ -1779,7 +1580,7 @@
rc = smb138x_master_probe(chip);
break;
case PARALLEL_SLAVE:
- rc = slave_probe(chip);
+ rc = smb138x_slave_probe(chip);
break;
default:
pr_err("Couldn't find a matching mode %d\n", chip->chg.mode);
@@ -1793,8 +1594,7 @@
goto cleanup;
}
- pr_info("%s probed successfully mode=%d pl_mode = %d\n",
- chip->name, chip->chg.mode, chip->dt.pl_mode);
+ pr_info("SMB138X probed successfully mode=%d\n", chip->chg.mode);
return rc;
cleanup:
diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c
index cf7c35d..deb0ce5 100644
--- a/drivers/regulator/cprh-kbss-regulator.c
+++ b/drivers/regulator/cprh-kbss-regulator.c
@@ -86,7 +86,7 @@
*/
#define CPRH_MSM8998_KBSS_FUSE_COMBO_COUNT 32
#define CPRH_SDM660_KBSS_FUSE_COMBO_COUNT 16
-#define CPRH_SDM845_KBSS_FUSE_COMBO_COUNT 16
+#define CPRH_SDM845_KBSS_FUSE_COMBO_COUNT 24
/*
* Constants which define the name of each fuse corner.
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 0bdcc99..a50e901 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -616,6 +616,15 @@
This enables bare minimum support of power management at platform level.
i.e WFI
+config MSM_QBT1000
+ bool "QBT1000 Ultrasonic Fingerprint Sensor"
+ help
+ This driver provides services for configuring the fingerprint
+ sensor hardware and for communicating with the trusted app which
+ uses it. It enables clocks and provides commands for loading
+ trusted apps, unloading them and marshalling buffers to the
+ trusted fingerprint app.
+
config APSS_CORE_EA
depends on CPU_FREQ && PM_OPP
bool "Qualcomm Technology Inc specific power aware driver"
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 9d175cd..9a7262e 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -65,6 +65,7 @@
obj-y += ramdump.o
endif
obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
+obj-$(CONFIG_MSM_QBT1000) += qbt1000.o
obj-$(CONFIG_WCD_DSP_GLINK) += wcd-dsp-glink.o
obj-$(CONFIG_MSM_EVENT_TIMER) += event_timer.o
obj-$(CONFIG_MSM_IDLE_STATS) += lpm-stats.o
diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c
index 4d2f54d..42f146d 100644
--- a/drivers/soc/qcom/dcc_v2.c
+++ b/drivers/soc/qcom/dcc_v2.c
@@ -74,6 +74,12 @@
#define DCC_RD_MOD_WR_DESCRIPTOR (BIT(31))
#define DCC_LINK_DESCRIPTOR (BIT(31) | BIT(30))
+#define DCC_READ_IND 0x00
+#define DCC_WRITE_IND (BIT(28))
+
+#define DCC_AHB_IND 0x00
+#define DCC_APB_IND BIT(29)
+
#define DCC_MAX_LINK_LIST 5
#define DCC_INVALID_LINK_LIST 0xFF
@@ -92,6 +98,13 @@
DCC_DATA_SINK_ATB
};
+enum dcc_descriptor_type {
+ DCC_ADDR_TYPE,
+ DCC_LOOP_TYPE,
+ DCC_READ_WRITE_TYPE,
+ DCC_WRITE_TYPE
+};
+
static const char * const str_dcc_data_sink[] = {
[DCC_DATA_SINK_SRAM] = "sram",
[DCC_DATA_SINK_ATB] = "atb",
@@ -103,15 +116,16 @@
};
struct dcc_config_entry {
- uint32_t base;
- uint32_t offset;
- uint32_t len;
- uint32_t index;
- uint32_t loop_cnt;
- uint32_t rd_mod_wr;
- uint32_t mask;
- bool rd_wr_entry;
- struct list_head list;
+ uint32_t base;
+ uint32_t offset;
+ uint32_t len;
+ uint32_t index;
+ uint32_t loop_cnt;
+ uint32_t write_val;
+ uint32_t mask;
+ bool apb_bus;
+ enum dcc_descriptor_type desc_type;
+ struct list_head list;
};
struct dcc_drvdata {
@@ -140,6 +154,7 @@
void *sram_buf;
struct msm_dump_data sram_data;
uint8_t curr_list;
+ uint8_t cti_trig;
};
static bool dcc_ready(struct dcc_drvdata *drvdata)
@@ -189,7 +204,7 @@
mutex_lock(&drvdata->mutex);
if (!dcc_ready(drvdata)) {
- dev_err(drvdata->dev, "DCC is not ready!\n");
+ dev_err(drvdata->dev, "DCC is not ready\n");
ret = -EBUSY;
goto err;
}
@@ -224,7 +239,7 @@
uint32_t loop_off = 0;
uint32_t link;
uint32_t pos, total_len = 0, loop_len = 0;
- uint32_t loop, loop_cnt;
+ uint32_t loop, loop_cnt = 0;
bool loop_start = false;
struct dcc_config_entry *entry;
@@ -233,7 +248,9 @@
link = 0;
list_for_each_entry(entry, &drvdata->cfg_head[curr_list], list) {
- if (entry->rd_wr_entry) {
+ switch (entry->desc_type) {
+ case DCC_READ_WRITE_TYPE:
+ {
if (link) {
/* write new offset = 1 to continue
* processing the list
@@ -255,12 +272,14 @@
dcc_sram_writel(drvdata, entry->mask, sram_offset);
sram_offset += 4;
- dcc_sram_writel(drvdata, entry->rd_mod_wr, sram_offset);
+ dcc_sram_writel(drvdata, entry->write_val, sram_offset);
sram_offset += 4;
- continue;
+ addr = 0;
+ break;
}
- if (entry->loop_cnt) {
+ case DCC_LOOP_TYPE:
+ {
/* Check if we need to write link of prev entry */
if (link) {
dcc_sram_writel(drvdata, link, sram_offset);
@@ -292,73 +311,130 @@
prev_off = 0;
prev_addr = addr;
- continue;
+ break;
}
- /* Address type */
- addr = (entry->base >> 4) & BM(0, 27);
- addr |= DCC_ADDR_DESCRIPTOR;
- off = entry->offset/4;
- total_len += entry->len * 4;
-
- if (!prev_addr || prev_addr != addr || prev_off > off) {
- /* Check if we need to write link of prev entry */
+ case DCC_WRITE_TYPE:
+ {
if (link) {
+ /* write new offset = 1 to continue
+ * processing the list
+ */
+ link |= ((0x1 << 8) & BM(8, 14));
dcc_sram_writel(drvdata, link, sram_offset);
sram_offset += 4;
+ /* Reset link and prev_off */
+ addr = 0x00;
+ prev_off = 0;
+ prev_addr = addr;
}
- dev_err(drvdata->dev,
- "DCC: sram address.%d\n", sram_offset);
- /* Write address */
+ off = entry->offset/4;
+ /* write new offset-length pair to correct position */
+ link |= ((off & BM(0, 7)) | BIT(15) |
+ ((entry->len << 8) & BM(8, 14)));
+ link |= DCC_LINK_DESCRIPTOR;
+
+ /* Address type */
+ addr = (entry->base >> 4) & BM(0, 27);
+ if (entry->apb_bus)
+ addr |= DCC_ADDR_DESCRIPTOR | DCC_WRITE_IND
+ | DCC_APB_IND;
+ else
+ addr |= DCC_ADDR_DESCRIPTOR | DCC_WRITE_IND
+ | DCC_AHB_IND;
+
dcc_sram_writel(drvdata, addr, sram_offset);
- sram_offset += 4;
+ sram_offset += 4;
- /* Reset link and prev_off */
- link = 0;
- prev_off = 0;
- }
-
- if ((off - prev_off) > 0xFF || entry->len > MAX_DCC_LEN) {
- dev_err(drvdata->dev,
- "DCC: Progamming error! Base: 0x%x, offset 0x%x.\n",
- entry->base, entry->offset);
- ret = -EINVAL;
- goto err;
- }
-
- if (link) {
- /*
- * link already has one offset-length so new
- * offset-length needs to be placed at bits [29:15]
- */
- pos = 15;
-
- /* Clear bits [31:16] */
- link &= BM(0, 14);
- } else {
- /*
- * link is empty, so new offset-length needs to be
- * placed at bits [15:0]
- */
- pos = 0;
- link = 1 << 15;
- }
-
- /* write new offset-length pair to correct position */
- link |= (((off-prev_off) & BM(0, 7)) |
- ((entry->len << 8) & BM(8, 14))) << pos;
-
- link |= DCC_LINK_DESCRIPTOR;
-
- if (pos) {
dcc_sram_writel(drvdata, link, sram_offset);
- sram_offset += 4;
+ sram_offset += 4;
+
+ dcc_sram_writel(drvdata, entry->write_val, sram_offset);
+ sram_offset += 4;
+ addr = 0x00;
link = 0;
+ break;
}
- prev_off = off;
- prev_addr = addr;
+ default:
+ {
+ /* Address type */
+ addr = (entry->base >> 4) & BM(0, 27);
+ if (entry->apb_bus)
+ addr |= DCC_ADDR_DESCRIPTOR | DCC_READ_IND
+ | DCC_APB_IND;
+ else
+ addr |= DCC_ADDR_DESCRIPTOR | DCC_READ_IND
+ | DCC_AHB_IND;
+
+ off = entry->offset/4;
+ total_len += entry->len * 4;
+
+ if (!prev_addr || prev_addr != addr || prev_off > off) {
+ /* Check if we need to write prev link entry */
+ if (link) {
+ dcc_sram_writel(drvdata,
+ link, sram_offset);
+ sram_offset += 4;
+ }
+ dev_dbg(drvdata->dev,
+ "DCC: sram address 0x%x\n",
+ sram_offset);
+
+ /* Write address */
+ dcc_sram_writel(drvdata, addr, sram_offset);
+ sram_offset += 4;
+
+ /* Reset link and prev_off */
+ link = 0;
+ prev_off = 0;
+ }
+
+ if ((off - prev_off) > 0xFF ||
+ entry->len > MAX_DCC_LEN) {
+ dev_err(drvdata->dev,
+ "DCC: Progamming error Base: 0x%x, offset 0x%x\n",
+ entry->base, entry->offset);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (link) {
+ /*
+ * link already has one offset-length so new
+ * offset-length needs to be placed at
+ * bits [29:15]
+ */
+ pos = 15;
+
+ /* Clear bits [31:16] */
+ link &= BM(0, 14);
+ } else {
+ /*
+ * link is empty, so new offset-length needs
+ * to be placed at bits [15:0]
+ */
+ pos = 0;
+ link = 1 << 15;
+ }
+
+ /* write new offset-length pair to correct position */
+ link |= (((off-prev_off) & BM(0, 7)) |
+ ((entry->len << 8) & BM(8, 14))) << pos;
+
+ link |= DCC_LINK_DESCRIPTOR;
+
+ if (pos) {
+ dcc_sram_writel(drvdata, link, sram_offset);
+ sram_offset += 4;
+ link = 0;
+ }
+
+ prev_off = off;
+ prev_addr = addr;
+ }
+ }
}
if (link) {
@@ -368,7 +444,7 @@
if (loop_start) {
dev_err(drvdata->dev,
- "DCC: Progamming error! Loop unterminated.\n");
+ "DCC: Progamming error: Loop unterminated\n");
ret = -EINVAL;
goto err;
}
@@ -457,7 +533,7 @@
*/
for (i = 0; i < 2; i++) {
if (!dcc_ready(drvdata))
- dev_err(drvdata->dev, "DCC is not ready!\n");
+ dev_err(drvdata->dev, "DCC is not ready\n");
dcc_writel(drvdata, 1,
DCC_LL_SW_TRIGGER(drvdata->curr_list));
@@ -476,13 +552,13 @@
return -EINVAL;
if (drvdata->enable[curr_list]) {
- dev_err(drvdata->dev, "DCC is already enabled!\n");
+ dev_err(drvdata->dev, "DCC is already enabled\n");
return -EINVAL;
}
lock_reg = dcc_readl(drvdata, DCC_LL_LOCK(curr_list));
if (lock_reg & 0x1) {
- dev_err(drvdata->dev, "DCC is already enabled!\n");
+ dev_err(drvdata->dev, "DCC is already enabled\n");
return -EINVAL;
}
@@ -525,8 +601,9 @@
dcc_writel(drvdata, 0, DCC_LL_TIMEOUT(list));
}
- /* 4. Configure data sink and function type */
- dcc_writel(drvdata, ((drvdata->data_sink << 4) |
+ /* 4. Configure trigger, data sink and function type */
+ dcc_writel(drvdata, BIT(9) | ((drvdata->cti_trig << 8) |
+ (drvdata->data_sink << 4) |
(drvdata->func_type[list])), DCC_LL_CFG(list));
/* 5. Clears interrupt status register */
@@ -565,7 +642,7 @@
mutex_lock(&drvdata->mutex);
if (!dcc_ready(drvdata))
- dev_err(drvdata->dev, "DCC is not ready! Disabling DCC...\n");
+ dev_err(drvdata->dev, "DCC is not ready Disabling DCC...\n");
for (curr_list = 0; curr_list < DCC_MAX_LINK_LIST; curr_list++) {
if (!drvdata->enable[curr_list])
@@ -600,7 +677,7 @@
mutex_lock(&drvdata->mutex);
lock_reg = dcc_readl(drvdata, DCC_LL_LOCK(val));
if (lock_reg & 0x1) {
- dev_err(drvdata->dev, "DCC linked list is already configured!\n");
+ dev_err(drvdata->dev, "DCC linked list is already configured\n");
mutex_unlock(&drvdata->mutex);
return -EINVAL;
}
@@ -783,25 +860,36 @@
mutex_lock(&drvdata->mutex);
list_for_each_entry(entry,
&drvdata->cfg_head[drvdata->curr_list], list) {
- if (entry->rd_wr_entry)
+ switch (entry->desc_type) {
+ case DCC_READ_WRITE_TYPE:
len = snprintf(local_buf, 64,
"Index: 0x%x, mask: 0x%x, val: 0x%x\n",
entry->index, entry->mask,
- entry->rd_mod_wr);
- else if (entry->loop_cnt)
+ entry->write_val);
+ break;
+ case DCC_LOOP_TYPE:
len = snprintf(local_buf, 64, "Index: 0x%x, Loop: %d\n",
entry->index, entry->loop_cnt);
- else
- len = snprintf(local_buf, 64,
- "Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x\n",
- entry->index, entry->base,
- entry->offset, entry->len);
-
- if ((count + len) > PAGE_SIZE) {
- dev_err(dev, "DCC: Couldn't write complete config!\n");
break;
+ case DCC_WRITE_TYPE:
+ len = snprintf(local_buf, 64,
+ "Write Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x APB: %d\n",
+ entry->index, entry->base,
+ entry->offset, entry->len,
+ entry->apb_bus);
+ break;
+ default:
+ len = snprintf(local_buf, 64,
+ "Read Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x APB: %d\n",
+ entry->index, entry->base,
+ entry->offset, entry->len,
+ entry->apb_bus);
}
+ if ((count + len) > PAGE_SIZE) {
+ dev_err(dev, "DCC: Couldn't write complete config\n");
+ break;
+ }
strlcat(buf, local_buf, PAGE_SIZE);
count += len;
}
@@ -812,7 +900,7 @@
}
static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr,
- unsigned int len)
+ unsigned int len, int apb_bus)
{
int ret;
struct dcc_config_entry *entry, *pentry;
@@ -821,7 +909,7 @@
mutex_lock(&drvdata->mutex);
if (!len) {
- dev_err(drvdata->dev, "DCC: Invalid length!\n");
+ dev_err(drvdata->dev, "DCC: Invalid length\n");
ret = -EINVAL;
goto err;
}
@@ -883,6 +971,8 @@
entry->offset = offset;
entry->len = min_t(uint32_t, len, MAX_DCC_LEN);
entry->index = drvdata->nr_config[drvdata->curr_list]++;
+ entry->desc_type = DCC_ADDR_TYPE;
+ entry->apb_bus = apb_bus;
INIT_LIST_HEAD(&entry->list);
list_add_tail(&entry->list,
&drvdata->cfg_head[drvdata->curr_list]);
@@ -902,24 +992,30 @@
struct device_attribute *attr,
const char *buf, size_t size)
{
- int ret, len;
+ int ret, len, apb_bus;
unsigned int base;
struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
int nval;
- nval = sscanf(buf, "%x %i", &base, &len);
- if (nval <= 0 || nval > 2)
+ nval = sscanf(buf, "%x %i %d", &base, &len, &apb_bus);
+ if (nval <= 0 || nval > 3)
return -EINVAL;
- if (nval == 1)
- len = 1;
-
if (drvdata->curr_list >= DCC_MAX_LINK_LIST) {
dev_err(dev, "Select link list to program using curr_list\n");
return -EINVAL;
}
- ret = dcc_config_add(drvdata, base, len);
+ if (nval == 1) {
+ len = 1;
+ apb_bus = 0;
+ } else if (nval == 2) {
+ apb_bus = 0;
+ } else {
+ apb_bus = 1;
+ }
+
+ ret = dcc_config_add(drvdata, base, len, apb_bus);
if (ret)
return ret;
@@ -1087,7 +1183,7 @@
}
if (list_empty(&drvdata->cfg_head[drvdata->curr_list])) {
- dev_err(drvdata->dev, "DCC: No read address programmed!\n");
+ dev_err(drvdata->dev, "DCC: No read address programmed\n");
ret = -EPERM;
goto err;
}
@@ -1098,9 +1194,9 @@
goto err;
}
- entry->rd_wr_entry = true;
+ entry->desc_type = DCC_READ_WRITE_TYPE;
entry->mask = mask;
- entry->rd_mod_wr = val;
+ entry->write_val = val;
entry->index = drvdata->nr_config[drvdata->curr_list]++;
INIT_LIST_HEAD(&entry->list);
list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]);
@@ -1110,6 +1206,91 @@
}
static DEVICE_ATTR(rd_mod_wr, 0200, NULL, dcc_rd_mod_wr);
+static ssize_t dcc_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret = size;
+ int nval;
+ unsigned int addr, write_val;
+ int apb_bus;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+ struct dcc_config_entry *entry;
+
+ mutex_lock(&drvdata->mutex);
+
+ nval = sscanf(buf, "%x %x %d", &addr, &write_val, &apb_bus);
+
+ if (drvdata->curr_list >= DCC_MAX_LINK_LIST) {
+ dev_err(dev, "Select link list to program using curr_list\n");
+ return -EINVAL;
+ }
+
+ if (nval <= 1 || nval > 3) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (nval == 3)
+ entry->apb_bus = true;
+
+ entry->desc_type = DCC_WRITE_TYPE;
+ entry->base = addr & BM(4, 31);
+ entry->offset = addr - entry->base;
+ entry->write_val = write_val;
+ entry->index = drvdata->nr_config[drvdata->curr_list]++;
+ entry->len = 1;
+ INIT_LIST_HEAD(&entry->list);
+ list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]);
+err:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+static DEVICE_ATTR(config_write, 0200, NULL, dcc_write);
+
+static ssize_t dcc_show_cti_trig(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", drvdata->cti_trig);
+}
+
+static ssize_t dcc_store_cti_trig(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned long val;
+ int ret = 0;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+ if (kstrtoul(buf, 16, &val))
+ return -EINVAL;
+
+ mutex_lock(&drvdata->mutex);
+
+ if (drvdata->enable[drvdata->curr_list]) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (val)
+ drvdata->cti_trig = 1;
+ else
+ drvdata->cti_trig = 0;
+out:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+static DEVICE_ATTR(cti_trig, 0644,
+ dcc_show_cti_trig, dcc_store_cti_trig);
+
static const struct device_attribute *dcc_attrs[] = {
&dev_attr_func_type,
&dev_attr_data_sink,
@@ -1123,6 +1304,8 @@
&dev_attr_loop,
&dev_attr_rd_mod_wr,
&dev_attr_curr_list,
+ &dev_attr_config_write,
+ &dev_attr_cti_trig,
NULL,
};
@@ -1134,7 +1317,7 @@
for (i = 0; attrs[i] != NULL; i++) {
ret = device_create_file(dev, attrs[i]);
if (ret) {
- dev_err(dev, "DCC: Couldn't create sysfs attribute: %s!\n",
+ dev_err(dev, "DCC: Couldn't create sysfs attribute: %s\n",
attrs[i]->attr.name);
break;
}
@@ -1173,7 +1356,7 @@
if (copy_to_user(data, buf, len)) {
dev_err(drvdata->dev,
- "DCC: Couldn't copy all data to user!\n");
+ "DCC: Couldn't copy all data to user\n");
kfree(buf);
return -EFAULT;
}
@@ -1372,7 +1555,7 @@
}
if (i == ARRAY_SIZE(str_dcc_data_sink)) {
- dev_err(dev, "Unknown sink type for DCC! Using '%s' as data sink\n",
+ dev_err(dev, "Unknown sink type for DCC Using '%s' as data sink\n",
str_dcc_data_sink[drvdata->data_sink]);
}
}
diff --git a/drivers/soc/qcom/memory_dump_v2.c b/drivers/soc/qcom/memory_dump_v2.c
index b9ce417..5ed66bf 100644
--- a/drivers/soc/qcom/memory_dump_v2.c
+++ b/drivers/soc/qcom/memory_dump_v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,9 @@
#include <linux/of_address.h>
#include <soc/qcom/memory_dump.h>
#include <soc/qcom/scm.h>
+#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
#define MSM_DUMP_TABLE_VERSION MSM_DUMP_MAKE_VERSION(2, 0)
@@ -195,3 +198,84 @@
}
early_initcall(init_debug_lar_unlock);
#endif
+
+static int mem_dump_probe(struct platform_device *pdev)
+{
+ struct device_node *child_node;
+ const struct device_node *node = pdev->dev.of_node;
+ static dma_addr_t dump_addr;
+ static void *dump_vaddr;
+ struct msm_dump_data *dump_data;
+ struct msm_dump_entry dump_entry;
+ int ret;
+ u32 size, id;
+
+ for_each_available_child_of_node(node, child_node) {
+ ret = of_property_read_u32(child_node, "qcom,dump-size", &size);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to find size for %s\n",
+ child_node->name);
+ continue;
+ }
+
+ ret = of_property_read_u32(child_node, "qcom,dump-id", &id);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to find id for %s\n",
+ child_node->name);
+ continue;
+ }
+
+ dump_vaddr = (void *) dma_alloc_coherent(&pdev->dev, size,
+ &dump_addr, GFP_KERNEL);
+
+ if (!dump_vaddr) {
+ dev_err(&pdev->dev, "Couldn't get memory for dumping\n");
+ continue;
+ }
+
+ memset(dump_vaddr, 0x0, size);
+
+ dump_data = devm_kzalloc(&pdev->dev,
+ sizeof(struct msm_dump_data), GFP_KERNEL);
+ if (!dump_data) {
+ dma_free_coherent(&pdev->dev, size, dump_vaddr,
+ dump_addr);
+ continue;
+ }
+
+ dump_data->addr = dump_addr;
+ dump_data->len = size;
+ dump_entry.id = id;
+ dump_entry.addr = virt_to_phys(dump_data);
+ ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+ if (ret) {
+ dev_err(&pdev->dev, "Data dump setup failed, id = %d\n",
+ id);
+ dma_free_coherent(&pdev->dev, size, dump_vaddr,
+ dump_addr);
+ devm_kfree(&pdev->dev, dump_data);
+ }
+ }
+ return 0;
+}
+
+static const struct of_device_id mem_dump_match_table[] = {
+ {.compatible = "qcom,mem-dump",},
+ {}
+};
+
+static struct platform_driver mem_dump_driver = {
+ .probe = mem_dump_probe,
+ .driver = {
+ .name = "msm_mem_dump",
+ .owner = THIS_MODULE,
+ .of_match_table = mem_dump_match_table,
+ },
+};
+
+static int __init mem_dump_init(void)
+{
+ return platform_driver_register(&mem_dump_driver);
+}
+
+pure_initcall(mem_dump_init);
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index 11e1b4d..1f28712 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -464,6 +464,8 @@
if (region == NULL) {
pil_err(priv->desc, "Failed to allocate relocatable region of size %zx\n",
size);
+ priv->region_start = 0;
+ priv->region_end = 0;
return -ENOMEM;
}
diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c
new file mode 100644
index 0000000..67a5e05
--- /dev/null
+++ b/drivers/soc/qcom/qbt1000.c
@@ -0,0 +1,1207 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#define DEBUG
+#define pr_fmt(fmt) "qbt1000:%s: " fmt, __func__
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/mutex.h>
+#include <linux/atomic.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/input.h>
+#include <linux/kfifo.h>
+#include <linux/poll.h>
+#include <uapi/linux/qbt1000.h>
+#include <soc/qcom/scm.h>
+#include "../../misc/qseecom_kernel.h"
+
+#define QBT1000_DEV "qbt1000"
+#define QBT1000_IN_DEV_NAME "qbt1000_key_input"
+#define QBT1000_IN_DEV_VERSION 0x0100
+#define MAX_FW_EVENTS 128
+#define FP_APP_CMD_RX_IPC 132
+#define FW_MAX_IPC_MSG_DATA_SIZE 0x500
+#define IPC_MSG_ID_CBGE_REQUIRED 29
+
+/*
+ * shared buffer size - init with max value,
+ * user space will provide new value upon tz app load
+ */
+static uint32_t g_app_buf_size = SZ_256K;
+static char const *const FP_APP_NAME = "fingerpr";
+
+struct finger_detect_gpio {
+ int gpio;
+ int active_low;
+ int irq;
+ struct work_struct work;
+ unsigned int key_code;
+ int power_key_enabled;
+ int last_gpio_state;
+ int event_reported;
+};
+
+struct fw_event_desc {
+ enum qbt1000_fw_event ev;
+};
+
+struct fw_ipc_info {
+ int gpio;
+ int irq;
+};
+
+struct qbt1000_drvdata {
+ struct class *qbt1000_class;
+ struct cdev qbt1000_cdev;
+ struct device *dev;
+ char *qbt1000_node;
+ struct clk **clocks;
+ unsigned int clock_count;
+ uint8_t clock_state;
+ unsigned int root_clk_idx;
+ unsigned int frequency;
+ atomic_t available;
+ struct mutex mutex;
+ struct mutex fw_events_mutex;
+ struct input_dev *in_dev;
+ struct fw_ipc_info fw_ipc;
+ struct finger_detect_gpio fd_gpio;
+ DECLARE_KFIFO(fw_events, struct fw_event_desc, MAX_FW_EVENTS);
+ wait_queue_head_t read_wait_queue;
+ struct qseecom_handle *app_handle;
+ struct qseecom_handle *fp_app_handle;
+};
+
+/*
+ * struct fw_ipc_cmd -
+ * used to store IPC commands to/from firmware
+ * @status - indicates whether sending/getting the IPC message was successful
+ * @msg_type - the type of IPC message
+ * @msg_len - the length of the message data
+ * @resp_needed - whether a response is needed for this message
+ * @msg_data - any extra data associated with the message
+ */
+struct fw_ipc_cmd {
+ uint32_t status;
+ uint32_t numMsgs;
+ uint8_t msg_data[FW_MAX_IPC_MSG_DATA_SIZE];
+};
+
+struct fw_ipc_header {
+ uint32_t msg_type;
+ uint32_t msg_len;
+ uint32_t resp_needed;
+};
+
+/*
+ * struct ipc_msg_type_to_fw_event -
+ * entry in mapping between an IPC message type to a firmware event
+ * @msg_type - IPC message type, as reported by firmware
+ * @fw_event - corresponding firmware event code to report to driver client
+ */
+struct ipc_msg_type_to_fw_event {
+ uint32_t msg_type;
+ enum qbt1000_fw_event fw_event;
+};
+
+/* mapping between firmware IPC message types to HLOS firmware events */
+struct ipc_msg_type_to_fw_event g_msg_to_event[] = {
+ {IPC_MSG_ID_CBGE_REQUIRED, FW_EVENT_CBGE_REQUIRED}
+};
+
+/**
+ * get_cmd_rsp_buffers() - Function sets cmd & rsp buffer pointers and
+ * aligns buffer lengths
+ * @hdl: index of qseecom_handle
+ * @cmd: req buffer - set to qseecom_handle.sbuf
+ * @cmd_len: ptr to req buffer len
+ * @rsp: rsp buffer - set to qseecom_handle.sbuf + offset
+ * @rsp_len: ptr to rsp buffer len
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static int get_cmd_rsp_buffers(struct qseecom_handle *hdl,
+ void **cmd,
+ uint32_t *cmd_len,
+ void **rsp,
+ uint32_t *rsp_len)
+{
+ /* 64 bytes alignment for QSEECOM */
+ *cmd_len = ALIGN(*cmd_len, 64);
+ *rsp_len = ALIGN(*rsp_len, 64);
+
+ if (((uint64_t)*rsp_len + (uint64_t)*cmd_len)
+ > (uint64_t)g_app_buf_size) {
+ pr_err("buffer too small to hold cmd=%d and rsp=%d\n",
+ *cmd_len, *rsp_len);
+ return -ENOMEM;
+ }
+
+ *cmd = hdl->sbuf;
+ *rsp = hdl->sbuf + *cmd_len;
+ return 0;
+}
+
+/**
+ * send_tz_cmd() - Function sends a command to TZ
+ *
+ * @drvdata: pointer to driver data
+ * @app_handle: handle to tz app
+ * @is_user_space: 1 if the cmd buffer is in user space, 0
+ * otherwise
+ * @cmd: command buffer to send
+ * @cmd_len: length of the command buffer
+ * @rsp: output, will be set to location of response buffer
+ * @rsp_len: max size of response
+ *
+ * Return: 0 on success.
+ */
+static int send_tz_cmd(struct qbt1000_drvdata *drvdata,
+ struct qseecom_handle *app_handle,
+ int is_user_space,
+ void *cmd, uint32_t cmd_len,
+ void **rsp, uint32_t rsp_len)
+{
+ int rc = 0;
+ void *aligned_cmd;
+ void *aligned_rsp;
+ uint32_t aligned_cmd_len;
+ uint32_t aligned_rsp_len;
+
+ /* init command and response buffers and align lengths */
+ aligned_cmd_len = cmd_len;
+ aligned_rsp_len = rsp_len;
+
+ rc = get_cmd_rsp_buffers(app_handle,
+ (void **)&aligned_cmd,
+ &aligned_cmd_len,
+ (void **)&aligned_rsp,
+ &aligned_rsp_len);
+
+ if (rc != 0)
+ goto end;
+
+ if (!aligned_cmd) {
+ dev_err(drvdata->dev, "%s: Null command buffer\n",
+ __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (aligned_cmd - cmd + cmd_len > g_app_buf_size) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ if (is_user_space) {
+ rc = copy_from_user(aligned_cmd, (void __user *)cmd,
+ cmd_len);
+ if (rc != 0) {
+ pr_err("failure to copy user space buf %d\n", rc);
+ rc = -EFAULT;
+ goto end;
+ }
+ } else
+ memcpy(aligned_cmd, cmd, cmd_len);
+
+ /* send cmd to TZ */
+ rc = qseecom_send_command(app_handle,
+ aligned_cmd,
+ aligned_cmd_len,
+ aligned_rsp,
+ aligned_rsp_len);
+
+ if (rc != 0) {
+ pr_err("failure to send tz cmd %d\n", rc);
+ goto end;
+ }
+
+ *rsp = aligned_rsp;
+
+end:
+ return rc;
+}
+
+/**
+ * qbt1000_open() - Function called when user space opens device.
+ * Successful if driver not currently open.
+ * @inode: ptr to inode object
+ * @file: ptr to file object
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static int qbt1000_open(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+
+ struct qbt1000_drvdata *drvdata = container_of(inode->i_cdev,
+ struct qbt1000_drvdata,
+ qbt1000_cdev);
+ file->private_data = drvdata;
+
+ pr_debug("qbt1000_open begin\n");
+ /* disallowing concurrent opens */
+ if (!atomic_dec_and_test(&drvdata->available)) {
+ atomic_inc(&drvdata->available);
+ rc = -EBUSY;
+ }
+
+ pr_debug("qbt1000_open end : %d\n", rc);
+ return rc;
+}
+
+/**
+ * qbt1000_release() - Function called when user space closes device.
+
+ * @inode: ptr to inode object
+ * @file: ptr to file object
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static int qbt1000_release(struct inode *inode, struct file *file)
+{
+ struct qbt1000_drvdata *drvdata;
+
+ if (!file || !file->private_data) {
+ pr_err("qbt1000_release: NULL pointer passed");
+ return -EINVAL;
+ }
+ drvdata = file->private_data;
+ atomic_inc(&drvdata->available);
+ return 0;
+}
+
+/**
+ * qbt1000_ioctl() - Function called when user space calls ioctl.
+ * @file: struct file - not used
+ * @cmd: cmd identifier:QBT1000_LOAD_APP,QBT1000_UNLOAD_APP,
+ * QBT1000_SEND_TZCMD
+ * @arg: ptr to relevant structe: either qbt1000_app or
+ * qbt1000_send_tz_cmd depending on which cmd is passed
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static long qbt1000_ioctl(
+ struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+ void __user *priv_arg = (void __user *)arg;
+ struct qbt1000_drvdata *drvdata;
+
+ if (!file || !file->private_data) {
+ pr_err("qbt1000_ioctl: NULL pointer passed");
+ return -EINVAL;
+ }
+
+ drvdata = file->private_data;
+
+ mutex_lock(&drvdata->mutex);
+
+ pr_debug("qbt1000_ioctl %d\n", cmd);
+
+ switch (cmd) {
+ case QBT1000_LOAD_APP:
+ {
+ struct qbt1000_app app;
+ struct qseecom_handle *app_handle;
+
+ if (copy_from_user(&app, priv_arg,
+ sizeof(app)) != 0) {
+ rc = -EFAULT;
+ pr_err("failed copy from user space-LOAD\n");
+ goto end;
+ }
+
+ if (!app.app_handle) {
+ dev_err(drvdata->dev, "%s: LOAD app_handle is null\n",
+ __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (drvdata->app_handle) {
+ dev_err(drvdata->dev, "%s: LOAD app already loaded, unloading first\n",
+ __func__);
+ drvdata->fp_app_handle = 0;
+ rc = qseecom_shutdown_app(&drvdata->app_handle);
+ if (rc != 0) {
+ dev_err(drvdata->dev, "%s: LOAD current app failed to shutdown\n",
+ __func__);
+ goto end;
+ }
+ }
+
+ pr_debug("app %s load before\n", app.name);
+
+ /* start the TZ app */
+ rc = qseecom_start_app(
+ &drvdata->app_handle, app.name, app.size);
+ if (rc == 0) {
+ g_app_buf_size = app.size;
+ rc = qseecom_set_bandwidth(drvdata->app_handle,
+ app.high_band_width == 1 ? true : false);
+ if (rc != 0) {
+ /* log error, allow to continue */
+ pr_err("App %s failed to set bw\n", app.name);
+ }
+ } else {
+ pr_err("app %s failed to load\n", app.name);
+ goto end;
+ }
+
+ /* copy a fake app handle to user */
+ app_handle = drvdata->app_handle ?
+ (struct qseecom_handle *)123456 : 0;
+ rc = copy_to_user((void __user *)app.app_handle, &app_handle,
+ sizeof(*app.app_handle));
+
+ if (rc != 0) {
+ dev_err(drvdata->dev,
+ "%s: Failed copy 2us LOAD rc:%d\n",
+ __func__, rc);
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ pr_debug("app %s load after\n", app.name);
+
+ if (!strcmp(app.name, FP_APP_NAME))
+ drvdata->fp_app_handle = drvdata->app_handle;
+
+ break;
+ }
+ case QBT1000_UNLOAD_APP:
+ {
+ struct qbt1000_app app;
+ struct qseecom_handle *app_handle = 0;
+
+ if (copy_from_user(&app, priv_arg,
+ sizeof(app)) != 0) {
+ rc = -ENOMEM;
+ pr_err("failed copy from user space-UNLOAD\n");
+ goto end;
+ }
+
+ if (!app.app_handle) {
+ dev_err(drvdata->dev, "%s: UNLOAD app_handle is null\n",
+ __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ rc = copy_from_user(&app_handle, app.app_handle,
+ sizeof(app_handle));
+
+ if (rc != 0) {
+ dev_err(drvdata->dev,
+ "%s: Failed copy from user space-UNLOAD handle rc:%d\n",
+ __func__, rc);
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ /* if the app hasn't been loaded already, return err */
+ if (!drvdata->app_handle) {
+ pr_err("app not loaded\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (drvdata->fp_app_handle == drvdata->app_handle)
+ drvdata->fp_app_handle = 0;
+
+ /* set bw & shutdown the TZ app */
+ qseecom_set_bandwidth(drvdata->app_handle,
+ app.high_band_width == 1 ? true : false);
+ rc = qseecom_shutdown_app(&drvdata->app_handle);
+ if (rc != 0) {
+ pr_err("app failed to shutdown\n");
+ goto end;
+ }
+
+ /* copy the app handle (should be null) to user */
+ rc = copy_to_user((void __user *)app.app_handle, &app_handle,
+ sizeof(*app.app_handle));
+
+ if (rc != 0) {
+ dev_err(drvdata->dev,
+ "%s: Failed copy 2us UNLOAD rc:%d\n",
+ __func__, rc);
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ break;
+ }
+ case QBT1000_SEND_TZCMD:
+ {
+ struct qbt1000_send_tz_cmd tzcmd;
+ void *rsp_buf;
+
+ if (copy_from_user(&tzcmd, priv_arg,
+ sizeof(tzcmd))
+ != 0) {
+ rc = -EFAULT;
+ pr_err("failed copy from user space %d\n", rc);
+ goto end;
+ }
+
+ if (tzcmd.req_buf_len > g_app_buf_size ||
+ tzcmd.rsp_buf_len > g_app_buf_size) {
+ rc = -ENOMEM;
+ pr_err("invalid cmd buf len, req=%d, rsp=%d\n",
+ tzcmd.req_buf_len, tzcmd.rsp_buf_len);
+ goto end;
+ }
+
+ /* if the app hasn't been loaded already, return err */
+ if (!drvdata->app_handle) {
+ pr_err("app not loaded\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ rc = send_tz_cmd(drvdata,
+ drvdata->app_handle, 1,
+ tzcmd.req_buf, tzcmd.req_buf_len,
+ &rsp_buf, tzcmd.rsp_buf_len);
+
+ if (rc < 0) {
+ pr_err("failure sending command to tz\n");
+ goto end;
+ }
+
+ /* copy rsp buf back to user space buffer */
+ rc = copy_to_user((void __user *)tzcmd.rsp_buf,
+ rsp_buf, tzcmd.rsp_buf_len);
+ if (rc != 0) {
+ pr_err("failed copy 2us rc:%d bytes %d:\n",
+ rc, tzcmd.rsp_buf_len);
+ rc = -EFAULT;
+ goto end;
+ }
+
+ break;
+ }
+ case QBT1000_SET_FINGER_DETECT_KEY:
+ {
+ struct qbt1000_set_finger_detect_key set_fd_key;
+
+ if (copy_from_user(&set_fd_key, priv_arg,
+ sizeof(set_fd_key))
+ != 0) {
+ rc = -EFAULT;
+ pr_err("failed copy from user space %d\n", rc);
+ goto end;
+ }
+
+ drvdata->fd_gpio.key_code = set_fd_key.key_code;
+
+ break;
+ }
+ case QBT1000_CONFIGURE_POWER_KEY:
+ {
+ struct qbt1000_configure_power_key power_key;
+
+ if (copy_from_user(&power_key, priv_arg,
+ sizeof(power_key))
+ != 0) {
+ rc = -EFAULT;
+ pr_err("failed copy from user space %d\n", rc);
+ goto end;
+ }
+
+ drvdata->fd_gpio.power_key_enabled = power_key.enable;
+
+ break;
+ }
+ default:
+ pr_err("invalid cmd %d\n", cmd);
+ rc = -ENOIOCTLCMD;
+ goto end;
+ }
+
+end:
+ mutex_unlock(&drvdata->mutex);
+ return rc;
+}
+
+static int get_events_fifo_len_locked(struct qbt1000_drvdata *drvdata)
+{
+ int len;
+
+ mutex_lock(&drvdata->fw_events_mutex);
+ len = kfifo_len(&drvdata->fw_events);
+ mutex_unlock(&drvdata->fw_events_mutex);
+
+ return len;
+}
+
+static ssize_t qbt1000_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct fw_event_desc fw_event;
+ struct qbt1000_drvdata *drvdata = filp->private_data;
+
+ if (cnt < sizeof(fw_event.ev))
+ return -EINVAL;
+
+ mutex_lock(&drvdata->fw_events_mutex);
+
+ while (kfifo_len(&drvdata->fw_events) == 0) {
+ mutex_unlock(&drvdata->fw_events_mutex);
+
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ pr_debug("fw_events fifo: empty, waiting\n");
+
+ if (wait_event_interruptible(drvdata->read_wait_queue,
+ (get_events_fifo_len_locked(drvdata) > 0)))
+ return -ERESTARTSYS;
+
+ mutex_lock(&drvdata->fw_events_mutex);
+ }
+
+ if (!kfifo_get(&drvdata->fw_events, &fw_event)) {
+ pr_debug("fw_events fifo: unexpectedly empty\n");
+
+ mutex_unlock(&drvdata->fw_events_mutex);
+ return -EINVAL;
+ }
+
+ mutex_unlock(&drvdata->fw_events_mutex);
+
+ pr_debug("fw_event: %d\n", (int)fw_event.ev);
+ return copy_to_user(ubuf, &fw_event.ev, sizeof(fw_event.ev));
+}
+
+static unsigned int qbt1000_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ struct qbt1000_drvdata *drvdata = filp->private_data;
+ unsigned int mask = 0;
+
+ poll_wait(filp, &drvdata->read_wait_queue, wait);
+
+ if (kfifo_len(&drvdata->fw_events) > 0)
+ mask |= (POLLIN | POLLRDNORM);
+
+ return mask;
+}
+
+static const struct file_operations qbt1000_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = qbt1000_ioctl,
+ .open = qbt1000_open,
+ .release = qbt1000_release,
+ .read = qbt1000_read,
+ .poll = qbt1000_poll
+};
+
+static int qbt1000_dev_register(struct qbt1000_drvdata *drvdata)
+{
+ dev_t dev_no;
+ int ret = 0;
+ size_t node_size;
+ char *node_name = QBT1000_DEV;
+ struct device *dev = drvdata->dev;
+ struct device *device;
+
+ node_size = strlen(node_name) + 1;
+
+ drvdata->qbt1000_node = devm_kzalloc(dev, node_size, GFP_KERNEL);
+ if (!drvdata->qbt1000_node) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ strlcpy(drvdata->qbt1000_node, node_name, node_size);
+
+ ret = alloc_chrdev_region(&dev_no, 0, 1, drvdata->qbt1000_node);
+ if (ret) {
+ pr_err("alloc_chrdev_region failed %d\n", ret);
+ goto err_alloc;
+ }
+
+ cdev_init(&drvdata->qbt1000_cdev, &qbt1000_fops);
+
+ drvdata->qbt1000_cdev.owner = THIS_MODULE;
+ ret = cdev_add(&drvdata->qbt1000_cdev, dev_no, 1);
+ if (ret) {
+ pr_err("cdev_add failed %d\n", ret);
+ goto err_cdev_add;
+ }
+
+ drvdata->qbt1000_class = class_create(THIS_MODULE,
+ drvdata->qbt1000_node);
+ if (IS_ERR(drvdata->qbt1000_class)) {
+ ret = PTR_ERR(drvdata->qbt1000_class);
+ pr_err("class_create failed %d\n", ret);
+ goto err_class_create;
+ }
+
+ device = device_create(drvdata->qbt1000_class, NULL,
+ drvdata->qbt1000_cdev.dev, drvdata,
+ drvdata->qbt1000_node);
+ if (IS_ERR(device)) {
+ ret = PTR_ERR(device);
+ pr_err("device_create failed %d\n", ret);
+ goto err_dev_create;
+ }
+
+ return 0;
+err_dev_create:
+ class_destroy(drvdata->qbt1000_class);
+err_class_create:
+ cdev_del(&drvdata->qbt1000_cdev);
+err_cdev_add:
+ unregister_chrdev_region(drvdata->qbt1000_cdev.dev, 1);
+err_alloc:
+ return ret;
+}
+
+/**
+ * qbt1000_create_input_device() - Function allocates an input
+ * device, configures it for key events and registers it
+ *
+ * @drvdata: ptr to driver data
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static int qbt1000_create_input_device(struct qbt1000_drvdata *drvdata)
+{
+ int rc = 0;
+
+ drvdata->in_dev = input_allocate_device();
+ if (drvdata->in_dev == NULL) {
+ dev_err(drvdata->dev, "%s: input_allocate_device() failed\n",
+ __func__);
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ drvdata->in_dev->name = QBT1000_IN_DEV_NAME;
+ drvdata->in_dev->phys = NULL;
+ drvdata->in_dev->id.bustype = BUS_HOST;
+ drvdata->in_dev->id.vendor = 0x0001;
+ drvdata->in_dev->id.product = 0x0001;
+ drvdata->in_dev->id.version = QBT1000_IN_DEV_VERSION;
+
+ drvdata->in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ drvdata->in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ drvdata->in_dev->keybit[BIT_WORD(KEY_HOMEPAGE)] |=
+ BIT_MASK(KEY_HOMEPAGE);
+ drvdata->in_dev->keybit[BIT_WORD(KEY_CAMERA)] |=
+ BIT_MASK(KEY_CAMERA);
+ drvdata->in_dev->keybit[BIT_WORD(KEY_VOLUMEDOWN)] |=
+ BIT_MASK(KEY_VOLUMEDOWN);
+ drvdata->in_dev->keybit[BIT_WORD(KEY_POWER)] |=
+ BIT_MASK(KEY_POWER);
+
+ input_set_abs_params(drvdata->in_dev, ABS_X,
+ 0,
+ 1000,
+ 0, 0);
+ input_set_abs_params(drvdata->in_dev, ABS_Y,
+ 0,
+ 1000,
+ 0, 0);
+
+ rc = input_register_device(drvdata->in_dev);
+ if (rc) {
+ dev_err(drvdata->dev, "%s: input_reg_dev() failed %d\n",
+ __func__, rc);
+ goto end;
+ }
+
+end:
+ if (rc)
+ input_free_device(drvdata->in_dev);
+ return rc;
+}
+
+static void purge_finger_events(struct qbt1000_drvdata *drvdata)
+{
+ int i, fifo_len;
+ struct fw_event_desc fw_event;
+
+ fifo_len = kfifo_len(&drvdata->fw_events);
+
+ for (i = 0; i < fifo_len; i++) {
+ if (!kfifo_get(&drvdata->fw_events, &fw_event))
+ pr_err("fw events fifo: could not remove oldest item\n");
+ else if (fw_event.ev != FW_EVENT_FINGER_DOWN
+ && fw_event.ev != FW_EVENT_FINGER_UP)
+ kfifo_put(&drvdata->fw_events, fw_event);
+ }
+}
+
+static void qbt1000_gpio_report_event(struct qbt1000_drvdata *drvdata)
+{
+ int state;
+ struct fw_event_desc fw_event;
+
+ state = (__gpio_get_value(drvdata->fd_gpio.gpio) ? 1 : 0)
+ ^ drvdata->fd_gpio.active_low;
+
+ if (drvdata->fd_gpio.event_reported
+ && state == drvdata->fd_gpio.last_gpio_state)
+ return;
+
+ pr_debug("gpio %d: report state %d\n", drvdata->fd_gpio.gpio, state);
+
+ drvdata->fd_gpio.event_reported = 1;
+ drvdata->fd_gpio.last_gpio_state = state;
+
+ if (drvdata->fd_gpio.key_code) {
+ input_event(drvdata->in_dev, EV_KEY,
+ drvdata->fd_gpio.key_code, !!state);
+ input_sync(drvdata->in_dev);
+ }
+
+ if (state && drvdata->fd_gpio.power_key_enabled) {
+ input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 1);
+ input_sync(drvdata->in_dev);
+ input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 0);
+ input_sync(drvdata->in_dev);
+ }
+
+ fw_event.ev = (state ? FW_EVENT_FINGER_DOWN : FW_EVENT_FINGER_UP);
+
+ mutex_lock(&drvdata->fw_events_mutex);
+
+ if (kfifo_is_full(&drvdata->fw_events)) {
+ struct fw_event_desc dummy_fw_event;
+
+ pr_warn("fw events fifo: full, dropping oldest item\n");
+ if (!kfifo_get(&drvdata->fw_events, &dummy_fw_event))
+ pr_err("fw events fifo: could not remove oldest item\n");
+ }
+
+ purge_finger_events(drvdata);
+
+ if (!kfifo_put(&drvdata->fw_events, fw_event))
+ pr_err("fw events fifo: error adding item\n");
+
+ mutex_unlock(&drvdata->fw_events_mutex);
+ wake_up_interruptible(&drvdata->read_wait_queue);
+}
+
+static void qbt1000_gpio_work_func(struct work_struct *work)
+{
+ struct qbt1000_drvdata *drvdata =
+ container_of(work, struct qbt1000_drvdata, fd_gpio.work);
+
+ qbt1000_gpio_report_event(drvdata);
+
+ pm_relax(drvdata->dev);
+}
+
+static irqreturn_t qbt1000_gpio_isr(int irq, void *dev_id)
+{
+ struct qbt1000_drvdata *drvdata = dev_id;
+
+ if (irq != drvdata->fd_gpio.irq) {
+ pr_warn("invalid irq %d (expected %d)\n",
+ irq, drvdata->fd_gpio.irq);
+ return IRQ_HANDLED;
+ }
+
+ pm_stay_awake(drvdata->dev);
+ schedule_work(&drvdata->fd_gpio.work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * qbt1000_ipc_irq_handler() - function processes IPC
+ * interrupts on its own thread
+ * @irq: the interrupt that occurred
+ * @dev_id: pointer to the qbt1000_drvdata
+ *
+ * Return: IRQ_HANDLED when complete
+ */
+static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
+{
+ uint8_t *msg_buffer;
+ struct fw_ipc_cmd *rx_cmd;
+ struct fw_ipc_header *header;
+ int i, j;
+ uint32_t rxipc = FP_APP_CMD_RX_IPC;
+ struct qbt1000_drvdata *drvdata = (struct qbt1000_drvdata *)dev_id;
+ int rc = 0;
+ uint32_t retry_count = 10;
+
+ pm_stay_awake(drvdata->dev);
+
+ mutex_lock(&drvdata->mutex);
+
+ if (irq != drvdata->fw_ipc.irq) {
+ pr_warn("invalid irq %d (expected %d)\n",
+ irq, drvdata->fw_ipc.irq);
+ goto end;
+ }
+
+ pr_debug("firmware interrupt received (irq %d)\n", irq);
+
+ if (!drvdata->fp_app_handle)
+ goto end;
+
+ while (retry_count > 0) {
+ /*
+ * send the TZ command to fetch the message from firmware
+ * TZ will process the message if it can
+ */
+ rc = send_tz_cmd(drvdata, drvdata->fp_app_handle, 0,
+ &rxipc, sizeof(rxipc),
+ (void *)&rx_cmd, sizeof(*rx_cmd));
+ if (rc < 0) {
+ msleep(50); // sleep for 50ms before retry
+ retry_count -= 1;
+ continue;
+ } else {
+ pr_err("retry_count %d\n", retry_count);
+ break;
+ }
+ }
+
+ if (rc < 0) {
+ pr_err("failure sending tz cmd %d\n", rxipc);
+ goto end;
+ }
+
+ if (rx_cmd->status != 0) {
+ pr_err("tz command failed to complete\n");
+ goto end;
+ }
+
+ msg_buffer = rx_cmd->msg_data;
+
+ for (j = 0; j < rx_cmd->numMsgs; j++) {
+ header = (struct fw_ipc_header *) msg_buffer;
+ /*
+ * given the IPC message type, search for a corresponding
+ * event for the driver client. If found, add to the events
+ * FIFO
+ */
+ for (i = 0; i < ARRAY_SIZE(g_msg_to_event); i++) {
+ if (g_msg_to_event[i].msg_type == header->msg_type) {
+ enum qbt1000_fw_event ev =
+ g_msg_to_event[i].fw_event;
+ struct fw_event_desc fw_ev_desc;
+
+ mutex_lock(&drvdata->fw_events_mutex);
+ pr_debug("fw events: add %d\n", (int) ev);
+ fw_ev_desc.ev = ev;
+
+ if (!kfifo_put(&drvdata->fw_events, fw_ev_desc))
+ pr_err("fw events: fifo full, drop event %d\n",
+ (int) ev);
+
+ mutex_unlock(&drvdata->fw_events_mutex);
+ break;
+ }
+ }
+ msg_buffer += sizeof(*header) + header->msg_len;
+ }
+ wake_up_interruptible(&drvdata->read_wait_queue);
+end:
+ mutex_unlock(&drvdata->mutex);
+ pm_relax(drvdata->dev);
+ return IRQ_HANDLED;
+}
+
+static int setup_fd_gpio_irq(struct platform_device *pdev,
+ struct qbt1000_drvdata *drvdata)
+{
+ int rc = 0;
+ int irq;
+ const char *desc = "qbt_finger_detect";
+
+ rc = devm_gpio_request_one(&pdev->dev, drvdata->fd_gpio.gpio,
+ GPIOF_IN, desc);
+
+ if (rc < 0) {
+ pr_err("failed to request gpio %d, error %d\n",
+ drvdata->fd_gpio.gpio, rc);
+ goto end;
+ }
+
+ irq = gpio_to_irq(drvdata->fd_gpio.gpio);
+ if (irq < 0) {
+ rc = irq;
+ pr_err("unable to get irq number for gpio %d, error %d\n",
+ drvdata->fd_gpio.gpio, rc);
+ goto end;
+ }
+
+ drvdata->fd_gpio.irq = irq;
+ INIT_WORK(&drvdata->fd_gpio.work, qbt1000_gpio_work_func);
+
+ rc = devm_request_any_context_irq(&pdev->dev, drvdata->fd_gpio.irq,
+ qbt1000_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ desc, drvdata);
+
+ if (rc < 0) {
+ pr_err("unable to claim irq %d; error %d\n",
+ drvdata->fd_gpio.irq, rc);
+ goto end;
+ }
+
+end:
+ return rc;
+}
+
+static int setup_ipc_irq(struct platform_device *pdev,
+ struct qbt1000_drvdata *drvdata)
+{
+ int rc = 0;
+ const char *desc = "qbt_ipc";
+
+ drvdata->fw_ipc.irq = gpio_to_irq(drvdata->fw_ipc.gpio);
+ pr_debug("\nirq %d gpio %d\n",
+ drvdata->fw_ipc.irq, drvdata->fw_ipc.gpio);
+ if (drvdata->fw_ipc.irq < 0) {
+ rc = drvdata->fw_ipc.irq;
+ pr_err("no irq for gpio %d, error=%d\n",
+ drvdata->fw_ipc.gpio, rc);
+ goto end;
+ }
+
+ rc = devm_gpio_request_one(&pdev->dev, drvdata->fw_ipc.gpio,
+ GPIOF_IN, desc);
+
+ if (rc < 0) {
+ pr_err("failed to request gpio %d, error %d\n",
+ drvdata->fw_ipc.gpio, rc);
+ goto end;
+ }
+
+ rc = devm_request_threaded_irq(&pdev->dev,
+ drvdata->fw_ipc.irq,
+ NULL,
+ qbt1000_ipc_irq_handler,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ desc,
+ drvdata);
+
+ if (rc < 0) {
+ pr_err("failed to register for ipc irq %d, rc = %d\n",
+ drvdata->fw_ipc.irq, rc);
+ goto end;
+ }
+
+end:
+ return rc;
+}
+
+/**
+ * qbt1000_read_device_tree() - Function reads device tree
+ * properties into driver data
+ * @pdev: ptr to platform device object
+ * @drvdata: ptr to driver data
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static int qbt1000_read_device_tree(struct platform_device *pdev,
+ struct qbt1000_drvdata *drvdata)
+{
+ int rc = 0;
+ uint32_t rate;
+ int gpio;
+ enum of_gpio_flags flags;
+
+ /* read clock frequency */
+ if (of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &rate) == 0) {
+ pr_debug("clk frequency %d\n", rate);
+ drvdata->frequency = rate;
+ }
+
+ /* read IPC gpio */
+ drvdata->fw_ipc.gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,ipc-gpio", 0);
+ if (drvdata->fw_ipc.gpio < 0) {
+ rc = drvdata->fw_ipc.gpio;
+ pr_err("ipc gpio not found, error=%d\n", rc);
+ goto end;
+ }
+
+ /**
+ * TODO: Need to revisit after adding GPIO in DTSI- read
+ * finger detect GPIO configuration
+ */
+
+ gpio = of_get_named_gpio_flags(pdev->dev.of_node,
+ "qcom,finger-detect-gpio", 0, &flags);
+ if (gpio < 0) {
+ pr_err("failed to get gpio flags\n");
+ rc = gpio;
+ goto end;
+ }
+
+ drvdata->fd_gpio.gpio = gpio;
+ drvdata->fd_gpio.active_low = flags & OF_GPIO_ACTIVE_LOW;
+
+end:
+ return rc;
+}
+
+/**
+ * qbt1000_probe() - Function loads hardware config from device tree
+ * @pdev: ptr to platform device object
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static int qbt1000_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct qbt1000_drvdata *drvdata;
+ int rc = 0;
+
+ pr_debug("qbt1000_probe begin\n");
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ rc = qbt1000_read_device_tree(pdev, drvdata);
+ if (rc < 0)
+ goto end;
+
+ atomic_set(&drvdata->available, 1);
+
+ mutex_init(&drvdata->mutex);
+ mutex_init(&drvdata->fw_events_mutex);
+
+ rc = qbt1000_dev_register(drvdata);
+ if (rc < 0)
+ goto end;
+
+ INIT_KFIFO(drvdata->fw_events);
+ init_waitqueue_head(&drvdata->read_wait_queue);
+
+ rc = qbt1000_create_input_device(drvdata);
+ if (rc < 0)
+ goto end;
+
+ rc = setup_fd_gpio_irq(pdev, drvdata);
+ if (rc < 0)
+ goto end;
+
+ rc = setup_ipc_irq(pdev, drvdata);
+ if (rc < 0)
+ goto end;
+
+ rc = device_init_wakeup(&pdev->dev, 1);
+ if (rc < 0)
+ goto end;
+
+end:
+ pr_debug("qbt1000_probe end : %d\n", rc);
+ return rc;
+}
+
+static int qbt1000_remove(struct platform_device *pdev)
+{
+ struct qbt1000_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ input_unregister_device(drvdata->in_dev);
+
+ mutex_destroy(&drvdata->mutex);
+ mutex_destroy(&drvdata->fw_events_mutex);
+
+ device_destroy(drvdata->qbt1000_class, drvdata->qbt1000_cdev.dev);
+ class_destroy(drvdata->qbt1000_class);
+ cdev_del(&drvdata->qbt1000_cdev);
+ unregister_chrdev_region(drvdata->qbt1000_cdev.dev, 1);
+
+ device_init_wakeup(&pdev->dev, 0);
+
+ return 0;
+}
+
+static int qbt1000_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int rc = 0;
+ struct qbt1000_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ /*
+ * Returning an error code if driver currently making a TZ call.
+ * Note: The purpose of this driver is to ensure that the clocks are on
+ * while making a TZ call. Hence the clock check to determine if the
+ * driver will allow suspend to occur.
+ */
+ if (!mutex_trylock(&drvdata->mutex))
+ return -EBUSY;
+
+ if (drvdata->clock_state)
+ rc = -EBUSY;
+ else {
+ enable_irq_wake(drvdata->fd_gpio.irq);
+ enable_irq_wake(drvdata->fw_ipc.irq);
+ }
+
+ mutex_unlock(&drvdata->mutex);
+
+ return rc;
+}
+
+static int qbt1000_resume(struct platform_device *pdev)
+{
+ struct qbt1000_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ disable_irq_wake(drvdata->fd_gpio.irq);
+ disable_irq_wake(drvdata->fw_ipc.irq);
+
+ return 0;
+}
+
+static const struct of_device_id qbt1000_match[] = {
+ { .compatible = "qcom,qbt1000" },
+ {}
+};
+
+static struct platform_driver qbt1000_plat_driver = {
+ .probe = qbt1000_probe,
+ .remove = qbt1000_remove,
+ .suspend = qbt1000_suspend,
+ .resume = qbt1000_resume,
+ .driver = {
+ .name = "qbt1000",
+ .owner = THIS_MODULE,
+ .of_match_table = qbt1000_match,
+ },
+};
+
+module_platform_driver(qbt1000_plat_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. QBT1000 driver");
diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c
index 82718c8..57f38d3 100644
--- a/drivers/soc/qcom/service-locator.c
+++ b/drivers/soc/qcom/service-locator.c
@@ -266,7 +266,6 @@
pd->total_domains = resp->total_domains;
if (!resp->total_domains) {
pr_err("No matching domains found\n");
- rc = -EIO;
goto out;
}
diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c
index 62e2384..221ae0c 100644
--- a/drivers/soc/qcom/service-notifier.c
+++ b/drivers/soc/qcom/service-notifier.c
@@ -373,13 +373,6 @@
mutex_unlock(&qmi_client_release_lock);
pr_info("Connection established between QMI handle and %d service\n",
data->instance_id);
- /* Register for indication messages about service */
- rc = qmi_register_ind_cb(data->clnt_handle, root_service_service_ind_cb,
- (void *)data);
- if (rc < 0)
- pr_err("Indication callback register failed(instance-id: %d) rc:%d\n",
- data->instance_id, rc);
-
mutex_lock(¬if_add_lock);
mutex_lock(&service_list_lock);
list_for_each_entry(service_notif, &service_list, list) {
@@ -402,6 +395,12 @@
}
mutex_unlock(&service_list_lock);
mutex_unlock(¬if_add_lock);
+ /* Register for indication messages about service */
+ rc = qmi_register_ind_cb(data->clnt_handle,
+ root_service_service_ind_cb, (void *)data);
+ if (rc < 0)
+ pr_err("Indication callback register failed(instance-id: %d) rc:%d\n",
+ data->instance_id, rc);
}
static void root_service_service_exit(struct qmi_client_info *data,
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 119ede3..8aff84c 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -36,6 +36,7 @@
#include <soc/qcom/boot_stats.h>
#define BUILD_ID_LENGTH 32
+#define CHIP_ID_LENGTH 32
#define SMEM_IMAGE_VERSION_BLOCKS_COUNT 32
#define SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE 128
#define SMEM_IMAGE_VERSION_SIZE 4096
@@ -199,6 +200,20 @@
struct socinfo_v0_13 {
struct socinfo_v0_12 v0_12;
uint32_t nproduct_id;
+ char chip_name[CHIP_ID_LENGTH];
+};
+
+struct socinfo_v0_14 {
+ struct socinfo_v0_13 v0_13;
+ uint32_t num_clusters;
+ uint32_t ncluster_array_offset;
+ uint32_t num_defective_parts;
+ uint32_t ndefective_parts_array_offset;
+};
+
+struct socinfo_v0_15 {
+ struct socinfo_v0_14 v0_14;
+ uint32_t nmodem_supported;
};
static union {
@@ -215,10 +230,12 @@
struct socinfo_v0_11 v0_11;
struct socinfo_v0_12 v0_12;
struct socinfo_v0_13 v0_13;
+ struct socinfo_v0_14 v0_14;
+ struct socinfo_v0_15 v0_15;
} *socinfo;
/* max socinfo format version supported */
-#define MAX_SOCINFO_FORMAT SOCINFO_VERSION(0, 13)
+#define MAX_SOCINFO_FORMAT SOCINFO_VERSION(0, 15)
static struct msm_soc_info cpu_of_id[] = {
@@ -705,6 +722,14 @@
: 0;
}
+static char *socinfo_get_chip_name(void)
+{
+ return socinfo ?
+ (socinfo_format >= SOCINFO_VERSION(0, 13) ?
+ socinfo->v0_13.chip_name : "N/A")
+ : "N/A";
+}
+
static uint32_t socinfo_get_nproduct_id(void)
{
return socinfo ?
@@ -713,6 +738,46 @@
: 0;
}
+static uint32_t socinfo_get_num_clusters(void)
+{
+ return socinfo ?
+ (socinfo_format >= SOCINFO_VERSION(0, 14) ?
+ socinfo->v0_14.num_clusters : 0)
+ : 0;
+}
+
+static uint32_t socinfo_get_ncluster_array_offset(void)
+{
+ return socinfo ?
+ (socinfo_format >= SOCINFO_VERSION(0, 14) ?
+ socinfo->v0_14.ncluster_array_offset : 0)
+ : 0;
+}
+
+static uint32_t socinfo_get_num_defective_parts(void)
+{
+ return socinfo ?
+ (socinfo_format >= SOCINFO_VERSION(0, 14) ?
+ socinfo->v0_14.num_defective_parts : 0)
+ : 0;
+}
+
+static uint32_t socinfo_get_ndefective_parts_array_offset(void)
+{
+ return socinfo ?
+ (socinfo_format >= SOCINFO_VERSION(0, 14) ?
+ socinfo->v0_14.ndefective_parts_array_offset : 0)
+ : 0;
+}
+
+static uint32_t socinfo_get_nmodem_supported(void)
+{
+ return socinfo ?
+ (socinfo_format >= SOCINFO_VERSION(0, 15) ?
+ socinfo->v0_15.nmodem_supported : 0)
+ : 0;
+}
+
enum pmic_model socinfo_get_pmic_model(void)
{
return socinfo ?
@@ -890,6 +955,15 @@
}
static ssize_t
+msm_get_chip_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+ socinfo_get_chip_name());
+}
+
+static ssize_t
msm_get_nproduct_id(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -899,6 +973,51 @@
}
static ssize_t
+msm_get_num_clusters(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n",
+ socinfo_get_num_clusters());
+}
+
+static ssize_t
+msm_get_ncluster_array_offset(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n",
+ socinfo_get_ncluster_array_offset());
+}
+
+static ssize_t
+msm_get_num_defective_parts(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n",
+ socinfo_get_num_defective_parts());
+}
+
+static ssize_t
+msm_get_ndefective_parts_array_offset(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n",
+ socinfo_get_ndefective_parts_array_offset());
+}
+
+static ssize_t
+msm_get_nmodem_supported(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n",
+ socinfo_get_nmodem_supported());
+}
+
+static ssize_t
msm_get_pmic_model(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1146,10 +1265,34 @@
__ATTR(raw_device_number, S_IRUGO,
msm_get_raw_device_number, NULL);
+static struct device_attribute msm_soc_attr_chip_name =
+ __ATTR(chip_name, 0444,
+ msm_get_chip_name, NULL);
+
static struct device_attribute msm_soc_attr_nproduct_id =
__ATTR(nproduct_id, 0444,
msm_get_nproduct_id, NULL);
+static struct device_attribute msm_soc_attr_num_clusters =
+ __ATTR(num_clusters, 0444,
+ msm_get_num_clusters, NULL);
+
+static struct device_attribute msm_soc_attr_ncluster_array_offset =
+ __ATTR(ncluster_array_offset, 0444,
+ msm_get_ncluster_array_offset, NULL);
+
+static struct device_attribute msm_soc_attr_num_defective_parts =
+ __ATTR(num_defective_parts, 0444,
+ msm_get_num_defective_parts, NULL);
+
+static struct device_attribute msm_soc_attr_ndefective_parts_array_offset =
+ __ATTR(ndefective_parts_array_offset, 0444,
+ msm_get_ndefective_parts_array_offset, NULL);
+
+static struct device_attribute msm_soc_attr_nmodem_supported =
+ __ATTR(nmodem_supported, 0444,
+ msm_get_nmodem_supported, NULL);
+
static struct device_attribute msm_soc_attr_pmic_model =
__ATTR(pmic_model, S_IRUGO,
msm_get_pmic_model, NULL);
@@ -1280,9 +1423,23 @@
device_create_file(msm_soc_device, &images);
switch (socinfo_format) {
+ case SOCINFO_VERSION(0, 15):
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_nmodem_supported);
+ case SOCINFO_VERSION(0, 14):
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_num_clusters);
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_ncluster_array_offset);
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_num_defective_parts);
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_ndefective_parts_array_offset);
case SOCINFO_VERSION(0, 13):
device_create_file(msm_soc_device,
&msm_soc_attr_nproduct_id);
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_chip_name);
case SOCINFO_VERSION(0, 12):
device_create_file(msm_soc_device,
&msm_soc_attr_chip_family);
@@ -1522,6 +1679,53 @@
socinfo->v0_13.nproduct_id);
break;
+ case SOCINFO_VERSION(0, 14):
+ pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u foundry_id=%u serial_number=%u num_pmics=%u chip_family=0x%x raw_device_family=0x%x raw_device_number=0x%x nproduct_id=0x%x num_clusters=0x%x ncluster_array_offset=0x%x num_defective_parts=0x%x ndefective_parts_array_offset=0x%x\n",
+ f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+ socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
+ socinfo->v0_3.hw_platform,
+ socinfo->v0_4.platform_version,
+ socinfo->v0_5.accessory_chip,
+ socinfo->v0_6.hw_platform_subtype,
+ socinfo->v0_7.pmic_model,
+ socinfo->v0_7.pmic_die_revision,
+ socinfo->v0_9.foundry_id,
+ socinfo->v0_10.serial_number,
+ socinfo->v0_11.num_pmics,
+ socinfo->v0_12.chip_family,
+ socinfo->v0_12.raw_device_family,
+ socinfo->v0_12.raw_device_number,
+ socinfo->v0_13.nproduct_id,
+ socinfo->v0_14.num_clusters,
+ socinfo->v0_14.ncluster_array_offset,
+ socinfo->v0_14.num_defective_parts,
+ socinfo->v0_14.ndefective_parts_array_offset);
+ break;
+
+ case SOCINFO_VERSION(0, 15):
+ pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u foundry_id=%u serial_number=%u num_pmics=%u chip_family=0x%x raw_device_family=0x%x raw_device_number=0x%x nproduct_id=0x%x num_clusters=0x%x ncluster_array_offset=0x%x num_defective_parts=0x%x ndefective_parts_array_offset=0x%x nmodem_supported=0x%x\n",
+ f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+ socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
+ socinfo->v0_3.hw_platform,
+ socinfo->v0_4.platform_version,
+ socinfo->v0_5.accessory_chip,
+ socinfo->v0_6.hw_platform_subtype,
+ socinfo->v0_7.pmic_model,
+ socinfo->v0_7.pmic_die_revision,
+ socinfo->v0_9.foundry_id,
+ socinfo->v0_10.serial_number,
+ socinfo->v0_11.num_pmics,
+ socinfo->v0_12.chip_family,
+ socinfo->v0_12.raw_device_family,
+ socinfo->v0_12.raw_device_number,
+ socinfo->v0_13.nproduct_id,
+ socinfo->v0_14.num_clusters,
+ socinfo->v0_14.ncluster_array_offset,
+ socinfo->v0_14.num_defective_parts,
+ socinfo->v0_14.ndefective_parts_array_offset,
+ socinfo->v0_15.nmodem_supported);
+ break;
+
default:
pr_err("Unknown format found: v%u.%u\n", f_maj, f_min);
break;
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 68f0217..9846c51 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -96,6 +96,7 @@
int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
int other_file = global_node_page_state(NR_FILE_PAGES) -
global_node_page_state(NR_SHMEM) -
+ global_node_page_state(NR_UNEVICTABLE) -
total_swapcache_pages();
if (lowmem_adj_size < array_size)
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 70390de..eb0a095 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -611,7 +611,7 @@
s = &dev->subdevices[i];
spriv = s->private;
- if (now > spriv->next_time_min) {
+ if (time_after_eq(now, spriv->next_time_min)) {
struct jr3_pci_poll_delay sub_delay;
sub_delay = jr3_pci_poll_subdevice(s);
@@ -727,11 +727,12 @@
s->insn_read = jr3_pci_ai_insn_read;
spriv = jr3_pci_alloc_spriv(dev, s);
- if (spriv) {
- /* Channel specific range and maxdata */
- s->range_table_list = spriv->range_table_list;
- s->maxdata_list = spriv->maxdata_list;
- }
+ if (!spriv)
+ return -ENOMEM;
+
+ /* Channel specific range and maxdata */
+ s->range_table_list = spriv->range_table_list;
+ s->maxdata_list = spriv->maxdata_list;
}
/* Reset DSP card */
diff --git a/drivers/staging/gdm724x/gdm_mux.c b/drivers/staging/gdm724x/gdm_mux.c
index 4009691..f03e43b 100644
--- a/drivers/staging/gdm724x/gdm_mux.c
+++ b/drivers/staging/gdm724x/gdm_mux.c
@@ -664,9 +664,8 @@
static void __exit gdm_usb_mux_exit(void)
{
- unregister_lte_tty_driver();
-
usb_deregister(&gdm_mux_driver);
+ unregister_lte_tty_driver();
}
module_init(gdm_usb_mux_init);
diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c
index e9b6b21..f759aa8 100644
--- a/drivers/staging/vt6656/usbpipe.c
+++ b/drivers/staging/vt6656/usbpipe.c
@@ -47,15 +47,25 @@
u16 index, u16 length, u8 *buffer)
{
int status = 0;
+ u8 *usb_buffer;
if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
return STATUS_FAILURE;
mutex_lock(&priv->usb_lock);
+ usb_buffer = kmemdup(buffer, length, GFP_KERNEL);
+ if (!usb_buffer) {
+ mutex_unlock(&priv->usb_lock);
+ return -ENOMEM;
+ }
+
status = usb_control_msg(priv->usb,
- usb_sndctrlpipe(priv->usb, 0), request, 0x40, value,
- index, buffer, length, USB_CTL_WAIT);
+ usb_sndctrlpipe(priv->usb, 0),
+ request, 0x40, value,
+ index, usb_buffer, length, USB_CTL_WAIT);
+
+ kfree(usb_buffer);
mutex_unlock(&priv->usb_lock);
@@ -75,15 +85,28 @@
u16 index, u16 length, u8 *buffer)
{
int status;
+ u8 *usb_buffer;
if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
return STATUS_FAILURE;
mutex_lock(&priv->usb_lock);
+ usb_buffer = kmalloc(length, GFP_KERNEL);
+ if (!usb_buffer) {
+ mutex_unlock(&priv->usb_lock);
+ return -ENOMEM;
+ }
+
status = usb_control_msg(priv->usb,
- usb_rcvctrlpipe(priv->usb, 0), request, 0xc0, value,
- index, buffer, length, USB_CTL_WAIT);
+ usb_rcvctrlpipe(priv->usb, 0),
+ request, 0xc0, value,
+ index, usb_buffer, length, USB_CTL_WAIT);
+
+ if (status == length)
+ memcpy(buffer, usb_buffer, length);
+
+ kfree(usb_buffer);
mutex_unlock(&priv->usb_lock);
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index b7d747e..40e50f2 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -4671,6 +4671,7 @@
continue;
}
atomic_set(&sess->session_reinstatement, 1);
+ atomic_set(&sess->session_fall_back_to_erl0, 1);
spin_unlock(&sess->conn_lock);
list_move_tail(&se_sess->sess_list, &free_list);
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index e980e2d..7e70fe8 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -1530,6 +1530,7 @@
return;
}
atomic_set(&sess->session_reinstatement, 1);
+ atomic_set(&sess->session_fall_back_to_erl0, 1);
spin_unlock(&sess->conn_lock);
iscsit_stop_time2retain_timer(sess);
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 15f79a2..96c55bc 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -204,6 +204,7 @@
initiatorname_param->value) &&
(sess_p->sess_ops->SessionType == sessiontype))) {
atomic_set(&sess_p->session_reinstatement, 1);
+ atomic_set(&sess_p->session_fall_back_to_erl0, 1);
spin_unlock(&sess_p->conn_lock);
iscsit_inc_session_usage_count(sess_p);
iscsit_stop_time2retain_timer(sess_p);
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index d545993..29f807b 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -594,8 +594,7 @@
if (ret < 0)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- if (ret)
- target_complete_cmd(cmd, SAM_STAT_GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index a53fb23..b3b1461 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -506,8 +506,11 @@
* been failed with a non-zero SCSI status.
*/
if (cmd->scsi_status) {
- pr_err("compare_and_write_callback: non zero scsi_status:"
+ pr_debug("compare_and_write_callback: non zero scsi_status:"
" 0x%02x\n", cmd->scsi_status);
+ *post_ret = 1;
+ if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION)
+ ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
goto out;
}
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index 342160e..04320d8 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1973,8 +1973,6 @@
chip->sensor[sen_idx].thermal_node = true;
snprintf(name, sizeof(name), "%s",
chip->adc->adc_channels[sen_idx].name);
- chip->sensor[sen_idx].meas_interval =
- QPNP_ADC_TM_MEAS_INTERVAL;
chip->sensor[sen_idx].low_thr =
QPNP_ADC_TM_M0_LOW_THR;
chip->sensor[sen_idx].high_thr =
@@ -2027,7 +2025,7 @@
rc = devm_request_irq(&pdev->dev, chip->adc->adc_irq_eoc,
qpnp_adc_tm_rc_thr_isr,
- IRQF_TRIGGER_RISING, "qpnp_adc_tm_interrupt", chip);
+ IRQF_TRIGGER_HIGH, "qpnp_adc_tm_interrupt", chip);
if (rc)
dev_err(&pdev->dev, "failed to request adc irq\n");
else
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index a23fa5e..2b90738 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -216,16 +216,11 @@
static void pty_flush_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
- struct tty_ldisc *ld;
if (!to)
return;
- ld = tty_ldisc_ref(to);
- tty_buffer_flush(to, ld);
- if (ld)
- tty_ldisc_deref(ld);
-
+ tty_buffer_flush(to, NULL);
if (to->packet) {
spin_lock_irq(&tty->ctrl_lock);
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index 8108da8..6deff2e 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -145,6 +145,7 @@
void *ipc_log_pwr;
void *ipc_log_misc;
unsigned int cur_baud;
+ int ioctl_count;
};
static const struct uart_ops msm_geni_serial_pops;
@@ -161,6 +162,8 @@
static unsigned int msm_geni_serial_tx_empty(struct uart_port *port);
static int msm_geni_serial_power_on(struct uart_port *uport);
static void msm_geni_serial_power_off(struct uart_port *uport);
+static int msm_geni_serial_poll_bit(struct uart_port *uport,
+ int offset, int bit_field, bool set);
static atomic_t uart_line_id = ATOMIC_INIT(0);
@@ -218,22 +221,22 @@
(unsigned int)addr, size, buf);
}
-static void check_tx_active(struct uart_port *uport)
+static bool check_tx_active(struct uart_port *uport)
{
- u32 geni_status = geni_read_reg_nolog(uport->membase,
- SE_GENI_STATUS);
-
- while ((geni_status & M_GENI_CMD_ACTIVE)) {
- cpu_relax();
- geni_status = geni_read_reg_nolog(uport->membase,
- SE_GENI_STATUS);
- }
+ /*
+ * Poll if the GENI STATUS bit for TX is cleared. If the bit is
+ * clear (poll condition met), return false, meaning tx isn't active
+ * else return true. So return not of the poll return.
+ */
+ return !msm_geni_serial_poll_bit(uport, SE_GENI_STATUS,
+ M_GENI_CMD_ACTIVE, false);
}
static int vote_clock_on(struct uart_port *uport)
{
int ret = 0;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
+ int usage_count = atomic_read(&uport->dev->power.usage_count);
if (!pm_runtime_enabled(uport->dev)) {
dev_err(uport->dev, "RPM not available.Can't enable clocks\n");
@@ -245,8 +248,10 @@
dev_err(uport->dev, "Failed to vote clock on\n");
return ret;
}
+ port->ioctl_count++;
__pm_relax(&port->geni_wake);
- IPC_LOG_MSG(port->ipc_log_pwr, "%s\n", __func__);
+ IPC_LOG_MSG(port->ipc_log_pwr, "%s rpm %d ioctl %d\n",
+ __func__, usage_count, port->ioctl_count);
return 0;
}
@@ -254,16 +259,29 @@
{
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
int ret = 0;
+ int usage_count = atomic_read(&uport->dev->power.usage_count);
if (!pm_runtime_enabled(uport->dev)) {
dev_err(uport->dev, "RPM not available.Can't enable clocks\n");
ret = -EPERM;
return ret;
}
- /* Block till any on going Tx goes out.*/
- check_tx_active(uport);
+ /* Check on going Tx. Don't block on this for now. */
+ if (check_tx_active(uport))
+ dev_warn(uport->dev, "%s: Vote off called during active Tx",
+ __func__);
+ if (!port->ioctl_count) {
+ dev_warn(uport->dev, "%s:Imbalanced vote off ioctl %d\n",
+ __func__, usage_count);
+ IPC_LOG_MSG(port->ipc_log_pwr,
+ "%s:Imbalanced vote_off from userspace rpm%d",
+ __func__, usage_count);
+ return 0;
+ }
+ port->ioctl_count--;
msm_geni_serial_power_off(uport);
- IPC_LOG_MSG(port->ipc_log_pwr, "%s\n", __func__);
+ IPC_LOG_MSG(port->ipc_log_pwr, "%s rpm %d ioctl %d\n",
+ __func__, usage_count, port->ioctl_count);
return 0;
};
@@ -398,20 +416,20 @@
bool cond = false;
unsigned int baud = 115200;
unsigned int fifo_bits = DEF_FIFO_DEPTH_WORDS * DEF_FIFO_WIDTH_BITS;
- unsigned long total_iter = 0;
+ unsigned long total_iter = 1000;
- if (uport->private_data) {
+ if (uport->private_data && !uart_console(uport)) {
port = GET_DEV_PORT(uport);
baud = (port->cur_baud ? port->cur_baud : 115200);
fifo_bits = port->tx_fifo_depth * port->tx_fifo_width;
+ /*
+ * Total polling iterations based on FIFO worth of bytes to be
+ * sent at current baud .Add a little fluff to the wait.
+ */
+ total_iter = ((fifo_bits * USEC_PER_SEC) / baud);
+ total_iter += 50;
}
- /*
- * Total polling iterations based on FIFO worth of bytes to be
- * sent at current baud .Add a little fluff to the wait.
- */
- total_iter = ((fifo_bits * USEC_PER_SEC) / baud);
- total_iter += 50;
while (iter < total_iter) {
reg = geni_read_reg_nolog(uport->membase, offset);
@@ -449,17 +467,11 @@
done = msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
M_CMD_DONE_EN, true);
if (!done) {
- geni_write_reg_nolog(M_GENI_CMD_CANCEL, uport->membase,
- SE_GENI_S_CMD_CTRL_REG);
- irq_clear |= M_CMD_CANCEL_EN;
- if (!msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
- M_CMD_CANCEL_EN, true)) {
- geni_write_reg_nolog(M_GENI_CMD_ABORT, uport->membase,
- SE_GENI_M_CMD_CTRL_REG);
- irq_clear |= M_CMD_ABORT_EN;
- msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ geni_write_reg_nolog(M_GENI_CMD_ABORT, uport->membase,
+ SE_GENI_M_CMD_CTRL_REG);
+ irq_clear |= M_CMD_ABORT_EN;
+ msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
M_CMD_ABORT_EN, true);
- }
}
geni_write_reg_nolog(irq_clear, uport->membase, SE_GENI_M_IRQ_CLEAR);
}
@@ -678,7 +690,6 @@
geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN);
/* Geni command setup/irq enables should complete before returning.*/
mb();
- IPC_LOG_MSG(msm_port->ipc_log_misc, "%s\n", __func__);
}
static void msm_geni_serial_stop_tx(struct uart_port *uport)
@@ -1032,23 +1043,33 @@
if (!uart_console(uport)) {
/* For now only assume FIFO mode. */
msm_port->xfer_mode = FIFO_MODE;
- ret = geni_se_init(uport->membase,
- msm_port->rx_wm, msm_port->rx_rfr);
- if (ret) {
- dev_err(uport->dev, "%s: Fail\n", __func__);
- goto exit_portsetup;
- }
-
- ret = geni_se_select_mode(uport->membase, msm_port->xfer_mode);
- if (ret)
- goto exit_portsetup;
-
se_get_packing_config(8, 4, false, &cfg0, &cfg1);
geni_write_reg_nolog(cfg0, uport->membase,
SE_GENI_TX_PACKING_CFG0);
geni_write_reg_nolog(cfg1, uport->membase,
SE_GENI_TX_PACKING_CFG1);
+ } else {
+ /*
+ * Make an unconditional cancel on the main sequencer to reset
+ * it else we could end up in data loss scenarios.
+ */
+ msm_port->xfer_mode = FIFO_MODE;
+ msm_geni_serial_poll_cancel_tx(uport);
+ se_get_packing_config(8, 1, false, &cfg0, &cfg1);
+ geni_write_reg_nolog(cfg0, uport->membase,
+ SE_GENI_TX_PACKING_CFG0);
+ geni_write_reg_nolog(cfg1, uport->membase,
+ SE_GENI_TX_PACKING_CFG1);
}
+ ret = geni_se_init(uport->membase, msm_port->rx_wm, msm_port->rx_rfr);
+ if (ret) {
+ dev_err(uport->dev, "%s: Fail\n", __func__);
+ goto exit_portsetup;
+ }
+
+ ret = geni_se_select_mode(uport->membase, msm_port->xfer_mode);
+ if (ret)
+ goto exit_portsetup;
msm_port->port_setup = true;
/*
@@ -1118,12 +1139,10 @@
if (unlikely(get_se_proto(uport->membase) != UART)) {
dev_err(uport->dev, "%s: Invalid FW %d loaded.\n",
__func__, get_se_proto(uport->membase));
- if (unlikely(get_se_proto(uport->membase) != UART)) {
- ret = -ENXIO;
- disable_irq(uport->irq);
- free_irq(uport->irq, msm_port);
- goto exit_startup;
- }
+ ret = -ENXIO;
+ disable_irq(uport->irq);
+ free_irq(uport->irq, msm_port);
+ goto exit_startup;
}
if (!msm_port->port_setup) {
@@ -1358,7 +1377,6 @@
int parity = 'n';
int flow = 'n';
int ret = 0;
- unsigned long cfg0, cfg1;
if (unlikely(co->index >= GENI_UART_NR_PORTS || co->index < 0))
return -ENXIO;
@@ -1386,14 +1404,6 @@
if (!dev_port->port_setup)
msm_geni_serial_port_setup(uport);
- /*
- * Make an unconditional cancel on the main sequencer to reset
- * it else we could end up in data loss scenarios.
- */
- msm_geni_serial_poll_cancel_tx(uport);
- se_get_packing_config(8, 1, false, &cfg0, &cfg1);
- geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0);
- geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -1438,9 +1448,6 @@
goto exit_geni_serial_earlyconsetup;
}
- geni_se_init(uport->membase, (DEF_FIFO_DEPTH_WORDS >> 1),
- (DEF_FIFO_DEPTH_WORDS - 2));
- geni_se_select_mode(uport->membase, FIFO_MODE);
/*
* Ignore Flow control.
* Disable Tx Parity.
@@ -1471,7 +1478,11 @@
* it else we could end up in data loss scenarios.
*/
msm_geni_serial_poll_cancel_tx(uport);
+ msm_geni_serial_abort_rx(uport);
se_get_packing_config(8, 1, false, &cfg0, &cfg1);
+ geni_se_init(uport->membase, (DEF_FIFO_DEPTH_WORDS >> 1),
+ (DEF_FIFO_DEPTH_WORDS - 2));
+ geni_se_select_mode(uport->membase, FIFO_MODE);
geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0);
geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1);
geni_write_reg_nolog(tx_trans_cfg, uport->membase,
@@ -1802,8 +1813,7 @@
}
if (port->wakeup_irq > 0)
enable_irq(port->wakeup_irq);
- IPC_LOG_MSG(port->ipc_log_pwr, "%s: Current usage count %d\n", __func__,
- atomic_read(&dev->power.usage_count));
+ IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__);
exit_runtime_suspend:
return ret;
}
@@ -1821,8 +1831,7 @@
dev_err(dev, "%s: Error ret %d\n", __func__, ret);
goto exit_runtime_resume;
}
- IPC_LOG_MSG(port->ipc_log_pwr, "%s: Current usage count %d\n", __func__,
- atomic_read(&dev->power.usage_count));
+ IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__);
exit_runtime_resume:
return ret;
}
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index a2a5299..44e5b5b 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1712,7 +1712,8 @@
return 0;
err_add_port:
- pm_runtime_put(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_qos_remove_request(&up->pm_qos_request);
device_init_wakeup(up->dev, false);
@@ -1725,9 +1726,13 @@
{
struct uart_omap_port *up = platform_get_drvdata(dev);
+ pm_runtime_get_sync(up->dev);
+
+ uart_remove_one_port(&serial_omap_reg, &up->port);
+
+ pm_runtime_dont_use_autosuspend(up->dev);
pm_runtime_put_sync(up->dev);
pm_runtime_disable(up->dev);
- uart_remove_one_port(&serial_omap_reg, &up->port);
pm_qos_remove_request(&up->pm_qos_request);
device_init_wakeup(&dev->dev, false);
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 3e2ef4f..d65f92b 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -906,14 +906,13 @@
return -ENOMEM;
}
- dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf,
+ dma->rx_addr = dma_map_single(p->port.dev, dma->rx_buf,
dma->rx_size, DMA_FROM_DEVICE);
spin_lock_irqsave(&p->port.lock, flags);
/* TX buffer */
- dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
- p->port.state->xmit.buf,
+ dma->tx_addr = dma_map_single(p->port.dev, p->port.state->xmit.buf,
UART_XMIT_SIZE, DMA_TO_DEVICE);
spin_unlock_irqrestore(&p->port.lock, flags);
@@ -927,7 +926,7 @@
if (dma->rx_chan) {
dmaengine_terminate_all(dma->rx_chan);
- dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
+ dma_unmap_single(p->port.dev, dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
kfree(dma->rx_buf);
dma_release_channel(dma->rx_chan);
@@ -936,7 +935,7 @@
if (dma->tx_chan) {
dmaengine_terminate_all(dma->tx_chan);
- dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr,
+ dma_unmap_single(p->port.dev, dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_release_channel(dma->tx_chan);
dma->tx_chan = NULL;
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 0a63695..0b845e5 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -58,7 +58,6 @@
#define WDM_SUSPENDING 8
#define WDM_RESETTING 9
#define WDM_OVERFLOW 10
-#define WDM_DRAIN_ON_OPEN 11
#define WDM_MAX 16
@@ -182,7 +181,7 @@
"nonzero urb status received: -ESHUTDOWN\n");
goto skip_error;
case -EPIPE:
- dev_dbg(&desc->intf->dev,
+ dev_err(&desc->intf->dev,
"nonzero urb status received: -EPIPE\n");
break;
default:
@@ -210,25 +209,6 @@
desc->reslength = length;
}
}
-
- /*
- * Handling devices with the WDM_DRAIN_ON_OPEN flag set:
- * If desc->resp_count is unset, then the urb was submitted
- * without a prior notification. If the device returned any
- * data, then this implies that it had messages queued without
- * notifying us. Continue reading until that queue is flushed.
- */
- if (!desc->resp_count) {
- if (!length) {
- /* do not propagate the expected -EPIPE */
- desc->rerr = 0;
- goto unlock;
- }
- dev_dbg(&desc->intf->dev, "got %d bytes without notification\n", length);
- set_bit(WDM_RESPONDING, &desc->flags);
- usb_submit_urb(desc->response, GFP_ATOMIC);
- }
-
skip_error:
set_bit(WDM_READ, &desc->flags);
wake_up(&desc->wait);
@@ -243,7 +223,6 @@
service_outstanding_interrupt(desc);
}
-unlock:
spin_unlock(&desc->iuspin);
}
@@ -686,17 +665,6 @@
dev_err(&desc->intf->dev,
"Error submitting int urb - %d\n", rv);
rv = usb_translate_errors(rv);
- } else if (test_bit(WDM_DRAIN_ON_OPEN, &desc->flags)) {
- /*
- * Some devices keep pending messages queued
- * without resending notifications. We must
- * flush the message queue before we can
- * assume a one-to-one relationship between
- * notifications and messages in the queue
- */
- dev_dbg(&desc->intf->dev, "draining queued data\n");
- set_bit(WDM_RESPONDING, &desc->flags);
- rv = usb_submit_urb(desc->response, GFP_KERNEL);
}
} else {
rv = 0;
@@ -803,8 +771,7 @@
/* --- hotplug --- */
static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep,
- u16 bufsize, int (*manage_power)(struct usb_interface *, int),
- bool drain_on_open)
+ u16 bufsize, int (*manage_power)(struct usb_interface *, int))
{
int rv = -ENOMEM;
struct wdm_device *desc;
@@ -891,68 +858,6 @@
desc->manage_power = manage_power;
- /*
- * "drain_on_open" enables a hack to work around a firmware
- * issue observed on network functions, in particular MBIM
- * functions.
- *
- * Quoting section 7 of the CDC-WMC r1.1 specification:
- *
- * "The firmware shall interpret GetEncapsulatedResponse as a
- * request to read response bytes. The firmware shall send
- * the next wLength bytes from the response. The firmware
- * shall allow the host to retrieve data using any number of
- * GetEncapsulatedResponse requests. The firmware shall
- * return a zero- length reply if there are no data bytes
- * available.
- *
- * The firmware shall send ResponseAvailable notifications
- * periodically, using any appropriate algorithm, to inform
- * the host that there is data available in the reply
- * buffer. The firmware is allowed to send ResponseAvailable
- * notifications even if there is no data available, but
- * this will obviously reduce overall performance."
- *
- * These requirements, although they make equally sense, are
- * often not implemented by network functions. Some firmwares
- * will queue data indefinitely, without ever resending a
- * notification. The result is that the driver and firmware
- * loses "syncronization" if the driver ever fails to respond
- * to a single notification, something which easily can happen
- * on release(). When this happens, the driver will appear to
- * never receive notifications for the most current data. Each
- * notification will only cause a single read, which returns
- * the oldest data in the firmware's queue.
- *
- * The "drain_on_open" hack resolves the situation by draining
- * data from the firmware until none is returned, without a
- * prior notification.
- *
- * This will inevitably race with the firmware, risking that
- * we read data from the device before handling the associated
- * notification. To make things worse, some of the devices
- * needing the hack do not implement the "return zero if no
- * data is available" requirement either. Instead they return
- * an error on the subsequent read in this case. This means
- * that "winning" the race can cause an unexpected EIO to
- * userspace.
- *
- * "winning" the race is more likely on resume() than on
- * open(), and the unexpected error is more harmful in the
- * middle of an open session. The hack is therefore only
- * applied on open(), and not on resume() where it logically
- * would be equally necessary. So we define open() as the only
- * driver <-> device "syncronization point". Should we happen
- * to lose a notification after open(), then syncronization
- * will be lost until release()
- *
- * The hack should not be enabled for CDC WDM devices
- * conforming to the CDC-WMC r1.1 specification. This is
- * ensured by setting drain_on_open to false in wdm_probe().
- */
- if (drain_on_open)
- set_bit(WDM_DRAIN_ON_OPEN, &desc->flags);
-
spin_lock(&wdm_device_list_lock);
list_add(&desc->device_list, &wdm_device_list);
spin_unlock(&wdm_device_list_lock);
@@ -1006,7 +911,7 @@
goto err;
ep = &iface->endpoint[0].desc;
- rv = wdm_create(intf, ep, maxcom, &wdm_manage_power, false);
+ rv = wdm_create(intf, ep, maxcom, &wdm_manage_power);
err:
return rv;
@@ -1038,7 +943,7 @@
{
int rv = -EINVAL;
- rv = wdm_create(intf, ep, bufsize, manage_power, true);
+ rv = wdm_create(intf, ep, bufsize, manage_power);
if (rv < 0)
goto err;
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 26a305f..ee33c0d 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1328,6 +1328,24 @@
*/
if (udev->parent && !PMSG_IS_AUTO(msg))
status = 0;
+
+ /*
+ * If the device is inaccessible, don't try to resume
+ * suspended interfaces and just return the error.
+ */
+ if (status && status != -EBUSY) {
+ int err;
+ u16 devstat;
+
+ err = usb_get_status(udev, USB_RECIP_DEVICE, 0,
+ &devstat);
+ if (err) {
+ dev_err(&udev->dev,
+ "Failed to suspend device, error %d\n",
+ status);
+ goto done;
+ }
+ }
}
/* If the suspend failed, resume interfaces that did get suspended */
@@ -1772,6 +1790,9 @@
int w, i;
struct usb_interface *intf;
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+
/* Fail if autosuspend is disabled, or any interfaces are in use, or
* any interface drivers require remote wakeup but it isn't available.
*/
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 822ced9..422ce7b 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -27,6 +27,7 @@
#define MAX_USB_MINORS 256
static const struct file_operations *usb_minors[MAX_USB_MINORS];
static DECLARE_RWSEM(minor_rwsem);
+static DEFINE_MUTEX(init_usb_class_mutex);
static int usb_open(struct inode *inode, struct file *file)
{
@@ -109,8 +110,9 @@
static void destroy_usb_class(void)
{
- if (usb_class)
- kref_put(&usb_class->kref, release_usb_class);
+ mutex_lock(&init_usb_class_mutex);
+ kref_put(&usb_class->kref, release_usb_class);
+ mutex_unlock(&init_usb_class_mutex);
}
int usb_major_init(void)
@@ -171,7 +173,10 @@
if (intf->minor >= 0)
return -EADDRINUSE;
+ mutex_lock(&init_usb_class_mutex);
retval = init_usb_class();
+ mutex_unlock(&init_usb_class_mutex);
+
if (retval)
return retval;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index edb7a9a..7388f73 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1075,6 +1075,9 @@
portstatus = portchange = 0;
status = hub_port_status(hub, port1, &portstatus, &portchange);
+ if (status)
+ goto abort;
+
if (udev || (portstatus & USB_PORT_STAT_CONNECTION))
dev_dbg(&port_dev->dev, "status %04x change %04x\n",
portstatus, portchange);
@@ -1207,7 +1210,7 @@
/* Scan all ports that need attention */
kick_hub_wq(hub);
-
+ abort:
if (type == HUB_INIT2 || type == HUB_INIT3) {
/* Allow autosuspend if it was suppressed */
disconnected:
@@ -2093,6 +2096,12 @@
dev_info(&udev->dev, "USB disconnect, device number %d\n",
udev->devnum);
+ /*
+ * Ensure that the pm runtime code knows that the USB device
+ * is in the process of being disconnected.
+ */
+ pm_runtime_barrier(&udev->dev);
+
usb_lock_device(udev);
hub_disconnect_children(udev);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index a159011..38614fa 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -3743,7 +3743,8 @@
}
}
- power_supply_get_property(mdwc->usb_psy, POWER_SUPPLY_PROP_TYPE, &pval);
+ power_supply_get_property(mdwc->usb_psy,
+ POWER_SUPPLY_PROP_REAL_TYPE, &pval);
if (pval.intval != POWER_SUPPLY_TYPE_USB)
return 0;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index da284fe..b040fdd 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -562,6 +562,7 @@
choice
tristate "USB Gadget Drivers"
default USB_ETH
+ optional
help
A Linux "Gadget Driver" talks to the USB Peripheral Controller
driver through the abstract "gadget" API. Some other operating
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index af1bca6..ea17164 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -591,14 +591,10 @@
ssize_t r = count;
unsigned xfer;
int ret = 0;
- size_t len;
+ size_t len = 0;
DBG(cdev, "mtp_read(%zu) state:%d\n", count, dev->state);
- len = usb_ep_align_maybe(cdev->gadget, dev->ep_out, count);
- if (len > MTP_BULK_BUFFER_SIZE)
- return -EINVAL;
-
/* we will block until we're online */
DBG(cdev, "mtp_read: waiting for online state\n");
ret = wait_event_interruptible(dev->read_wq,
@@ -613,6 +609,14 @@
return -EINVAL;
spin_lock_irq(&dev->lock);
+ if (dev->ep_out->desc) {
+ len = usb_ep_align_maybe(cdev->gadget, dev->ep_out, count);
+ if (len > MTP_BULK_BUFFER_SIZE) {
+ spin_unlock_irq(&dev->lock);
+ return -EINVAL;
+ }
+ }
+
if (dev->state == STATE_CANCELED) {
/* report cancelation to userspace */
dev->state = STATE_READY;
@@ -968,6 +972,10 @@
break;
}
+ if (read_req->status) {
+ r = read_req->status;
+ break;
+ }
/* Check if we aligned the size due to MTU constraint */
if (count < read_req->length)
read_req->actual = (read_req->actual > count ?
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index b59efd2..40504c8 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1494,6 +1494,17 @@
*/
max_esit_payload = xhci_get_max_esit_payload(udev, ep);
interval = xhci_get_endpoint_interval(udev, ep);
+
+ /* Periodic endpoint bInterval limit quirk */
+ if (usb_endpoint_xfer_int(&ep->desc) ||
+ usb_endpoint_xfer_isoc(&ep->desc)) {
+ if ((xhci->quirks & XHCI_LIMIT_ENDPOINT_INTERVAL_7) &&
+ udev->speed >= USB_SPEED_HIGH &&
+ interval >= 7) {
+ interval = 6;
+ }
+ }
+
mult = xhci_get_endpoint_mult(udev, ep);
max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
max_burst = xhci_get_endpoint_max_burst(udev, ep);
@@ -2752,7 +2763,7 @@
(xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) |
xhci->cmd_ring->cycle_state;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Setting command ring address to 0x%x", val);
+ "// Setting command ring address to 0x%016llx", val_64);
xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
xhci_dbg_cmd_ptrs(xhci);
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 954abfd..93f566c 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -199,6 +199,9 @@
pdev->device == 0x1042)
xhci->quirks |= XHCI_BROKEN_STREAMS;
+ if (pdev->vendor == PCI_VENDOR_ID_TI && pdev->device == 0x8241)
+ xhci->quirks |= XHCI_LIMIT_ENDPOINT_INTERVAL_7;
+
if (xhci->quirks & XHCI_RESET_ON_RESUME)
xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
"QUIRK: Resetting on resume");
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 918f659..86d578e 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1667,6 +1667,7 @@
#define XHCI_MISSING_CAS (1 << 24)
/* For controller with a broken Port Disable implementation */
#define XHCI_BROKEN_PORT_PED (1 << 25)
+#define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
unsigned int num_active_eps;
unsigned int limit_active_eps;
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 5c8210d..d94927e 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -159,6 +159,7 @@
case USB_ENDPOINT_XFER_INT:
if (dev->info->intr)
goto try_intr;
+ continue;
case USB_ENDPOINT_XFER_ISOC:
if (dev->info->iso)
goto try_iso;
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 3ee2938..d951abb 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -2374,7 +2374,7 @@
pd->vbus_present = val.intval;
ret = power_supply_get_property(pd->usb_psy,
- POWER_SUPPLY_PROP_TYPE, &val);
+ POWER_SUPPLY_PROP_REAL_TYPE, &val);
if (ret) {
usbpd_err(&pd->dev, "Unable to read USB TYPE: %d\n", ret);
return ret;
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index d8d13ee..1dc75db 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -873,6 +873,7 @@
{ USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID,
USB_CLASS_VENDOR_SPEC,
USB_SUBCLASS_VENDOR_SPEC, 0x00) },
+ { USB_DEVICE_INTERFACE_NUMBER(ACTEL_VID, MICROSEMI_ARROW_SF2PLUS_BOARD_PID, 2) },
{ USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
{ USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 48ee04c..71fb9e5 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -873,6 +873,12 @@
#define FIC_VID 0x1457
#define FIC_NEO1973_DEBUG_PID 0x5118
+/*
+ * Actel / Microsemi
+ */
+#define ACTEL_VID 0x1514
+#define MICROSEMI_ARROW_SF2PLUS_BOARD_PID 0x2008
+
/* Olimex */
#define OLIMEX_VID 0x15BA
#define OLIMEX_ARM_USB_OCD_PID 0x0003
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 2ba1942..1d48e62 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -130,57 +130,36 @@
rb_erase(&old->node, &iommu->dma_list);
}
-struct vwork {
- struct mm_struct *mm;
- long npage;
- struct work_struct work;
-};
-
-/* delayed decrement/increment for locked_vm */
-static void vfio_lock_acct_bg(struct work_struct *work)
+static int vfio_lock_acct(long npage, bool *lock_cap)
{
- struct vwork *vwork = container_of(work, struct vwork, work);
- struct mm_struct *mm;
+ int ret;
- mm = vwork->mm;
- down_write(&mm->mmap_sem);
- mm->locked_vm += vwork->npage;
- up_write(&mm->mmap_sem);
- mmput(mm);
- kfree(vwork);
-}
+ if (!npage)
+ return 0;
-static void vfio_lock_acct(long npage)
-{
- struct vwork *vwork;
- struct mm_struct *mm;
+ if (!current->mm)
+ return -ESRCH; /* process exited */
- if (!current->mm || !npage)
- return; /* process exited or nothing to do */
+ ret = down_write_killable(¤t->mm->mmap_sem);
+ if (!ret) {
+ if (npage > 0) {
+ if (lock_cap ? !*lock_cap : !capable(CAP_IPC_LOCK)) {
+ unsigned long limit;
- if (down_write_trylock(¤t->mm->mmap_sem)) {
- current->mm->locked_vm += npage;
+ limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+
+ if (current->mm->locked_vm + npage > limit)
+ ret = -ENOMEM;
+ }
+ }
+
+ if (!ret)
+ current->mm->locked_vm += npage;
+
up_write(¤t->mm->mmap_sem);
- return;
}
- /*
- * Couldn't get mmap_sem lock, so must setup to update
- * mm->locked_vm later. If locked_vm were atomic, we
- * wouldn't need this silliness
- */
- vwork = kmalloc(sizeof(struct vwork), GFP_KERNEL);
- if (!vwork)
- return;
- mm = get_task_mm(current);
- if (!mm) {
- kfree(vwork);
- return;
- }
- INIT_WORK(&vwork->work, vfio_lock_acct_bg);
- vwork->mm = mm;
- vwork->npage = npage;
- schedule_work(&vwork->work);
+ return ret;
}
/*
@@ -262,9 +241,9 @@
static long vfio_pin_pages(unsigned long vaddr, long npage,
int prot, unsigned long *pfn_base)
{
- unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+ unsigned long pfn = 0, limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
bool lock_cap = capable(CAP_IPC_LOCK);
- long ret, i;
+ long ret, i = 1;
bool rsvd;
if (!current->mm)
@@ -283,16 +262,11 @@
return -ENOMEM;
}
- if (unlikely(disable_hugepages)) {
- if (!rsvd)
- vfio_lock_acct(1);
- return 1;
- }
+ if (unlikely(disable_hugepages))
+ goto out;
/* Lock all the consecutive pages from pfn_base */
- for (i = 1, vaddr += PAGE_SIZE; i < npage; i++, vaddr += PAGE_SIZE) {
- unsigned long pfn = 0;
-
+ for (vaddr += PAGE_SIZE; i < npage; i++, vaddr += PAGE_SIZE) {
ret = vaddr_get_pfn(vaddr, prot, &pfn);
if (ret)
break;
@@ -308,12 +282,24 @@
put_pfn(pfn, prot);
pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n",
__func__, limit << PAGE_SHIFT);
- break;
+ ret = -ENOMEM;
+ goto unpin_out;
}
}
+out:
if (!rsvd)
- vfio_lock_acct(i);
+ ret = vfio_lock_acct(i, &lock_cap);
+
+unpin_out:
+ if (ret) {
+ if (!rsvd) {
+ for (pfn = *pfn_base ; i ; pfn++, i--)
+ put_pfn(pfn, prot);
+ }
+
+ return ret;
+ }
return i;
}
@@ -328,7 +314,7 @@
unlocked += put_pfn(pfn++, prot);
if (do_accounting)
- vfio_lock_acct(-unlocked);
+ vfio_lock_acct(-unlocked, NULL);
return unlocked;
}
@@ -390,7 +376,7 @@
cond_resched();
}
- vfio_lock_acct(-unlocked);
+ vfio_lock_acct(-unlocked, NULL);
}
static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 9ad527f..2924bddb 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -102,12 +102,11 @@
{
struct address_space *mapping = bdev->bd_inode->i_mapping;
- if (mapping->nrpages == 0)
- return;
-
- invalidate_bh_lrus();
- lru_add_drain_all(); /* make sure all lru add caches are flushed */
- invalidate_mapping_pages(mapping, 0, -1);
+ if (mapping->nrpages) {
+ invalidate_bh_lrus();
+ lru_add_drain_all(); /* make sure all lru add caches are flushed */
+ invalidate_mapping_pages(mapping, 0, -1);
+ }
/* 99% of the time, we don't need to flush the cleancache on the bdev.
* But, for the strange corners, lets be cautious
*/
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
index febc28f..75267cd 100644
--- a/fs/ceph/xattr.c
+++ b/fs/ceph/xattr.c
@@ -392,6 +392,7 @@
if (update_xattr) {
int err = 0;
+
if (xattr && (flags & XATTR_CREATE))
err = -EEXIST;
else if (!xattr && (flags & XATTR_REPLACE))
@@ -399,12 +400,14 @@
if (err) {
kfree(name);
kfree(val);
+ kfree(*newxattr);
return err;
}
if (update_xattr < 0) {
if (xattr)
__remove_xattr(ci, xattr);
kfree(name);
+ kfree(*newxattr);
return 0;
}
}
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index 02b071bf..a0b3e7d 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -83,6 +83,9 @@
case SFM_COLON:
*target = ':';
break;
+ case SFM_DOUBLEQUOTE:
+ *target = '"';
+ break;
case SFM_ASTERISK:
*target = '*';
break;
@@ -418,6 +421,9 @@
case ':':
dest_char = cpu_to_le16(SFM_COLON);
break;
+ case '"':
+ dest_char = cpu_to_le16(SFM_DOUBLEQUOTE);
+ break;
case '*':
dest_char = cpu_to_le16(SFM_ASTERISK);
break;
diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
index 479bc0a..07ade70 100644
--- a/fs/cifs/cifs_unicode.h
+++ b/fs/cifs/cifs_unicode.h
@@ -57,6 +57,7 @@
* not conflict (although almost does) with the mapping above.
*/
+#define SFM_DOUBLEQUOTE ((__u16) 0xF020)
#define SFM_ASTERISK ((__u16) 0xF021)
#define SFM_QUESTION ((__u16) 0xF025)
#define SFM_COLON ((__u16) 0xF022)
@@ -64,8 +65,8 @@
#define SFM_LESSTHAN ((__u16) 0xF023)
#define SFM_PIPE ((__u16) 0xF027)
#define SFM_SLASH ((__u16) 0xF026)
-#define SFM_PERIOD ((__u16) 0xF028)
-#define SFM_SPACE ((__u16) 0xF029)
+#define SFM_SPACE ((__u16) 0xF028)
+#define SFM_PERIOD ((__u16) 0xF029)
/*
* Mapping mechanism to use when one of the seven reserved characters is
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 15261ba..c0c2530 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -87,6 +87,7 @@
extern mempool_t *cifs_mid_poolp;
struct workqueue_struct *cifsiod_wq;
+struct workqueue_struct *cifsoplockd_wq;
__u32 cifs_lock_secret;
/*
@@ -1283,9 +1284,16 @@
goto out_clean_proc;
}
+ cifsoplockd_wq = alloc_workqueue("cifsoplockd",
+ WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
+ if (!cifsoplockd_wq) {
+ rc = -ENOMEM;
+ goto out_destroy_cifsiod_wq;
+ }
+
rc = cifs_fscache_register();
if (rc)
- goto out_destroy_wq;
+ goto out_destroy_cifsoplockd_wq;
rc = cifs_init_inodecache();
if (rc)
@@ -1333,7 +1341,9 @@
cifs_destroy_inodecache();
out_unreg_fscache:
cifs_fscache_unregister();
-out_destroy_wq:
+out_destroy_cifsoplockd_wq:
+ destroy_workqueue(cifsoplockd_wq);
+out_destroy_cifsiod_wq:
destroy_workqueue(cifsiod_wq);
out_clean_proc:
cifs_proc_clean();
@@ -1356,6 +1366,7 @@
cifs_destroy_mids();
cifs_destroy_inodecache();
cifs_fscache_unregister();
+ destroy_workqueue(cifsoplockd_wq);
destroy_workqueue(cifsiod_wq);
cifs_proc_clean();
}
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b3830f7..48ef401 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1651,6 +1651,7 @@
extern const struct slow_work_ops cifs_oplock_break_ops;
extern struct workqueue_struct *cifsiod_wq;
+extern struct workqueue_struct *cifsoplockd_wq;
extern __u32 cifs_lock_secret;
extern mempool_t *cifs_mid_poolp;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 586fdac..1f91c9d 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -717,6 +717,9 @@
if (rc)
return rc;
+ if (server->capabilities & CAP_UNICODE)
+ smb->hdr.Flags2 |= SMBFLG2_UNICODE;
+
/* set up echo request */
smb->hdr.Tid = 0xffff;
smb->hdr.WordCount = 1;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index b8015de..1a54569 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2839,16 +2839,14 @@
{
struct cifs_sb_info *old = CIFS_SB(sb);
struct cifs_sb_info *new = mnt_data->cifs_sb;
+ bool old_set = old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH;
+ bool new_set = new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH;
- if (old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) {
- if (!(new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH))
- return 0;
- /* The prepath should be null terminated strings */
- if (strcmp(new->prepath, old->prepath))
- return 0;
-
+ if (old_set && new_set && !strcmp(new->prepath, old->prepath))
return 1;
- }
+ else if (!old_set && !new_set)
+ return 1;
+
return 0;
}
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 0015287..bdba9e7 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -264,10 +264,14 @@
rc = -EOPNOTSUPP;
break;
case CIFS_IOC_GET_MNT_INFO:
+ if (pSMBFile == NULL)
+ break;
tcon = tlink_tcon(pSMBFile->tlink);
rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg);
break;
case CIFS_ENUMERATE_SNAPSHOTS:
+ if (pSMBFile == NULL)
+ break;
if (arg == 0) {
rc = -EINVAL;
goto cifs_ioc_exit;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index c672915..5419afe 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -492,7 +492,7 @@
CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
&pCifsInode->flags);
- queue_work(cifsiod_wq,
+ queue_work(cifsoplockd_wq,
&netfile->oplock_break);
netfile->oplock_break_cancelled = false;
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 9730780..967dfe6 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -494,7 +494,7 @@
else
cfile->oplock_break_cancelled = true;
- queue_work(cifsiod_wq, &cfile->oplock_break);
+ queue_work(cifsoplockd_wq, &cfile->oplock_break);
kfree(lw);
return true;
}
@@ -638,7 +638,8 @@
CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
&cinode->flags);
spin_unlock(&cfile->file_info_lock);
- queue_work(cifsiod_wq, &cfile->oplock_break);
+ queue_work(cifsoplockd_wq,
+ &cfile->oplock_break);
spin_unlock(&tcon->open_file_lock);
spin_unlock(&cifs_tcp_ses_lock);
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 007abf7..36334fe 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -924,6 +924,7 @@
}
if (snapshot_in.snapshot_array_size < sizeof(struct smb_snapshot_array)) {
rc = -ERANGE;
+ kfree(retbuf);
return rc;
}
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 8021853..7c1c6c3 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -569,8 +569,12 @@
}
if (rsplen != sizeof(struct validate_negotiate_info_rsp)) {
- cifs_dbg(VFS, "invalid size of protocol negotiate response\n");
- return -EIO;
+ cifs_dbg(VFS, "invalid protocol negotiate response size: %d\n",
+ rsplen);
+
+ /* relax check since Mac returns max bufsize allowed on ioctl */
+ if (rsplen > CIFSMaxBufSize)
+ return -EIO;
}
/* check validate negotiate info response matches what we got earlier */
@@ -1670,8 +1674,12 @@
* than one credit. Windows typically sets this smaller, but for some
* ioctls it may be useful to allow server to send more. No point
* limiting what the server can send as long as fits in one credit
+ * Unfortunately - we can not handle more than CIFS_MAX_MSG_SIZE
+ * (by default, note that it can be overridden to make max larger)
+ * in responses (except for read responses which can be bigger.
+ * We may want to bump this limit up
*/
- req->MaxOutputResponse = cpu_to_le32(0xFF00); /* < 64K uses 1 credit */
+ req->MaxOutputResponse = cpu_to_le32(CIFSMaxBufSize);
if (is_fsctl)
req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL);
diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
index abc1884..bb4e209 100644
--- a/fs/crypto/policy.c
+++ b/fs/crypto/policy.c
@@ -161,27 +161,61 @@
}
EXPORT_SYMBOL(fscrypt_get_policy);
+/**
+ * fscrypt_has_permitted_context() - is a file's encryption policy permitted
+ * within its directory?
+ *
+ * @parent: inode for parent directory
+ * @child: inode for file being looked up, opened, or linked into @parent
+ *
+ * Filesystems must call this before permitting access to an inode in a
+ * situation where the parent directory is encrypted (either before allowing
+ * ->lookup() to succeed, or for a regular file before allowing it to be opened)
+ * and before any operation that involves linking an inode into an encrypted
+ * directory, including link, rename, and cross rename. It enforces the
+ * constraint that within a given encrypted directory tree, all files use the
+ * same encryption policy. The pre-access check is needed to detect potentially
+ * malicious offline violations of this constraint, while the link and rename
+ * checks are needed to prevent online violations of this constraint.
+ *
+ * Return: 1 if permitted, 0 if forbidden. If forbidden, the caller must fail
+ * the filesystem operation with EPERM.
+ */
int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
{
- struct fscrypt_info *parent_ci, *child_ci;
+ const struct fscrypt_operations *cops = parent->i_sb->s_cop;
+ const struct fscrypt_info *parent_ci, *child_ci;
+ struct fscrypt_context parent_ctx, child_ctx;
int res;
- if ((parent == NULL) || (child == NULL)) {
- printk(KERN_ERR "parent %p child %p\n", parent, child);
- BUG_ON(1);
- }
-
/* No restrictions on file types which are never encrypted */
if (!S_ISREG(child->i_mode) && !S_ISDIR(child->i_mode) &&
!S_ISLNK(child->i_mode))
return 1;
- /* no restrictions if the parent directory is not encrypted */
- if (!parent->i_sb->s_cop->is_encrypted(parent))
+ /* No restrictions if the parent directory is unencrypted */
+ if (!cops->is_encrypted(parent))
return 1;
- /* if the child directory is not encrypted, this is always a problem */
- if (!parent->i_sb->s_cop->is_encrypted(child))
+
+ /* Encrypted directories must not contain unencrypted files */
+ if (!cops->is_encrypted(child))
return 0;
+
+ /*
+ * Both parent and child are encrypted, so verify they use the same
+ * encryption policy. Compare the fscrypt_info structs if the keys are
+ * available, otherwise retrieve and compare the fscrypt_contexts.
+ *
+ * Note that the fscrypt_context retrieval will be required frequently
+ * when accessing an encrypted directory tree without the key.
+ * Performance-wise this is not a big deal because we already don't
+ * really optimize for file access without the key (to the extent that
+ * such access is even possible), given that any attempted access
+ * already causes a fscrypt_context retrieval and keyring search.
+ *
+ * In any case, if an unexpected error occurs, fall back to "forbidden".
+ */
+
res = fscrypt_get_encryption_info(parent);
if (res)
return 0;
@@ -190,17 +224,32 @@
return 0;
parent_ci = parent->i_crypt_info;
child_ci = child->i_crypt_info;
- if (!parent_ci && !child_ci)
- return 1;
- if (!parent_ci || !child_ci)
+
+ if (parent_ci && child_ci) {
+ return memcmp(parent_ci->ci_master_key, child_ci->ci_master_key,
+ FS_KEY_DESCRIPTOR_SIZE) == 0 &&
+ (parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
+ (parent_ci->ci_filename_mode ==
+ child_ci->ci_filename_mode) &&
+ (parent_ci->ci_flags == child_ci->ci_flags);
+ }
+
+ res = cops->get_context(parent, &parent_ctx, sizeof(parent_ctx));
+ if (res != sizeof(parent_ctx))
return 0;
- return (memcmp(parent_ci->ci_master_key,
- child_ci->ci_master_key,
- FS_KEY_DESCRIPTOR_SIZE) == 0 &&
- (parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
- (parent_ci->ci_filename_mode == child_ci->ci_filename_mode) &&
- (parent_ci->ci_flags == child_ci->ci_flags));
+ res = cops->get_context(child, &child_ctx, sizeof(child_ctx));
+ if (res != sizeof(child_ctx))
+ return 0;
+
+ return memcmp(parent_ctx.master_key_descriptor,
+ child_ctx.master_key_descriptor,
+ FS_KEY_DESCRIPTOR_SIZE) == 0 &&
+ (parent_ctx.contents_encryption_mode ==
+ child_ctx.contents_encryption_mode) &&
+ (parent_ctx.filenames_encryption_mode ==
+ child_ctx.filenames_encryption_mode) &&
+ (parent_ctx.flags == child_ctx.flags);
}
EXPORT_SYMBOL(fscrypt_has_permitted_context);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 3cb7fa2..42723b2 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -5741,6 +5741,11 @@
file_update_time(vma->vm_file);
down_read(&EXT4_I(inode)->i_mmap_sem);
+
+ ret = ext4_convert_inline_data(inode);
+ if (ret)
+ goto out_ret;
+
/* Delalloc case is easy... */
if (test_opt(inode->i_sb, DELALLOC) &&
!ext4_should_journal_data(inode) &&
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index ef3b4eb..08ecdee 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -223,8 +223,7 @@
if (ret)
goto out;
- if ((iattr->ia_valid & ATTR_SIZE) &&
- iattr->ia_size != i_size_read(inode)) {
+ if (iattr->ia_valid & ATTR_SIZE) {
ret = orangefs_setattr_size(inode, iattr);
if (ret)
goto out;
diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c
index a290ff6..7c31593 100644
--- a/fs/orangefs/namei.c
+++ b/fs/orangefs/namei.c
@@ -193,8 +193,6 @@
goto out;
}
- ORANGEFS_I(inode)->getattr_time = jiffies - 1;
-
gossip_debug(GOSSIP_NAME_DEBUG,
"%s:%s:%d "
"Found good inode [%lu] with count [%d]\n",
diff --git a/fs/orangefs/xattr.c b/fs/orangefs/xattr.c
index 74a81b1..237c9c0 100644
--- a/fs/orangefs/xattr.c
+++ b/fs/orangefs/xattr.c
@@ -76,11 +76,8 @@
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
- if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) {
- gossip_err("Invalid key length (%d)\n",
- (int)strlen(name));
+ if (strlen(name) > ORANGEFS_MAX_XATTR_NAMELEN)
return -EINVAL;
- }
fsuid = from_kuid(&init_user_ns, current_fsuid());
fsgid = from_kgid(&init_user_ns, current_fsgid());
@@ -172,6 +169,9 @@
struct orangefs_kernel_op_s *new_op = NULL;
int ret = -ENOMEM;
+ if (strlen(name) > ORANGEFS_MAX_XATTR_NAMELEN)
+ return -EINVAL;
+
down_write(&orangefs_inode->xattr_sem);
new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR);
if (!new_op)
@@ -231,23 +231,13 @@
"%s: name %s, buffer_size %zd\n",
__func__, name, size);
- if (size >= ORANGEFS_MAX_XATTR_VALUELEN ||
- flags < 0) {
- gossip_err("orangefs_inode_setxattr: bogus values of size(%d), flags(%d)\n",
- (int)size,
- flags);
+ if (size > ORANGEFS_MAX_XATTR_VALUELEN)
return -EINVAL;
- }
+ if (strlen(name) > ORANGEFS_MAX_XATTR_NAMELEN)
+ return -EINVAL;
internal_flag = convert_to_internal_xattr_flags(flags);
- if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) {
- gossip_err
- ("orangefs_inode_setxattr: bogus key size (%d)\n",
- (int)(strlen(name)));
- return -EINVAL;
- }
-
/* This is equivalent to a removexattr */
if (size == 0 && value == NULL) {
gossip_debug(GOSSIP_XATTR_DEBUG,
@@ -358,7 +348,7 @@
returned_count = new_op->downcall.resp.listxattr.returned_count;
if (returned_count < 0 ||
- returned_count >= ORANGEFS_MAX_XATTR_LISTLEN) {
+ returned_count > ORANGEFS_MAX_XATTR_LISTLEN) {
gossip_err("%s: impossible value for returned_count:%d:\n",
__func__,
returned_count);
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 14984d9..43033a3 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -704,6 +704,7 @@
if (psi->flags & PSTORE_FLAGS_PMSG)
pstore_register_pmsg();
+ /* Start watching for new records, if desired. */
if (pstore_update_ms >= 0) {
pstore_timer.expires = jiffies +
msecs_to_jiffies(pstore_update_ms);
@@ -726,6 +727,11 @@
void pstore_unregister(struct pstore_info *psi)
{
+ /* Stop timer and make sure all work has finished. */
+ pstore_update_ms = -1;
+ del_timer_sync(&pstore_timer);
+ flush_work(&pstore_work);
+
if (psi->flags & PSTORE_FLAGS_PMSG)
pstore_unregister_pmsg();
if (psi->flags & PSTORE_FLAGS_FTRACE)
@@ -825,7 +831,9 @@
schedule_work(&pstore_work);
}
- mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms));
+ if (pstore_update_ms >= 0)
+ mod_timer(&pstore_timer,
+ jiffies + msecs_to_jiffies(pstore_update_ms));
}
module_param(backend, charp, 0444);
diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c
index ae2b4ba..a231681 100644
--- a/fs/sdcardfs/dentry.c
+++ b/fs/sdcardfs/dentry.c
@@ -34,6 +34,8 @@
struct dentry *parent_lower_dentry = NULL;
struct dentry *lower_cur_parent_dentry = NULL;
struct dentry *lower_dentry = NULL;
+ struct inode *inode;
+ struct sdcardfs_inode_data *data;
if (flags & LOOKUP_RCU)
return -ECHILD;
@@ -103,6 +105,19 @@
spin_unlock(&dentry->d_lock);
spin_unlock(&lower_dentry->d_lock);
}
+ if (!err)
+ goto out;
+
+ /* If our top's inode is gone, we may be out of date */
+ inode = d_inode(dentry);
+ if (inode) {
+ data = top_data_get(SDCARDFS_I(inode));
+ if (data->abandoned) {
+ d_drop(dentry);
+ err = 0;
+ }
+ data_put(data);
+ }
out:
dput(parent_dentry);
diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c
index 5a0ef38..1239d1c 100644
--- a/fs/sdcardfs/derived_perm.c
+++ b/fs/sdcardfs/derived_perm.c
@@ -26,28 +26,28 @@
struct sdcardfs_inode_info *pi = SDCARDFS_I(parent);
struct sdcardfs_inode_info *ci = SDCARDFS_I(child);
- ci->perm = PERM_INHERIT;
- ci->userid = pi->userid;
- ci->d_uid = pi->d_uid;
- ci->under_android = pi->under_android;
- ci->under_cache = pi->under_cache;
- ci->under_obb = pi->under_obb;
- set_top(ci, pi->top);
+ ci->data->perm = PERM_INHERIT;
+ ci->data->userid = pi->data->userid;
+ ci->data->d_uid = pi->data->d_uid;
+ ci->data->under_android = pi->data->under_android;
+ ci->data->under_cache = pi->data->under_cache;
+ ci->data->under_obb = pi->data->under_obb;
+ set_top(ci, pi->top_data);
}
/* helper function for derived state */
void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid,
- uid_t uid, bool under_android,
- struct inode *top)
+ uid_t uid, bool under_android,
+ struct sdcardfs_inode_data *top)
{
struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
- info->perm = perm;
- info->userid = userid;
- info->d_uid = uid;
- info->under_android = under_android;
- info->under_cache = false;
- info->under_obb = false;
+ info->data->perm = perm;
+ info->data->userid = userid;
+ info->data->d_uid = uid;
+ info->data->under_android = under_android;
+ info->data->under_cache = false;
+ info->data->under_obb = false;
set_top(info, top);
}
@@ -58,7 +58,8 @@
const struct qstr *name)
{
struct sdcardfs_inode_info *info = SDCARDFS_I(d_inode(dentry));
- struct sdcardfs_inode_info *parent_info = SDCARDFS_I(d_inode(parent));
+ struct sdcardfs_inode_data *parent_data =
+ SDCARDFS_I(d_inode(parent))->data;
appid_t appid;
unsigned long user_num;
int err;
@@ -82,60 +83,61 @@
if (!S_ISDIR(d_inode(dentry)->i_mode))
return;
/* Derive custom permissions based on parent and current node */
- switch (parent_info->perm) {
+ switch (parent_data->perm) {
case PERM_INHERIT:
case PERM_ANDROID_PACKAGE_CACHE:
/* Already inherited above */
break;
case PERM_PRE_ROOT:
/* Legacy internal layout places users at top level */
- info->perm = PERM_ROOT;
+ info->data->perm = PERM_ROOT;
err = kstrtoul(name->name, 10, &user_num);
if (err)
- info->userid = 0;
+ info->data->userid = 0;
else
- info->userid = user_num;
- set_top(info, &info->vfs_inode);
+ info->data->userid = user_num;
+ set_top(info, info->data);
break;
case PERM_ROOT:
/* Assume masked off by default. */
if (qstr_case_eq(name, &q_Android)) {
/* App-specific directories inside; let anyone traverse */
- info->perm = PERM_ANDROID;
- info->under_android = true;
- set_top(info, &info->vfs_inode);
+ info->data->perm = PERM_ANDROID;
+ info->data->under_android = true;
+ set_top(info, info->data);
}
break;
case PERM_ANDROID:
if (qstr_case_eq(name, &q_data)) {
/* App-specific directories inside; let anyone traverse */
- info->perm = PERM_ANDROID_DATA;
- set_top(info, &info->vfs_inode);
+ info->data->perm = PERM_ANDROID_DATA;
+ set_top(info, info->data);
} else if (qstr_case_eq(name, &q_obb)) {
/* App-specific directories inside; let anyone traverse */
- info->perm = PERM_ANDROID_OBB;
- info->under_obb = true;
- set_top(info, &info->vfs_inode);
+ info->data->perm = PERM_ANDROID_OBB;
+ info->data->under_obb = true;
+ set_top(info, info->data);
/* Single OBB directory is always shared */
} else if (qstr_case_eq(name, &q_media)) {
/* App-specific directories inside; let anyone traverse */
- info->perm = PERM_ANDROID_MEDIA;
- set_top(info, &info->vfs_inode);
+ info->data->perm = PERM_ANDROID_MEDIA;
+ set_top(info, info->data);
}
break;
case PERM_ANDROID_OBB:
case PERM_ANDROID_DATA:
case PERM_ANDROID_MEDIA:
- info->perm = PERM_ANDROID_PACKAGE;
+ info->data->perm = PERM_ANDROID_PACKAGE;
appid = get_appid(name->name);
- if (appid != 0 && !is_excluded(name->name, parent_info->userid))
- info->d_uid = multiuser_get_uid(parent_info->userid, appid);
- set_top(info, &info->vfs_inode);
+ if (appid != 0 && !is_excluded(name->name, parent_data->userid))
+ info->data->d_uid =
+ multiuser_get_uid(parent_data->userid, appid);
+ set_top(info, info->data);
break;
case PERM_ANDROID_PACKAGE:
if (qstr_case_eq(name, &q_cache)) {
- info->perm = PERM_ANDROID_PACKAGE_CACHE;
- info->under_cache = true;
+ info->data->perm = PERM_ANDROID_PACKAGE_CACHE;
+ info->data->under_cache = true;
}
break;
}
@@ -166,7 +168,8 @@
struct inode *delegated_inode = NULL;
int error;
struct sdcardfs_inode_info *info;
- struct sdcardfs_inode_info *info_top;
+ struct sdcardfs_inode_data *info_d;
+ struct sdcardfs_inode_data *info_top;
perm_t perm;
struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
uid_t uid = sbi->options.fs_low_uid;
@@ -174,15 +177,16 @@
struct iattr newattrs;
info = SDCARDFS_I(d_inode(dentry));
- perm = info->perm;
- if (info->under_obb) {
+ info_d = info->data;
+ perm = info_d->perm;
+ if (info_d->under_obb) {
perm = PERM_ANDROID_OBB;
- } else if (info->under_cache) {
+ } else if (info_d->under_cache) {
perm = PERM_ANDROID_PACKAGE_CACHE;
} else if (perm == PERM_INHERIT) {
- info_top = SDCARDFS_I(grab_top(info));
+ info_top = top_data_get(info);
perm = info_top->perm;
- release_top(info);
+ data_put(info_top);
}
switch (perm) {
@@ -192,7 +196,7 @@
case PERM_ANDROID_MEDIA:
case PERM_ANDROID_PACKAGE:
case PERM_ANDROID_PACKAGE_CACHE:
- uid = multiuser_get_uid(info->userid, uid);
+ uid = multiuser_get_uid(info_d->userid, uid);
break;
case PERM_ANDROID_OBB:
uid = AID_MEDIA_OBB;
@@ -207,24 +211,24 @@
case PERM_ANDROID_DATA:
case PERM_ANDROID_MEDIA:
if (S_ISDIR(d_inode(dentry)->i_mode))
- gid = multiuser_get_uid(info->userid, AID_MEDIA_RW);
+ gid = multiuser_get_uid(info_d->userid, AID_MEDIA_RW);
else
- gid = multiuser_get_uid(info->userid, get_type(name));
+ gid = multiuser_get_uid(info_d->userid, get_type(name));
break;
case PERM_ANDROID_OBB:
gid = AID_MEDIA_OBB;
break;
case PERM_ANDROID_PACKAGE:
- if (uid_is_app(info->d_uid))
- gid = multiuser_get_ext_gid(info->d_uid);
+ if (uid_is_app(info_d->d_uid))
+ gid = multiuser_get_ext_gid(info_d->d_uid);
else
- gid = multiuser_get_uid(info->userid, AID_MEDIA_RW);
+ gid = multiuser_get_uid(info_d->userid, AID_MEDIA_RW);
break;
case PERM_ANDROID_PACKAGE_CACHE:
- if (uid_is_app(info->d_uid))
- gid = multiuser_get_ext_cache_gid(info->d_uid);
+ if (uid_is_app(info_d->d_uid))
+ gid = multiuser_get_ext_cache_gid(info_d->d_uid);
else
- gid = multiuser_get_uid(info->userid, AID_MEDIA_RW);
+ gid = multiuser_get_uid(info_d->userid, AID_MEDIA_RW);
break;
case PERM_PRE_ROOT:
default:
@@ -257,11 +261,13 @@
sdcardfs_put_lower_path(dentry, &path);
}
-static int descendant_may_need_fixup(struct sdcardfs_inode_info *info, struct limit_search *limit)
+static int descendant_may_need_fixup(struct sdcardfs_inode_data *data,
+ struct limit_search *limit)
{
- if (info->perm == PERM_ROOT)
- return (limit->flags & BY_USERID)?info->userid == limit->userid:1;
- if (info->perm == PERM_PRE_ROOT || info->perm == PERM_ANDROID)
+ if (data->perm == PERM_ROOT)
+ return (limit->flags & BY_USERID) ?
+ data->userid == limit->userid : 1;
+ if (data->perm == PERM_PRE_ROOT || data->perm == PERM_ANDROID)
return 1;
return 0;
}
@@ -292,7 +298,7 @@
}
info = SDCARDFS_I(d_inode(dentry));
- if (needs_fixup(info->perm)) {
+ if (needs_fixup(info->data->perm)) {
list_for_each_entry(child, &dentry->d_subdirs, d_child) {
spin_lock_nested(&child->d_lock, depth + 1);
if (!(limit->flags & BY_NAME) || qstr_case_eq(&child->d_name, &limit->name)) {
@@ -305,7 +311,7 @@
}
spin_unlock(&child->d_lock);
}
- } else if (descendant_may_need_fixup(info, limit)) {
+ } else if (descendant_may_need_fixup(info->data, limit)) {
list_for_each_entry(child, &dentry->d_subdirs, d_child) {
__fixup_perms_recursive(child, limit, depth + 1);
}
@@ -349,12 +355,12 @@
struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
struct qstr obb = QSTR_LITERAL("obb");
- if (parent_info->perm == PERM_ANDROID &&
+ if (parent_info->data->perm == PERM_ANDROID &&
qstr_case_eq(&dentry->d_name, &obb)) {
/* /Android/obb is the base obbpath of DERIVED_UNIFIED */
if (!(sbi->options.multiuser == false
- && parent_info->userid == 0)) {
+ && parent_info->data->userid == 0)) {
ret = 1;
}
}
@@ -415,11 +421,11 @@
spin_lock(&SDCARDFS_D(dentry)->lock);
if (sbi->options.multiuser) {
- if (parent_info->perm == PERM_PRE_ROOT &&
+ if (parent_info->data->perm == PERM_PRE_ROOT &&
qstr_case_eq(&dentry->d_name, &q_obb)) {
ret = 1;
}
- } else if (parent_info->perm == PERM_ANDROID &&
+ } else if (parent_info->data->perm == PERM_ANDROID &&
qstr_case_eq(&dentry->d_name, &q_obb)) {
ret = 1;
}
diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c
index 4d558b8..d48da41 100644
--- a/fs/sdcardfs/inode.c
+++ b/fs/sdcardfs/inode.c
@@ -23,7 +23,8 @@
#include <linux/ratelimit.h>
/* Do not directly use this function. Use OVERRIDE_CRED() instead. */
-const struct cred *override_fsids(struct sdcardfs_sb_info *sbi, struct sdcardfs_inode_info *info)
+const struct cred *override_fsids(struct sdcardfs_sb_info *sbi,
+ struct sdcardfs_inode_data *data)
{
struct cred *cred;
const struct cred *old_cred;
@@ -33,10 +34,10 @@
if (!cred)
return NULL;
- if (info->under_obb)
+ if (data->under_obb)
uid = AID_MEDIA_OBB;
else
- uid = multiuser_get_uid(info->userid, sbi->options.fs_low_uid);
+ uid = multiuser_get_uid(data->userid, sbi->options.fs_low_uid);
cred->fsuid = make_kuid(&init_user_ns, uid);
cred->fsgid = make_kgid(&init_user_ns, sbi->options.fs_low_gid);
@@ -96,7 +97,8 @@
if (err)
goto out;
- err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path, SDCARDFS_I(dir)->userid);
+ err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path,
+ SDCARDFS_I(dir)->data->userid);
if (err)
goto out;
fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir));
@@ -267,7 +269,7 @@
struct path lower_path;
struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
const struct cred *saved_cred = NULL;
- struct sdcardfs_inode_info *pi = SDCARDFS_I(dir);
+ struct sdcardfs_inode_data *pd = SDCARDFS_I(dir)->data;
int touch_err = 0;
struct fs_struct *saved_fs;
struct fs_struct *copied_fs;
@@ -336,7 +338,7 @@
make_nomedia_in_obb = 1;
}
- err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path, pi->userid);
+ err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path, pd->userid);
if (err) {
unlock_dir(lower_parent_dentry);
goto out;
@@ -349,12 +351,13 @@
fixup_lower_ownership(dentry, dentry->d_name.name);
unlock_dir(lower_parent_dentry);
if ((!sbi->options.multiuser) && (qstr_case_eq(&dentry->d_name, &q_obb))
- && (pi->perm == PERM_ANDROID) && (pi->userid == 0))
+ && (pd->perm == PERM_ANDROID) && (pd->userid == 0))
make_nomedia_in_obb = 1;
/* When creating /Android/data and /Android/obb, mark them as .nomedia */
if (make_nomedia_in_obb ||
- ((pi->perm == PERM_ANDROID) && (qstr_case_eq(&dentry->d_name, &q_data)))) {
+ ((pd->perm == PERM_ANDROID)
+ && (qstr_case_eq(&dentry->d_name, &q_data)))) {
REVERT_CRED(saved_cred);
OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(d_inode(dentry)));
set_fs_pwd(current->fs, &lower_path);
@@ -620,7 +623,7 @@
{
int err;
struct inode tmp;
- struct inode *top = grab_top(SDCARDFS_I(inode));
+ struct sdcardfs_inode_data *top = top_data_get(SDCARDFS_I(inode));
if (!top)
return -EINVAL;
@@ -637,10 +640,11 @@
* locks must be dealt with to avoid undefined behavior.
*/
copy_attrs(&tmp, inode);
- tmp.i_uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid);
- tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, SDCARDFS_I(top)));
- tmp.i_mode = (inode->i_mode & S_IFMT) | get_mode(mnt, SDCARDFS_I(top));
- release_top(SDCARDFS_I(inode));
+ tmp.i_uid = make_kuid(&init_user_ns, top->d_uid);
+ tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, top));
+ tmp.i_mode = (inode->i_mode & S_IFMT)
+ | get_mode(mnt, SDCARDFS_I(inode), top);
+ data_put(top);
tmp.i_sb = inode->i_sb;
if (IS_POSIXACL(inode))
pr_warn("%s: This may be undefined behavior...\n", __func__);
@@ -692,11 +696,12 @@
struct dentry *parent;
struct inode tmp;
struct dentry tmp_d;
- struct inode *top;
+ struct sdcardfs_inode_data *top;
+
const struct cred *saved_cred = NULL;
inode = d_inode(dentry);
- top = grab_top(SDCARDFS_I(inode));
+ top = top_data_get(SDCARDFS_I(inode));
if (!top)
return -EINVAL;
@@ -714,11 +719,12 @@
*
*/
copy_attrs(&tmp, inode);
- tmp.i_uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid);
- tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, SDCARDFS_I(top)));
- tmp.i_mode = (inode->i_mode & S_IFMT) | get_mode(mnt, SDCARDFS_I(top));
+ tmp.i_uid = make_kuid(&init_user_ns, top->d_uid);
+ tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, top));
+ tmp.i_mode = (inode->i_mode & S_IFMT)
+ | get_mode(mnt, SDCARDFS_I(inode), top);
tmp.i_size = i_size_read(inode);
- release_top(SDCARDFS_I(inode));
+ data_put(top);
tmp.i_sb = inode->i_sb;
tmp_d.d_inode = &tmp;
@@ -821,17 +827,17 @@
struct inode *inode, struct kstat *stat)
{
struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
- struct inode *top = grab_top(info);
+ struct sdcardfs_inode_data *top = top_data_get(info);
if (!top)
return -EINVAL;
stat->dev = inode->i_sb->s_dev;
stat->ino = inode->i_ino;
- stat->mode = (inode->i_mode & S_IFMT) | get_mode(mnt, SDCARDFS_I(top));
+ stat->mode = (inode->i_mode & S_IFMT) | get_mode(mnt, info, top);
stat->nlink = inode->i_nlink;
- stat->uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid);
- stat->gid = make_kgid(&init_user_ns, get_gid(mnt, SDCARDFS_I(top)));
+ stat->uid = make_kuid(&init_user_ns, top->d_uid);
+ stat->gid = make_kgid(&init_user_ns, get_gid(mnt, top));
stat->rdev = inode->i_rdev;
stat->size = i_size_read(inode);
stat->atime = inode->i_atime;
@@ -839,7 +845,7 @@
stat->ctime = inode->i_ctime;
stat->blksize = (1 << inode->i_blkbits);
stat->blocks = inode->i_blocks;
- release_top(info);
+ data_put(top);
return 0;
}
diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c
index 706329d..17761c5 100644
--- a/fs/sdcardfs/lookup.c
+++ b/fs/sdcardfs/lookup.c
@@ -71,7 +71,7 @@
static int sdcardfs_inode_test(struct inode *inode, void *candidate_data/*void *candidate_lower_inode*/)
{
struct inode *current_lower_inode = sdcardfs_lower_inode(inode);
- userid_t current_userid = SDCARDFS_I(inode)->userid;
+ userid_t current_userid = SDCARDFS_I(inode)->data->userid;
if (current_lower_inode == ((struct inode_data *)candidate_data)->lower_inode &&
current_userid == ((struct inode_data *)candidate_data)->id)
@@ -438,7 +438,8 @@
goto out;
}
- ret = __sdcardfs_lookup(dentry, flags, &lower_parent_path, SDCARDFS_I(dir)->userid);
+ ret = __sdcardfs_lookup(dentry, flags, &lower_parent_path,
+ SDCARDFS_I(dir)->data->userid);
if (IS_ERR(ret))
goto out;
if (ret)
diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c
index 953d215..3c5b51d 100644
--- a/fs/sdcardfs/main.c
+++ b/fs/sdcardfs/main.c
@@ -327,13 +327,13 @@
mutex_lock(&sdcardfs_super_list_lock);
if (sb_info->options.multiuser) {
setup_derived_state(d_inode(sb->s_root), PERM_PRE_ROOT,
- sb_info->options.fs_user_id, AID_ROOT,
- false, d_inode(sb->s_root));
+ sb_info->options.fs_user_id, AID_ROOT,
+ false, SDCARDFS_I(d_inode(sb->s_root))->data);
snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name);
} else {
setup_derived_state(d_inode(sb->s_root), PERM_ROOT,
- sb_info->options.fs_user_id, AID_ROOT,
- false, d_inode(sb->s_root));
+ sb_info->options.fs_user_id, AID_ROOT,
+ false, SDCARDFS_I(d_inode(sb->s_root))->data);
snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name);
}
fixup_tmp_permissions(d_inode(sb->s_root));
diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c
index 5ea6469..00a0f65 100644
--- a/fs/sdcardfs/packagelist.c
+++ b/fs/sdcardfs/packagelist.c
@@ -156,7 +156,7 @@
struct qstr q_android_secure = QSTR_LITERAL("android_secure");
/* Always block security-sensitive files at root */
- if (parent_node && SDCARDFS_I(parent_node)->perm == PERM_ROOT) {
+ if (parent_node && SDCARDFS_I(parent_node)->data->perm == PERM_ROOT) {
if (qstr_case_eq(name, &q_autorun)
|| qstr_case_eq(name, &q__android_secure)
|| qstr_case_eq(name, &q_android_secure)) {
diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h
index 380982b..3687b22 100644
--- a/fs/sdcardfs/sdcardfs.h
+++ b/fs/sdcardfs/sdcardfs.h
@@ -30,6 +30,7 @@
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/aio.h>
+#include <linux/kref.h>
#include <linux/mm.h>
#include <linux/mount.h>
#include <linux/namei.h>
@@ -81,7 +82,8 @@
*/
#define fixup_tmp_permissions(x) \
do { \
- (x)->i_uid = make_kuid(&init_user_ns, SDCARDFS_I(x)->d_uid); \
+ (x)->i_uid = make_kuid(&init_user_ns, \
+ SDCARDFS_I(x)->data->d_uid); \
(x)->i_gid = make_kgid(&init_user_ns, AID_SDCARD_RW); \
(x)->i_mode = ((x)->i_mode & S_IFMT) | 0775;\
} while (0)
@@ -97,14 +99,14 @@
*/
#define OVERRIDE_CRED(sdcardfs_sbi, saved_cred, info) \
do { \
- saved_cred = override_fsids(sdcardfs_sbi, info); \
+ saved_cred = override_fsids(sdcardfs_sbi, info->data); \
if (!saved_cred) \
return -ENOMEM; \
} while (0)
#define OVERRIDE_CRED_PTR(sdcardfs_sbi, saved_cred, info) \
do { \
- saved_cred = override_fsids(sdcardfs_sbi, info); \
+ saved_cred = override_fsids(sdcardfs_sbi, info->data); \
if (!saved_cred) \
return ERR_PTR(-ENOMEM); \
} while (0)
@@ -142,9 +144,11 @@
struct sdcardfs_sb_info;
struct sdcardfs_mount_options;
struct sdcardfs_inode_info;
+struct sdcardfs_inode_data;
/* Do not directly use this function. Use OVERRIDE_CRED() instead. */
-const struct cred *override_fsids(struct sdcardfs_sb_info *sbi, struct sdcardfs_inode_info *info);
+const struct cred *override_fsids(struct sdcardfs_sb_info *sbi,
+ struct sdcardfs_inode_data *data);
/* Do not directly use this function, use REVERT_CRED() instead. */
void revert_fsids(const struct cred *old_cred);
@@ -178,18 +182,26 @@
const struct vm_operations_struct *lower_vm_ops;
};
-/* sdcardfs inode data in memory */
-struct sdcardfs_inode_info {
- struct inode *lower_inode;
- /* state derived based on current position in hierachy */
+struct sdcardfs_inode_data {
+ struct kref refcount;
+ bool abandoned;
+
perm_t perm;
userid_t userid;
uid_t d_uid;
bool under_android;
bool under_cache;
bool under_obb;
+};
+
+/* sdcardfs inode data in memory */
+struct sdcardfs_inode_info {
+ struct inode *lower_inode;
+ /* state derived based on current position in hierarchy */
+ struct sdcardfs_inode_data *data;
+
/* top folder for ownership */
- struct inode *top;
+ struct sdcardfs_inode_data *top_data;
struct inode vfs_inode;
};
@@ -351,39 +363,56 @@
static inline bool sbinfo_has_sdcard_magic(struct sdcardfs_sb_info *sbinfo)
{
- return sbinfo && sbinfo->sb && sbinfo->sb->s_magic == SDCARDFS_SUPER_MAGIC;
+ return sbinfo && sbinfo->sb
+ && sbinfo->sb->s_magic == SDCARDFS_SUPER_MAGIC;
}
-/* grab a refererence if we aren't linking to ourself */
-static inline void set_top(struct sdcardfs_inode_info *info, struct inode *top)
+static inline struct sdcardfs_inode_data *data_get(
+ struct sdcardfs_inode_data *data)
{
- struct inode *old_top = NULL;
-
- BUG_ON(IS_ERR_OR_NULL(top));
- if (info->top && info->top != &info->vfs_inode)
- old_top = info->top;
- if (top != &info->vfs_inode)
- igrab(top);
- info->top = top;
- iput(old_top);
+ if (data)
+ kref_get(&data->refcount);
+ return data;
}
-static inline struct inode *grab_top(struct sdcardfs_inode_info *info)
+static inline struct sdcardfs_inode_data *top_data_get(
+ struct sdcardfs_inode_info *info)
{
- struct inode *top = info->top;
+ return data_get(info->top_data);
+}
+
+extern void data_release(struct kref *ref);
+
+static inline void data_put(struct sdcardfs_inode_data *data)
+{
+ kref_put(&data->refcount, data_release);
+}
+
+static inline void release_own_data(struct sdcardfs_inode_info *info)
+{
+ /*
+ * This happens exactly once per inode. At this point, the inode that
+ * originally held this data is about to be freed, and all references
+ * to it are held as a top value, and will likely be released soon.
+ */
+ info->data->abandoned = true;
+ data_put(info->data);
+}
+
+static inline void set_top(struct sdcardfs_inode_info *info,
+ struct sdcardfs_inode_data *top)
+{
+ struct sdcardfs_inode_data *old_top = info->top_data;
if (top)
- return igrab(top);
- else
- return NULL;
+ data_get(top);
+ info->top_data = top;
+ if (old_top)
+ data_put(old_top);
}
-static inline void release_top(struct sdcardfs_inode_info *info)
-{
- iput(info->top);
-}
-
-static inline int get_gid(struct vfsmount *mnt, struct sdcardfs_inode_info *info)
+static inline int get_gid(struct vfsmount *mnt,
+ struct sdcardfs_inode_data *data)
{
struct sdcardfs_vfsmount_options *opts = mnt->data;
@@ -396,10 +425,12 @@
*/
return AID_SDCARD_RW;
else
- return multiuser_get_uid(info->userid, opts->gid);
+ return multiuser_get_uid(data->userid, opts->gid);
}
-static inline int get_mode(struct vfsmount *mnt, struct sdcardfs_inode_info *info)
+static inline int get_mode(struct vfsmount *mnt,
+ struct sdcardfs_inode_info *info,
+ struct sdcardfs_inode_data *data)
{
int owner_mode;
int filtered_mode;
@@ -407,12 +438,12 @@
int visible_mode = 0775 & ~opts->mask;
- if (info->perm == PERM_PRE_ROOT) {
+ if (data->perm == PERM_PRE_ROOT) {
/* Top of multi-user view should always be visible to ensure
* secondary users can traverse inside.
*/
visible_mode = 0711;
- } else if (info->under_android) {
+ } else if (data->under_android) {
/* Block "other" access to Android directories, since only apps
* belonging to a specific user should be in there; we still
* leave +x open for the default view.
@@ -481,8 +512,9 @@
userid_t userid;
};
-extern void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid,
- uid_t uid, bool under_android, struct inode *top);
+extern void setup_derived_state(struct inode *inode, perm_t perm,
+ userid_t userid, uid_t uid, bool under_android,
+ struct sdcardfs_inode_data *top);
extern void get_derived_permission(struct dentry *parent, struct dentry *dentry);
extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name);
extern void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit);
@@ -601,7 +633,7 @@
{
dest->i_mode = (src->i_mode & S_IFMT) | S_IRWXU | S_IRWXG |
S_IROTH | S_IXOTH; /* 0775 */
- dest->i_uid = make_kuid(&init_user_ns, SDCARDFS_I(dest)->d_uid);
+ dest->i_uid = make_kuid(&init_user_ns, SDCARDFS_I(dest)->data->d_uid);
dest->i_gid = make_kgid(&init_user_ns, AID_SDCARD_RW);
dest->i_rdev = src->i_rdev;
dest->i_atime = src->i_atime;
diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c
index 8a9c9c7..7f4539b 100644
--- a/fs/sdcardfs/super.c
+++ b/fs/sdcardfs/super.c
@@ -26,6 +26,23 @@
*/
static struct kmem_cache *sdcardfs_inode_cachep;
+/*
+ * To support the top references, we must track some data separately.
+ * An sdcardfs_inode_info always has a reference to its data, and once set up,
+ * also has a reference to its top. The top may be itself, in which case it
+ * holds two references to its data. When top is changed, it takes a ref to the
+ * new data and then drops the ref to the old data.
+ */
+static struct kmem_cache *sdcardfs_inode_data_cachep;
+
+void data_release(struct kref *ref)
+{
+ struct sdcardfs_inode_data *data =
+ container_of(ref, struct sdcardfs_inode_data, refcount);
+
+ kmem_cache_free(sdcardfs_inode_data_cachep, data);
+}
+
/* final actions when unmounting a file system */
static void sdcardfs_put_super(struct super_block *sb)
{
@@ -166,6 +183,7 @@
struct inode *lower_inode;
truncate_inode_pages(&inode->i_data, 0);
+ set_top(SDCARDFS_I(inode), NULL);
clear_inode(inode);
/*
* Decrement a reference to a lower_inode, which was incremented
@@ -173,13 +191,13 @@
*/
lower_inode = sdcardfs_lower_inode(inode);
sdcardfs_set_lower_inode(inode, NULL);
- set_top(SDCARDFS_I(inode), inode);
iput(lower_inode);
}
static struct inode *sdcardfs_alloc_inode(struct super_block *sb)
{
struct sdcardfs_inode_info *i;
+ struct sdcardfs_inode_data *d;
i = kmem_cache_alloc(sdcardfs_inode_cachep, GFP_KERNEL);
if (!i)
@@ -188,6 +206,16 @@
/* memset everything up to the inode to 0 */
memset(i, 0, offsetof(struct sdcardfs_inode_info, vfs_inode));
+ d = kmem_cache_alloc(sdcardfs_inode_data_cachep,
+ GFP_KERNEL | __GFP_ZERO);
+ if (!d) {
+ kmem_cache_free(sdcardfs_inode_cachep, i);
+ return NULL;
+ }
+
+ i->data = d;
+ kref_init(&d->refcount);
+
i->vfs_inode.i_version = 1;
return &i->vfs_inode;
}
@@ -196,6 +224,7 @@
{
struct inode *inode = container_of(head, struct inode, i_rcu);
+ release_own_data(SDCARDFS_I(inode));
kmem_cache_free(sdcardfs_inode_cachep, SDCARDFS_I(inode));
}
@@ -214,20 +243,30 @@
int sdcardfs_init_inode_cache(void)
{
- int err = 0;
-
sdcardfs_inode_cachep =
kmem_cache_create("sdcardfs_inode_cache",
sizeof(struct sdcardfs_inode_info), 0,
SLAB_RECLAIM_ACCOUNT, init_once);
+
if (!sdcardfs_inode_cachep)
- err = -ENOMEM;
- return err;
+ return -ENOMEM;
+
+ sdcardfs_inode_data_cachep =
+ kmem_cache_create("sdcardfs_inode_data_cache",
+ sizeof(struct sdcardfs_inode_data), 0,
+ SLAB_RECLAIM_ACCOUNT, NULL);
+ if (!sdcardfs_inode_data_cachep) {
+ kmem_cache_destroy(sdcardfs_inode_cachep);
+ return -ENOMEM;
+ }
+
+ return 0;
}
/* sdcardfs inode cache destructor */
void sdcardfs_destroy_inode_cache(void)
{
+ kmem_cache_destroy(sdcardfs_inode_data_cachep);
kmem_cache_destroy(sdcardfs_inode_cachep);
}
diff --git a/fs/xattr.c b/fs/xattr.c
index 2d13b4e..ed8c374 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -530,7 +530,7 @@
size = XATTR_SIZE_MAX;
kvalue = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
if (!kvalue) {
- kvalue = vmalloc(size);
+ kvalue = vzalloc(size);
if (!kvalue)
return -ENOMEM;
}
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h
index a95d494..115b62f 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h
@@ -185,19 +185,17 @@
#define GPLL0 167
#define GPLL0_OUT_EVEN 168
#define GPLL0_OUT_MAIN 169
-#define GPLL1 170
-#define GPLL1_OUT_MAIN 171
-#define GCC_UFS_CARD_AXI_HW_CTL_CLK 172
-#define GCC_UFS_PHY_AXI_HW_CTL_CLK 173
-#define GCC_UFS_CARD_UNIPRO_CORE_HW_CTL_CLK 174
-#define GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK 175
-#define GCC_UFS_CARD_ICE_CORE_HW_CTL_CLK 176
-#define GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK 177
-#define GCC_AGGRE_UFS_CARD_AXI_HW_CTL_CLK 178
-#define GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK 179
-#define GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK 180
-#define GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK 181
-#define GCC_GPU_IREF_CLK 182
+#define GCC_UFS_CARD_AXI_HW_CTL_CLK 170
+#define GCC_UFS_PHY_AXI_HW_CTL_CLK 171
+#define GCC_UFS_CARD_UNIPRO_CORE_HW_CTL_CLK 172
+#define GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK 173
+#define GCC_UFS_CARD_ICE_CORE_HW_CTL_CLK 174
+#define GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK 175
+#define GCC_AGGRE_UFS_CARD_AXI_HW_CTL_CLK 176
+#define GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK 177
+#define GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK 178
+#define GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK 179
+#define GCC_GPU_IREF_CLK 180
/* GCC reset clocks */
#define GCC_GPU_BCR 0
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 77912a1..72f9211 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -247,6 +247,7 @@
POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
POWER_SUPPLY_PROP_HW_CURRENT_MAX,
+ POWER_SUPPLY_PROP_REAL_TYPE,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h
index 657ac07..5947107 100644
--- a/include/linux/qcom-geni-se.h
+++ b/include/linux/qcom-geni-se.h
@@ -308,6 +308,22 @@
#define SE_DMA_RX_MAX_BURST (0xD5C)
#define SE_DMA_RX_FLUSH (0xD60)
+/* SE_DMA_TX_IRQ_STAT Register fields */
+#define TX_DMA_DONE (BIT(0))
+#define TX_EOT (BIT(1))
+#define TX_SBE (BIT(2))
+#define TX_RESET_DONE (BIT(3))
+
+/* SE_DMA_RX_IRQ_STAT Register fields */
+#define RX_DMA_DONE (BIT(0))
+#define RX_EOT (BIT(1))
+#define RX_SBE (BIT(2))
+#define RX_RESET_DONE (BIT(3))
+#define RX_FLUSH_DONE (BIT(4))
+#define RX_GENI_GP_IRQ (GENMASK(10, 5))
+#define RX_GENI_CANCEL_IRQ (BIT(11))
+#define RX_GENI_GP_IRQ_EXT (GENMASK(13, 12))
+
#define DEFAULT_BUS_WIDTH (4)
#define DEFAULT_SE_CLK (19200000)
diff --git a/include/trace/events/pdc.h b/include/trace/events/pdc.h
new file mode 100644
index 0000000..400e959
--- /dev/null
+++ b/include/trace/events/pdc.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM pdc
+
+#if !defined(_TRACE_PDC_) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_PDC_H_
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(irq_pin_config,
+
+ TP_PROTO(char *func, u32 pin, u32 hwirq, u32 type, u32 enable),
+
+ TP_ARGS(func, pin, hwirq, type, enable),
+
+ TP_STRUCT__entry(
+ __field(char *, func)
+ __field(u32, pin)
+ __field(u32, hwirq)
+ __field(u32, type)
+ __field(u32, enable)
+ ),
+
+ TP_fast_assign(
+ __entry->pin = pin;
+ __entry->func = func;
+ __entry->hwirq = hwirq;
+ __entry->type = type;
+ __entry->enable = enable;
+ ),
+
+ TP_printk("%s hwirq:%u pin:%u type:%u enable:%u",
+ __entry->func, __entry->pin, __entry->hwirq, __entry->type,
+ __entry->enable)
+);
+
+#endif
+#define TRACE_INCLUDE_FILE pdc
+#include <trace/define_trace.h>
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index eb18389..ab38f9e 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -321,6 +321,8 @@
/* sde custom events */
#define DRM_EVENT_HISTOGRAM 0x80000000
#define DRM_EVENT_AD_BACKLIGHT 0x80000001
+#define DRM_EVENT_CRTC_POWER 0x80000002
+#define DRM_EVENT_SYS_BACKLIGHT 0x80000003
#define DRM_IOCTL_MSM_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GET_PARAM, struct drm_msm_param)
#define DRM_IOCTL_MSM_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_NEW, struct drm_msm_gem_new)
diff --git a/include/uapi/drm/msm_drm_pp.h b/include/uapi/drm/msm_drm_pp.h
index e809c03..d9155a9 100644
--- a/include/uapi/drm/msm_drm_pp.h
+++ b/include/uapi/drm/msm_drm_pp.h
@@ -96,8 +96,8 @@
* @c2_c1: Holds c2/c1 values
*/
struct drm_msm_3d_col {
- __u32 c0;
__u32 c2_c1;
+ __u32 c0;
};
/**
* struct drm_msm_3d_gamut - 3d gamut feature structure
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 7c1899e..7cf7779 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -382,6 +382,7 @@
header-y += psci.h
header-y += ptp_clock.h
header-y += ptrace.h
+header-y += qbt1000.h
header-y += qcedev.h
header-y += qcota.h
header-y += qnx4_fs.h
diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h
index ea68202..57c2ca4 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -130,89 +130,123 @@
* enum ipa_client_type - names for the various IPA "clients"
* these are from the perspective of the clients, for e.g.
* HSIC1_PROD means HSIC client is the producer and IPA is the
- * consumer
+ * consumer.
+ * PROD clients are always even, and CONS clients are always odd.
+ * Add new clients in the end of the list and update IPA_CLIENT_MAX
*/
enum ipa_client_type {
- IPA_CLIENT_PROD,
- IPA_CLIENT_HSIC1_PROD = IPA_CLIENT_PROD,
- IPA_CLIENT_WLAN1_PROD,
- IPA_CLIENT_HSIC2_PROD,
- IPA_CLIENT_USB2_PROD,
- IPA_CLIENT_HSIC3_PROD,
- IPA_CLIENT_USB3_PROD,
- IPA_CLIENT_HSIC4_PROD,
- IPA_CLIENT_USB4_PROD,
- IPA_CLIENT_HSIC5_PROD,
- IPA_CLIENT_USB_PROD,
- IPA_CLIENT_A5_WLAN_AMPDU_PROD,
- IPA_CLIENT_A2_EMBEDDED_PROD,
- IPA_CLIENT_A2_TETHERED_PROD,
- IPA_CLIENT_APPS_LAN_PROD,
- IPA_CLIENT_APPS_WAN_PROD,
+ IPA_CLIENT_HSIC1_PROD = 0,
+ IPA_CLIENT_HSIC1_CONS = 1,
+
+ IPA_CLIENT_HSIC2_PROD = 2,
+ IPA_CLIENT_HSIC2_CONS = 3,
+
+ IPA_CLIENT_HSIC3_PROD = 4,
+ IPA_CLIENT_HSIC3_CONS = 5,
+
+ IPA_CLIENT_HSIC4_PROD = 6,
+ IPA_CLIENT_HSIC4_CONS = 7,
+
+ IPA_CLIENT_HSIC5_PROD = 8,
+ IPA_CLIENT_HSIC5_CONS = 9,
+
+ IPA_CLIENT_WLAN1_PROD = 10,
+ IPA_CLIENT_WLAN1_CONS = 11,
+
+ IPA_CLIENT_A5_WLAN_AMPDU_PROD = 12,
+ IPA_CLIENT_WLAN2_CONS = 13,
+
+ /* RESERVERD PROD = 14, */
+ IPA_CLIENT_WLAN3_CONS = 15,
+
+ /* RESERVERD PROD = 16, */
+ IPA_CLIENT_WLAN4_CONS = 17,
+
+ IPA_CLIENT_USB_PROD = 18,
+ IPA_CLIENT_USB_CONS = 19,
+
+ IPA_CLIENT_USB2_PROD = 20,
+ IPA_CLIENT_USB2_CONS = 21,
+
+ IPA_CLIENT_USB3_PROD = 22,
+ IPA_CLIENT_USB3_CONS = 23,
+
+ IPA_CLIENT_USB4_PROD = 24,
+ IPA_CLIENT_USB4_CONS = 25,
+
+ IPA_CLIENT_UC_USB_PROD = 26,
+ IPA_CLIENT_USB_DPL_CONS = 27,
+
+ IPA_CLIENT_A2_EMBEDDED_PROD = 28,
+ IPA_CLIENT_A2_EMBEDDED_CONS = 29,
+
+ IPA_CLIENT_A2_TETHERED_PROD = 30,
+ IPA_CLIENT_A2_TETHERED_CONS = 31,
+
+ IPA_CLIENT_APPS_LAN_PROD = 32,
+ IPA_CLIENT_APPS_LAN_CONS = 33,
+
+ IPA_CLIENT_APPS_WAN_PROD = 34,
IPA_CLIENT_APPS_LAN_WAN_PROD = IPA_CLIENT_APPS_WAN_PROD,
- IPA_CLIENT_APPS_CMD_PROD,
- IPA_CLIENT_ODU_PROD,
- IPA_CLIENT_MHI_PROD,
- IPA_CLIENT_Q6_LAN_PROD,
- IPA_CLIENT_Q6_WAN_PROD,
- IPA_CLIENT_Q6_CMD_PROD,
- IPA_CLIENT_MEMCPY_DMA_SYNC_PROD,
- IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD,
- IPA_CLIENT_Q6_DECOMP_PROD,
- IPA_CLIENT_Q6_DECOMP2_PROD,
- IPA_CLIENT_UC_USB_PROD,
- IPA_CLIENT_ETHERNET_PROD,
+ IPA_CLIENT_APPS_WAN_CONS = 35,
- /* Below PROD client type is only for test purpose */
- IPA_CLIENT_TEST_PROD,
- IPA_CLIENT_TEST1_PROD,
- IPA_CLIENT_TEST2_PROD,
- IPA_CLIENT_TEST3_PROD,
- IPA_CLIENT_TEST4_PROD,
+ IPA_CLIENT_APPS_CMD_PROD = 36,
+ IPA_CLIENT_A5_LAN_WAN_CONS = 37,
- IPA_CLIENT_CONS,
- IPA_CLIENT_HSIC1_CONS = IPA_CLIENT_CONS,
- IPA_CLIENT_WLAN1_CONS,
- IPA_CLIENT_HSIC2_CONS,
- IPA_CLIENT_USB2_CONS,
- IPA_CLIENT_WLAN2_CONS,
- IPA_CLIENT_HSIC3_CONS,
- IPA_CLIENT_USB3_CONS,
- IPA_CLIENT_WLAN3_CONS,
- IPA_CLIENT_HSIC4_CONS,
- IPA_CLIENT_USB4_CONS,
- IPA_CLIENT_WLAN4_CONS,
- IPA_CLIENT_HSIC5_CONS,
- IPA_CLIENT_USB_CONS,
- IPA_CLIENT_USB_DPL_CONS,
- IPA_CLIENT_A2_EMBEDDED_CONS,
- IPA_CLIENT_A2_TETHERED_CONS,
- IPA_CLIENT_A5_LAN_WAN_CONS,
- IPA_CLIENT_APPS_LAN_CONS,
- IPA_CLIENT_APPS_WAN_CONS,
- IPA_CLIENT_ODU_EMB_CONS,
- IPA_CLIENT_ODU_TETH_CONS,
- IPA_CLIENT_MHI_CONS,
- IPA_CLIENT_Q6_LAN_CONS,
- IPA_CLIENT_Q6_WAN_CONS,
- IPA_CLIENT_Q6_DUN_CONS,
- IPA_CLIENT_MEMCPY_DMA_SYNC_CONS,
- IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS,
- IPA_CLIENT_Q6_DECOMP_CONS,
- IPA_CLIENT_Q6_DECOMP2_CONS,
- IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS,
- IPA_CLIENT_ETHERNET_CONS,
+ IPA_CLIENT_ODU_PROD = 38,
+ IPA_CLIENT_ODU_EMB_CONS = 39,
- /* Below CONS client type is only for test purpose */
- IPA_CLIENT_TEST_CONS,
- IPA_CLIENT_TEST1_CONS,
- IPA_CLIENT_TEST2_CONS,
- IPA_CLIENT_TEST3_CONS,
- IPA_CLIENT_TEST4_CONS,
+ /* RESERVERD PROD = 40, */
+ IPA_CLIENT_ODU_TETH_CONS = 41,
- IPA_CLIENT_MAX,
+ IPA_CLIENT_MHI_PROD = 42,
+ IPA_CLIENT_MHI_CONS = 43,
+
+ IPA_CLIENT_MEMCPY_DMA_SYNC_PROD = 44,
+ IPA_CLIENT_MEMCPY_DMA_SYNC_CONS = 45,
+
+ IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD = 46,
+ IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS = 47,
+
+ IPA_CLIENT_ETHERNET_PROD = 48,
+ IPA_CLIENT_ETHERNET_CONS = 49,
+
+ IPA_CLIENT_Q6_LAN_PROD = 50,
+ IPA_CLIENT_Q6_LAN_CONS = 51,
+
+ IPA_CLIENT_Q6_WAN_PROD = 52,
+ IPA_CLIENT_Q6_WAN_CONS = 53,
+
+ IPA_CLIENT_Q6_CMD_PROD = 54,
+ IPA_CLIENT_Q6_DUN_CONS = 55,
+
+ IPA_CLIENT_Q6_DECOMP_PROD = 56,
+ IPA_CLIENT_Q6_DECOMP_CONS = 57,
+
+ IPA_CLIENT_Q6_DECOMP2_PROD = 58,
+ IPA_CLIENT_Q6_DECOMP2_CONS = 59,
+
+ /* RESERVERD PROD = 60, */
+ IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS = 61,
+
+ IPA_CLIENT_TEST_PROD = 62,
+ IPA_CLIENT_TEST_CONS = 63,
+
+ IPA_CLIENT_TEST1_PROD = 64,
+ IPA_CLIENT_TEST1_CONS = 65,
+
+ IPA_CLIENT_TEST2_PROD = 66,
+ IPA_CLIENT_TEST2_CONS = 67,
+
+ IPA_CLIENT_TEST3_PROD = 68,
+ IPA_CLIENT_TEST3_CONS = 69,
+
+ IPA_CLIENT_TEST4_PROD = 70,
+ IPA_CLIENT_TEST4_CONS = 71,
};
+#define IPA_CLIENT_MAX (IPA_CLIENT_TEST4_CONS + 1)
+
#define IPA_CLIENT_IS_APPS_CONS(client) \
((client) == IPA_CLIENT_APPS_LAN_CONS || \
(client) == IPA_CLIENT_APPS_WAN_CONS)
@@ -317,8 +351,8 @@
enum ipa_rule_type {
IPA_RULE_HASHABLE,
IPA_RULE_NON_HASHABLE,
- IPA_RULE_TYPE_MAX
};
+#define IPA_RULE_TYPE_MAX (IPA_RULE_NON_HASHABLE + 1)
/**
* enum ipa_flt_action - action field of filtering rule
@@ -405,35 +439,44 @@
/**
* enum ipa_rm_resource_name - IPA RM clients identification names
*
- * Add new mapping to ipa_rm_prod_index() / ipa_rm_cons_index()
- * when adding new entry to this enum.
+ * PROD resources are always even, and CONS resources are always odd.
+ * Add new clients in the end of the list and update IPA_RM_RESOURCE_MAX
*/
enum ipa_rm_resource_name {
- IPA_RM_RESOURCE_PROD = 0,
- IPA_RM_RESOURCE_Q6_PROD = IPA_RM_RESOURCE_PROD,
- IPA_RM_RESOURCE_USB_PROD,
- IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
- IPA_RM_RESOURCE_HSIC_PROD,
- IPA_RM_RESOURCE_STD_ECM_PROD,
- IPA_RM_RESOURCE_RNDIS_PROD,
- IPA_RM_RESOURCE_WWAN_0_PROD,
- IPA_RM_RESOURCE_WLAN_PROD,
- IPA_RM_RESOURCE_ODU_ADAPT_PROD,
- IPA_RM_RESOURCE_MHI_PROD,
- IPA_RM_RESOURCE_ETHERNET_PROD,
- IPA_RM_RESOURCE_PROD_MAX,
+ IPA_RM_RESOURCE_Q6_PROD = 0,
+ IPA_RM_RESOURCE_Q6_CONS = 1,
- IPA_RM_RESOURCE_Q6_CONS = IPA_RM_RESOURCE_PROD_MAX,
- IPA_RM_RESOURCE_USB_CONS,
- IPA_RM_RESOURCE_USB_DPL_CONS,
- IPA_RM_RESOURCE_HSIC_CONS,
- IPA_RM_RESOURCE_WLAN_CONS,
- IPA_RM_RESOURCE_APPS_CONS,
- IPA_RM_RESOURCE_ODU_ADAPT_CONS,
- IPA_RM_RESOURCE_MHI_CONS,
- IPA_RM_RESOURCE_ETHERNET_CONS,
- IPA_RM_RESOURCE_MAX
+ IPA_RM_RESOURCE_USB_PROD = 2,
+ IPA_RM_RESOURCE_USB_CONS = 3,
+
+ IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD = 4,
+ IPA_RM_RESOURCE_USB_DPL_CONS = 5,
+
+ IPA_RM_RESOURCE_HSIC_PROD = 6,
+ IPA_RM_RESOURCE_HSIC_CONS = 7,
+
+ IPA_RM_RESOURCE_STD_ECM_PROD = 8,
+ IPA_RM_RESOURCE_APPS_CONS = 9,
+
+ IPA_RM_RESOURCE_RNDIS_PROD = 10,
+ /* RESERVED CONS = 11, */
+
+ IPA_RM_RESOURCE_WWAN_0_PROD = 12,
+ /* RESERVED CONS = 13, */
+
+ IPA_RM_RESOURCE_WLAN_PROD = 14,
+ IPA_RM_RESOURCE_WLAN_CONS = 15,
+
+ IPA_RM_RESOURCE_ODU_ADAPT_PROD = 16,
+ IPA_RM_RESOURCE_ODU_ADAPT_CONS = 17,
+
+ IPA_RM_RESOURCE_MHI_PROD = 18,
+ IPA_RM_RESOURCE_MHI_CONS = 19,
+
+ IPA_RM_RESOURCE_ETHERNET_PROD = 20,
+ IPA_RM_RESOURCE_ETHERNET_CONS = 21,
};
+#define IPA_RM_RESOURCE_MAX (IPA_RM_RESOURCE_ETHERNET_CONS + 1)
/**
* enum ipa_hw_type - IPA hardware version type
@@ -465,8 +508,8 @@
IPA_HW_v3_5 = 12,
IPA_HW_v3_5_1 = 13,
IPA_HW_v4_0 = 14,
- IPA_HW_MAX
};
+#define IPA_HW_MAX (IPA_HW_v4_0 + 1)
#define IPA_HW_v4_0 IPA_HW_v4_0
@@ -700,8 +743,8 @@
IPA_HDR_L2_NONE,
IPA_HDR_L2_ETHERNET_II,
IPA_HDR_L2_802_3,
- IPA_HDR_L2_MAX,
};
+#define IPA_HDR_L2_MAX (IPA_HDR_L2_802_3 + 1)
/**
* enum ipa_hdr_l2_type - Processing context type
@@ -717,8 +760,8 @@
IPA_HDR_PROC_ETHII_TO_802_3,
IPA_HDR_PROC_802_3_TO_ETHII,
IPA_HDR_PROC_802_3_TO_802_3,
- IPA_HDR_PROC_MAX,
};
+#define IPA_HDR_PROC_MAX (IPA_HDR_PROC_802_3_TO_802_3 + 1)
/**
* struct ipa_rt_rule - attributes of a routing rule
diff --git a/include/uapi/linux/qbt1000.h b/include/uapi/linux/qbt1000.h
new file mode 100644
index 0000000..a4f0dca
--- /dev/null
+++ b/include/uapi/linux/qbt1000.h
@@ -0,0 +1,99 @@
+#ifndef _UAPI_QBT1000_H_
+#define _UAPI_QBT1000_H_
+
+#define MAX_NAME_SIZE 32
+
+/*
+ * enum qbt1000_commands -
+ * enumeration of command options
+ * @QBT1000_LOAD_APP - cmd loads TZ app
+ * @QBT1000_UNLOAD_APP - cmd unloads TZ app
+ * @QBT1000_SEND_TZCMD - sends cmd to TZ app
+ * @QBT1000_SET_FINGER_DETECT_KEY - sets the input key to send on finger detect
+ * @QBT1000_CONFIGURE_POWER_KEY - enables/disables sending the power key on
+ finger down events
+*/
+enum qbt1000_commands {
+ QBT1000_LOAD_APP = 100,
+ QBT1000_UNLOAD_APP = 101,
+ QBT1000_SEND_TZCMD = 102,
+ QBT1000_SET_FINGER_DETECT_KEY = 103,
+ QBT1000_CONFIGURE_POWER_KEY = 104
+};
+
+/*
+ * enum qbt1000_fw_event -
+ * enumeration of firmware events
+ * @FW_EVENT_FINGER_DOWN - finger down detected
+ * @FW_EVENT_FINGER_UP - finger up detected
+ * @FW_EVENT_INDICATION - an indication IPC from the firmware is pending
+ */
+enum qbt1000_fw_event {
+ FW_EVENT_FINGER_DOWN = 1,
+ FW_EVENT_FINGER_UP = 2,
+ FW_EVENT_CBGE_REQUIRED = 3,
+};
+
+/*
+ * struct qbt1000_app -
+ * used to load and unload apps in TZ
+ * @app_handle - qseecom handle for clients
+ * @name - Name of secure app to load
+ * @size - Size of requested buffer of secure app
+ * @high_band_width - 1 - for high bandwidth usage
+ * 0 - for normal bandwidth usage
+ */
+struct qbt1000_app {
+ struct qseecom_handle **app_handle;
+ char name[MAX_NAME_SIZE];
+ uint32_t size;
+ uint8_t high_band_width;
+};
+
+/*
+ * struct qbt1000_send_tz_cmd -
+ * used to cmds to TZ App
+ * @app_handle - qseecom handle for clients
+ * @req_buf - Buffer containing request for secure app
+ * @req_buf_len - Length of request buffer
+ * @rsp_buf - Buffer containing response from secure app
+ * @rsp_buf_len - Length of response buffer
+ */
+struct qbt1000_send_tz_cmd {
+ struct qseecom_handle *app_handle;
+ uint8_t *req_buf;
+ uint32_t req_buf_len;
+ uint8_t *rsp_buf;
+ uint32_t rsp_buf_len;
+};
+
+/*
+ * struct qbt1000_erie_event -
+ * used to receive events from Erie
+ * @buf - Buffer containing event from Erie
+ * @buf_len - Length of buffer
+ */
+struct qbt1000_erie_event {
+ uint8_t *buf;
+ uint32_t buf_len;
+};
+
+/*
+ * struct qbt1000_set_finger_detect_key -
+ * used to configure the input key which is sent on finger down/up event
+ * @key_code - Key code to send on finger down/up. 0 disables sending key events
+ */
+struct qbt1000_set_finger_detect_key {
+ unsigned int key_code;
+};
+
+/*
+ * struct qbt1000_configure_power_key -
+ * used to configure whether the power key is sent on finger down
+ * @enable - if non-zero, power key is sent on finger down
+ */
+struct qbt1000_configure_power_key {
+ unsigned int enable;
+};
+
+#endif /* _UAPI_QBT1000_H_ */
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index a70b90d..c61c56f 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/debug_locks.h>
#include <linux/osq_lock.h>
+#include <linux/delay.h>
/*
* In the DEBUG case we are using the "NULL fastpath" for mutexes,
@@ -378,6 +379,17 @@
* values at the cost of a few extra spins.
*/
cpu_relax_lowlatency();
+
+ /*
+ * On arm systems, we must slow down the waiter's repeated
+ * aquisition of spin_mlock and atomics on the lock count, or
+ * we risk starving out a thread attempting to release the
+ * mutex. The mutex slowpath release must take spin lock
+ * wait_lock. This spin lock can share a monitor with the
+ * other waiter atomics in the mutex data structure, so must
+ * take care to rate limit the waiters.
+ */
+ udelay(1);
}
osq_unlock(&lock->osq);
diff --git a/kernel/padata.c b/kernel/padata.c
index b4a3c0a..e4a8f8d 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -358,7 +358,7 @@
cpumask_and(pd->cpumask.pcpu, pcpumask, cpu_online_mask);
if (!alloc_cpumask_var(&pd->cpumask.cbcpu, GFP_KERNEL)) {
- free_cpumask_var(pd->cpumask.cbcpu);
+ free_cpumask_var(pd->cpumask.pcpu);
return -ENOMEM;
}
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index ccb2321..b6fb796 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3327,33 +3327,6 @@
static inline void sched_freq_tick(int cpu) { }
#endif /* CONFIG_CPU_FREQ_GOV_SCHED */
-#ifdef CONFIG_SCHED_WALT
-static atomic64_t walt_irq_work_lastq_ws;
-
-static inline u64 walt_window_start_of(struct rq *rq)
-{
- return rq->window_start;
-}
-
-static inline void run_walt_irq_work(u64 window_start, struct rq *rq)
-{
- /* No HMP since that uses sched_get_cpus_busy */
- if (rq->window_start != window_start &&
- atomic_cmpxchg(&walt_irq_work_lastq_ws, window_start,
- rq->window_start) == window_start)
- irq_work_queue(&rq->irq_work);
-}
-#else
-static inline u64 walt_window_start_of(struct rq *rq)
-{
- return 0;
-}
-
-static inline void run_walt_irq_work(u64 window_start, struct rq *rq)
-{
-}
-#endif
-
/*
* This function gets called by the timer code, with HZ frequency.
* We call it with interrupts disabled.
@@ -3367,22 +3340,14 @@
bool early_notif;
u32 old_load;
struct related_thread_group *grp;
- u64 window_start;
sched_clock_tick();
raw_spin_lock(&rq->lock);
- /*
- * Record current window_start. If after utra() below the window
- * has rolled over, schedule a load-reporting irq-work
- */
- window_start = walt_window_start_of(rq);
-
old_load = task_load(curr);
set_window_start(rq);
-
wallclock = sched_ktime_clock();
update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0);
@@ -3392,8 +3357,6 @@
calc_global_load_tick(rq);
cpufreq_update_util(rq, 0);
- run_walt_irq_work(window_start, rq);
-
early_notif = early_detection_notify(rq, wallclock);
raw_spin_unlock(&rq->lock);
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 82e6490..6ccd3a7 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -12319,7 +12319,7 @@
return;
new_cpu = energy_aware_wake_cpu(p, cpu, 0);
- if (new_cpu != cpu) {
+ if (capacity_orig_of(new_cpu) > capacity_orig_of(cpu)) {
active_balance = kick_active_balance(rq, p, new_cpu);
if (active_balance) {
mark_reserved(new_cpu);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 29b6e3d..5220511 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1816,6 +1816,7 @@
walt_load->prev_window_util = util;
walt_load->nl = nl;
+ walt_load->pl = 0;
}
}
#endif
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index 58854b0..b89abbd 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -47,6 +47,7 @@
static struct cpu_cycle_counter_cb cpu_cycle_counter_cb;
static bool use_cycle_counter;
DEFINE_MUTEX(cluster_lock);
+static atomic64_t walt_irq_work_lastq_ws;
u64 sched_ktime_clock(void)
{
@@ -298,11 +299,12 @@
*/
__read_mostly int sched_freq_aggregate_threshold;
-static void
+static u64
update_window_start(struct rq *rq, u64 wallclock, int event)
{
s64 delta;
int nr_windows;
+ u64 old_window_start = rq->window_start;
delta = wallclock - rq->window_start;
/* If the MPM global timer is cleared, set delta as 0 to avoid kernel BUG happening */
@@ -312,7 +314,7 @@
}
if (delta < sched_ravg_window)
- return;
+ return old_window_start;
nr_windows = div64_u64(delta, sched_ravg_window);
rq->window_start += (u64)nr_windows * (u64)sched_ravg_window;
@@ -320,6 +322,8 @@
rq->cum_window_demand = rq->hmp_stats.cumulative_runnable_avg;
if (event == PUT_PREV_TASK)
rq->cum_window_demand += rq->curr->ravg.demand;
+
+ return old_window_start;
}
int register_cpu_cycle_counter_cb(struct cpu_cycle_counter_cb *cb)
@@ -913,12 +917,13 @@
{
static int sync_cpu_available;
- if (rq->window_start)
+ if (likely(rq->window_start))
return;
if (!sync_cpu_available) {
- rq->window_start = sched_ktime_clock();
+ rq->window_start = 1;
sync_cpu_available = 1;
+ atomic_set(&walt_irq_work_lastq_ws, rq->window_start);
} else {
struct rq *sync_rq = cpu_rq(cpumask_any(cpu_online_mask));
@@ -1904,11 +1909,24 @@
trace_sched_get_task_cpu_cycles(cpu, event, rq->cc.cycles, rq->cc.time);
}
+static inline void run_walt_irq_work(u64 old_window_start, struct rq *rq)
+{
+ u64 result;
+
+ if (old_window_start == rq->window_start)
+ return;
+
+ result = atomic_cmpxchg(&walt_irq_work_lastq_ws, old_window_start,
+ rq->window_start);
+ if (result == old_window_start)
+ irq_work_queue(&rq->irq_work);
+}
+
/* Reflect task activity on its demand and cpu's busy time statistics */
void update_task_ravg(struct task_struct *p, struct rq *rq, int event,
u64 wallclock, u64 irqtime)
{
- u64 runtime;
+ u64 runtime, old_window_start;
if (!rq->window_start || sched_disable_window_stats ||
p->ravg.mark_start == wallclock)
@@ -1916,7 +1934,7 @@
lockdep_assert_held(&rq->lock);
- update_window_start(rq, wallclock, event);
+ old_window_start = update_window_start(rq, wallclock, event);
if (!p->ravg.mark_start) {
update_task_cpu_cycles(p, cpu_of(rq));
@@ -1936,6 +1954,8 @@
rq->cc.cycles, rq->cc.time, &rq->grp_time);
p->ravg.mark_start = wallclock;
+
+ run_walt_irq_work(old_window_start, rq);
}
u32 sched_get_init_task_load(struct task_struct *p)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 8e57301..0ca9565 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3152,6 +3152,7 @@
enum compact_priority prio, enum compact_result *compact_result)
{
struct page *page;
+ unsigned int noreclaim_flag = current->flags & PF_MEMALLOC;
if (!order)
return NULL;
@@ -3159,7 +3160,7 @@
current->flags |= PF_MEMALLOC;
*compact_result = try_to_compact_pages(gfp_mask, order, alloc_flags, ac,
prio);
- current->flags &= ~PF_MEMALLOC;
+ current->flags = (current->flags & ~PF_MEMALLOC) | noreclaim_flag;
if (*compact_result <= COMPACT_INACTIVE)
return NULL;
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 48f9471..c88a600 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -1680,7 +1680,8 @@
if (msg->msg_flags & MSG_OOB)
return -EOPNOTSUPP;
- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
+ if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE|
+ MSG_CMSG_COMPAT))
return -EINVAL;
if (len < 4 || len > HCI_MAX_FRAME_SIZE)
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 963732e..58dfa23 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -740,7 +740,7 @@
if (msg_data_left(msg) < chunk) {
if (__skb_checksum_complete(skb))
- goto csum_error;
+ return -EINVAL;
if (skb_copy_datagram_msg(skb, hlen, msg, chunk))
goto fault;
} else {
@@ -748,15 +748,16 @@
if (skb_copy_and_csum_datagram(skb, hlen, &msg->msg_iter,
chunk, &csum))
goto fault;
- if (csum_fold(csum))
- goto csum_error;
+
+ if (csum_fold(csum)) {
+ iov_iter_revert(&msg->msg_iter, chunk);
+ return -EINVAL;
+ }
+
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
netdev_rx_csum_fault(skb->dev);
}
return 0;
-csum_error:
- iov_iter_revert(&msg->msg_iter, chunk);
- return -EINVAL;
fault:
return -EFAULT;
}
diff --git a/sound/soc/codecs/wcd9330.c b/sound/soc/codecs/wcd9330.c
index 0b07393..4278e36 100644
--- a/sound/soc/codecs/wcd9330.c
+++ b/sound/soc/codecs/wcd9330.c
@@ -1536,6 +1536,13 @@
tomtom_mad_input = ucontrol->value.integer.value[0];
micb_4_int_reg = tomtom->resmgr.reg_addr->micb_4_int_rbias;
+ if (tomtom_mad_input >= ARRAY_SIZE(tomtom_conn_mad_text)) {
+ dev_err(codec->dev,
+ "%s: tomtom_mad_input = %d out of bounds\n",
+ __func__, tomtom_mad_input);
+ return -EINVAL;
+ }
+
pr_debug("%s: tomtom_mad_input = %s\n", __func__,
tomtom_conn_mad_text[tomtom_mad_input]);
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index d4db55f..36382ba 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -1,5 +1,5 @@
-snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \
- msm-compress-q6-v2.o msm-compr-q6-v2.o \
+snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o \
+ msm-pcm-routing-v2.o msm-compress-q6-v2.o \
msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
msm-lsm-client.o msm-pcm-host-voice-v2.o \
diff --git a/sound/soc/msm/qdsp6v2/audio_cal_utils.c b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
index 5d4a0ba..820aa1b 100644
--- a/sound/soc/msm/qdsp6v2/audio_cal_utils.c
+++ b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
@@ -646,7 +646,9 @@
return cal_block;
err:
kfree(cal_block->cal_info);
+ cal_block->cal_info = NULL;
kfree(cal_block->client_info);
+ cal_block->client_info = NULL;
kfree(cal_block);
cal_block = NULL;
return cal_block;
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
deleted file mode 100644
index 449325c..0000000
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ /dev/null
@@ -1,1714 +0,0 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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/err.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/pcm.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-#include <sound/q6asm-v2.h>
-#include <sound/pcm_params.h>
-#include <asm/dma.h>
-#include <linux/dma-mapping.h>
-#include <linux/msm_audio_ion.h>
-
-#include <sound/timer.h>
-
-#include "msm-compr-q6-v2.h"
-#include "msm-pcm-routing-v2.h"
-#include <sound/tlv.h>
-
-#define COMPRE_CAPTURE_NUM_PERIODS 16
-/* Allocate the worst case frame size for compressed audio */
-#define COMPRE_CAPTURE_HEADER_SIZE (sizeof(struct snd_compr_audio_info))
-/* Changing period size to 4032. 4032 will make sure COMPRE_CAPTURE_PERIOD_SIZE
- * is 4096 with meta data size of 64 and MAX_NUM_FRAMES_PER_BUFFER 1
- */
-#define COMPRE_CAPTURE_MAX_FRAME_SIZE (4032)
-#define COMPRE_CAPTURE_PERIOD_SIZE ((COMPRE_CAPTURE_MAX_FRAME_SIZE + \
- COMPRE_CAPTURE_HEADER_SIZE) * \
- MAX_NUM_FRAMES_PER_BUFFER)
-#define COMPRE_OUTPUT_METADATA_SIZE (sizeof(struct output_meta_data_st))
-#define COMPRESSED_LR_VOL_MAX_STEPS 0x20002000
-
-#define MAX_AC3_PARAM_SIZE (18*2*sizeof(int))
-#define AMR_WB_BAND_MODE 8
-#define AMR_WB_DTX_MODE 0
-
-
-const DECLARE_TLV_DB_LINEAR(compr_rx_vol_gain, 0,
- COMPRESSED_LR_VOL_MAX_STEPS);
-
-static struct audio_locks the_locks;
-
-static struct snd_pcm_hardware msm_compr_hardware_capture = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .rate_min = 8000,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 8,
- .buffer_bytes_max =
- COMPRE_CAPTURE_PERIOD_SIZE * COMPRE_CAPTURE_NUM_PERIODS,
- .period_bytes_min = COMPRE_CAPTURE_PERIOD_SIZE,
- .period_bytes_max = COMPRE_CAPTURE_PERIOD_SIZE,
- .periods_min = COMPRE_CAPTURE_NUM_PERIODS,
- .periods_max = COMPRE_CAPTURE_NUM_PERIODS,
- .fifo_size = 0,
-};
-
-static struct snd_pcm_hardware msm_compr_hardware_playback = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
- .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
- .rate_min = 8000,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 8,
- .buffer_bytes_max = 1024 * 1024,
- .period_bytes_min = 128 * 1024,
- .period_bytes_max = 256 * 1024,
- .periods_min = 4,
- .periods_max = 8,
- .fifo_size = 0,
-};
-
-/* Conventional and unconventional sample rate supported */
-static unsigned int supported_sample_rates[] = {
- 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
-};
-
-/* Add supported codecs for compress capture path */
-static uint32_t supported_compr_capture_codecs[] = {
- SND_AUDIOCODEC_AMRWB
-};
-
-static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
- .count = ARRAY_SIZE(supported_sample_rates),
- .list = supported_sample_rates,
- .mask = 0,
-};
-
-static bool msm_compr_capture_codecs(uint32_t req_codec)
-{
- int i;
-
- pr_debug("%s req_codec:%d\n", __func__, req_codec);
- if (req_codec == 0)
- return false;
- for (i = 0; i < ARRAY_SIZE(supported_compr_capture_codecs); i++) {
- if (req_codec == supported_compr_capture_codecs[i])
- return true;
- }
- return false;
-}
-
-static void compr_event_handler(uint32_t opcode,
- uint32_t token, uint32_t *payload, void *priv)
-{
- struct compr_audio *compr = priv;
- struct msm_audio *prtd = &compr->prtd;
- struct snd_pcm_substream *substream = prtd->substream;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct audio_aio_write_param param;
- struct audio_aio_read_param read_param;
- struct audio_buffer *buf = NULL;
- phys_addr_t temp;
- struct output_meta_data_st output_meta_data;
- uint32_t *ptrmem = (uint32_t *)payload;
- int i = 0;
- int time_stamp_flag = 0;
- int buffer_length = 0;
- int stop_playback = 0;
-
- pr_debug("%s opcode =%08x\n", __func__, opcode);
- switch (opcode) {
- case ASM_DATA_EVENT_WRITE_DONE_V2: {
- uint32_t *ptrmem = (uint32_t *)¶m;
-
- pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
- pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
- prtd->pcm_irq_pos += prtd->pcm_count;
- if (atomic_read(&prtd->start))
- snd_pcm_period_elapsed(substream);
- else
- if (substream->timer_running)
- snd_timer_interrupt(substream->timer, 1);
- atomic_inc(&prtd->out_count);
- wake_up(&the_locks.write_wait);
- if (!atomic_read(&prtd->start)) {
- atomic_set(&prtd->pending_buffer, 1);
- break;
- }
- atomic_set(&prtd->pending_buffer, 0);
-
- /*
- * check for underrun
- */
- snd_pcm_stream_lock_irq(substream);
- if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
- runtime->render_flag |= SNDRV_RENDER_STOPPED;
- stop_playback = 1;
- }
- snd_pcm_stream_unlock_irq(substream);
-
- if (stop_playback) {
- pr_err("underrun! render stopped\n");
- break;
- }
-
- buf = prtd->audio_client->port[IN].buf;
- pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
- __func__, prtd->pcm_count, prtd->out_head);
- temp = buf[0].phys + (prtd->out_head * prtd->pcm_count);
- pr_debug("%s:writing buffer[%d] from 0x%pK\n",
- __func__, prtd->out_head, &temp);
-
- if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
- time_stamp_flag = SET_TIMESTAMP;
- else
- time_stamp_flag = NO_TIMESTAMP;
- memcpy(&output_meta_data, (char *)(buf->data +
- prtd->out_head * prtd->pcm_count),
- COMPRE_OUTPUT_METADATA_SIZE);
-
- buffer_length = output_meta_data.frame_size;
- pr_debug("meta_data_length: %d, frame_length: %d\n",
- output_meta_data.meta_data_length,
- output_meta_data.frame_size);
- pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
- output_meta_data.timestamp_msw,
- output_meta_data.timestamp_lsw);
- if (buffer_length == 0) {
- pr_debug("Received a zero length buffer-break out");
- break;
- }
- param.paddr = temp + output_meta_data.meta_data_length;
- param.len = buffer_length;
- param.msw_ts = output_meta_data.timestamp_msw;
- param.lsw_ts = output_meta_data.timestamp_lsw;
- param.flags = time_stamp_flag;
- param.uid = prtd->session_id;
- for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
- i++, ++ptrmem)
- pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
- if (q6asm_async_write(prtd->audio_client,
- ¶m) < 0)
- pr_err("%s:q6asm_async_write failed\n",
- __func__);
- else
- prtd->out_head =
- (prtd->out_head + 1) & (runtime->periods - 1);
- break;
- }
- case ASM_DATA_EVENT_RENDERED_EOS:
- pr_debug("ASM_DATA_CMDRSP_EOS\n");
- if (atomic_read(&prtd->eos)) {
- pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
- prtd->cmd_ack = 1;
- wake_up(&the_locks.eos_wait);
- atomic_set(&prtd->eos, 0);
- }
- break;
- case ASM_DATA_EVENT_READ_DONE_V2: {
- pr_debug("ASM_DATA_EVENT_READ_DONE\n");
- pr_debug("buf = %pK, data = 0x%X, *data = %pK,\n"
- "prtd->pcm_irq_pos = %d\n",
- prtd->audio_client->port[OUT].buf,
- *(uint32_t *)prtd->audio_client->port[OUT].buf->data,
- prtd->audio_client->port[OUT].buf->data,
- prtd->pcm_irq_pos);
-
- memcpy(prtd->audio_client->port[OUT].buf->data +
- prtd->pcm_irq_pos, (ptrmem + READDONE_IDX_SIZE),
- COMPRE_CAPTURE_HEADER_SIZE);
- pr_debug("buf = %pK, updated data = 0x%X, *data = %pK\n",
- prtd->audio_client->port[OUT].buf,
- *(uint32_t *)(prtd->audio_client->port[OUT].buf->data +
- prtd->pcm_irq_pos),
- prtd->audio_client->port[OUT].buf->data);
- if (!atomic_read(&prtd->start))
- break;
- pr_debug("frame size=%d, buffer = 0x%X\n",
- ptrmem[READDONE_IDX_SIZE],
- ptrmem[READDONE_IDX_BUFADD_LSW]);
- if (ptrmem[READDONE_IDX_SIZE] > COMPRE_CAPTURE_MAX_FRAME_SIZE) {
- pr_err("Frame length exceeded the max length");
- break;
- }
- buf = prtd->audio_client->port[OUT].buf;
-
- pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%pK\n",
- prtd->pcm_irq_pos, &buf[0].phys);
- read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE;
- read_param.paddr = buf[0].phys +
- prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE;
- prtd->pcm_irq_pos += prtd->pcm_count;
-
- if (atomic_read(&prtd->start))
- snd_pcm_period_elapsed(substream);
-
- q6asm_async_read(prtd->audio_client, &read_param);
- break;
- }
- case APR_BASIC_RSP_RESULT: {
- switch (payload[0]) {
- case ASM_SESSION_CMD_RUN_V2: {
- if (substream->stream
- != SNDRV_PCM_STREAM_PLAYBACK) {
- atomic_set(&prtd->start, 1);
- break;
- }
- if (!atomic_read(&prtd->pending_buffer))
- break;
- pr_debug("%s: writing %d bytes of buffer[%d] to dsp\n",
- __func__, prtd->pcm_count, prtd->out_head);
- buf = prtd->audio_client->port[IN].buf;
- pr_debug("%s: writing buffer[%d] from 0x%pK head %d count %d\n",
- __func__, prtd->out_head, &buf[0].phys,
- prtd->pcm_count, prtd->out_head);
- if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
- time_stamp_flag = SET_TIMESTAMP;
- else
- time_stamp_flag = NO_TIMESTAMP;
- memcpy(&output_meta_data, (char *)(buf->data +
- prtd->out_head * prtd->pcm_count),
- COMPRE_OUTPUT_METADATA_SIZE);
- buffer_length = output_meta_data.frame_size;
- pr_debug("meta_data_length: %d, frame_length: %d\n",
- output_meta_data.meta_data_length,
- output_meta_data.frame_size);
- pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
- output_meta_data.timestamp_msw,
- output_meta_data.timestamp_lsw);
- param.paddr = buf[prtd->out_head].phys
- + output_meta_data.meta_data_length;
- param.len = buffer_length;
- param.msw_ts = output_meta_data.timestamp_msw;
- param.lsw_ts = output_meta_data.timestamp_lsw;
- param.flags = time_stamp_flag;
- param.uid = prtd->session_id;
- param.metadata_len = COMPRE_OUTPUT_METADATA_SIZE;
- if (q6asm_async_write(prtd->audio_client,
- ¶m) < 0)
- pr_err("%s:q6asm_async_write failed\n",
- __func__);
- else
- prtd->out_head =
- (prtd->out_head + 1)
- & (runtime->periods - 1);
- atomic_set(&prtd->pending_buffer, 0);
- }
- break;
- case ASM_STREAM_CMD_FLUSH:
- pr_debug("ASM_STREAM_CMD_FLUSH\n");
- prtd->cmd_ack = 1;
- wake_up(&the_locks.flush_wait);
- break;
- default:
- break;
- }
- break;
- }
- default:
- pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
- break;
- }
-}
-
-static int msm_compr_send_ddp_cfg(struct audio_client *ac,
- struct snd_dec_ddp *ddp)
-{
- int i, rc;
-
- pr_debug("%s\n", __func__);
-
- if (ddp->params_length / 2 > SND_DEC_DDP_MAX_PARAMS) {
- pr_err("%s: Invalid number of params %u, max allowed %u\n",
- __func__, ddp->params_length / 2,
- SND_DEC_DDP_MAX_PARAMS);
- return -EINVAL;
- }
-
- for (i = 0; i < ddp->params_length/2; i++) {
- rc = q6asm_ds1_set_endp_params(ac, ddp->params_id[i],
- ddp->params_value[i]);
- if (rc) {
- pr_err("sending params_id: %d failed\n",
- ddp->params_id[i]);
- return rc;
- }
- }
- return 0;
-}
-
-static int msm_compr_playback_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
- struct msm_audio *prtd = &compr->prtd;
- struct snd_pcm_hw_params *params;
- struct asm_aac_cfg aac_cfg;
- uint16_t bits_per_sample = 16;
- int ret;
-
- struct asm_softpause_params softpause = {
- .enable = SOFT_PAUSE_ENABLE,
- .period = SOFT_PAUSE_PERIOD,
- .step = SOFT_PAUSE_STEP,
- .rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
- };
- struct asm_softvolume_params softvol = {
- .period = SOFT_VOLUME_PERIOD,
- .step = SOFT_VOLUME_STEP,
- .rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
- };
-
- pr_debug("%s\n", __func__);
-
- params = &soc_prtd->dpcm[substream->stream].hw_params;
- if (runtime->format == SNDRV_PCM_FORMAT_S24_LE)
- bits_per_sample = 24;
-
- ret = q6asm_open_write_v2(prtd->audio_client,
- compr->codec, bits_per_sample);
- if (ret < 0) {
- pr_err("%s: Session out open failed\n",
- __func__);
- return -ENOMEM;
- }
- msm_pcm_routing_reg_phy_stream(
- soc_prtd->dai_link->id,
- prtd->audio_client->perf_mode,
- prtd->session_id,
- substream->stream);
- /*
- * the number of channels are required to call volume api
- * accoridngly. So, get channels from hw params
- */
- if ((params_channels(params) > 0) &&
- (params_periods(params) <= runtime->hw.channels_max))
- prtd->channel_mode = params_channels(params);
-
- ret = q6asm_set_softpause(prtd->audio_client, &softpause);
- if (ret < 0)
- pr_err("%s: Send SoftPause Param failed ret=%d\n",
- __func__, ret);
- ret = q6asm_set_softvolume(prtd->audio_client, &softvol);
- if (ret < 0)
- pr_err("%s: Send SoftVolume Param failed ret=%d\n",
- __func__, ret);
-
- ret = q6asm_set_io_mode(prtd->audio_client,
- (COMPRESSED_IO | ASYNC_IO_MODE));
- if (ret < 0) {
- pr_err("%s: Set IO mode failed\n", __func__);
- return -ENOMEM;
- }
-
- prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
- prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
- prtd->pcm_irq_pos = 0;
- /* rate and channels are sent to audio driver */
- prtd->samp_rate = runtime->rate;
- prtd->channel_mode = runtime->channels;
- prtd->out_head = 0;
- atomic_set(&prtd->out_count, runtime->periods);
-
- if (prtd->enabled)
- return 0;
-
- switch (compr->info.codec_param.codec.id) {
- case SND_AUDIOCODEC_MP3:
- /* No media format block for mp3 */
- break;
- case SND_AUDIOCODEC_AAC:
- pr_debug("%s: SND_AUDIOCODEC_AAC\n", __func__);
- memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg));
- aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
- aac_cfg.format = 0x03;
- aac_cfg.ch_cfg = runtime->channels;
- aac_cfg.sample_rate = runtime->rate;
- ret = q6asm_media_format_block_aac(prtd->audio_client,
- &aac_cfg);
- if (ret < 0)
- pr_err("%s: CMD Format block failed\n", __func__);
- break;
- case SND_AUDIOCODEC_AC3: {
- struct snd_dec_ddp *ddp =
- &compr->info.codec_param.codec.options.ddp;
- pr_debug("%s: SND_AUDIOCODEC_AC3\n", __func__);
- ret = msm_compr_send_ddp_cfg(prtd->audio_client, ddp);
- if (ret < 0)
- pr_err("%s: DDP CMD CFG failed\n", __func__);
- break;
- }
- case SND_AUDIOCODEC_EAC3: {
- struct snd_dec_ddp *ddp =
- &compr->info.codec_param.codec.options.ddp;
- pr_debug("%s: SND_AUDIOCODEC_EAC3\n", __func__);
- ret = msm_compr_send_ddp_cfg(prtd->audio_client, ddp);
- if (ret < 0)
- pr_err("%s: DDP CMD CFG failed\n", __func__);
- break;
- }
- default:
- return -EINVAL;
- }
-
- prtd->enabled = 1;
- prtd->cmd_ack = 0;
- prtd->cmd_interrupt = 0;
-
- return 0;
-}
-
-static int msm_compr_capture_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
- struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
- struct snd_codec *codec = &compr->info.codec_param.codec;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
- struct audio_aio_read_param read_param;
- uint16_t bits_per_sample = 16;
- int ret = 0;
- int i;
-
- prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
- prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
- prtd->pcm_irq_pos = 0;
-
- if (runtime->format == SNDRV_PCM_FORMAT_S24_LE)
- bits_per_sample = 24;
-
- if (!msm_compr_capture_codecs(
- compr->info.codec_param.codec.id)) {
- /*
- * request codec invalid or not supported,
- * use default compress format
- */
- compr->info.codec_param.codec.id =
- SND_AUDIOCODEC_AMRWB;
- }
- switch (compr->info.codec_param.codec.id) {
- case SND_AUDIOCODEC_AMRWB:
- pr_debug("q6asm_open_read(FORMAT_AMRWB)\n");
- ret = q6asm_open_read(prtd->audio_client,
- FORMAT_AMRWB);
- if (ret < 0) {
- pr_err("%s: compressed Session out open failed\n",
- __func__);
- return -ENOMEM;
- }
- pr_debug("msm_pcm_routing_reg_phy_stream\n");
- msm_pcm_routing_reg_phy_stream(
- soc_prtd->dai_link->id,
- prtd->audio_client->perf_mode,
- prtd->session_id, substream->stream);
- break;
- default:
- pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n");
- /*
- * ret = q6asm_open_read_compressed(prtd->audio_client,
- * MAX_NUM_FRAMES_PER_BUFFER,
- * COMPRESSED_META_DATA_MODE);
- */
- ret = -EINVAL;
- break;
- }
-
- if (ret < 0) {
- pr_err("%s: compressed Session out open failed\n",
- __func__);
- return -ENOMEM;
- }
-
- ret = q6asm_set_io_mode(prtd->audio_client,
- (COMPRESSED_IO | ASYNC_IO_MODE));
- if (ret < 0) {
- pr_err("%s: Set IO mode failed\n", __func__);
- return -ENOMEM;
- }
-
- if (!msm_compr_capture_codecs(codec->id)) {
- /*
- * request codec invalid or not supported,
- * use default compress format
- */
- codec->id = SND_AUDIOCODEC_AMRWB;
- }
- /* rate and channels are sent to audio driver */
- prtd->samp_rate = runtime->rate;
- prtd->channel_mode = runtime->channels;
-
- if (prtd->enabled)
- return ret;
- read_param.len = prtd->pcm_count;
-
- switch (codec->id) {
- case SND_AUDIOCODEC_AMRWB:
- pr_debug("SND_AUDIOCODEC_AMRWB\n");
- ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client,
- MAX_NUM_FRAMES_PER_BUFFER,
- /*
- * use fixed band mode and dtx mode
- * band mode - 23.85 kbps
- */
- AMR_WB_BAND_MODE,
- /* dtx mode - disable */
- AMR_WB_DTX_MODE);
- if (ret < 0)
- pr_err("%s: CMD Format block failed: %d\n",
- __func__, ret);
- break;
- default:
- pr_debug("No config for codec %d\n", codec->id);
- }
- pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n"
- "pcm_count = %d, periods = %d\n",
- __func__, prtd->samp_rate, prtd->channel_mode,
- prtd->pcm_size, prtd->pcm_count, runtime->periods);
-
- for (i = 0; i < runtime->periods; i++) {
- read_param.uid = i;
- switch (codec->id) {
- case SND_AUDIOCODEC_AMRWB:
- read_param.len = prtd->pcm_count
- - COMPRE_CAPTURE_HEADER_SIZE;
- read_param.paddr = buf[i].phys
- + COMPRE_CAPTURE_HEADER_SIZE;
- pr_debug("Push buffer [%d] to DSP, paddr: %pK, vaddr: %pK\n",
- i, &read_param.paddr,
- buf[i].data);
- q6asm_async_read(prtd->audio_client, &read_param);
- break;
- default:
- read_param.paddr = buf[i].phys;
- /* q6asm_async_read_compressed(prtd->audio_client,
- * &read_param);
- */
- pr_debug("%s: To add support for read compressed\n",
- __func__);
- ret = -EINVAL;
- break;
- }
- }
- prtd->periods = runtime->periods;
-
- prtd->enabled = 1;
-
- return ret;
-}
-
-static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- int ret = 0;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
-
- pr_debug("%s\n", __func__);
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- prtd->pcm_irq_pos = 0;
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- if (!msm_compr_capture_codecs(
- compr->info.codec_param.codec.id)) {
- /*
- * request codec invalid or not supported,
- * use default compress format
- */
- compr->info.codec_param.codec.id =
- SND_AUDIOCODEC_AMRWB;
- }
- switch (compr->info.codec_param.codec.id) {
- case SND_AUDIOCODEC_AMRWB:
- break;
- default:
- msm_pcm_routing_reg_psthr_stream(
- soc_prtd->dai_link->id,
- prtd->session_id, substream->stream);
- break;
- }
- }
- atomic_set(&prtd->pending_buffer, 1);
- /* fallthrough */
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- pr_debug("%s: Trigger start\n", __func__);
- q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
- atomic_set(&prtd->start, 1);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- switch (compr->info.codec_param.codec.id) {
- case SND_AUDIOCODEC_AMRWB:
- break;
- default:
- msm_pcm_routing_reg_psthr_stream(
- soc_prtd->dai_link->id,
- prtd->session_id, substream->stream);
- break;
- }
- }
- atomic_set(&prtd->start, 0);
- runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
- break;
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
- q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
- atomic_set(&prtd->start, 0);
- runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static void populate_codec_list(struct compr_audio *compr,
- struct snd_pcm_runtime *runtime)
-{
- pr_debug("%s\n", __func__);
- /* MP3 Block */
- compr->info.compr_cap.num_codecs = 5;
- compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
- compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
- compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
- compr->info.compr_cap.max_fragments = runtime->hw.periods_max;
- compr->info.compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
- compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
- compr->info.compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
- compr->info.compr_cap.codecs[3] = SND_AUDIOCODEC_EAC3;
- compr->info.compr_cap.codecs[4] = SND_AUDIOCODEC_AMRWB;
- /* Add new codecs here */
-}
-
-static int msm_compr_open(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr;
- struct msm_audio *prtd;
- int ret = 0;
-
- pr_debug("%s\n", __func__);
- compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL);
- if (compr == NULL) {
- pr_err("Failed to allocate memory for msm_audio\n");
- return -ENOMEM;
- }
- prtd = &compr->prtd;
- prtd->substream = substream;
- runtime->render_flag = SNDRV_DMA_MODE;
- prtd->audio_client = q6asm_audio_client_alloc(
- (app_cb)compr_event_handler, compr);
- if (!prtd->audio_client) {
- pr_info("%s: Could not allocate memory\n", __func__);
- kfree(prtd);
- return -ENOMEM;
- }
-
- prtd->audio_client->perf_mode = false;
- pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
-
- prtd->session_id = prtd->audio_client->session;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- runtime->hw = msm_compr_hardware_playback;
- prtd->cmd_ack = 1;
- } else {
- runtime->hw = msm_compr_hardware_capture;
- }
-
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_sample_rates);
- if (ret < 0)
- pr_info("snd_pcm_hw_constraint_list failed\n");
- /* Ensure that buffer size is a multiple of period size */
- ret = snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS);
- if (ret < 0)
- pr_info("snd_pcm_hw_constraint_integer failed\n");
-
- prtd->dsp_cnt = 0;
- atomic_set(&prtd->pending_buffer, 1);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- compr->codec = FORMAT_MP3;
- populate_codec_list(compr, runtime);
- runtime->private_data = compr;
- atomic_set(&prtd->eos, 0);
- return 0;
-}
-
-static int compressed_set_volume(struct msm_audio *prtd, uint32_t volume)
-{
- int rc = 0;
- int avg_vol = 0;
- int lgain = (volume >> 16) & 0xFFFF;
- int rgain = volume & 0xFFFF;
-
- if (prtd && prtd->audio_client) {
- pr_debug("%s: channels %d volume 0x%x\n", __func__,
- prtd->channel_mode, volume);
- if ((prtd->channel_mode == 2) &&
- (lgain != rgain)) {
- pr_debug("%s: call q6asm_set_lrgain\n", __func__);
- rc = q6asm_set_lrgain(prtd->audio_client, lgain, rgain);
- } else {
- avg_vol = (lgain + rgain)/2;
- pr_debug("%s: call q6asm_set_volume\n", __func__);
- rc = q6asm_set_volume(prtd->audio_client, avg_vol);
- }
- if (rc < 0) {
- pr_err("%s: Send Volume command failed rc=%d\n",
- __func__, rc);
- }
- }
- return rc;
-}
-
-static int msm_compr_playback_close(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
- int dir = 0;
-
- pr_debug("%s\n", __func__);
-
- dir = IN;
- atomic_set(&prtd->pending_buffer, 0);
-
- prtd->pcm_irq_pos = 0;
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
- q6asm_audio_client_buf_free_contiguous(dir,
- prtd->audio_client);
- msm_pcm_routing_dereg_phy_stream(
- soc_prtd->dai_link->id,
- SNDRV_PCM_STREAM_PLAYBACK);
- q6asm_audio_client_free(prtd->audio_client);
- kfree(prtd);
- return 0;
-}
-
-static int msm_compr_capture_close(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
- int dir = OUT;
-
- pr_debug("%s\n", __func__);
- atomic_set(&prtd->pending_buffer, 0);
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
- q6asm_audio_client_buf_free_contiguous(dir,
- prtd->audio_client);
- msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
- SNDRV_PCM_STREAM_CAPTURE);
- q6asm_audio_client_free(prtd->audio_client);
- kfree(prtd);
- return 0;
-}
-
-static int msm_compr_close(struct snd_pcm_substream *substream)
-{
- int ret = 0;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- ret = msm_compr_playback_close(substream);
- else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ret = msm_compr_capture_close(substream);
- return ret;
-}
-
-static int msm_compr_prepare(struct snd_pcm_substream *substream)
-{
- int ret = 0;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- ret = msm_compr_playback_prepare(substream);
- else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ret = msm_compr_capture_prepare(substream);
- return ret;
-}
-
-static snd_pcm_uframes_t msm_compr_pointer(struct snd_pcm_substream *substream)
-{
-
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
-
- if (prtd->pcm_irq_pos >= prtd->pcm_size)
- prtd->pcm_irq_pos = 0;
-
- pr_debug("%s: pcm_irq_pos = %d, pcm_size = %d, sample_bits = %d,\n"
- "frame_bits = %d\n", __func__, prtd->pcm_irq_pos,
- prtd->pcm_size, runtime->sample_bits,
- runtime->frame_bits);
- return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
-}
-
-static int msm_compr_mmap(struct snd_pcm_substream *substream,
- struct vm_area_struct *vma)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct msm_audio *prtd = runtime->private_data;
- struct audio_client *ac = prtd->audio_client;
- struct audio_port_data *apd = ac->port;
- struct audio_buffer *ab;
- int dir = -1;
-
- prtd->mmap_flag = 1;
- runtime->render_flag = SNDRV_NON_DMA_MODE;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dir = IN;
- else
- dir = OUT;
- ab = &(apd[dir].buf[0]);
-
- return msm_audio_ion_mmap(ab, vma);
-}
-
-static int msm_compr_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
- struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
- struct audio_buffer *buf;
- int dir, ret;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dir = IN;
- else
- dir = OUT;
- /* Modifying kernel hardware params based on userspace config */
- if (params_periods(params) > 0 &&
- (params_periods(params) != runtime->hw.periods_max)) {
- runtime->hw.periods_max = params_periods(params);
- }
- if (params_period_bytes(params) > 0 &&
- (params_period_bytes(params) != runtime->hw.period_bytes_min)) {
- runtime->hw.period_bytes_min = params_period_bytes(params);
- }
- runtime->hw.buffer_bytes_max =
- runtime->hw.period_bytes_min * runtime->hw.periods_max;
- pr_debug("allocate %zd buffers each of size %d\n",
- runtime->hw.period_bytes_min,
- runtime->hw.periods_max);
- ret = q6asm_audio_client_buf_alloc_contiguous(dir,
- prtd->audio_client,
- runtime->hw.period_bytes_min,
- runtime->hw.periods_max);
- if (ret < 0) {
- pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
- ret);
- return -ENOMEM;
- }
- buf = prtd->audio_client->port[dir].buf;
-
- dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
- dma_buf->dev.dev = substream->pcm->card->dev;
- dma_buf->private_data = NULL;
- dma_buf->area = buf[0].data;
- dma_buf->addr = buf[0].phys;
- dma_buf->bytes = runtime->hw.buffer_bytes_max;
-
- pr_debug("%s: buf[%pK]dma_buf->area[%pK]dma_buf->addr[%pK]\n"
- "dma_buf->bytes[%zd]\n", __func__,
- (void *)buf, (void *)dma_buf->area,
- &dma_buf->addr, dma_buf->bytes);
- if (!dma_buf->area)
- return -ENOMEM;
-
- snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
- return 0;
-}
-
-static int msm_compr_ioctl_shared(struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
-{
- int rc = 0;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
- uint64_t timestamp;
- uint64_t temp;
-
- switch (cmd) {
- case SNDRV_COMPRESS_TSTAMP: {
- struct snd_compr_tstamp *tstamp;
-
- pr_debug("SNDRV_COMPRESS_TSTAMP\n");
- tstamp = arg;
- memset(tstamp, 0x0, sizeof(*tstamp));
- rc = q6asm_get_session_time(prtd->audio_client, ×tamp);
- if (rc < 0) {
- pr_err("%s: Get Session Time return value =%lld\n",
- __func__, timestamp);
- return -EAGAIN;
- }
- temp = (timestamp * 2 * runtime->channels);
- temp = temp * (runtime->rate/1000);
- temp = div_u64(temp, 1000);
- tstamp->sampling_rate = runtime->rate;
- tstamp->timestamp = timestamp;
- pr_debug("%s: bytes_consumed:,timestamp = %lld,\n",
- __func__,
- tstamp->timestamp);
- return 0;
- }
- case SNDRV_COMPRESS_GET_CAPS: {
- struct snd_compr_caps *caps;
-
- caps = arg;
- memset(caps, 0, sizeof(*caps));
- pr_debug("SNDRV_COMPRESS_GET_CAPS\n");
- memcpy(caps, &compr->info.compr_cap, sizeof(*caps));
- return 0;
- }
- case SNDRV_COMPRESS_SET_PARAMS:
- pr_debug("SNDRV_COMPRESS_SET_PARAMS:\n");
- memcpy(&compr->info.codec_param, (void *) arg,
- sizeof(struct snd_compr_params));
- switch (compr->info.codec_param.codec.id) {
- case SND_AUDIOCODEC_MP3:
- /* For MP3 we dont need any other parameter */
- pr_debug("SND_AUDIOCODEC_MP3\n");
- compr->codec = FORMAT_MP3;
- break;
- case SND_AUDIOCODEC_AAC:
- pr_debug("SND_AUDIOCODEC_AAC\n");
- compr->codec = FORMAT_MPEG4_AAC;
- break;
- case SND_AUDIOCODEC_AC3: {
- char params_value[MAX_AC3_PARAM_SIZE];
- int *params_value_data = (int *)params_value;
- /* 36 is the max param length for ddp */
- int i;
- struct snd_dec_ddp *ddp =
- &compr->info.codec_param.codec.options.ddp;
- uint32_t params_length = 0;
-
- memset(params_value, 0, MAX_AC3_PARAM_SIZE);
- /* check integer overflow */
- if (ddp->params_length > UINT_MAX/sizeof(int)) {
- pr_err("%s: Integer overflow ddp->params_length %d\n",
- __func__, ddp->params_length);
- return -EINVAL;
- }
- params_length = ddp->params_length*sizeof(int);
- if (params_length > MAX_AC3_PARAM_SIZE) {
- /*MAX is 36*sizeof(int) this should not happen*/
- pr_err("%s: params_length(%d) is greater than %zd\n",
- __func__, params_length, MAX_AC3_PARAM_SIZE);
- return -EINVAL;
- }
- pr_debug("SND_AUDIOCODEC_AC3\n");
- compr->codec = FORMAT_AC3;
- pr_debug("params_length: %d\n", ddp->params_length);
- for (i = 0; i < params_length/sizeof(int); i++)
- pr_debug("params_value[%d]: %x\n", i,
- params_value_data[i]);
- for (i = 0; i < ddp->params_length/2; i++) {
- ddp->params_id[i] = params_value_data[2*i];
- ddp->params_value[i] = params_value_data[2*i+1];
- }
- if (atomic_read(&prtd->start)) {
- rc = msm_compr_send_ddp_cfg(prtd->audio_client,
- ddp);
- if (rc < 0)
- pr_err("%s: DDP CMD CFG failed\n",
- __func__);
- }
- break;
- }
- case SND_AUDIOCODEC_EAC3: {
- char params_value[MAX_AC3_PARAM_SIZE];
- int *params_value_data = (int *)params_value;
- /* 36 is the max param length for ddp */
- int i;
- struct snd_dec_ddp *ddp =
- &compr->info.codec_param.codec.options.ddp;
- uint32_t params_length = 0;
-
- memset(params_value, 0, MAX_AC3_PARAM_SIZE);
- /* check integer overflow */
- if (ddp->params_length > UINT_MAX/sizeof(int)) {
- pr_err("%s: Integer overflow ddp->params_length %d\n",
- __func__, ddp->params_length);
- return -EINVAL;
- }
- params_length = ddp->params_length*sizeof(int);
- if (params_length > MAX_AC3_PARAM_SIZE) {
- /*MAX is 36*sizeof(int) this should not happen*/
- pr_err("%s: params_length(%d) is greater than %zd\n",
- __func__, params_length, MAX_AC3_PARAM_SIZE);
- return -EINVAL;
- }
- pr_debug("SND_AUDIOCODEC_EAC3\n");
- compr->codec = FORMAT_EAC3;
- pr_debug("params_length: %d\n", ddp->params_length);
- for (i = 0; i < ddp->params_length; i++)
- pr_debug("params_value[%d]: %x\n", i,
- params_value_data[i]);
- for (i = 0; i < ddp->params_length/2; i++) {
- ddp->params_id[i] = params_value_data[2*i];
- ddp->params_value[i] = params_value_data[2*i+1];
- }
- if (atomic_read(&prtd->start)) {
- rc = msm_compr_send_ddp_cfg(prtd->audio_client,
- ddp);
- if (rc < 0)
- pr_err("%s: DDP CMD CFG failed\n",
- __func__);
- }
- break;
- }
- default:
- pr_debug("FORMAT_LINEAR_PCM\n");
- compr->codec = FORMAT_LINEAR_PCM;
- break;
- }
- return 0;
- case SNDRV_PCM_IOCTL1_RESET:
- pr_debug("SNDRV_PCM_IOCTL1_RESET\n");
- /* Flush only when session is started during CAPTURE,
- * while PLAYBACK has no such restriction.
- */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
- (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
- atomic_read(&prtd->start))) {
- if (atomic_read(&prtd->eos)) {
- prtd->cmd_interrupt = 1;
- wake_up(&the_locks.eos_wait);
- atomic_set(&prtd->eos, 0);
- }
-
- /* A unlikely race condition possible with FLUSH
- * DRAIN if ack is set by flush and reset by drain
- */
- prtd->cmd_ack = 0;
- rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
- if (rc < 0) {
- pr_err("%s: flush cmd failed rc=%d\n",
- __func__, rc);
- return rc;
- }
- rc = wait_event_timeout(the_locks.flush_wait,
- prtd->cmd_ack, 5 * HZ);
- if (!rc)
- pr_err("Flush cmd timeout\n");
- prtd->pcm_irq_pos = 0;
- }
- break;
- case SNDRV_COMPRESS_DRAIN:
- pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__);
- if (atomic_read(&prtd->pending_buffer)) {
- pr_debug("%s: no pending writes, drain would block\n",
- __func__);
- return -EWOULDBLOCK;
- }
-
- atomic_set(&prtd->eos, 1);
- atomic_set(&prtd->pending_buffer, 0);
- prtd->cmd_ack = 0;
- q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
- /* Wait indefinitely for DRAIN. Flush can also signal this*/
- rc = wait_event_interruptible(the_locks.eos_wait,
- (prtd->cmd_ack || prtd->cmd_interrupt));
-
- if (rc < 0)
- pr_err("EOS cmd interrupted\n");
- pr_debug("%s: SNDRV_COMPRESS_DRAIN out of wait\n", __func__);
-
- if (prtd->cmd_interrupt)
- rc = -EINTR;
-
- prtd->cmd_interrupt = 0;
- return rc;
- default:
- break;
- }
- return snd_pcm_lib_ioctl(substream, cmd, arg);
-}
-#ifdef CONFIG_COMPAT
-struct snd_enc_wma32 {
- u32 super_block_align; /* WMA Type-specific data */
- u32 encodeopt1;
- u32 encodeopt2;
-};
-
-struct snd_enc_vorbis32 {
- s32 quality;
- u32 managed;
- u32 max_bit_rate;
- u32 min_bit_rate;
- u32 downmix;
-};
-
-struct snd_enc_real32 {
- u32 quant_bits;
- u32 start_region;
- u32 num_regions;
-};
-
-struct snd_enc_flac32 {
- u32 num;
- u32 gain;
-};
-
-struct snd_enc_generic32 {
- u32 bw; /* encoder bandwidth */
- s32 reserved[15];
-};
-struct snd_dec_ddp32 {
- u32 params_length;
- u32 params_id[18];
- u32 params_value[18];
-};
-
-union snd_codec_options32 {
- struct snd_enc_wma32 wma;
- struct snd_enc_vorbis32 vorbis;
- struct snd_enc_real32 real;
- struct snd_enc_flac32 flac;
- struct snd_enc_generic32 generic;
- struct snd_dec_ddp32 ddp;
-};
-
-struct snd_codec32 {
- u32 id;
- u32 ch_in;
- u32 ch_out;
- u32 sample_rate;
- u32 bit_rate;
- u32 rate_control;
- u32 profile;
- u32 level;
- u32 ch_mode;
- u32 format;
- u32 align;
- union snd_codec_options32 options;
- u32 reserved[3];
-};
-
-struct snd_compressed_buffer32 {
- u32 fragment_size;
- u32 fragments;
-};
-
-struct snd_compr_params32 {
- struct snd_compressed_buffer32 buffer;
- struct snd_codec32 codec;
- u8 no_wake_mode;
-};
-
-struct snd_compr_caps32 {
- u32 num_codecs;
- u32 direction;
- u32 min_fragment_size;
- u32 max_fragment_size;
- u32 min_fragments;
- u32 max_fragments;
- u32 codecs[MAX_NUM_CODECS];
- u32 reserved[11];
-};
-struct snd_compr_tstamp32 {
- u32 byte_offset;
- u32 copied_total;
- compat_ulong_t pcm_frames;
- compat_ulong_t pcm_io_frames;
- u32 sampling_rate;
- compat_u64 timestamp;
-};
-enum {
- SNDRV_COMPRESS_TSTAMP32 = _IOR('C', 0x20, struct snd_compr_tstamp32),
- SNDRV_COMPRESS_GET_CAPS32 = _IOWR('C', 0x10, struct snd_compr_caps32),
- SNDRV_COMPRESS_SET_PARAMS32 =
- _IOW('C', 0x12, struct snd_compr_params32),
-};
-static int msm_compr_compat_ioctl(struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
-{
- int err = 0;
-
- switch (cmd) {
- case SNDRV_COMPRESS_TSTAMP32: {
- struct snd_compr_tstamp tstamp;
- struct snd_compr_tstamp32 tstamp32;
-
- memset(&tstamp, 0, sizeof(tstamp));
- memset(&tstamp32, 0, sizeof(tstamp32));
- cmd = SNDRV_COMPRESS_TSTAMP;
- err = msm_compr_ioctl_shared(substream, cmd, &tstamp);
- if (err) {
- pr_err("%s: COMPRESS_TSTAMP failed rc %d\n",
- __func__, err);
- goto bail_out;
- }
- tstamp32.byte_offset = tstamp.byte_offset;
- tstamp32.copied_total = tstamp.copied_total;
- tstamp32.pcm_frames = tstamp.pcm_frames;
- tstamp32.pcm_io_frames = tstamp.pcm_io_frames;
- tstamp32.sampling_rate = tstamp.sampling_rate;
- tstamp32.timestamp = tstamp.timestamp;
- if (copy_to_user(arg, &tstamp32, sizeof(tstamp32))) {
- pr_err("%s: copytouser failed COMPRESS_TSTAMP32\n",
- __func__);
- err = -EFAULT;
- }
- break;
- }
- case SNDRV_COMPRESS_GET_CAPS32: {
- struct snd_compr_caps caps;
- struct snd_compr_caps32 caps32;
- u32 i;
-
- memset(&caps, 0, sizeof(caps));
- memset(&caps32, 0, sizeof(caps32));
- cmd = SNDRV_COMPRESS_GET_CAPS;
- err = msm_compr_ioctl_shared(substream, cmd, &caps);
- if (err) {
- pr_err("%s: GET_CAPS failed rc %d\n",
- __func__, err);
- goto bail_out;
- }
- pr_debug("SNDRV_COMPRESS_GET_CAPS_32\n");
- if (!err && caps.num_codecs >= MAX_NUM_CODECS) {
- pr_err("%s: Invalid number of codecs\n", __func__);
- err = -EINVAL;
- goto bail_out;
- }
- caps32.direction = caps.direction;
- caps32.max_fragment_size = caps.max_fragment_size;
- caps32.max_fragments = caps.max_fragments;
- caps32.min_fragment_size = caps.min_fragment_size;
- caps32.num_codecs = caps.num_codecs;
- for (i = 0; i < caps.num_codecs; i++)
- caps32.codecs[i] = caps.codecs[i];
- if (copy_to_user(arg, &caps32, sizeof(caps32))) {
- pr_err("%s: copytouser failed COMPRESS_GETCAPS32\n",
- __func__);
- err = -EFAULT;
- }
- break;
- }
- case SNDRV_COMPRESS_SET_PARAMS32: {
- struct snd_compr_params32 params32;
- struct snd_compr_params params;
-
- memset(¶ms32, 0, sizeof(params32));
- memset(¶ms, 0, sizeof(params));
- cmd = SNDRV_COMPRESS_SET_PARAMS;
- if (copy_from_user(¶ms32, arg, sizeof(params32))) {
- pr_err("%s: copyfromuser failed SET_PARAMS32\n",
- __func__);
- err = -EFAULT;
- goto bail_out;
- }
- params.no_wake_mode = params32.no_wake_mode;
- params.codec.id = params32.codec.id;
- params.codec.ch_in = params32.codec.ch_in;
- params.codec.ch_out = params32.codec.ch_out;
- params.codec.sample_rate = params32.codec.sample_rate;
- params.codec.bit_rate = params32.codec.bit_rate;
- params.codec.rate_control = params32.codec.rate_control;
- params.codec.profile = params32.codec.profile;
- params.codec.level = params32.codec.level;
- params.codec.ch_mode = params32.codec.ch_mode;
- params.codec.format = params32.codec.format;
- params.codec.align = params32.codec.align;
-
- switch (params.codec.id) {
- case SND_AUDIOCODEC_WMA:
- case SND_AUDIOCODEC_WMA_PRO:
- params.codec.options.wma.encodeopt1 =
- params32.codec.options.wma.encodeopt1;
- params.codec.options.wma.encodeopt2 =
- params32.codec.options.wma.encodeopt2;
- params.codec.options.wma.super_block_align =
- params32.codec.options.wma.super_block_align;
- break;
- case SND_AUDIOCODEC_VORBIS:
- params.codec.options.vorbis.downmix =
- params32.codec.options.vorbis.downmix;
- params.codec.options.vorbis.managed =
- params32.codec.options.vorbis.managed;
- params.codec.options.vorbis.max_bit_rate =
- params32.codec.options.vorbis.max_bit_rate;
- params.codec.options.vorbis.min_bit_rate =
- params32.codec.options.vorbis.min_bit_rate;
- params.codec.options.vorbis.quality =
- params32.codec.options.vorbis.quality;
- break;
- case SND_AUDIOCODEC_REAL:
- params.codec.options.real.num_regions =
- params32.codec.options.real.num_regions;
- params.codec.options.real.quant_bits =
- params32.codec.options.real.quant_bits;
- params.codec.options.real.start_region =
- params32.codec.options.real.start_region;
- break;
- case SND_AUDIOCODEC_FLAC:
- params.codec.options.flac.gain =
- params32.codec.options.flac.gain;
- params.codec.options.flac.num =
- params32.codec.options.flac.num;
- break;
- case SND_AUDIOCODEC_DTS:
- case SND_AUDIOCODEC_DTS_PASS_THROUGH:
- case SND_AUDIOCODEC_DTS_LBR:
- case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH:
- case SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK:
- break;
- case SND_AUDIOCODEC_AC3:
- case SND_AUDIOCODEC_EAC3:
- params.codec.options.ddp.params_length =
- params32.codec.options.ddp.params_length;
- memcpy(params.codec.options.ddp.params_value,
- params32.codec.options.ddp.params_value,
- sizeof(params32.codec.options.ddp.params_value));
- memcpy(params.codec.options.ddp.params_id,
- params32.codec.options.ddp.params_id,
- sizeof(params32.codec.options.ddp.params_id));
- break;
- default:
- params.codec.options.generic.bw =
- params32.codec.options.generic.bw;
- break;
- }
- if (!err)
- err = msm_compr_ioctl_shared(substream, cmd, ¶ms);
- break;
- }
- default:
- err = msm_compr_ioctl_shared(substream, cmd, arg);
- }
-bail_out:
- return err;
-
-}
-#endif
-static int msm_compr_ioctl(struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
-{
- int err = 0;
-
- if (!substream) {
- pr_err("%s: Invalid params\n", __func__);
- return -EINVAL;
- }
- pr_debug("%s called with cmd = %d\n", __func__, cmd);
- switch (cmd) {
- case SNDRV_COMPRESS_TSTAMP: {
- struct snd_compr_tstamp tstamp;
-
- if (!arg) {
- pr_err("%s: Invalid params Tstamp\n", __func__);
- return -EINVAL;
- }
- err = msm_compr_ioctl_shared(substream, cmd, &tstamp);
- if (err)
- pr_err("%s: COMPRESS_TSTAMP failed rc %d\n",
- __func__, err);
- if (!err && copy_to_user(arg, &tstamp, sizeof(tstamp))) {
- pr_err("%s: copytouser failed COMPRESS_TSTAMP\n",
- __func__);
- err = -EFAULT;
- }
- break;
- }
- case SNDRV_COMPRESS_GET_CAPS: {
- struct snd_compr_caps cap;
-
- if (!arg) {
- pr_err("%s: Invalid params getcaps\n", __func__);
- return -EINVAL;
- }
- pr_debug("SNDRV_COMPRESS_GET_CAPS\n");
- err = msm_compr_ioctl_shared(substream, cmd, &cap);
- if (err)
- pr_err("%s: GET_CAPS failed rc %d\n",
- __func__, err);
- if (!err && copy_to_user(arg, &cap, sizeof(cap))) {
- pr_err("%s: copytouser failed GET_CAPS\n",
- __func__);
- err = -EFAULT;
- }
- break;
- }
- case SNDRV_COMPRESS_SET_PARAMS: {
- struct snd_compr_params params;
-
- if (!arg) {
- pr_err("%s: Invalid params setparam\n", __func__);
- return -EINVAL;
- }
- if (copy_from_user(¶ms, arg,
- sizeof(struct snd_compr_params))) {
- pr_err("%s: SET_PARAMS\n", __func__);
- return -EFAULT;
- }
- err = msm_compr_ioctl_shared(substream, cmd, ¶ms);
- if (err)
- pr_err("%s: SET_PARAMS failed rc %d\n",
- __func__, err);
- break;
- }
- default:
- err = msm_compr_ioctl_shared(substream, cmd, arg);
- }
- return err;
-}
-
-static int msm_compr_restart(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
- struct audio_aio_write_param param;
- struct audio_buffer *buf = NULL;
- struct output_meta_data_st output_meta_data;
- int time_stamp_flag = 0;
- int buffer_length = 0;
-
- pr_debug("%s, trigger restart\n", __func__);
-
- if (runtime->render_flag & SNDRV_RENDER_STOPPED) {
- buf = prtd->audio_client->port[IN].buf;
- pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
- __func__, prtd->pcm_count, prtd->out_head);
- pr_debug("%s:writing buffer[%d] from 0x%08x\n",
- __func__, prtd->out_head,
- ((unsigned int)buf[0].phys
- + (prtd->out_head * prtd->pcm_count)));
-
- if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
- time_stamp_flag = SET_TIMESTAMP;
- else
- time_stamp_flag = NO_TIMESTAMP;
- memcpy(&output_meta_data, (char *)(buf->data +
- prtd->out_head * prtd->pcm_count),
- COMPRE_OUTPUT_METADATA_SIZE);
-
- buffer_length = output_meta_data.frame_size;
- pr_debug("meta_data_length: %d, frame_length: %d\n",
- output_meta_data.meta_data_length,
- output_meta_data.frame_size);
- pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
- output_meta_data.timestamp_msw,
- output_meta_data.timestamp_lsw);
-
- param.paddr = (unsigned long)buf[0].phys
- + (prtd->out_head * prtd->pcm_count)
- + output_meta_data.meta_data_length;
- param.len = buffer_length;
- param.msw_ts = output_meta_data.timestamp_msw;
- param.lsw_ts = output_meta_data.timestamp_lsw;
- param.flags = time_stamp_flag;
- param.uid = prtd->session_id;
- if (q6asm_async_write(prtd->audio_client,
- ¶m) < 0)
- pr_err("%s:q6asm_async_write failed\n",
- __func__);
- else
- prtd->out_head =
- (prtd->out_head + 1) & (runtime->periods - 1);
-
- runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
- return 0;
- }
- return 0;
-}
-
-static int msm_compr_volume_ctl_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int rc = 0;
- struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
- struct snd_pcm_substream *substream =
- vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
- struct msm_audio *prtd;
- int volume = ucontrol->value.integer.value[0];
-
- pr_debug("%s: volume : %x\n", __func__, volume);
- if (!substream)
- return -ENODEV;
- if (!substream->runtime)
- return 0;
- prtd = substream->runtime->private_data;
- if (prtd)
- rc = compressed_set_volume(prtd, volume);
-
- return rc;
-}
-
-static int msm_compr_volume_ctl_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
- struct snd_pcm_substream *substream =
- vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
- struct msm_audio *prtd;
-
- pr_debug("%s\n", __func__);
- if (!substream)
- return -ENODEV;
- if (!substream->runtime)
- return 0;
- prtd = substream->runtime->private_data;
- if (prtd)
- ucontrol->value.integer.value[0] = prtd->volume;
- return 0;
-}
-
-static int msm_compr_add_controls(struct snd_soc_pcm_runtime *rtd)
-{
- int ret = 0;
- struct snd_pcm *pcm = rtd->pcm;
- struct snd_pcm_volume *volume_info;
- struct snd_kcontrol *kctl;
-
- dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
- ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- NULL, 1, rtd->dai_link->id,
- &volume_info);
- if (ret < 0)
- return ret;
- kctl = volume_info->kctl;
- kctl->put = msm_compr_volume_ctl_put;
- kctl->get = msm_compr_volume_ctl_get;
- kctl->tlv.p = compr_rx_vol_gain;
- return 0;
-}
-
-static const struct snd_pcm_ops msm_compr_ops = {
- .open = msm_compr_open,
- .hw_params = msm_compr_hw_params,
- .close = msm_compr_close,
- .ioctl = msm_compr_ioctl,
- .prepare = msm_compr_prepare,
- .trigger = msm_compr_trigger,
- .pointer = msm_compr_pointer,
- .mmap = msm_compr_mmap,
- .restart = msm_compr_restart,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = msm_compr_compat_ioctl,
-#endif
-};
-
-static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_card *card = rtd->card->snd_card;
- int ret = 0;
-
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
- ret = msm_compr_add_controls(rtd);
- if (ret)
- pr_err("%s, kctl add failed\n", __func__);
- return ret;
-}
-
-static struct snd_soc_platform_driver msm_soc_platform = {
- .ops = &msm_compr_ops,
- .pcm_new = msm_asoc_pcm_new,
-};
-
-static int msm_compr_probe(struct platform_device *pdev)
-{
-
- dev_info(&pdev->dev, "%s: dev name %s\n",
- __func__, dev_name(&pdev->dev));
-
- return snd_soc_register_platform(&pdev->dev,
- &msm_soc_platform);
-}
-
-static int msm_compr_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
-}
-
-static const struct of_device_id msm_compr_dt_match[] = {
- {.compatible = "qcom,msm-compr-dsp"},
- {}
-};
-MODULE_DEVICE_TABLE(of, msm_compr_dt_match);
-
-static struct platform_driver msm_compr_driver = {
- .driver = {
- .name = "msm-compr-dsp",
- .owner = THIS_MODULE,
- .of_match_table = msm_compr_dt_match,
- },
- .probe = msm_compr_probe,
- .remove = msm_compr_remove,
-};
-
-static int __init msm_soc_platform_init(void)
-{
- init_waitqueue_head(&the_locks.enable_wait);
- init_waitqueue_head(&the_locks.eos_wait);
- init_waitqueue_head(&the_locks.write_wait);
- init_waitqueue_head(&the_locks.read_wait);
- init_waitqueue_head(&the_locks.flush_wait);
-
- return platform_driver_register(&msm_compr_driver);
-}
-module_init(msm_soc_platform_init);
-
-static void __exit msm_soc_platform_exit(void)
-{
- platform_driver_unregister(&msm_compr_driver);
-}
-module_exit(msm_soc_platform_exit);
-
-MODULE_DESCRIPTION("PCM module platform driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
deleted file mode 100644
index d6e3ec6..0000000
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef _MSM_COMPR_H
-#define _MSM_COMPR_H
-#include <sound/apr_audio-v2.h>
-#include <sound/q6asm-v2.h>
-#include <sound/compress_params.h>
-#include <sound/compress_offload.h>
-#include <sound/compress_driver.h>
-
-#include "msm-pcm-q6-v2.h"
-
-struct compr_info {
- struct snd_compr_caps compr_cap;
- struct snd_compr_codec_caps codec_caps;
- struct snd_compr_params codec_param;
-};
-
-struct compr_audio {
- struct msm_audio prtd;
- struct compr_info info;
- uint32_t codec;
-};
-
-#endif /*_MSM_COMPR_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 37dd31f..421769e 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -1165,28 +1165,27 @@
break;
case SNDRV_LSM_SET_FWK_MODE_CONFIG: {
- u32 *mode = NULL;
+ u32 mode;
- if (!arg) {
- dev_err(rtd->dev,
- "%s: Invalid param arg for ioctl %s session %d\n",
- __func__, "SNDRV_LSM_SET_FWK_MODE_CONFIG",
- prtd->lsm_client->session);
- rc = -EINVAL;
- break;
+ if (copy_from_user(&mode, arg, sizeof(mode))) {
+ dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n",
+ __func__, "LSM_SET_FWK_MODE_CONFIG");
+ return -EFAULT;
}
- mode = (u32 *)arg;
- if (prtd->lsm_client->event_mode == *mode) {
+
+ dev_dbg(rtd->dev, "%s: ioctl %s, enable = %d\n",
+ __func__, "SNDRV_LSM_SET_FWK_MODE_CONFIG", mode);
+ if (prtd->lsm_client->event_mode == mode) {
dev_dbg(rtd->dev,
"%s: mode for %d already set to %d\n",
- __func__, prtd->lsm_client->session, *mode);
+ __func__, prtd->lsm_client->session, mode);
rc = 0;
} else {
dev_dbg(rtd->dev, "%s: Event mode = %d\n",
- __func__, *mode);
- rc = q6lsm_set_fwk_mode_cfg(prtd->lsm_client, *mode);
+ __func__, mode);
+ rc = q6lsm_set_fwk_mode_cfg(prtd->lsm_client, mode);
if (!rc)
- prtd->lsm_client->event_mode = *mode;
+ prtd->lsm_client->event_mode = mode;
else
dev_err(rtd->dev,
"%s: set event mode failed %d\n",
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index c5a6e0b1..78bd632 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -1826,7 +1826,7 @@
filt->addr = start;
if (filt->range && !filt->size && !filt->sym_to) {
filt->size = size;
- no_size = !!size;
+ no_size = !size;
}
}
@@ -1840,7 +1840,7 @@
if (err)
return err;
filt->size = start + size - filt->addr;
- no_size = !!size;
+ no_size = !size;
}
/* The very last symbol in kallsyms does not imply a particular size */
diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c
index 4af4707..e717fed 100644
--- a/tools/testing/selftests/x86/ldt_gdt.c
+++ b/tools/testing/selftests/x86/ldt_gdt.c
@@ -403,6 +403,51 @@
}
}
+#ifdef __i386__
+
+#ifndef SA_RESTORE
+#define SA_RESTORER 0x04000000
+#endif
+
+/*
+ * The UAPI header calls this 'struct sigaction', which conflicts with
+ * glibc. Sigh.
+ */
+struct fake_ksigaction {
+ void *handler; /* the real type is nasty */
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+ unsigned char sigset[8];
+};
+
+static void fix_sa_restorer(int sig)
+{
+ struct fake_ksigaction ksa;
+
+ if (syscall(SYS_rt_sigaction, sig, NULL, &ksa, 8) == 0) {
+ /*
+ * glibc has a nasty bug: it sometimes writes garbage to
+ * sa_restorer. This interacts quite badly with anything
+ * that fiddles with SS because it can trigger legacy
+ * stack switching. Patch it up. See:
+ *
+ * https://sourceware.org/bugzilla/show_bug.cgi?id=21269
+ */
+ if (!(ksa.sa_flags & SA_RESTORER) && ksa.sa_restorer) {
+ ksa.sa_restorer = NULL;
+ if (syscall(SYS_rt_sigaction, sig, &ksa, NULL,
+ sizeof(ksa.sigset)) != 0)
+ err(1, "rt_sigaction");
+ }
+ }
+}
+#else
+static void fix_sa_restorer(int sig)
+{
+ /* 64-bit glibc works fine. */
+}
+#endif
+
static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
int flags)
{
@@ -414,6 +459,7 @@
if (sigaction(sig, &sa, 0))
err(1, "sigaction");
+ fix_sa_restorer(sig);
}
static jmp_buf jmpbuf;