Merge "arm/dt: msm8226: Add support for Primary AUXPCM"
diff --git a/Documentation/ata/ahci_msm.txt b/Documentation/ata/ahci_msm.txt
new file mode 100644
index 0000000..2f84834
--- /dev/null
+++ b/Documentation/ata/ahci_msm.txt
@@ -0,0 +1,322 @@
+Introduction
+============
+The SATA Host Controller developed for Qualcomm SoC is used
+to facilitate SATA storage devices that connect to SoC through a
+standard SATA cable interface. The MSM Advanced Host Controller
+Interface (AHCI) driver interfaces with the generic Linux AHCI driver
+and communicates with the AHCI controller for data movement between
+system memory and SATA devices (persistent storage).
+
+Hardware description
+====================
+Serial Advanced Technology Attachment (SATA) is a communication
+protocol designed to transfer data between a computer and storage
+devices (Hard Disk Drive(HDD), Solid State Drives(SSD) etc.).
+First generation (Gen1) SATA interfaces communicate at a serial
+rate of 1.5Gb/s and use low-voltage differential signaling on
+serial links. With 8b-10b encoding, the effective data throughput
+for Gen1 interface is 150MB/s.
+
+The SATA host controller in Qualcomm chipsets adheres to the AHCI 1.3
+specification which describes the interface between system software
+and the host controller, as well as the functional behavior needed
+for software to communicate with the SATA host controller.
+
+The SATA PHY hardware macro in Qualcomm chipsets adheres to the
+SATA 3.0 specification with Gen1 serial interface. This is used to
+serialize and de-serialize data and communicates with SATA HDD. Also,
+the PHY can detect SATA HDD during hot swap and raise an interrupt to
+the CPU through AHCI controller to notify about the detection/removal.
+
+The following figure shows the SATA architecture block diagram as
+implemented in MSM chipsets.
+
+ +---------+
+ |SATA Disk|
+ | Drive |
+ +---------+
+ ^ ^
+ Tx | | Rx
+ v v
++--------------+ +--------------+ +-----------+
+| System Memory| | SATA PHY | | CPU |
++--------------+ +--------------+ +-----------+
+ ^ ^ ^ ^ ^
+ | | | | |
+ | v v | |
+ | +------------------+(Interrupt)|
+ | | SATA CONTROLLER |-----+ |
+ | +------------------+ |
+ | ^ ^ |
+ | | | |
+ v v v v
+ <--------------------------------------------------------->
+< System Fabric (Control and Data) >
+ <--------------------------------------------------------->
+
+Some controller capabilities:
+- Supports 64-bit addressing
+- Supports native command queueing (upto 32 commands)
+- Supports First-party DMA to move data to and from system memory
+- ATA-7 command set compliant
+- Port multiplier support for some chipsets
+- Supports aggressive power management (partial, slumber modes)
+- Supports asynchronous notification
+
+Software description
+====================
+The SATA driver uses the generic interface to read/write data to
+the Hard Disk Drive (HDD). It uses following components in Linux
+to interface with the generic block layer which then interfaces
+with file system or user processes.
+
+1) AHCI platform Driver (includes MSM-specific glue driver)
+2) LIBAHCI
+3) LIBATA
+4) SCSI
+
+AHCI platform driver registers as a device driver for platform
+device registered during SoC board initialization. It is responsible
+for platform specific tasks like PHY configuration, clock initial-
+ization, claiming memory resources etc. Also, implements certain
+functionality that deviates from the standard specification.
+
+Library "LIBAHCI" implements software layer functionality described
+in the standard AHCI specification. It interfaces with the LIBATA
+framework to execute SATA the command set. It converts ATA task files
+into AHCI command descriptors and pass them to the controller for
+execution. It handles controller interrupts and sends command
+completion events to the upper layers. It implements a controller-
+specific reset and recover mechanism in case of errors. It implements
+link power management policies - partial, slumber modes, runtime power
+management and platform power management. It abstracts the low-level
+controller details from the LIBATA framework.
+
+"LIBATA" is a helper library for implementing ATA and SATA command
+protocol as described in standard ATA and SATA specifications. It
+builds read/write requests from SCSI commands and pass them to the
+low-level controller driver (LLD). It handshakes with the SATA
+device using standard commands to understand capabilities and carry
+out device configurations. It interfaces with the SCSI layer to manage
+underlying disks. It manages different devices connected to each host
+port using a port multiplier. Also, it manages the link PHY component,
+the interconnect interface and any external interface (cables, etc.)
+that follow the SATA electrical specification.
+
+The SCSI layer is a helper library for translating generic block layer
+commands to SCSI commands and pass them on to the LIBATA framework.
+Certain generic stuff like device scan, media change, and hot plug
+detection are handled. This layer handles all types of SCSI devices,
+and SATA storage devices are one class of SCSI devices. It also provides
+the IOCTL interface to manage disks from userspace.
+
+Following is the logical code flow:
+
+ +------------------------+
+ | File System (ext4 etc.)|
+ +------------------------+
+ ^
+ |
+ v
+ +------------------------+
+ | Generic Block Layer |
+ +------------------------+
+ ^
+ |
+ v
+ +------------------------+
+ | SCSI Layer |
+ +------------------------+
+ ^
+ |
+ v
+ +------------------------+
+ | LIBATA library |
+ +------------------------+
+ ^
+ |
+ v
+ +------------------------+
+ | LIBAHCI library |
+ +------------------------+
+ ^
+ |
+ v
+ +------------------------+
+ | AHCI platform driver + |
+ | MSM AHCI glue driver |
+ +------------------------+
+
+Design
+======
+The MSM AHCI driver acts as a glue driver for the Linux
+AHCI controller driver. It provides the following functionality:
+- Registers as a driver for msm_sata device which has an AHCI-compliant
+ controller and PHY as resources.
+- Registers an AHCI platform device in the probe function providing
+ ahci platform data
+- AHCI platform data consists of the following callbacks:
+ - init
+ o PHY resource acquisition
+ o Clock and voltage regulator initialization
+ o PHY calibration
+ - exit
+ o PHY power down
+ o Clock and voltage regulator turn off
+ - suspend
+ - resume
+ o Sequence described in the next section.
+- The Linux AHCI platform driver then probes the AHCI device and
+ initializes it according to the standard AHCI specification.
+- The SATA drive is detected as part of scsi_scan_host() called by
+ LIBAHCI after controller initialization.
+
+Power Management
+================
+Various power modes are supported by this driver.
+
+Platform suspend/resume:
+During suspend:
+- PHY analog blocks are powered down
+- Controller and PHY is kept in Power-on-Reset (POR) mode
+- Clocks and voltage regulators are gated
+
+During resume:
+- Clocks and voltage regulators are ungated
+- PHY is powered up and calibrated to functional mode
+- Controller is re-initialized to process commands.
+
+Runtime suspend/resume:
+- Execute the same steps as in platform suspend/resume.
+- Runtime suspend/resume is disabled by default due to regressions
+ in hot-plug detection (specification limitation). The users can
+ enable runtime power management with following shell commands.
+
+ # cd /sys/devices/platform/msm_sata.0/ahci.0/
+ # echo auto > ./power/control
+ # echo auto > ./ata1/power/control
+ # echo auto > ./ata1/host0/target0:0:0/0:0:0:0/power/control
+
+ Note: The device will be runtime-suspended only when user unmounts
+ all the partitions.
+
+Link power management (defined by AHCI 1.3 specification):
+- Automatic low power mode transition are supported.
+- AHCI supports two power modes: partial and slumber.
+- Software uses Inteface Communication Control (ICC) bits in AHCI
+ register space to enable automatic partial/slumber state.
+- Partial mode:
+ - Software asserts automatic partial mode when the use
+ case demands low latency resume.
+ - Upon receiving partial mode signal, PHY disables byte clocks
+ and re-enables them during resume and thus has low latency.
+- Slumber mode:
+ - Software asserts automatic slumber mode when the use
+ case demands low power consumption and can withstand
+ high resume latencies.
+ - Upon receiving slumber mode signal, PHY disables byte
+ clocks and some internal circuitry. Upon resume PHY
+ enables byte clocks and reacquires the PLL lock.
+- Once the software enables partial/slumber modes, the transitioning
+ into these modes are automatic and is handled by hardware without
+ software intervention while the controller is idle with no outstanding
+ commands to process.
+
+- The Linux AHCI link power management defines three modes:
+ - max_performance (default mode)
+ Doesn't allow partial/slumber transition when host is idle.
+ - medium_power (Partial mode)
+ Following shell commands are used to enable this mode:
+
+ # cd /sys/devices/platform/msm_sata.0/ahci.0/
+ # echo medium_power > ./ata1/host0/scsi_host/host0/link_power_management_policy
+
+ - min_power (Slumber mode)
+ Following shell commands are used to enable this mode:
+
+ # cd /sys/devices/platform/msm_sata.0/ahci.0/
+ # echo min_power > ./ata1/host0/scsi_host/host0/link_power_management_policy
+
+SMP/multi-core
+==============
+The MSM AHCI driver hooks only init, exit, suspend, resume callbacks to
+the AHCI driver which are serialized by design and hence the driver, which
+is inherently SMP safe.
+
+Security
+========
+None.
+
+Performance
+===========
+The theoretical performance with Gen1 SATA PHY is 150MB/s (8b/10b encoding).
+The performance is dependent on various factors, mainly:
+- Capabilities of the external SATA hard disk connected to the MSM SATA port
+- Various system bus frequencies and system loads
+- System memory capabilities
+- Benchmark test applications that collect performance numbers
+
+One example of the maximum performance achieved in a specific system
+configuration follows:
+
+Benchmark: Iozone sequential performance
+Block size: 128K
+File size: 1GB
+Platform: APQ8064 V2 CDP
+CPU Governor: Performance
+
+SanDisk SSD (i100 64GB):
+Read - 135MB/s
+Write - 125MB/s
+
+Western Digital HDD (WD20EURS 2TB):
+Read - 121MB/s
+Write - 98MB/s
+
+Interface
+=========
+The MSM AHCI controller driver provides function pointers as the
+required interface to the Linux AHCI controller driver. The main
+routines implemented are init, exit, suspend, and resume for handling
+MSM-specific initialization, freeing of resources on exit, and
+MSM-specific power management tweaks during suspend power collapse.
+
+Driver parameters
+=================
+None.
+
+Config options
+==============
+Config option SATA_AHCI_MSM in drivers/ata/Kconfig enables this driver.
+
+Dependencies
+============
+The MSM AHCI controller driver is dependent on Linux AHCI driver,
+Linux ATA framework, Linux SCSI framework and Linux generic block layer.
+
+While configuring the kernel, the following options should be set:
+
+- CONFIG_BLOCK
+- CONFIG_SCSI
+- CONFIG_ATA
+- CONFIG_SATA_AHCI_PLATFORM
+
+User space utilities
+====================
+Any user space component that can mount a block device can be used to
+read/write data into persistent storage. However, at the time of this
+writing there are no utilities that author is aware of that can manage
+h/w from userspace.
+
+Other
+=====
+None.
+
+Known issues
+============
+None.
+
+To do
+=====
+- Device tree support.
+- MSM bus frequency voting support.
diff --git a/Documentation/devicetree/bindings/arm/msm/acpuclock/acpuclock-a7.txt b/Documentation/devicetree/bindings/arm/msm/acpuclock/acpuclock-a7.txt
index 7a15f6a..a77d435 100644
--- a/Documentation/devicetree/bindings/arm/msm/acpuclock/acpuclock-a7.txt
+++ b/Documentation/devicetree/bindings/arm/msm/acpuclock/acpuclock-a7.txt
@@ -10,7 +10,6 @@
- reg-names: name of the bases for the above registers. "rcg_base"
is expected.
- a7_cpu-supply: regulator to supply a7 cpu
-- a7_mem-supply: regulator to supply a7 l2 cache
Example:
qcom,acpuclk@f9011050 {
@@ -18,5 +17,4 @@
reg = <0xf9011050 0x8>;
reg-names = "rcg_base";
a7_cpu-supply = <&pm8026_s2>;
- a7_mem-supply = <&pm8026_l3>;
};
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 203730f..439418d 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -13,8 +13,10 @@
Required properties:
- compatible: Must be "qcom,cpr-regulator"
- reg: Register addresses for RBCPR and efuse
-- reg-names: Register names. Must be "rbcpr" and "efuse_phys"
+- reg-names: Register names. Must be "rbcpr", "pvs_efuse"
+ and "cpr_efuse"
- regulator-name: A string used to describe the regulator
+- interrupts: Interrupt line from RBCPR to interrupt controller.
- regulator-min-microvolt: Minimum corner value as min constraint, which
should be 1 for SVS corner
- regulator-max-microvolt: Maximum corner value as max constraint, which
@@ -23,9 +25,6 @@
represent total number of PVS bins. It should
not exceed a maximum of 5 for total number of
32 bins.
-- qcom,efuse-bit-pos: A list of integers whose length must equal
- to qcom,num-efuse-bits and each integer indicates
- bit position in efuse memory from LSB to MSB
- qcom,pvs-bin-process: A list of integers whose length is equal to 2 to
the power of qcom,num-efuse-bits. The location or
0-based index of an element in the list corresponds
@@ -44,8 +43,25 @@
0 (SVS voltage): 1050000 uV
1 (NORMAL voltage): 1150000 uV
2 (TURBO voltage): 1275000 uV
- 3 (SUPER_TURBO voltage): 1275000 uV
- vdd-apc-supply: Regulator to supply VDD APC power
+- qcom,vdd-apc-step-up-limit: Limit of vdd-apc-supply steps for scaling up.
+- qcom,vdd-apc-step-down-limit: Limit of vdd-apc-supply steps for scaling down.
+- qcom,cpr-ref-clk: The reference clock in kHz.
+- qcom,cpr-timer-delay: The delay in microseconds for the timer interval.
+- qcom,cpr-timer-cons-up: Consecutive number of timer interval (qcom,cpr-timer-delay)
+ occurred before issuing UP interrupt.
+- qcom,cpr-timer-cons-down: Consecutive number of timer interval (qcom,cpr-timer-delay)
+ occurred before issuing DOWN interrupt.
+- qcom,cpr-irq-line: Internal interrupt route signal of RBCPR, one of 0, 1 or 2.
+- qcom,cpr-step-quotient: Number of CPR quotient (RO count) per vdd-apc-supply step
+ to issue error_steps.
+- qcom,cpr-up-threshold: The threshold for CPR to issue interrupt when
+ error_steps is greater than it when stepping up.
+- qcom,cpr-down-threshold: The threshold for CPR to issue interrupt when
+ error_steps is greater than it when stepping down.
+- qcom,cpr-idle-clocks: Idle clock cycles RO can be in.
+- qcom,cpr-gcnt-time: The time for gate count in microseconds.
+- qcom,cpr-apc-volt-step: The voltage in microvolt per CPR step, such as 5000uV.
Optional properties:
@@ -61,28 +77,42 @@
2 => equal to slow speed corner ceiling
3 => equal to qcom,vdd-mx-vmax
This is required when vdd-mx-supply is present.
+- qcom,cpr-enable: Present: CPR enabled by default.
+ Not Present: CPR disable by default.
Example:
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
- reg = <0xf9018000 0x1000>,
- <0xfc4b80b0 8>;
- reg-names = "rbcpr", "efuse_phys";
+ reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
+ reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+ interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <4>;
+ regulator-max-microvolt = <3>;
qcom,num-efuse-bits = <5>;
- qcom,efuse-bit-pos = <6 7 8 9 10>;
- qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
- qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
- qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000 1200000>;
- qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000 1140000>;
+ qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
+ qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000>;
vdd-apc-supply = <&pm8226_s2>;
vdd-mx-supply = <&pm8226_l3_ao>;
qcom,vdd-mx-vmax = <1350000>;
qcom,vdd-mx-vmin-method = <1>;
+ qcom,vdd-apc-step-up-limit = <1>;
+ qcom,vdd-apc-step-down-limit = <1>;
+ qcom,cpr-ref-clk = <19200>;
+ qcom,cpr-timer-delay = <5000>;
+ qcom,cpr-timer-cons-up = <1>;
+ qcom,cpr-timer-cons-down = <2>;
+ qcom,cpr-irq-line = <0>;
+ qcom,cpr-step-quotient = <15>;
+ qcom,cpr-up-threshold = <1>;
+ qcom,cpr-down-threshold = <2>;
+ qcom,cpr-idle-clocks = <5>;
+ qcom,cpr-gcnt-time = <1>;
+ qcom,cpr-apc-volt-step = <5000>;
};
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index 31600ca..23498e5 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -56,15 +56,15 @@
Optional child nodes
- qcom,<vdd restriction child node name>: Define the name of the child node.
- If this property exisits, qcom,vdd-rstr-reg, qcom,levels,
- qcom,min-level and qcom,freq-req need to exist, otherwise
- we return an error.
+ If this property exisits, qcom,vdd-rstr-reg, qcom,levels
+ need to exist. qcom,min-level is optional if qcom,freq-req
+ exists, otherwise it's required.
- qcom,vdd-rstr-reg: Name of the rail
- qcom,levels: Array of the level values. Unit is corner voltage for voltage request
or kHz for frequency request.
- qcom,min-level: Request this level as minimum level when disabling voltage
- restriction. Unit is corner voltage for voltage request
- or kHz for frequency request.
+ restriction. Unit is corner voltage for voltage request.
+ This will not be required if qcom,freq-req exists.
- qcom,freq-req: Flag to determine if we should restrict frequency on this rail
instead of voltage.
@@ -92,5 +92,11 @@
qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
qcom,min-level = <1>; /* No Request */
};
+
+ qcom,vdd-apps-rstr{
+ qcom,vdd-rstr-reg = "vdd_apps";
+ qcom,levels = <1881600 1958400 2265600>;
+ qcom,freq-req;
+ };
};
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index 25219cd..ce797d3 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -19,7 +19,8 @@
"arm,coresight-stm" for coresight stm trace device,
"arm,coresight-etm" for coresight etm trace devices,
"qcom,coresight-csr" for coresight csr device,
- "arm,coresight-cti" for coresight cti devices
+ "arm,coresight-cti" for coresight cti devices,
+ "qcom,coresight-hwevent" for coresight hardware event devices
- reg : physical base address and length of the register set(s) of the component
- reg-names : names corresponding to each reg property value. The reg-names that
need to be used with corresponding compatible string for a coresight device
@@ -61,6 +62,12 @@
compatible : should be "arm,coresight-cti"
reg-names : should be:
"cti<num>-base" - physical base address of cti registers
+ - for coresight hardware event devices:
+ compatible : should be "qcom,coresight-hwevent"
+ reg-names : should be:
+ "<ss-mux>" - physical base address of hardware event mux
+ control registers where <ss-mux> is subsystem mux it
+ represents
- coresight-id : unique integer identifier for the component
- coresight-name : unique descriptive name of the component
- coresight-nr-inports : number of input ports on the component
@@ -105,6 +112,7 @@
- qcom,setb-gpios-drv : active drive strength for set B gpios
- qcom,setb-gpios-pull : active pull configuration for set B gpios
- qcom,setb-gpios-dir : active direction for set B gpios
+- qcom,hwevent-clks : list of clocks required by hardware event driver
Examples:
@@ -213,3 +221,17 @@
coresight-name = "coresight-cti1";
coresight-nr-inports = <0>;
};
+
+ hwevent: hwevent@fdf30018 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0xfdf30018 0x80>,
+ <0xf9011080 0x80>,
+ <0xfd4ab160 0x80>;
+ reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+
+ coresight-id = <29>;
+ coresight-name = "coresight-hwevent";
+ coresight-nr-inports = <0>;
+
+ qcom,hwevent-clks = "core_mmss_clk";
+ };
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index a3f3a06..9bc949e 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -112,6 +112,18 @@
compression feature in the rotator.
- qcom,mdss-has-decimation: Boolean property to indicate the presence of
decimation feature in fetch.
+- qcom,mdss-ad-off: Array of offset addresses for the available
+ Assertive Display (AD) blocks. These offsets
+ are calculated from the register "mdp_phys"
+ defined in reg property. The number of AD
+ offsets should be less than or equal to the
+ number of mixers driving interfaces defined in
+ property: qcom,mdss-mixer-intf-off. Assumes
+ that AD blocks are aligned with the mixer
+ offsets as well (i.e. the first mixer offset
+ corresponds to the same pathway as the first
+ AD offset).
+
Optional subnodes:
Child nodes representing the frame buffer virtual devices.
diff --git a/Documentation/devicetree/bindings/input/gen_vkeys.txt b/Documentation/devicetree/bindings/input/gen_vkeys.txt
index da99e19..2f8d65e 100644
--- a/Documentation/devicetree/bindings/input/gen_vkeys.txt
+++ b/Documentation/devicetree/bindings/input/gen_vkeys.txt
@@ -12,6 +12,9 @@
- qcom,panel-maxy : Maximum y-coordinate of touch panel
- qcom,key-codes : Array of key codes for virtual keys
+Optional properties:
+ - qcom,y-offset : Offset of y-location for virtual keys, default 0
+
Example:
gen-vkeys {
compatible = "qcom,gen-vkeys";
@@ -21,4 +24,5 @@
qcom,panel-maxx = <760>;
qcom,panel-maxy = <1424>;
qcom,key-codes = <158 139 102 217>;
+ qcom,y-offset = <35>;
};
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
index cc1ffc2..706ffe6 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
@@ -11,17 +11,21 @@
- qcom,iommu-pmu-ngroups: Number of Performance Monitor Unit (PMU) groups.
- qcom,iommu-pmu-ncounters: Number of PMU counters per group.
- qcom,iommu-pmu-event-classes: List of event classes supported.
+- qcom,needs-alt-core-clk : boolean to enable the secondary core clock for
+ access to the IOMMU configuration registers
+
- List of sub nodes, one for each of the translation context banks supported.
- Each sub node has the following required properties:
+ Required properties for each sub-node:
- - reg : offset and length of the register set for the context bank.
- - interrupts : should contain the context bank interrupt.
- - qcom,iommu-ctx-mids : List of machine identifiers associated with this
- translation context.
- - label : Name of the context bank
+ - compatible : "qcom,msm-smmu-v0-ctx"
+ - reg : offset and length of the register set for the context bank.
+ - interrupts : should contain the context bank interrupt.
+ - qcom,iommu-ctx-mids : List of machine identifiers associated with this
+ translation context.
+ - label : Name of the context bank
-Optional properties:
- - none
+ Optional properties for each sub-node:
+ - none
Example:
@@ -39,6 +43,7 @@
0x11>;
qcom,iommu-ctx@fd000000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd000000 0x1000>;
interrupts = <0 250 0>;
qcom,iommu-ctx-mids = <0 3>;
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
index 2c47f74..56f4767 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
@@ -25,6 +25,7 @@
- List of sub nodes, one for each of the translation context banks supported.
Each sub node has the following required properties:
+ - compatible : "qcom,msm-smmu-v1-ctx"
- reg : offset and length of the register set for the context bank.
- interrupts : should contain the context bank interrupt.
- qcom,iommu-ctx-sids : List of stream identifiers associated with this
@@ -65,12 +66,14 @@
0x01>;
qcom,iommu-ctx@fda6c000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda6c000 0x1000>;
interrupts = <0 70 0>;
qcom,iommu-ctx-sids = <0 2>;
label = "ctx_0";
};
qcom,iommu-ctx@fda6d000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda6d000 0x1000>;
interrupts = <0 71 0>;
qcom,iommu-ctx-sids = <1>;
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index a221433..c409ea6 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -4,7 +4,7 @@
controlling LEDs that are part of PMIC on Qualcomm reference
platforms. The PMIC is connected to Host processor via
SPMI bus. This driver supports various LED modules such as
-WLED (white LED), RGB LED and flash LED.
+Keypad backlight, WLED (white LED), RGB LED and flash LED.
Each LED module is represented as a node of "leds-qpnp". This
node will further contain the type of LED supported and its
@@ -45,6 +45,7 @@
- qcom,saftey-timer: include for safety timer use, otherwise watchdog timer will be used
- linux,default-trigger: trigger the led from external modules such as display
- qcom,default-state: default state of the led, should be "on" or "off"
+- qcom,torch-enable: set flash led to torch mode
RGB Led is a tri-colored led, Red, Blue & Green.
@@ -76,6 +77,18 @@
- qcom,source-sel: select power source, default 1 (enabled)
- qcom,mode-ctrl: select operation mode, default 0x60 = Mode Sink
+Keypad backlight is a backlight source for buttons. It supports four rows
+and the required rows are enabled by specifying values in the properties.
+
+Required properties for keypad backlight:
+- qcom,mode: mode the led should operate in, options 0 = PWM, 1 = LPG
+- qcom,pwm-channel: pwm channel the led will operate on
+- qcom,pwm-us: time the pwm device will modulate at (us)
+- qcom,row-src-sel-val: select source for rows. One bit is used for each row.
+ Specify 0 for vph_pwr and 1 for vbst for each row.
+- qcom,row-scan-val: select rows for scanning
+- qcom,row-scan-en: row scan enable
+
Example:
qcom,leds@a200 {
@@ -174,3 +187,18 @@
};
};
+ qcom,leds@e200 {
+ status = "okay";
+ qcom,kpdbl {
+ label = "kpdbl";
+ linux,name = "button-backlight";
+ qcom,mode = <0>;
+ qcom,pwm-channel = <8>;
+ qcom,pwm-us = <1000>;
+ qcom,id = <7>;
+ qcom,max-current = <20>;
+ qcom,row-src-sel-val = <0x00>;
+ qcom,row-scan-en = <0x01>;
+ qcom,row-scan-val = <0x01>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
index 199862f..85ccc5d 100644
--- a/Documentation/devicetree/bindings/pil/pil-pronto.txt
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -14,6 +14,7 @@
- vdd_pronto_pll-supply: regulator to supply pronto pll.
- qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
- qcom,gpio-err-fatal: GPIO used by the wcnss to indicate error fatal to the Apps.
+- qcom,gpio-err-ready: GPIO used by the wcnss to indicate error ready to the Apps.
- qcom,gpio-proxy-unvote: GPIO used by the wcnss to trigger proxy unvoting in
the Apps
- qcom,gpio-force-stop: GPIO used by the Apps to force the wcnss to shutdown.
@@ -32,6 +33,7 @@
/* GPIO input from wcnss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
qcom,proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
/* GPIO output to wcnss */
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index 4cbff52..a7a3f0c 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -15,6 +15,7 @@
- vdd_cx-supply: Reference to the regulator that supplies the vdd_cx domain.
- qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
- qcom,gpio-err-fatal: GPIO used by the lpass to indicate error fatal to the apps.
+- qcom,gpio-err-ready: GPIO used by the lpass to indicate apps error service is ready.
- qcom,gpio-force-stop: GPIO used by the apps to force the lpass to shutdown.
- qcom,gpio-proxy-unvote: GPIO used by the lpass to indicate apps clock is ready.
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 2d20794..ded8f77 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -12,21 +12,26 @@
- reg-names: Names of the bases for the above registers. "qdsp6_base",
"halt_base", "rmb_base", and "restart_reg" are expected.
- interrupts: The modem watchdog interrupt
-- vdd_mss-supply: Reference to the regulator that supplies the processor.
- vdd_cx-supply: Reference to the regulator that supplies the vdd_cx domain.
- vdd_mx-supply: Reference to the regulator that supplies the memory rail.
- qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
- qcom,gpio-err-fatal: GPIO used by the modem to indicate error fatal to the apps.
+- qcom,gpio-err-ready: GPIO used by the modem to indicate error ready to the apps.
- qcom,gpio-proxy-unvote: GPIO used by the modem to trigger proxy unvoting in
the apps.
- qcom,gpio-force-stop: GPIO used by the apps to force the modem to shutdown.
Optional properties:
+- vdd_mss-supply: Reference to the regulator that supplies the processor.
+ This may be a shared regulator that is already voted
+ on in the PIL proxy voting code (and also managed by the
+ modem on its own), hence we mark it as as optional.
- vdd_pll-supply: Reference to the regulator that supplies the PLL's rail.
- qcom,vdd_pll: Voltage to be set for the PLL's rail.
- reg-names: "cxrail_bhs_reg" - control register for modem power
domain.
-- qcom,is-loadable: Boolean- Present if the image needs to be loaded.
+- qcom,is-not-loadable: Boolean- Present if the image does not need to
+ be loaded.
- qcom,pil-self-auth: Boolean- True if authentication is required.
Example:
@@ -43,12 +48,13 @@
vdd_cx-supply = <&pm8841_s2>;
vdd_mx-supply = <&pm8841_s1>;
- qcom,is-loadable;
+ qcom,is-not-loadable;
qcom,firmware-name = "mba";
qcom,pil-self-auth;
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index 6d093f0..e6f0da5 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -47,7 +47,7 @@
SoC recalculations when the current SoC is below
qcom,low-soc-calculate-soc-threshold or when battery
voltage is below qcom,low-voltage-threshold.
-- qcom,soc-calculate-soc-ms : The time period between subsequent SoC
+- qcom,calculate-soc-ms : The time period between subsequent SoC
recalculations when the current SoC is above or equal
qcom,low-soc-calculate-soc-threshold.
- qcom,chg-term-ua : current in micro-amps when charging is considered done.
diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
index eb62ea1..f2cfe34 100644
--- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -11,9 +11,10 @@
Optional properties:
- parent-supply: phandle to the parent supply/regulator node
- - qcom,retain-mems: For Oxili GDSCs only: Presence currently denotes a hardware
- requirement to assert the forced memory retention signals
- in the core's clock branch control register.
+ - qcom,clock-names: List of string names for core clocks
+ - qcom,retain-mems: Presence denotes a hardware requirement to leave the
+ forced memory retention signals in the core's clock
+ branch control register asserted.
Example:
gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
@@ -21,4 +22,5 @@
regulator-name = "gdsc_oxili_gx";
parent-supply = <&pm8841_s4>;
reg = <0xfd8c4024 0x4>;
+ qcom,clock-names = "core_clk";
};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 383e50d..9f6cb16 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -458,9 +458,12 @@
- qcom,sec-auxpcm-gpio-din : GPIO on which Secondary AUXPCM DIN signal is coming.
- qcom,sec-auxpcm-gpio-dout : GPIO on which Secondary AUXPCM DOUT signal is coming.
- qcom,us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
-
Optional properties:
- qcom,hdmi-audio-rx: specifies if HDMI audio support is enabled or not.
+- qcom,ext-ult-spk-amp-gpio : GPIO for enabling of speaker path amplifier.
+
+- qcom,ext-ult-lo-amp-gpio: GPIO to enable external ultrasound lineout
+ amplifier.
Example:
@@ -502,6 +505,7 @@
qcom,us-euro-gpios = <&pm8941_gpios 20 0>;
qcom,hdmi-audio-rx;
+ qcom,ext-ult-lo-amp-gpio = <&pm8941_gpios 6 0>;
qcom,prim-auxpcm-gpio-clk = <&msmgpio 65 0>;
qcom,prim-auxpcm-gpio-sync = <&msmgpio 66 0>;
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 777933a..9abf54e 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -76,6 +76,8 @@
dynamically.
Supplies in this list are off by default.
+ - qcom,cdc-micbias2-headset-only: Boolean. Allow micbias 2 only to headset mic.
+
Example:
taiko_codec {
@@ -138,6 +140,7 @@
qcom,cdc-slim-ifd = "taiko-slim-ifd";
qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 00 17 02];
qcom,cdc-dmic-sample-rate = <4800000>;
+ qcom,cdc-micbias2-headset-only;
};
Wcd9xxx audio CODEC in I2C mode
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 1613856..de1577d 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -61,6 +61,9 @@
Used for allowing USB to respond for remote wakup.
- qcom,hsusb-otg-delay-lpm: If present then USB core will wait one second
after disconnect before entering low power mode.
+- qcom,hsusb-otg-delay-lpm-hndshk-on-disconnect: If present then USB core will
+ wait for the handshake with the IPA to complete before entering low
+ power mode.
- <supply-name>-supply: handle to the regulator device tree node.
Optional "supply-name" is "vbus_otg" to supply vbus in host mode.
- qcom,vdd-voltage-level: This property must be a list of three integer
@@ -147,6 +150,8 @@
update USB PID and serial numbers used by bootloader in DLOAD mode.
- qcom,android-usb-swfi-latency : value to be used by device to vote
for DMA latency in microsecs.
+- qcom,android-usb-cdrom : if this property is present then device creates
+ a new LUN as CD-ROM
Example Android USB device node :
android_usb@fc42b0c8 {
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index 5391734..282257c 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -45,6 +45,8 @@
bits 6-12 PARAMETER_OVERRIDE_B
bits 13-19 PARAMETER_OVERRIDE_C
bits 20-25 PARAMETER_OVERRIDE_D
+- qcom,skip-charger-detection: If present then charger detection using BC1.2
+ is not supported and attached host should always be assumed as SDP.
Sub nodes:
- Sub node for "DWC3- USB3 controller".
diff --git a/Documentation/workqueue.txt b/Documentation/workqueue.txt
index a0b577d..a6ab4b6 100644
--- a/Documentation/workqueue.txt
+++ b/Documentation/workqueue.txt
@@ -89,25 +89,28 @@
The cmwq design differentiates between the user-facing workqueues that
subsystems and drivers queue work items on and the backend mechanism
-which manages thread-pool and processes the queued work items.
+which manages thread-pools and processes the queued work items.
The backend is called gcwq. There is one gcwq for each possible CPU
-and one gcwq to serve work items queued on unbound workqueues.
+and one gcwq to serve work items queued on unbound workqueues. Each
+gcwq has two thread-pools - one for normal work items and the other
+for high priority ones.
Subsystems and drivers can create and queue work items through special
workqueue API functions as they see fit. They can influence some
aspects of the way the work items are executed by setting flags on the
workqueue they are putting the work item on. These flags include
-things like CPU locality, reentrancy, concurrency limits and more. To
-get a detailed overview refer to the API description of
+things like CPU locality, reentrancy, concurrency limits, priority and
+more. To get a detailed overview refer to the API description of
alloc_workqueue() below.
-When a work item is queued to a workqueue, the target gcwq is
-determined according to the queue parameters and workqueue attributes
-and appended on the shared worklist of the gcwq. For example, unless
-specifically overridden, a work item of a bound workqueue will be
-queued on the worklist of exactly that gcwq that is associated to the
-CPU the issuer is running on.
+When a work item is queued to a workqueue, the target gcwq and
+thread-pool is determined according to the queue parameters and
+workqueue attributes and appended on the shared worklist of the
+thread-pool. For example, unless specifically overridden, a work item
+of a bound workqueue will be queued on the worklist of either normal
+or highpri thread-pool of the gcwq that is associated to the CPU the
+issuer is running on.
For any worker pool implementation, managing the concurrency level
(how many execution contexts are active) is an important issue. cmwq
@@ -115,26 +118,26 @@
Minimal to save resources and sufficient in that the system is used at
its full capacity.
-Each gcwq bound to an actual CPU implements concurrency management by
-hooking into the scheduler. The gcwq is notified whenever an active
-worker wakes up or sleeps and keeps track of the number of the
-currently runnable workers. Generally, work items are not expected to
-hog a CPU and consume many cycles. That means maintaining just enough
-concurrency to prevent work processing from stalling should be
-optimal. As long as there are one or more runnable workers on the
-CPU, the gcwq doesn't start execution of a new work, but, when the
-last running worker goes to sleep, it immediately schedules a new
-worker so that the CPU doesn't sit idle while there are pending work
-items. This allows using a minimal number of workers without losing
-execution bandwidth.
+Each thread-pool bound to an actual CPU implements concurrency
+management by hooking into the scheduler. The thread-pool is notified
+whenever an active worker wakes up or sleeps and keeps track of the
+number of the currently runnable workers. Generally, work items are
+not expected to hog a CPU and consume many cycles. That means
+maintaining just enough concurrency to prevent work processing from
+stalling should be optimal. As long as there are one or more runnable
+workers on the CPU, the thread-pool doesn't start execution of a new
+work, but, when the last running worker goes to sleep, it immediately
+schedules a new worker so that the CPU doesn't sit idle while there
+are pending work items. This allows using a minimal number of workers
+without losing execution bandwidth.
Keeping idle workers around doesn't cost other than the memory space
for kthreads, so cmwq holds onto idle ones for a while before killing
them.
For an unbound wq, the above concurrency management doesn't apply and
-the gcwq for the pseudo unbound CPU tries to start executing all work
-items as soon as possible. The responsibility of regulating
+the thread-pools for the pseudo unbound CPU try to start executing all
+work items as soon as possible. The responsibility of regulating
concurrency level is on the users. There is also a flag to mark a
bound wq to ignore the concurrency management. Please refer to the
API section for details.
@@ -205,31 +208,22 @@
WQ_HIGHPRI
- Work items of a highpri wq are queued at the head of the
- worklist of the target gcwq and start execution regardless of
- the current concurrency level. In other words, highpri work
- items will always start execution as soon as execution
- resource is available.
+ Work items of a highpri wq are queued to the highpri
+ thread-pool of the target gcwq. Highpri thread-pools are
+ served by worker threads with elevated nice level.
- Ordering among highpri work items is preserved - a highpri
- work item queued after another highpri work item will start
- execution after the earlier highpri work item starts.
-
- Although highpri work items are not held back by other
- runnable work items, they still contribute to the concurrency
- level. Highpri work items in runnable state will prevent
- non-highpri work items from starting execution.
-
- This flag is meaningless for unbound wq.
+ Note that normal and highpri thread-pools don't interact with
+ each other. Each maintain its separate pool of workers and
+ implements concurrency management among its workers.
WQ_CPU_INTENSIVE
Work items of a CPU intensive wq do not contribute to the
concurrency level. In other words, runnable CPU intensive
- work items will not prevent other work items from starting
- execution. This is useful for bound work items which are
- expected to hog CPU cycles so that their execution is
- regulated by the system scheduler.
+ work items will not prevent other work items in the same
+ thread-pool from starting execution. This is useful for bound
+ work items which are expected to hog CPU cycles so that their
+ execution is regulated by the system scheduler.
Although CPU intensive work items don't contribute to the
concurrency level, start of their executions is still
@@ -239,14 +233,6 @@
This flag is meaningless for unbound wq.
- WQ_HIGHPRI | WQ_CPU_INTENSIVE
-
- This combination makes the wq avoid interaction with
- concurrency management completely and behave as a simple
- per-CPU execution context provider. Work items queued on a
- highpri CPU-intensive wq start execution as soon as resources
- are available and don't affect execution of other work items.
-
@max_active:
@max_active determines the maximum number of execution contexts per
@@ -328,20 +314,7 @@
35 w2 wakes up and finishes
Now, let's assume w1 and w2 are queued to a different wq q1 which has
-WQ_HIGHPRI set,
-
- TIME IN MSECS EVENT
- 0 w1 and w2 start and burn CPU
- 5 w1 sleeps
- 10 w2 sleeps
- 10 w0 starts and burns CPU
- 15 w0 sleeps
- 15 w1 wakes up and finishes
- 20 w2 wakes up and finishes
- 25 w0 wakes up and burns CPU
- 30 w0 finishes
-
-If q1 has WQ_CPU_INTENSIVE set,
+WQ_CPU_INTENSIVE set,
TIME IN MSECS EVENT
0 w0 starts and burns CPU
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
new file mode 100644
index 0000000..c56f06a
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -0,0 +1,609 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "dsi-panel-sharp-qhd-video.dtsi"
+/include/ "msm8974-leds.dtsi"
+
+/ {
+ serial@f991e000 {
+ status = "ok";
+ };
+
+ qcom,mdss_dsi_sharp_qhd_video {
+ status = "ok";
+ };
+
+ qcom,hdmi_tx@fd922100 {
+ status = "ok";
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ general {
+ label = "general";
+ gpios = <&pm8941_gpios 23 0x1>;
+ linux,input-type = <1>;
+ linux,code = <102>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+
+ bt_ar3002 {
+ compatible = "qca,ar3002";
+ qca,bt-reset-gpio = <&pm8941_gpios 34 0>;
+ };
+
+ hsic_hub {
+ compatible = "qcom,hsic-smsc-hub";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
+
+ hsic_host: hsic@f9a00000 {
+ compatible = "qcom,hsic-host";
+ reg = <0xf9a00000 0x400>;
+ #address-cells = <0>;
+ interrupt-parent = <&hsic_host>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 136 0
+ 1 &intc 0 148 0
+ 2 &msmgpio 144 0x8>;
+ interrupt-names = "core_irq", "async_irq", "wakeup";
+ HSIC_VDDCX-supply = <&pm8841_s2>;
+ HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+ hsic,strobe-gpio = <&msmgpio 144 0x00>;
+ hsic,data-gpio = <&msmgpio 145 0x00>;
+ hsic,ignore-cal-pad-config;
+ hsic,strobe-pad-offset = <0x2050>;
+ hsic,data-pad-offset = <0x2054>;
+
+ qcom,msm-bus,name = "hsic";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <85 512 0 0>,
+ <85 512 40000 160000>;
+ };
+ };
+
+ i2c@f9923000 {
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <61 0x2>;
+ vdd_ana-supply = <&pm8941_l18>;
+ vcc_i2c-supply = <&pm8941_s3>;
+ atmel,reset-gpio = <&msmgpio 60 0x00>;
+ atmel,irq-gpio = <&msmgpio 61 0x00>;
+ atmel,panel-coords = <0 0 566 1067>;
+ atmel,display-coords = <0 0 540 960>;
+ atmel,i2c-pull-up;
+ atmel,cfg_1 {
+ atmel,family-id = <0x81>;
+ atmel,variant-id = <0x19>;
+ atmel,version = <0x10>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 38, Instance = 0 */
+ 0F 02 00 17 04 0C 00 00
+ /* Object 7, Instance = 0 */
+ 30 FF 19
+ /* Object 8, Instance = 0 */
+ 1B 00 05 01 00 00 08 08 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 13 0B 00 10 23 01 03
+ 0A 0F 01 0B 04 05 28 0A 2B 04
+ 36 02 00 00 00 00 8F 28 8F 50
+ 12 0F 32 32 02
+ /* Object 15, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00
+ /* Object 23, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00
+ /* Object 40, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 00 03 10 30 00 00 01 00 00
+ /* Object 47, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 48, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00
+ ];
+ };
+ };
+ };
+
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "atmel_mxt_ts";
+ qcom,disp-maxx = <540>;
+ qcom,disp-maxy = <960>;
+ qcom,panel-maxx = <566>;
+ qcom,panel-maxy = <1067>;
+ qcom,key-codes = <158 139 102 217>;
+ };
+
+ sound {
+ qcom,model = "apq8074-taiko-db-snd-card";
+ qcom,hdmi-audio-rx;
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "AMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Analog Mic4",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
+ "AMIC5", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Analog Mic6",
+ "AMIC6", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Analog Mic7",
+ "DMIC1", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic1",
+ "DMIC2", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic2",
+ "DMIC3", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic3",
+ "DMIC4", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic4",
+ "DMIC5", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic5",
+ "DMIC6", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic6";
+ };
+};
+
+&mdss_fb0 {
+ qcom,memory-reservation-size = <0x1000000>; /* size 16MB */
+};
+
+&sdcc3 {
+ qcom,sup-voltages = <2000 2000>;
+ status = "ok";
+};
+
+&pm8941_l19 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <3300000>;
+ regulator-always-on;
+};
+
+&pm8941_l10 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ regulator-always-on;
+};
+
+&uart7 {
+ status = "ok";
+ qcom,tx-gpio = <&msmgpio 41 0x00>;
+ qcom,rx-gpio = <&msmgpio 42 0x00>;
+ qcom,cts-gpio = <&msmgpio 43 0x00>;
+ qcom,rfr-gpio = <&msmgpio 44 0x00>;
+};
+
+&usb3 {
+ qcom,charging-disabled;
+};
+
+&slim_msm {
+ taiko_codec {
+ qcom,cdc-micbias2-ext-cap;
+ qcom,cdc-micbias3-ext-cap;
+ };
+};
+
+&pm8941_gpios {
+ gpio@c000 { /* GPIO 1 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,src-sel = <0>;
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,src-sel = <0>;
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,src-sel = <0>;
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ /* TUSB3_HUB-RESET */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <0>; /* QPNP_PIN_PULL_30 */
+ qcom,vin-sel = <0>; /* QPNP_PIN_VIN0 VPH */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-sel = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,invert = <1>; /* Keep it out of reset */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ /* HSIC_HUB-RESET */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,pull = <5>; /* PULL_NO */
+ qcom,out-strength = <2>; /* STRENGTH_MED */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c800 { /* GPIO 9 */
+ /* GbE_RST_N */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <0>; /* QPNP_PIN_PULL_30 */
+ qcom,vin-sel = <0>; /* QPNP_PIN_VIN0 VPH */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-sel = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,invert = <1>; /* Keep it out of reset */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c900 { /* GPIO 10 */
+ /* SATA_RST_N */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <0>; /* QPNP_PIN_PULL_30 */
+ qcom,vin-sel = <0>; /* QPNP_PIN_VIN0 VPH */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-sel = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,invert = <1>; /* Keep it out of reset */
+ qcom,master-en = <1>;
+ };
+
+ gpio@ca00 { /* GPIO 11 */
+ };
+
+ gpio@cb00 { /* GPIO 12 */
+ };
+
+ gpio@cc00 { /* GPIO 13 */
+ };
+
+ gpio@cd00 { /* GPIO 14 */
+ };
+
+ gpio@ce00 { /* GPIO 15 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@cf00 { /* GPIO 16 */
+ };
+
+ gpio@d000 { /* GPIO 17 */
+ };
+
+ gpio@d100 { /* GPIO 18 */
+ };
+
+ gpio@d200 { /* GPIO 19 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-sel = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,master-en = <1>;
+ };
+
+ gpio@d300 { /* GPIO 20 */
+ };
+
+ gpio@d400 { /* GPIO 21 */
+ };
+
+ gpio@d500 { /* GPIO 22 */
+ };
+
+ gpio@d600 { /* GPIO 23 */
+ };
+
+ gpio@d700 { /* GPIO 24 */
+ };
+
+ gpio@d800 { /* GPIO 25 */
+ };
+
+ gpio@d900 { /* GPIO 26 */
+ };
+
+ gpio@da00 { /* GPIO 27 */
+ };
+
+ gpio@db00 { /* GPIO 28 */
+ };
+
+ gpio@dc00 { /* GPIO 29 */
+ qcom,pull = <0>; /* set to default pull */
+ qcom,master-en = <1>;
+ qcom,vin-sel = <2>; /* select 1.8 V source */
+ };
+
+ gpio@dd00 { /* GPIO 30 */
+ };
+
+ gpio@de00 { /* GPIO 31 */
+ };
+
+ gpio@df00 { /* GPIO 32 */
+ };
+
+ gpio@e000 { /* GPIO 33 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-sel = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,invert = <1>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@e100 { /* GPIO 34 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-sel = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,invert = <0>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@e200 { /* GPIO 35 */
+ };
+
+ gpio@e300 { /* GPIO 36 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <3>; /* QPNP_PIN_OUT_STRENGTH_HIGH */
+ qcom,src-sel = <3>; /* QPNP_PIN_SEL_FUNC_2 */
+ qcom,master-en = <1>;
+ };
+};
+
+&pm8941_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+&pm8841_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3*/
+ };
+
+ mpp@a300 { /* MPP 4*/
+ };
+};
+
+&spi_epm {
+ epm-adc@0 {
+ compatible = "cy,epm-adc-cy8c5568lti-114";
+ reg = <0>;
+ interrupt-parent = <&msmgpio>;
+ spi-max-frequency = <960000>;
+ qcom,channels = <31>;
+ qcom,gain = <50 50 50 50 50 100 50 50 50 50
+ 50 50 50 50 100 50 50 50 50 100
+ 50 50 50 100 50 50 50 1 1 1
+ 1>;
+ qcom,rsense = <40 10 10 25 10 1000 75 25 10 25
+ 33 500 200 10 500 100 33 200 25 100
+ 75 500 50 200 5 5 3 1 1 1
+ 1>;
+ qcom,channel-type = <0xf0000000>;
+ };
+};
+
+&spmi_bus {
+ qcom,pm8941@1 {
+ qcom,leds@d000 {
+ qcom,rgb_2 {
+ status = "ok";
+ qcom,default-state = "on";
+ qcom,turn-off-delay-ms = <1000>;
+ };
+ };
+
+ qcom,leds@d800 {
+ status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck = <1>;
+ qcom,default-state = "on";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ };
+ };
+ };
+};
+
+&pm8941_chg {
+ status = "ok";
+
+ qcom,chg-charging-disabled;
+
+ qcom,chg-chgr@1000 {
+ status = "ok";
+ };
+
+ qcom,chg-buck@1100 {
+ status = "ok";
+ };
+
+ qcom,chg-usb-chgpth@1300 {
+ status = "ok";
+ };
+
+ qcom,chg-dc-chgpth@1400 {
+ status = "ok";
+ };
+
+ qcom,chg-boost@1500 {
+ status = "ok";
+ };
+
+ qcom,chg-misc@1600 {
+ status = "ok";
+ };
+};
+
+&sdhc_1 {
+ vdd-supply = <&pm8941_l20>;
+ vdd-io-supply = <&pm8941_s3>;
+
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,nonremovable;
+ status = "ok";
+};
+
+&sdhc_2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+
+ vdd-supply = <&pm8941_l21>;
+ vdd-io-supply = <&pm8941_l13>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/apq8074-v2-dragonboard.dts b/arch/arm/boot/dts/apq8074-v2-dragonboard.dts
new file mode 100644
index 0000000..5a6f5f3
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v2-dragonboard.dts
@@ -0,0 +1,22 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "apq8074-v2.dtsi"
+/include/ "apq8074-dragonboard.dtsi"
+
+/ {
+ model = "Qualcomm APQ 8074v2 DRAGONBOARD";
+ compatible = "qcom,apq8074-dragonboard", "qcom,apq8074", "qcom,dragonboard";
+ qcom,msm-id = <184 10 0x20000>;
+};
diff --git a/arch/arm/boot/dts/apq8074-v2.dtsi b/arch/arm/boot/dts/apq8074-v2.dtsi
index 3b65236..9c93ed4 100644
--- a/arch/arm/boot/dts/apq8074-v2.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.dtsi
@@ -18,7 +18,7 @@
/include/ "msm8974-v2.dtsi"
-/ {
+&soc {
qcom,qseecom@a700000 {
compatible = "qcom,qseecom";
reg = <0x0a700000 0x500000>;
diff --git a/arch/arm/boot/dts/apq8084-ion.dtsi b/arch/arm/boot/dts/apq8084-ion.dtsi
index aac4230..ea954b8 100644
--- a/arch/arm/boot/dts/apq8084-ion.dtsi
+++ b/arch/arm/boot/dts/apq8084-ion.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,ion {
compatible = "qcom,msm-ion";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/apq8084-regulator.dtsi b/arch/arm/boot/dts/apq8084-regulator.dtsi
new file mode 100644
index 0000000..00991b3
--- /dev/null
+++ b/arch/arm/boot/dts/apq8084-regulator.dtsi
@@ -0,0 +1,327 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/* QPNP controlled regulators: */
+
+&spmi_bus {
+ qcom,pma8084@1 {
+ pma8084_s1: regulator@1400 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
+
+ /* PMA8084 S2 + S12 = 2 phase VDD_CX supply */
+ pma8084_s2: regulator@1700 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
+
+ pma8084_s3: regulator@1a00 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
+
+ pma8084_s4: regulator@1d00 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
+
+ pma8084_s5: regulator@2000 {
+ regulator-min-microvolt = <2150000>;
+ regulator-max-microvolt = <2150000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ /* PMA8084 S6 + S7 = 2 phase VDD_GFX supply */
+ pma8084_s6: regulator@2300 {
+ regulator-min-microvolt = <815000>;
+ regulator-max-microvolt = <900000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ /* PMA8084 S8 + S9 + S10 + S11 = 4 phase VDD_APC supply */
+ pma8084_s8: regulator@2900 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
+
+ /* Output of PMA8084 L1 and L11 is tied together. */
+ pma8084_l1: regulator@4000 {
+ parent-supply = <&pma8084_s3>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <10000>;
+ status = "okay";
+ };
+
+ pma8084_l2: regulator@4100 {
+ parent-supply = <&pma8084_s3>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l3: regulator@4200 {
+ parent-supply = <&pma8084_s3>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l4: regulator@4300 {
+ parent-supply = <&pma8084_s3>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l6: regulator@4500 {
+ parent-supply = <&pma8084_s5>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l8: regulator@4700 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l9: regulator@4800 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l10: regulator@4900 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l12: regulator@4b00 {
+ parent-supply = <&pma8084_s5>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l13: regulator@4c00 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l14: regulator@4d00 {
+ parent-supply = <&pma8084_s5>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l15: regulator@4e00 {
+ parent-supply = <&pma8084_s5>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l16: regulator@4f00 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l17: regulator@5000 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l18: regulator@5100 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l19: regulator@5200 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l20: regulator@5300 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l21: regulator@5400 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l22: regulator@5500 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l23: regulator@5600 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l24: regulator@5700 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l25: regulator@5800 {
+ regulator-min-microvolt = <2100000>;
+ regulator-max-microvolt = <2100000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l26: regulator@5900 {
+ parent-supply = <&pma8084_s5>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l27: regulator@5a00 {
+ parent-supply = <&pma8084_s3>;
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_lvs1: regulator@8000 {
+ parent-supply = <&pma8084_s4>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_lvs2: regulator@8100 {
+ parent-supply = <&pma8084_s4>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_lvs3: regulator@8200 {
+ parent-supply = <&pma8084_s4>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_lvs4: regulator@8300 {
+ parent-supply = <&pma8084_s4>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_mvs1: regulator@8400 {
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+ };
+};
+
diff --git a/arch/arm/boot/dts/apq8084-sim.dts b/arch/arm/boot/dts/apq8084-sim.dts
index 45d625c..e206d4d 100644
--- a/arch/arm/boot/dts/apq8084-sim.dts
+++ b/arch/arm/boot/dts/apq8084-sim.dts
@@ -22,7 +22,9 @@
aliases {
serial0 = &uart0;
};
+};
+&soc {
uart0: serial@f991f000 {
status = "ok";
};
@@ -71,3 +73,101 @@
status = "ok";
};
+
+&pma8084_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+
+ gpio@c800 { /* GPIO 9 */
+ };
+
+ gpio@c900 { /* GPIO 10 */
+ };
+
+ gpio@ca00 { /* GPIO 11 */
+ };
+
+ gpio@cb00 { /* GPIO 12 */
+ };
+
+ gpio@cc00 { /* GPIO 13 */
+ };
+
+ gpio@cd00 { /* GPIO 14 */
+ };
+
+ gpio@ce00 { /* GPIO 15 */
+ };
+
+ gpio@cf00 { /* GPIO 16 */
+ };
+
+ gpio@d000 { /* GPIO 17 */
+ };
+
+ gpio@d100 { /* GPIO 18 */
+ };
+
+ gpio@d200 { /* GPIO 19 */
+ };
+
+ gpio@d300 { /* GPIO 20 */
+ };
+
+ gpio@d400 { /* GPIO 21 */
+ };
+
+ gpio@d500 { /* GPIO 22 */
+ };
+};
+
+&pma8084_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+&usb3 {
+ qcom,skip-charger-detection;
+};
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index c3c3759..7a1bbef 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -10,13 +10,21 @@
* GNU General Public License for more details.
*/
-/include/ "skeleton.dtsi"
-/include/ "apq8084-ion.dtsi"
+/include/ "skeleton64.dtsi"
/ {
model = "Qualcomm APQ 8084";
compatible = "qcom,apq8084";
interrupt-parent = <&intc>;
+ soc: soc { };
+};
+
+/include/ "apq8084-ion.dtsi"
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0xffffffff>;
intc: interrupt-controller@f9000000 {
compatible = "qcom,msm-qgic2";
@@ -107,4 +115,93 @@
qcom,bus-width = <4>;
status = "disabled";
};
+
+ spmi_bus: qcom,spmi@fc4c0000 {
+ cell-index = <0>;
+ compatible = "qcom,spmi-pmic-arb";
+ reg-names = "core", "intr", "cnfg";
+ reg = <0xfc4cf000 0x1000>,
+ <0Xfc4cb000 0x1000>,
+ <0Xfc4ca000 0x1000>;
+ /* 190,ee0_krait_hlos_spmi_periph_irq */
+ /* 187,channel_0_krait_hlos_trans_done_irq */
+ interrupts = <0 190 0>, <0 187 0>;
+ qcom,not-wakeup;
+ qcom,pmic-arb-ee = <0>;
+ qcom,pmic-arb-channel = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ };
+
+ usb3: qcom,ssusb@f9200000 {
+ compatible = "qcom,dwc-usb3-msm";
+ reg = <0xf9200000 0xfc000>,
+ <0xfd4ab000 0x4>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ interrupts = <0 133 0>;
+ interrupt-names = "hs_phy_irq";
+ ssusb_vdd_dig-supply = <&pma8084_s1>;
+ SSUSB_1p8-supply = <&pma8084_l6>;
+ hsusb_vdd_dig-supply = <&pma8084_s1>;
+ HSUSB_1p8-supply = <&pma8084_l6>;
+ HSUSB_3p3-supply = <&pma8084_l24>;
+ qcom,dwc-usb3-msm-dbm-eps = <4>;
+ qcom,vdd-voltage-level = <0 900000 1050000>;
+
+ dwc3@f9200000 {
+ compatible = "synopsys,dwc3";
+ reg = <0xf9200000 0xfc000>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 131 0>, <0 179 0>;
+ interrupt-names = "irq", "otg_irq";
+ tx-fifo-resize;
+ };
+ };
+
+ android_usb {
+ compatible = "qcom,android-usb";
+ };
+
+ qcom,ocmem@fdd00000 {
+ compatible = "qcom,msm-ocmem";
+ reg = <0xfdd00000 0x2000>,
+ <0xfdd02000 0x2000>,
+ <0xfe039000 0x400>,
+ <0xfec00000 0x200000>;
+ reg-names = "ocmem_ctrl_physical", "dm_ctrl_physical", "br_ctrl_physical", "ocmem_physical";
+ interrupts = <0 76 0 0 77 0>;
+ interrupt-names = "ocmem_irq", "dm_irq";
+ qcom,ocmem-num-regions = <0x4>;
+ qcom,ocmem-num-macros = <0x20>;
+ qcom,resource-type = <0x706d636f>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0xfec00000 0x200000>;
+
+ partition@0 {
+ reg = <0x0 0x180000>;
+ qcom,ocmem-part-name = "graphics";
+ qcom,ocmem-part-min = <0x80000>;
+ };
+
+ partition@80000 {
+ reg = <0x180000 0x80000>;
+ qcom,ocmem-part-name = "lp_audio";
+ qcom,ocmem-part-min = <0x80000>;
+ };
+
+ partition@100000 {
+ reg = <0x180000 0x80000>;
+ qcom,ocmem-part-name = "video";
+ qcom,ocmem-part-min = <0x55000>;
+ };
+
+ };
};
+
+/include/ "msm-pma8084.dtsi"
+/include/ "apq8084-regulator.dtsi"
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
new file mode 100644
index 0000000..7942567
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
@@ -0,0 +1,530 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+ qcom,mdss_dsi_nt35590_720p_cmd {
+ compatible = "qcom,mdss-dsi-panel";
+ label = "nt35590 720p command mode dsi panel";
+ status = "disable";
+ qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+ qcom,rst-gpio = <&msmgpio 25 0>;
+ qcom,te-gpio = <&msmgpio 24 0>;
+ qcom,mdss-pan-res = <720 1280>;
+ qcom,mdss-pan-bpp = <24>;
+ qcom,mdss-pan-dest = "display_1";
+ qcom,mdss-pan-porch-values = <164 8 140 1 1 6>;
+ qcom,mdss-pan-underflow-clr = <0xff>;
+ qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+ qcom,mdss-pan-bl-levels = <1 4095>;
+ qcom,mdss-pan-dsi-mode = <1>;
+ qcom,mdss-vsync-enable = <1>;
+ qcom,mdss-hw-vsync-mode = <1>;
+ qcom,mdss-pan-dsi-h-pulse-mode = <1>;
+ qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+ qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+ qcom,mdss-pan-dsi-traffic-mode = <2>;
+ qcom,mdss-pan-dsi-dst-format = <8>;
+ qcom,mdss-pan-insert-dcs-cmd = <1>;
+ qcom,mdss-pan-wr-mem-continue = <0x3c>;
+ qcom,mdss-pan-wr-mem-start = <0x2c>;
+ qcom,mdss-pan-te-sel = <1>;
+ qcom,mdss-pan-dsi-vc = <0>;
+ qcom,mdss-pan-dsi-rgb-swap = <0>;
+ qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>; /* 4 lanes */
+ qcom,mdss-pan-dsi-dlane-swap = <0>;
+ qcom,mdss-pan-dsi-t-clk = <0x2c 0x20>;
+ qcom,mdss-pan-dsi-stream = <0>;
+ qcom,mdss-pan-dsi-mdp-tr = <0x0>;
+ qcom,mdss-pan-dsi-dma-tr = <0x04>;
+ qcom,mdss-pan-dsi-frame-rate = <60>;
+ qcom,panel-phy-regulatorSettings = [07 09 03 00 /* Regualotor settings */
+ 20 00 01];
+ qcom,panel-phy-timingSettings = [7d 25 1d 00 37 33
+ 22 27 1e 03 04 00];
+ qcom,panel-phy-strengthCtrl = [ff 06];
+ qcom,panel-phy-bistCtrl = [00 00 b1 ff /* BIST Ctrl settings */
+ 00 00];
+ qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
+ 00 00 00 00 05 00 00 01 97 /* lane1 config */
+ 00 00 00 00 0a 00 00 01 97 /* lane2 config */
+ 00 00 00 00 0f 00 00 01 97 /* lane3 config */
+ 00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
+ qcom,panel-on-cmds = [29 01 00 00 00 02 FF EE
+ 29 01 00 00 00 02 26 08
+ 29 01 00 00 00 02 26 00
+ 29 01 00 00 10 02 FF 00
+ 29 01 00 00 00 02 BA 03
+ 29 01 00 00 00 02 C2 08
+ 29 01 00 00 00 02 FF 01
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 00 4A
+ 29 01 00 00 00 02 01 33
+ 29 01 00 00 00 02 02 53
+ 29 01 00 00 00 02 03 55
+ 29 01 00 00 00 02 04 55
+ 29 01 00 00 00 02 05 33
+ 29 01 00 00 00 02 06 22
+ 29 01 00 00 00 02 08 56
+ 29 01 00 00 00 02 09 8F
+ 29 01 00 00 00 02 36 73
+ 29 01 00 00 00 02 0B 9F
+ 29 01 00 00 00 02 0C 9F
+ 29 01 00 00 00 02 0D 2F
+ 29 01 00 00 00 02 0E 24
+ 29 01 00 00 00 02 11 83
+ 29 01 00 00 00 02 12 03
+ 29 01 00 00 00 02 71 2C
+ 29 01 00 00 00 02 6F 03
+ 29 01 00 00 00 02 0F 0A
+ 29 01 00 00 00 02 FF 05
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 01 00
+ 29 01 00 00 00 02 02 8B
+ 29 01 00 00 00 02 03 82
+ 29 01 00 00 00 02 04 82
+ 29 01 00 00 00 02 05 30
+ 29 01 00 00 00 02 06 33
+ 29 01 00 00 00 02 07 01
+ 29 01 00 00 00 02 08 00
+ 29 01 00 00 00 02 09 46
+ 29 01 00 00 00 02 0A 46
+ 29 01 00 00 00 02 0D 0B
+ 29 01 00 00 00 02 0E 1D
+ 29 01 00 00 00 02 0F 08
+ 29 01 00 00 00 02 10 53
+ 29 01 00 00 00 02 11 00
+ 29 01 00 00 00 02 12 00
+ 29 01 00 00 00 02 14 01
+ 29 01 00 00 00 02 15 00
+ 29 01 00 00 00 02 16 05
+ 29 01 00 00 00 02 17 00
+ 29 01 00 00 00 02 19 7F
+ 29 01 00 00 00 02 1A FF
+ 29 01 00 00 00 02 1B 0F
+ 29 01 00 00 00 02 1C 00
+ 29 01 00 00 00 02 1D 00
+ 29 01 00 00 00 02 1E 00
+ 29 01 00 00 00 02 1F 07
+ 29 01 00 00 00 02 20 00
+ 29 01 00 00 00 02 21 06
+ 29 01 00 00 00 02 22 55
+ 29 01 00 00 00 02 23 4D
+ 29 01 00 00 00 02 2D 02
+ 29 01 00 00 00 02 28 01
+ 29 01 00 00 00 02 2F 02
+ 29 01 00 00 00 02 83 01
+ 29 01 00 00 00 02 9E 58
+ 29 01 00 00 00 02 9F 6A
+ 29 01 00 00 00 02 A0 01
+ 29 01 00 00 00 02 A2 10
+ 29 01 00 00 00 02 BB 0A
+ 29 01 00 00 00 02 BC 0A
+ 29 01 00 00 00 02 32 08
+ 29 01 00 00 00 02 33 B8
+ 29 01 00 00 00 02 36 01
+ 29 01 00 00 00 02 37 00
+ 29 01 00 00 00 02 43 00
+ 29 01 00 00 00 02 4B 21
+ 29 01 00 00 00 02 4C 03
+ 29 01 00 00 00 02 50 21
+ 29 01 00 00 00 02 51 03
+ 29 01 00 00 00 02 58 21
+ 29 01 00 00 00 02 59 03
+ 29 01 00 00 00 02 5D 21
+ 29 01 00 00 00 02 5E 03
+ 29 01 00 00 00 02 6C 00
+ 29 01 00 00 00 02 6D 00
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 FF 01
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 75 00
+ 29 01 00 00 00 02 76 7D
+ 29 01 00 00 00 02 77 00
+ 29 01 00 00 00 02 78 8A
+ 29 01 00 00 00 02 79 00
+ 29 01 00 00 00 02 7A 9C
+ 29 01 00 00 00 02 7B 00
+ 29 01 00 00 00 02 7C B1
+ 29 01 00 00 00 02 7D 00
+ 29 01 00 00 00 02 7E BF
+ 29 01 00 00 00 02 7F 00
+ 29 01 00 00 00 02 80 CF
+ 29 01 00 00 00 02 81 00
+ 29 01 00 00 00 02 82 DD
+ 29 01 00 00 00 02 83 00
+ 29 01 00 00 00 02 84 E8
+ 29 01 00 00 00 02 85 00
+ 29 01 00 00 00 02 86 F2
+ 29 01 00 00 00 02 87 01
+ 29 01 00 00 00 02 88 1F
+ 29 01 00 00 00 02 89 01
+ 29 01 00 00 00 02 8A 41
+ 29 01 00 00 00 02 8B 01
+ 29 01 00 00 00 02 8C 78
+ 29 01 00 00 00 02 8D 01
+ 29 01 00 00 00 02 8E A5
+ 29 01 00 00 00 02 8F 01
+ 29 01 00 00 00 02 90 EE
+ 29 01 00 00 00 02 91 02
+ 29 01 00 00 00 02 92 29
+ 29 01 00 00 00 02 93 02
+ 29 01 00 00 00 02 94 2A
+ 29 01 00 00 00 02 95 02
+ 29 01 00 00 00 02 96 5D
+ 29 01 00 00 00 02 97 02
+ 29 01 00 00 00 02 98 93
+ 29 01 00 00 00 02 99 02
+ 29 01 00 00 00 02 9A B8
+ 29 01 00 00 00 02 9B 02
+ 29 01 00 00 00 02 9C E7
+ 29 01 00 00 00 02 9D 03
+ 29 01 00 00 00 02 9E 07
+ 29 01 00 00 00 02 9F 03
+ 29 01 00 00 00 02 A0 37
+ 29 01 00 00 00 02 A2 03
+ 29 01 00 00 00 02 A3 46
+ 29 01 00 00 00 02 A4 03
+ 29 01 00 00 00 02 A5 56
+ 29 01 00 00 00 02 A6 03
+ 29 01 00 00 00 02 A7 66
+ 29 01 00 00 00 02 A9 03
+ 29 01 00 00 00 02 AA 7A
+ 29 01 00 00 00 02 AB 03
+ 29 01 00 00 00 02 AC 93
+ 29 01 00 00 00 02 AD 03
+ 29 01 00 00 00 02 AE A3
+ 29 01 00 00 00 02 AF 03
+ 29 01 00 00 00 02 B0 B4
+ 29 01 00 00 00 02 B1 03
+ 29 01 00 00 00 02 B2 CB
+ 29 01 00 00 00 02 B3 00
+ 29 01 00 00 00 02 B4 7D
+ 29 01 00 00 00 02 B5 00
+ 29 01 00 00 00 02 B6 8A
+ 29 01 00 00 00 02 B7 00
+ 29 01 00 00 00 02 B8 9C
+ 29 01 00 00 00 02 B9 00
+ 29 01 00 00 00 02 BA B1
+ 29 01 00 00 00 02 BB 00
+ 29 01 00 00 00 02 BC BF
+ 29 01 00 00 00 02 BD 00
+ 29 01 00 00 00 02 BE CF
+ 29 01 00 00 00 02 BF 00
+ 29 01 00 00 00 02 C0 DD
+ 29 01 00 00 00 02 C1 00
+ 29 01 00 00 00 02 C2 E8
+ 29 01 00 00 00 02 C3 00
+ 29 01 00 00 00 02 C4 F2
+ 29 01 00 00 00 02 C5 01
+ 29 01 00 00 00 02 C6 1F
+ 29 01 00 00 00 02 C7 01
+ 29 01 00 00 00 02 C8 41
+ 29 01 00 00 00 02 C9 01
+ 29 01 00 00 00 02 CA 78
+ 29 01 00 00 00 02 CB 01
+ 29 01 00 00 00 02 CC A5
+ 29 01 00 00 00 02 CD 01
+ 29 01 00 00 00 02 CE EE
+ 29 01 00 00 00 02 CF 02
+ 29 01 00 00 00 02 D0 29
+ 29 01 00 00 00 02 D1 02
+ 29 01 00 00 00 02 D2 2A
+ 29 01 00 00 00 02 D3 02
+ 29 01 00 00 00 02 D4 5D
+ 29 01 00 00 00 02 D5 02
+ 29 01 00 00 00 02 D6 93
+ 29 01 00 00 00 02 D7 02
+ 29 01 00 00 00 02 D8 B8
+ 29 01 00 00 00 02 D9 02
+ 29 01 00 00 00 02 DA E7
+ 29 01 00 00 00 02 DB 03
+ 29 01 00 00 00 02 DC 07
+ 29 01 00 00 00 02 DD 03
+ 29 01 00 00 00 02 DE 37
+ 29 01 00 00 00 02 DF 03
+ 29 01 00 00 00 02 E0 46
+ 29 01 00 00 00 02 E1 03
+ 29 01 00 00 00 02 E2 56
+ 29 01 00 00 00 02 E3 03
+ 29 01 00 00 00 02 E4 66
+ 29 01 00 00 00 02 E5 03
+ 29 01 00 00 00 02 E6 7A
+ 29 01 00 00 00 02 E7 03
+ 29 01 00 00 00 02 E8 93
+ 29 01 00 00 00 02 E9 03
+ 29 01 00 00 00 02 EA A3
+ 29 01 00 00 00 02 EB 03
+ 29 01 00 00 00 02 EC B4
+ 29 01 00 00 00 02 ED 03
+ 29 01 00 00 00 02 EE CB
+ 29 01 00 00 00 02 EF 00
+ 29 01 00 00 00 02 F0 ED
+ 29 01 00 00 00 02 F1 00
+ 29 01 00 00 00 02 F2 F3
+ 29 01 00 00 00 02 F3 00
+ 29 01 00 00 00 02 F4 FE
+ 29 01 00 00 00 02 F5 01
+ 29 01 00 00 00 02 F6 09
+ 29 01 00 00 00 02 F7 01
+ 29 01 00 00 00 02 F8 13
+ 29 01 00 00 00 02 F9 01
+ 29 01 00 00 00 02 FA 1D
+ 29 01 00 00 00 02 FF 02
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 00 01
+ 29 01 00 00 00 02 01 26
+ 29 01 00 00 00 02 02 01
+ 29 01 00 00 00 02 03 2F
+ 29 01 00 00 00 02 04 01
+ 29 01 00 00 00 02 05 37
+ 29 01 00 00 00 02 06 01
+ 29 01 00 00 00 02 07 56
+ 29 01 00 00 00 02 08 01
+ 29 01 00 00 00 02 09 70
+ 29 01 00 00 00 02 0A 01
+ 29 01 00 00 00 02 0B 9D
+ 29 01 00 00 00 02 0C 01
+ 29 01 00 00 00 02 0D C2
+ 29 01 00 00 00 02 0E 01
+ 29 01 00 00 00 02 0F FF
+ 29 01 00 00 00 02 10 02
+ 29 01 00 00 00 02 11 31
+ 29 01 00 00 00 02 12 02
+ 29 01 00 00 00 02 13 32
+ 29 01 00 00 00 02 14 02
+ 29 01 00 00 00 02 15 60
+ 29 01 00 00 00 02 16 02
+ 29 01 00 00 00 02 17 94
+ 29 01 00 00 00 02 18 02
+ 29 01 00 00 00 02 19 B5
+ 29 01 00 00 00 02 1A 02
+ 29 01 00 00 00 02 1B E3
+ 29 01 00 00 00 02 1C 03
+ 29 01 00 00 00 02 1D 03
+ 29 01 00 00 00 02 1E 03
+ 29 01 00 00 00 02 1F 2D
+ 29 01 00 00 00 02 20 03
+ 29 01 00 00 00 02 21 3A
+ 29 01 00 00 00 02 22 03
+ 29 01 00 00 00 02 23 48
+ 29 01 00 00 00 02 24 03
+ 29 01 00 00 00 02 25 57
+ 29 01 00 00 00 02 26 03
+ 29 01 00 00 00 02 27 68
+ 29 01 00 00 00 02 28 03
+ 29 01 00 00 00 02 29 7B
+ 29 01 00 00 00 02 2A 03
+ 29 01 00 00 00 02 2B 90
+ 29 01 00 00 00 02 2D 03
+ 29 01 00 00 00 02 2F A0
+ 29 01 00 00 00 02 30 03
+ 29 01 00 00 00 02 31 CB
+ 29 01 00 00 00 02 32 00
+ 29 01 00 00 00 02 33 ED
+ 29 01 00 00 00 02 34 00
+ 29 01 00 00 00 02 35 F3
+ 29 01 00 00 00 02 36 00
+ 29 01 00 00 00 02 37 FE
+ 29 01 00 00 00 02 38 01
+ 29 01 00 00 00 02 39 09
+ 29 01 00 00 00 02 3A 01
+ 29 01 00 00 00 02 3B 13
+ 29 01 00 00 00 02 3D 01
+ 29 01 00 00 00 02 3F 1D
+ 29 01 00 00 00 02 40 01
+ 29 01 00 00 00 02 41 26
+ 29 01 00 00 00 02 42 01
+ 29 01 00 00 00 02 43 2F
+ 29 01 00 00 00 02 44 01
+ 29 01 00 00 00 02 45 37
+ 29 01 00 00 00 02 46 01
+ 29 01 00 00 00 02 47 56
+ 29 01 00 00 00 02 48 01
+ 29 01 00 00 00 02 49 70
+ 29 01 00 00 00 02 4A 01
+ 29 01 00 00 00 02 4B 9D
+ 29 01 00 00 00 02 4C 01
+ 29 01 00 00 00 02 4D C2
+ 29 01 00 00 00 02 4E 01
+ 29 01 00 00 00 02 4F FF
+ 29 01 00 00 00 02 50 02
+ 29 01 00 00 00 02 51 31
+ 29 01 00 00 00 02 52 02
+ 29 01 00 00 00 02 53 32
+ 29 01 00 00 00 02 54 02
+ 29 01 00 00 00 02 55 60
+ 29 01 00 00 00 02 56 02
+ 29 01 00 00 00 02 58 94
+ 29 01 00 00 00 02 59 02
+ 29 01 00 00 00 02 5A B5
+ 29 01 00 00 00 02 5B 02
+ 29 01 00 00 00 02 5C E3
+ 29 01 00 00 00 02 5D 03
+ 29 01 00 00 00 02 5E 03
+ 29 01 00 00 00 02 5F 03
+ 29 01 00 00 00 02 60 2D
+ 29 01 00 00 00 02 61 03
+ 29 01 00 00 00 02 62 3A
+ 29 01 00 00 00 02 63 03
+ 29 01 00 00 00 02 64 48
+ 29 01 00 00 00 02 65 03
+ 29 01 00 00 00 02 66 57
+ 29 01 00 00 00 02 67 03
+ 29 01 00 00 00 02 68 68
+ 29 01 00 00 00 02 69 03
+ 29 01 00 00 00 02 6A 7B
+ 29 01 00 00 00 02 6B 03
+ 29 01 00 00 00 02 6C 90
+ 29 01 00 00 00 02 6D 03
+ 29 01 00 00 00 02 6E A0
+ 29 01 00 00 00 02 6F 03
+ 29 01 00 00 00 02 70 CB
+ 29 01 00 00 00 02 71 00
+ 29 01 00 00 00 02 72 19
+ 29 01 00 00 00 02 73 00
+ 29 01 00 00 00 02 74 36
+ 29 01 00 00 00 02 75 00
+ 29 01 00 00 00 02 76 55
+ 29 01 00 00 00 02 77 00
+ 29 01 00 00 00 02 78 70
+ 29 01 00 00 00 02 79 00
+ 29 01 00 00 00 02 7A 83
+ 29 01 00 00 00 02 7B 00
+ 29 01 00 00 00 02 7C 99
+ 29 01 00 00 00 02 7D 00
+ 29 01 00 00 00 02 7E A8
+ 29 01 00 00 00 02 7F 00
+ 29 01 00 00 00 02 80 B7
+ 29 01 00 00 00 02 81 00
+ 29 01 00 00 00 02 82 C5
+ 29 01 00 00 00 02 83 00
+ 29 01 00 00 00 02 84 F7
+ 29 01 00 00 00 02 85 01
+ 29 01 00 00 00 02 86 1E
+ 29 01 00 00 00 02 87 01
+ 29 01 00 00 00 02 88 60
+ 29 01 00 00 00 02 89 01
+ 29 01 00 00 00 02 8A 95
+ 29 01 00 00 00 02 8B 01
+ 29 01 00 00 00 02 8C E1
+ 29 01 00 00 00 02 8D 02
+ 29 01 00 00 00 02 8E 20
+ 29 01 00 00 00 02 8F 02
+ 29 01 00 00 00 02 90 23
+ 29 01 00 00 00 02 91 02
+ 29 01 00 00 00 02 92 59
+ 29 01 00 00 00 02 93 02
+ 29 01 00 00 00 02 94 94
+ 29 01 00 00 00 02 95 02
+ 29 01 00 00 00 02 96 B4
+ 29 01 00 00 00 02 97 02
+ 29 01 00 00 00 02 98 E1
+ 29 01 00 00 00 02 99 03
+ 29 01 00 00 00 02 9A 01
+ 29 01 00 00 00 02 9B 03
+ 29 01 00 00 00 02 9C 28
+ 29 01 00 00 00 02 9D 03
+ 29 01 00 00 00 02 9E 30
+ 29 01 00 00 00 02 9F 03
+ 29 01 00 00 00 02 A0 37
+ 29 01 00 00 00 02 A2 03
+ 29 01 00 00 00 02 A3 3B
+ 29 01 00 00 00 02 A4 03
+ 29 01 00 00 00 02 A5 40
+ 29 01 00 00 00 02 A6 03
+ 29 01 00 00 00 02 A7 50
+ 29 01 00 00 00 02 A9 03
+ 29 01 00 00 00 02 AA 6D
+ 29 01 00 00 00 02 AB 03
+ 29 01 00 00 00 02 AC 80
+ 29 01 00 00 00 02 AD 03
+ 29 01 00 00 00 02 AE CB
+ 29 01 00 00 00 02 AF 00
+ 29 01 00 00 00 02 B0 19
+ 29 01 00 00 00 02 B1 00
+ 29 01 00 00 00 02 B2 36
+ 29 01 00 00 00 02 B3 00
+ 29 01 00 00 00 02 B4 55
+ 29 01 00 00 00 02 B5 00
+ 29 01 00 00 00 02 B6 70
+ 29 01 00 00 00 02 B7 00
+ 29 01 00 00 00 02 B8 83
+ 29 01 00 00 00 02 B9 00
+ 29 01 00 00 00 02 BA 99
+ 29 01 00 00 00 02 BB 00
+ 29 01 00 00 00 02 BC A8
+ 29 01 00 00 00 02 BD 00
+ 29 01 00 00 00 02 BE B7
+ 29 01 00 00 00 02 BF 00
+ 29 01 00 00 00 02 C0 C5
+ 29 01 00 00 00 02 C1 00
+ 29 01 00 00 00 02 C2 F7
+ 29 01 00 00 00 02 C3 01
+ 29 01 00 00 00 02 C4 1E
+ 29 01 00 00 00 02 C5 01
+ 29 01 00 00 00 02 C6 60
+ 29 01 00 00 00 02 C7 01
+ 29 01 00 00 00 02 C8 95
+ 29 01 00 00 00 02 C9 01
+ 29 01 00 00 00 02 CA E1
+ 29 01 00 00 00 02 CB 02
+ 29 01 00 00 00 02 CC 20
+ 29 01 00 00 00 02 CD 02
+ 29 01 00 00 00 02 CE 23
+ 29 01 00 00 00 02 CF 02
+ 29 01 00 00 00 02 D0 59
+ 29 01 00 00 00 02 D1 02
+ 29 01 00 00 00 02 D2 94
+ 29 01 00 00 00 02 D3 02
+ 29 01 00 00 00 02 D4 B4
+ 29 01 00 00 00 02 D5 02
+ 29 01 00 00 00 02 D6 E1
+ 29 01 00 00 00 02 D7 03
+ 29 01 00 00 00 02 D8 01
+ 29 01 00 00 00 02 D9 03
+ 29 01 00 00 00 02 DA 28
+ 29 01 00 00 00 02 DB 03
+ 29 01 00 00 00 02 DC 30
+ 29 01 00 00 00 02 DD 03
+ 29 01 00 00 00 02 DE 37
+ 29 01 00 00 00 02 DF 03
+ 29 01 00 00 00 02 E0 3B
+ 29 01 00 00 00 02 E1 03
+ 29 01 00 00 00 02 E2 40
+ 29 01 00 00 00 02 E3 03
+ 29 01 00 00 00 02 E4 50
+ 29 01 00 00 00 02 E5 03
+ 29 01 00 00 00 02 E6 6D
+ 29 01 00 00 00 02 E7 03
+ 29 01 00 00 00 02 E8 80
+ 29 01 00 00 00 02 E9 03
+ 29 01 00 00 00 02 EA CB
+ 29 01 00 00 00 02 FF 01
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 FF 02
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 FF 04
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 FF 00
+ 29 01 00 00 64 02 11 00
+ 29 01 00 00 00 02 FF EE
+ 29 01 00 00 00 02 12 50
+ 29 01 00 00 00 02 13 02
+ 29 01 00 00 00 02 6A 60
+ 29 01 00 00 00 02 FF 00
+ 29 01 00 00 78 02 29 00];
+ qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+ qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+ 05 01 00 00 78 02 10 00];
+ qcom,off-cmds-dsi-state = "DSI_HS_MODE";
+ };
+};
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index c0c9107..10ca8a8 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_dsi_nt35590_720p_video {
compatible = "qcom,mdss-dsi-panel";
label = "nt35590 720p video mode dsi panel";
diff --git a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
index 448d357..a27a88a 100644
--- a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_dsi_orise_720p_video {
compatible = "qcom,mdss-dsi-panel";
label = "orise 720p video mode dsi panel";
diff --git a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
index f853285..d182bac 100644
--- a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_dsi_sharp_qhd_video {
compatible = "qcom,mdss-dsi-panel";
label = "sharp QHD LS043T1LE01 video mode dsi panel";
diff --git a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
index 9a734a0..3b39dea 100644
--- a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_dsi_sim_video {
compatible = "qcom,mdss-dsi-panel";
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index 2937cde..82b57cd 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_dsi_toshiba_720p_video {
compatible = "qcom,mdss-dsi-panel";
diff --git a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
new file mode 100644
index 0000000..a3718aa
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
@@ -0,0 +1,120 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+ qcom,dsi_v2_truly_wvga_video {
+ compatible = "qcom,dsi-panel-v2";
+ label = "Truly WVGA video mode dsi panel";
+ qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+ qcom,rst-gpio = <&msmgpio 41 0>;
+ qcom,mode-selection-gpio = <&msmgpio 7 0>;
+ vdda-supply = <&pm8110_l19>;
+ vddio-supply=<&pm8110_l14>;
+ qcom,mdss-pan-res = <480 800>;
+ qcom,mdss-pan-bpp = <24>;
+ qcom,mdss-pan-dest = "display_1";
+ qcom,mdss-pan-porch-values = <40 8 160 10 2 12>;
+ qcom,mdss-pan-underflow-clr = <0xff>;
+ qcom,mdss-pan-bl-levels = <1 255>;
+ qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+ qcom,mdss-pan-dsi-mode = <0>;
+ qcom,mdss-pan-dsi-h-pulse-mode = <0>;
+ qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+ qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+ qcom,mdss-pan-dsi-traffic-mode = <1>;
+ qcom,mdss-pan-dsi-dst-format = <3>;
+ qcom,mdss-pan-dsi-vc = <0>;
+ qcom,mdss-pan-dsi-rgb-swap = <0>;
+ qcom,mdss-pan-dsi-data-lanes = <1 1 0 0>;
+ qcom,mdss-pan-dsi-dlane-swap = <0>;
+ qcom,mdss-pan-dsi-t-clk = <0x1b 0x04>;
+ qcom,mdss-pan-dsi-stream = <0>;
+ qcom,mdss-pan-dsi-mdp-tr = <0x0>;/*todo*/
+ qcom,mdss-pan-dsi-dma-tr = <0x04>;
+ qcom,mdss-pan-dsi-frame-rate = <60>;
+ qcom,panel-phy-regulatorSettings =[09 08 05 00 20 03];
+ qcom,panel-phy-timingSettings = [5D 12 0C 00 33 38
+ 10 16 1E 03 04 00];
+ qcom,panel-phy-strengthCtrl = [ff 06];
+ qcom,panel-phy-bistCtrl = [03 03 00 00 0f 00];
+ qcom,panel-phy-laneConfig =
+ [80 45 00 00 01 66 /*lane0**/
+ 80 45 00 00 01 66 /*lane1*/
+ 80 45 00 00 01 66 /*lane2*/
+ 80 45 00 00 01 66 /*lane3*/
+ 40 67 00 00 01 88]; /*Clk*/
+
+ qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+ qcom,panel-on-cmds = [
+ 05 01 00 00 01 02
+ 01 00
+ 23 01 00 00 01 02
+ b0 04
+ 29 01 00 00 01 03
+ b3 02 00
+ 23 01 00 00 01 02
+ bd 00
+ 29 01 00 00 01 03
+ c0 18 66
+ 29 01 00 00 01 10
+ c1 23 31 99 21 20 00 30 28 0c 0c
+ 00 00 00 21 01
+ 29 01 00 00 01 07
+ c2 10 06 06 01 03 00
+ 29 01 00 00 01 19
+ c8 04 10 18 20 2e 46 3c 28 1f 18
+ 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ 29 01 00 00 01 19
+ c9 04 10 18 20 2e 46 3c 28 1f 18
+ 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ 29 01 00 00 01 19
+ ca 04 10 18 20 2e 46 3c 28 1f 18
+ 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ 29 01 00 00 01 11
+ d0 29 03 ce a6 00 43 20 10 01 00
+ 01 01 00 03 01 00
+ 29 01 00 00 01 08
+ d1 18 0C 23 03 75 02 50
+ 23 01 00 00 01 02
+ d3 11
+ 29 01 00 00 01 03
+ d5 2a 2a
+ 29 01 00 00 01 03
+ de 01 41
+ 23 01 00 00 01 02
+ e6 51
+ 23 01 00 00 01 02
+ fa 03
+ 23 01 00 00 64 02
+ d6 28
+ 39 01 00 00 01 05
+ 2a 00 00 01 df
+ 39 01 00 00 01 05
+ 2b 00 00 03 1f
+ 15 01 00 00 01 02
+ 35 00
+ 39 01 00 00 01 03
+ 44 00 50
+ 15 01 00 00 01 02
+ 36 c1
+ 15 01 00 00 01 02
+ 3a 77
+ 05 01 00 00 96 02
+ 11 00
+ 05 01 00 00 64 02
+ 29 00
+ ];
+ qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+ 05 01 00 00 78 02 10 00];
+ qcom,off-cmds-dsi-state = "DSI_LP_MODE";
+ };
+};
diff --git a/arch/arm/boot/dts/mpq8092-ion.dtsi b/arch/arm/boot/dts/mpq8092-ion.dtsi
index 2cd2f7b..ee3fbc4 100644
--- a/arch/arm/boot/dts/mpq8092-ion.dtsi
+++ b/arch/arm/boot/dts/mpq8092-ion.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,ion {
compatible = "qcom,msm-ion";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/mpq8092-regulator.dtsi b/arch/arm/boot/dts/mpq8092-regulator.dtsi
index b724a3d..e6866e5 100644
--- a/arch/arm/boot/dts/mpq8092-regulator.dtsi
+++ b/arch/arm/boot/dts/mpq8092-regulator.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,9 +15,9 @@
&spmi_bus {
- qcom,pm8644@1 {
+ qcom,pma8084@1 {
- pm8644_s3: regulator@1a00 {
+ pma8084_s3: regulator@1a00 {
regulator-min-microvolt = <1350000>;
regulator-max-microvolt = <1350000>;
qcom,enable-time = <500>;
@@ -27,7 +27,7 @@
status = "okay";
};
- pm8644_s4: regulator@1d00 {
+ pma8084_s4: regulator@1d00 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
qcom,enable-time = <500>;
@@ -37,7 +37,7 @@
status = "okay";
};
- pm8644_s5: regulator@2000 {
+ pma8084_s5: regulator@2000 {
regulator-min-microvolt = <2150000>;
regulator-max-microvolt = <2150000>;
qcom,enable-time = <500>;
@@ -45,7 +45,7 @@
status = "okay";
};
- pm8644_s6: regulator@2300 {
+ pma8084_s6: regulator@2300 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <900000>;
qcom,enable-time = <500>;
@@ -53,7 +53,7 @@
status = "okay";
};
- pm8644_s7: regulator@2600 {
+ pma8084_s7: regulator@2600 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <900000>;
qcom,enable-time = <500>;
@@ -61,7 +61,7 @@
status = "okay";
};
- pm8644_s8: regulator@2900 {
+ pma8084_s8: regulator@2900 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <900000>;
qcom,enable-time = <500>;
@@ -69,8 +69,8 @@
status = "okay";
};
- pm8644_l1: regulator@4000 {
- parent-supply = <&pm8644_s3>;
+ pma8084_l1: regulator@4000 {
+ parent-supply = <&pma8084_s3>;
regulator-min-microvolt = <1225000>;
regulator-max-microvolt = <1225000>;
qcom,enable-time = <200>;
@@ -80,8 +80,8 @@
status = "okay";
};
- pm8644_l2: regulator@4100 {
- parent-supply = <&pm8644_s3>;
+ pma8084_l2: regulator@4100 {
+ parent-supply = <&pma8084_s3>;
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <900000>;
qcom,enable-time = <200>;
@@ -89,8 +89,8 @@
status = "okay";
};
- pm8644_l3: regulator@4200 {
- parent-supply = <&pm8644_s3>;
+ pma8084_l3: regulator@4200 {
+ parent-supply = <&pma8084_s3>;
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
qcom,enable-time = <200>;
@@ -98,8 +98,8 @@
status = "okay";
};
- pm8644_l4: regulator@4300 {
- parent-supply = <&pm8644_s3>;
+ pma8084_l4: regulator@4300 {
+ parent-supply = <&pma8084_s3>;
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
qcom,enable-time = <200>;
@@ -107,8 +107,8 @@
status = "okay";
};
- pm8644_l6: regulator@4500 {
- parent-supply = <&pm8644_s5>;
+ pma8084_l6: regulator@4500 {
+ parent-supply = <&pma8084_s5>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
qcom,enable-time = <200>;
@@ -116,7 +116,7 @@
status = "okay";
};
- pm8644_l8: regulator@4700 {
+ pma8084_l8: regulator@4700 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
qcom,enable-time = <200>;
@@ -124,7 +124,7 @@
status = "okay";
};
- pm8644_l9: regulator@4800 {
+ pma8084_l9: regulator@4800 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2950000>;
qcom,enable-time = <200>;
@@ -132,7 +132,7 @@
status = "okay";
};
- pm8644_l10: regulator@4900 {
+ pma8084_l10: regulator@4900 {
regulator-min-microvolt = <2000000>;
regulator-max-microvolt = <2000000>;
qcom,enable-time = <200>;
@@ -140,8 +140,8 @@
status = "okay";
};
- pm8644_l11: regulator@4a00 {
- parent-supply = <&pm8644_s3>;
+ pma8084_l11: regulator@4a00 {
+ parent-supply = <&pma8084_s3>;
regulator-min-microvolt = <1300000>;
regulator-max-microvolt = <1300000>;
qcom,enable-time = <200>;
@@ -149,8 +149,8 @@
status = "okay";
};
- pm8644_l12: regulator@4b00 {
- parent-supply = <&pm8644_s5>;
+ pma8084_l12: regulator@4b00 {
+ parent-supply = <&pma8084_s5>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
qcom,enable-time = <200>;
@@ -158,7 +158,7 @@
status = "okay";
};
- pm8644_l13: regulator@4c00 {
+ pma8084_l13: regulator@4c00 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2950000>;
qcom,enable-time = <200>;
@@ -166,8 +166,8 @@
status = "okay";
};
- pm8644_l14: regulator@4d00 {
- parent-supply = <&pm8644_s5>;
+ pma8084_l14: regulator@4d00 {
+ parent-supply = <&pma8084_s5>;
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
qcom,enable-time = <200>;
@@ -175,8 +175,8 @@
status = "okay";
};
- pm8644_l15: regulator@4e00 {
- parent-supply = <&pm8644_s5>;
+ pma8084_l15: regulator@4e00 {
+ parent-supply = <&pma8084_s5>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
qcom,enable-time = <200>;
@@ -184,8 +184,8 @@
status = "okay";
};
- pm8644_l16: regulator@4f00 {
- parent-supply = <&pm8644_s4>;
+ pma8084_l16: regulator@4f00 {
+ parent-supply = <&pma8084_s4>;
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <750000>;
qcom,enable-time = <200>;
@@ -193,7 +193,7 @@
status = "okay";
};
- pm8644_l17: regulator@5000 {
+ pma8084_l17: regulator@5000 {
regulator-min-microvolt = <3150000>;
regulator-max-microvolt = <3150000>;
qcom,enable-time = <200>;
@@ -203,7 +203,7 @@
status = "okay";
};
- pm8644_l18: regulator@5100 {
+ pma8084_l18: regulator@5100 {
regulator-min-microvolt = <2850000>;
regulator-max-microvolt = <2850000>;
qcom,enable-time = <200>;
@@ -211,8 +211,8 @@
status = "okay";
};
- pm8644_l19: regulator@5200 {
- parent-supply = <&pm8644_s4>;
+ pma8084_l19: regulator@5200 {
+ parent-supply = <&pma8084_s4>;
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <1500000>;
qcom,enable-time = <200>;
@@ -220,7 +220,7 @@
status = "okay";
};
- pm8644_l20: regulator@5300 {
+ pma8084_l20: regulator@5300 {
regulator-min-microvolt = <2950000>;
regulator-max-microvolt = <2950000>;
qcom,enable-time = <200>;
@@ -228,7 +228,7 @@
status = "okay";
};
- pm8644_l21: regulator@5400 {
+ pma8084_l21: regulator@5400 {
regulator-min-microvolt = <2950000>;
regulator-max-microvolt = <2950000>;
qcom,enable-time = <200>;
@@ -236,7 +236,7 @@
status = "okay";
};
- pm8644_l22: regulator@5500 {
+ pma8084_l22: regulator@5500 {
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <2500000>;
qcom,enable-time = <200>;
@@ -244,7 +244,7 @@
status = "okay";
};
- pm8644_l23: regulator@5600 {
+ pma8084_l23: regulator@5600 {
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
qcom,enable-time = <200>;
@@ -252,7 +252,7 @@
status = "okay";
};
- pm8644_l24: regulator@5700 {
+ pma8084_l24: regulator@5700 {
regulator-min-microvolt = <3075000>;
regulator-max-microvolt = <3075000>;
qcom,enable-time = <200>;
@@ -260,27 +260,21 @@
status = "okay";
};
- pm8644_lvs1: regulator@8000 {
- parent-supply = <&pm8644_s4>;
+ pma8084_lvs1: regulator@8000 {
+ parent-supply = <&pma8084_s4>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
status = "okay";
};
- pm8644_lvs2: regulator@8100 {
- parent-supply = <&pm8644_s4>;
+ pma8084_lvs2: regulator@8100 {
+ parent-supply = <&pma8084_s4>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
status = "okay";
};
- pm8644_mvs1: regulator@8200 {
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8644_mvs2: regulator@8300 {
+ pma8084_mvs1: regulator@8400 {
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
status = "okay";
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
index 0cbfa33..ce97d4d 100644
--- a/arch/arm/boot/dts/mpq8092-sim.dts
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,7 +18,9 @@
model = "Qualcomm MPQ8092 Simulator";
compatible = "qcom,mpq8092-sim", "qcom,mpq8092";
qcom,msm-id = <126 16 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
@@ -28,7 +30,7 @@
};
};
-&pm8644_gpios {
+&pma8084_gpios {
gpio@c000 { /* GPIO 1 */
};
@@ -94,72 +96,9 @@
gpio@d500 { /* GPIO 22 */
};
-
- gpio@d600 { /* GPIO 23 */
- };
-
- gpio@d700 { /* GPIO 24 */
- };
-
- gpio@d800 { /* GPIO 25 */
- };
-
- gpio@d900 { /* GPIO 26 */
- };
-
- gpio@da00 { /* GPIO 27 */
- };
-
- gpio@db00 { /* GPIO 28 */
- };
-
- gpio@dc00 { /* GPIO 29 */
- };
-
- gpio@dd00 { /* GPIO 30 */
- };
-
- gpio@de00 { /* GPIO 31 */
- };
-
- gpio@df00 { /* GPIO 32 */
- };
-
- gpio@e000 { /* GPIO 33 */
- };
-
- gpio@e100 { /* GPIO 34 */
- };
-
- gpio@e200 { /* GPIO 35 */
- };
-
- gpio@e300 { /* GPIO 36 */
- };
-
- gpio@e400 { /* GPIO 37 */
- };
-
- gpio@e500 { /* GPIO 38 */
- };
-
- gpio@e600 { /* GPIO 39 */
- };
-
- gpio@e700 { /* GPIO 40 */
- };
-
- gpio@e800 { /* GPIO 41 */
- };
-
- gpio@e900 { /* GPIO 42 */
- };
-
- gpio@ea00 { /* GPIO 43 */
- };
};
-&pm8644_mpps {
+&pma8084_mpps {
mpp@a000 { /* MPP 1 */
};
@@ -177,4 +116,10 @@
mpp@a500 { /* MPP 6 */
};
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
};
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 5c904b4..4dea9e0 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -11,15 +11,24 @@
*/
/include/ "skeleton.dtsi"
-/include/ "mpq8092-iommu.dtsi"
-/include/ "msm-gdsc.dtsi"
-/include/ "mpq8092-ion.dtsi"
/ {
model = "Qualcomm MPQ8092";
compatible = "qcom,mpq8092";
interrupt-parent = <&intc>;
+ soc: soc { };
+};
+
+/include/ "mpq8092-iommu.dtsi"
+/include/ "msm-gdsc.dtsi"
+/include/ "mpq8092-ion.dtsi"
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
intc: interrupt-controller@f9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
@@ -151,5 +160,5 @@
status = "ok";
};
-/include/ "msm-pm8644.dtsi"
+/include/ "msm-pma8084.dtsi"
/include/ "mpq8092-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm-gdsc.dtsi b/arch/arm/boot/dts/msm-gdsc.dtsi
index cfd68fa..d4c5061 100644
--- a/arch/arm/boot/dts/msm-gdsc.dtsi
+++ b/arch/arm/boot/dts/msm-gdsc.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -13,7 +13,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
gdsc_venus: qcom,gdsc@fd8c1024 {
compatible = "qcom,gdsc";
regulator-name = "gdsc_venus";
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index 0c44fb5..35829a7 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
lpass_iommu: qcom,iommu@fd000000 {
compatible = "qcom,msm-smmu-v0";
#address-cells = <1>;
@@ -30,6 +30,7 @@
status = "disabled";
lpass_q6_fw: qcom,iommu-ctx@fd000000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd000000 0x1000>;
interrupts = <0 250 0>;
qcom,iommu-ctx-mids = <0 15>;
@@ -37,6 +38,7 @@
};
lpass_audio_shared: qcom,iommu-ctx@fd001000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd001000 0x1000>;
interrupts = <0 250 0>;
qcom,iommu-ctx-mids = <1>;
@@ -44,6 +46,7 @@
};
lpass_video_shared: qcom,iommu-ctx@fd002000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd002000 0x1000>;
interrupts = <0 250 0>;
qcom,iommu-ctx-mids = <2>;
@@ -51,6 +54,7 @@
};
lpass_q6_spare: qcom,iommu-ctx@fd003000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd003000 0x1000>;
interrupts = <0 250 0>;
qcom,iommu-ctx-mids = <3 4 5 6 7 8 9 10 11 12 13 14>;
@@ -77,6 +81,7 @@
status = "disabled";
qcom,iommu-ctx@fd010000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd010000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <0>;
@@ -84,6 +89,7 @@
};
qcom,iommu-ctx@fd011000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd011000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <1>;
@@ -91,6 +97,7 @@
};
qcom,iommu-ctx@fd012000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd012000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <2>;
@@ -98,6 +105,7 @@
};
qcom,iommu-ctx@fd013000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd013000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <3>;
@@ -105,6 +113,7 @@
};
qcom,iommu-ctx@fd014000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd014000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <4>;
@@ -112,6 +121,7 @@
};
qcom,iommu-ctx@fd015000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd015000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <5>;
@@ -119,6 +129,7 @@
};
qcom,iommu-ctx@fd016000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd016000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <6>;
@@ -126,6 +137,7 @@
};
qcom,iommu-ctx@fd017000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd017000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <7>;
@@ -152,6 +164,7 @@
status = "disabled";
qcom,iommu-ctx@fd860000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd860000 0x1000>;
interrupts = <0 247 0>;
qcom,iommu-ctx-mids = <0 1 3>;
@@ -159,6 +172,7 @@
};
qcom,iommu-ctx@fd861000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd861000 0x1000>;
interrupts = <0 247 0>;
qcom,iommu-ctx-mids = <2>;
@@ -185,6 +199,7 @@
status = "disabled";
qcom,iommu-ctx@fd870000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd870000 0x1000>;
interrupts = <0 47 0>;
qcom,iommu-ctx-mids = <0>;
@@ -192,6 +207,7 @@
};
qcom,iommu-ctx@fd871000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd871000 0x1000>;
interrupts = <0 47 0>;
qcom,iommu-ctx-mids = <1>;
@@ -207,6 +223,7 @@
reg = <0xfd880000 0x10000>;
interrupts = <0 38 0>;
qcom,glb-offset = <0xF000>;
+ qcom,needs-alt-core-clk;
label = "gfx_iommu";
qcom,iommu-pmu-ngroups = <1>;
qcom,iommu-pmu-ncounters = <4>;
@@ -218,6 +235,7 @@
status = "disabled";
qcom,iommu-ctx@fd880000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd880000 0x1000>;
interrupts = <0 241 0>;
qcom,iommu-ctx-mids = <0 1 2 3 4 5 6 7 8 9 10 11 12 13
@@ -226,6 +244,7 @@
};
qcom,iommu-ctx@fd881000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd881000 0x1000>;
interrupts = <0 241 0>;
qcom,iommu-ctx-mids = <16 17 18 19 20 21 22 23 24 25
@@ -234,6 +253,7 @@
};
qcom,iommu-ctx@fd882000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd882000 0x1000>;
interrupts = <0 241 0>;
qcom,iommu-ctx-mids = <>;
@@ -260,6 +280,7 @@
status = "disabled";
qcom,iommu-ctx@fd890000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd890000 0x1000>;
interrupts = <0 65 0>;
qcom,iommu-ctx-mids = <0>;
@@ -267,6 +288,7 @@
};
qcom,iommu-ctx@fd891000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd891000 0x1000>;
interrupts = <0 65 0>;
qcom,iommu-ctx-mids = <1>;
diff --git a/arch/arm/boot/dts/msm-iommu-v1.dtsi b/arch/arm/boot/dts/msm-iommu-v1.dtsi
index 71dcc6a..ab46861 100644
--- a/arch/arm/boot/dts/msm-iommu-v1.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v1.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
jpeg_iommu: qcom,iommu@fda64000 {
compatible = "qcom,msm-smmu-v1";
#address-cells = <1>;
@@ -77,6 +77,7 @@
0x0>;
qcom,iommu-ctx@fda6c000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda6c000 0x1000>;
interrupts = <0 70 0>;
qcom,iommu-ctx-sids = <0>;
@@ -84,6 +85,7 @@
};
qcom,iommu-ctx@fda6d000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda6d000 0x1000>;
interrupts = <0 70 0>;
qcom,iommu-ctx-sids = <1>;
@@ -91,6 +93,7 @@
};
qcom,iommu-ctx@fda6e000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda6e000 0x1000>;
interrupts = <0 70 0>;
qcom,iommu-ctx-sids = <2>;
@@ -170,6 +173,7 @@
0x0>;
qcom,iommu-ctx@fd930000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfd930000 0x1000>;
interrupts = <0 47 0>;
qcom,iommu-ctx-sids = <0>;
@@ -177,6 +181,7 @@
};
qcom,iommu-ctx@fd931000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfd931000 0x1000>;
interrupts = <0 47 0>;
qcom,iommu-ctx-sids = <1>;
@@ -185,6 +190,7 @@
};
qcom,iommu-ctx@fd932000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfd932000 0x1000>;
interrupts = <0 47 0>;
qcom,iommu-ctx-sids = <>;
@@ -279,6 +285,7 @@
0x0>;
venus_ns: qcom,iommu-ctx@fdc8c000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8c000 0x1000>;
interrupts = <0 42 0>;
qcom,iommu-ctx-sids = <0 1 2 3 4 5>;
@@ -286,6 +293,7 @@
};
venus_cp: qcom,iommu-ctx@fdc8d000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8d000 0x1000>;
interrupts = <0 42 0>;
qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84 0x85>;
@@ -294,6 +302,7 @@
};
venus_fw: qcom,iommu-ctx@fdc8e000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8e000 0x1000>;
interrupts = <0 42 0>;
qcom,iommu-ctx-sids = <0xc0 0xc6>;
@@ -363,6 +372,7 @@
0x0>;
qcom,iommu-ctx@fdb18000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdb18000 0x1000>;
interrupts = <0 241 0>;
qcom,iommu-ctx-sids = <0>;
@@ -370,6 +380,7 @@
};
qcom,iommu-ctx@fdb19000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdb19000 0x1000>;
interrupts = <0 241 0>;
qcom,iommu-ctx-sids = <1>;
@@ -449,6 +460,7 @@
0x0>;
qcom,iommu-ctx@fda4c000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda4c000 0x1000>;
interrupts = <0 65 0>;
qcom,iommu-ctx-sids = <0>;
@@ -456,6 +468,7 @@
};
qcom,iommu-ctx@fda4d000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda4d000 0x1000>;
interrupts = <0 65 0>;
qcom,iommu-ctx-sids = <1>;
@@ -463,6 +476,7 @@
};
qcom,iommu-ctx@fda4e000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda4e000 0x1000>;
interrupts = <0 65 0>;
qcom,iommu-ctx-sids = <2>;
diff --git a/arch/arm/boot/dts/msm-pm8019.dtsi b/arch/arm/boot/dts/msm-pm8019.dtsi
index 689bf0f..fad9d86 100755
--- a/arch/arm/boot/dts/msm-pm8019.dtsi
+++ b/arch/arm/boot/dts/msm-pm8019.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -196,6 +196,21 @@
qcom,fast-avg-setup = <0>;
};
};
+
+ pm8019_adc_tm: vadc@3400 {
+ compatible = "qcom,qpnp-adc-tm";
+ reg = <0x3400 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x34 0x0>,
+ <0x0 0x34 0x3>,
+ <0x0 0x34 0x4>;
+ interrupt-names = "eoc-int-en-set",
+ "high-thr-en-set",
+ "low-thr-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1800>;
+ };
};
qcom,pm8019@1 {
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index b88b991..e22e398 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -22,6 +22,29 @@
#address-cells = <1>;
#size-cells = <1>;
+ qcom,power-on@800 {
+ compatible = "qcom,qpnp-power-on";
+ reg = <0x800 0x100>;
+ interrupts = <0x0 0x8 0x0>,
+ <0x0 0x8 0x1>,
+ <0x0 0x8 0x4>;
+ interrupt-names = "kpdpwr", "resin", "resin-bark";
+ qcom,pon-dbc-delay = <15625>;
+ qcom,system-reset;
+
+ qcom,pon_1 {
+ qcom,pon-type = <0>;
+ qcom,pull-up = <1>;
+ linux,code = <116>;
+ };
+
+ qcom,pon_2 {
+ qcom,pon-type = <1>;
+ qcom,pull-up = <1>;
+ linux,code = <114>;
+ };
+ };
+
pm8110_chg: qcom,charger {
spmi-dev-container;
compatible = "qcom,qpnp-charger";
@@ -116,6 +139,66 @@
};
};
+ pm8110_gpios: gpios {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-pin";
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "pm8110-gpio";
+
+ gpio@c000 {
+ reg = <0xc000 0x100>;
+ qcom,pin-num = <1>;
+ };
+
+ gpio@c100 {
+ reg = <0xc100 0x100>;
+ qcom,pin-num = <2>;
+ };
+
+ gpio@c200 {
+ reg = <0xc200 0x100>;
+ qcom,pin-num = <3>;
+ };
+
+ gpio@c300 {
+ reg = <0xc300 0x100>;
+ qcom,pin-num = <4>;
+ };
+ };
+
+ pm8110_mpps: mpps {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-pin";
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "pm8110-mpp";
+
+ mpp@a000 {
+ reg = <0xa000 0x100>;
+ qcom,pin-num = <1>;
+ };
+
+ mpp@a100 {
+ reg = <0xa100 0x100>;
+ qcom,pin-num = <2>;
+ };
+
+ mpp@a200 {
+ reg = <0xa200 0x100>;
+ qcom,pin-num = <3>;
+ };
+
+ mpp@a300 {
+ reg = <0xa300 0x100>;
+ qcom,pin-num = <4>;
+ };
+ };
+
pm8110_vadc: vadc@3100 {
compatible = "qcom,qpnp-vadc";
reg = <0x3100 0x100>;
@@ -182,6 +265,57 @@
};
};
+ pm8110_bms: qcom,bms {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-bms";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+
+ qcom,r-sense-uohm = <10000>;
+ qcom,v-cutoff-uv = <3400000>;
+ qcom,max-voltage-uv = <4200000>;
+ qcom,r-conn-mohm = <0>;
+ qcom,shutdown-soc-valid-limit = <20>;
+ qcom,adjust-soc-low-threshold = <15>;
+ qcom,ocv-voltage-high-threshold-uv = <3750000>;
+ qcom,ocv-voltage-low-threshold-uv = <3650000>;
+ qcom,low-soc-calculate-soc-threshold = <15>;
+ qcom,low-soc-calculate-soc-ms = <5000>;
+ qcom,calculate-soc-ms = <20000>;
+ qcom,chg-term-ua = <100000>;
+ qcom,batt-type = <0>;
+ qcom,low-voltage-threshold = <3420000>;
+ qcom,low-ocv-correction-limit-uv = <100>;
+ qcom,high-ocv-correction-limit-uv = <50>;
+ qcom,hold-soc-est = <3>;
+
+ qcom,bms-iadc@3800 {
+ reg = <0x3800 0x100>;
+ };
+
+ qcom,bms-bms@4000 {
+ reg = <0x4000 0x100>;
+ interrupts = <0x0 0x40 0x0>,
+ <0x0 0x40 0x1>,
+ <0x0 0x40 0x2>,
+ <0x0 0x40 0x3>,
+ <0x0 0x40 0x4>,
+ <0x0 0x40 0x5>,
+ <0x0 0x40 0x6>,
+ <0x0 0x40 0x7>;
+
+ interrupt-names = "vsense_for_r",
+ "vsense_avg",
+ "sw_cc_thr",
+ "ocv_thr",
+ "charge_begin",
+ "good_ocv",
+ "ocv_for_r",
+ "cc_thr";
+ };
+ };
+
qcom,pm8110_rtc {
spmi-dev-container;
compatible = "qcom,qpnp-rtc";
@@ -200,6 +334,12 @@
};
};
+ qcom,leds@a100 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xa100 0x100>;
+ label = "mpp";
+ };
+
qcom,leds@a200 {
compatible = "qcom,leds-qpnp";
reg = <0xa200 0x100>;
@@ -432,5 +572,12 @@
reg = <0x5500 0x100>;
status = "disabled";
};
+
+ qcom,vibrator@c000 {
+ compatible = "qcom,qpnp-vibrator";
+ reg = <0xc000 0x100>;
+ label = "vibrator";
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 41920d5..4d6751c 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -61,7 +61,7 @@
qcom,vinmin-mv = <4200>;
qcom,vbatdet-delta-mv = <150>;
qcom,ibatmax-ma = <1500>;
- qcom,ibatterm-ma = <200>;
+ qcom,ibatterm-ma = <100>;
qcom,ibatsafe-ma = <1500>;
qcom,thermal-mitigation = <1500 700 600 325>;
qcom,tchg-mins = <150>;
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 43b7d03..ce6bc63 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -175,6 +175,7 @@
qcom,vddsafe-mv = <4200>;
qcom,vinmin-mv = <4200>;
qcom,ibatmax-ma = <1500>;
+ qcom,ibatterm-ma = <100>;
qcom,ibatsafe-ma = <1500>;
qcom,thermal-mitigation = <1500 700 600 325>;
qcom,cool-bat-decidegc = <100>;
@@ -183,7 +184,7 @@
qcom,warm-bat-decidegc = <450>;
qcom,warm-bat-mv = <4100>;
qcom,ibatmax-cool-ma = <350>;
- qcom,vbatdet-delta-mv = <350>;
+ qcom,vbatdet-delta-mv = <100>;
qcom,tchg-mins = <150>;
qcom,chgr@1000 {
@@ -584,10 +585,10 @@
};
chan@3 {
- label = "spare1";
+ label = "spare1_div3";
reg = <3>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <6>;
+ qcom,pre-div-channel-scaling = <1>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
@@ -595,10 +596,10 @@
};
chan@4 {
- label = "spare2";
+ label = "usb_id_mv";
reg = <4>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <6>;
+ qcom,pre-div-channel-scaling = <1>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
@@ -849,7 +850,7 @@
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "absolute";
- qcom,scale-function = <1>;
+ qcom,scale-function = <3>;
qcom,hw-settle-time = <0>;
qcom,fast-avg-setup = <3>;
qcom,btm-channel-number = <0x70>;
@@ -872,7 +873,7 @@
reg = <0xb5>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "absolute";
+ qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <3>;
diff --git a/arch/arm/boot/dts/msm-pm8644.dtsi b/arch/arm/boot/dts/msm-pma8084.dtsi
similarity index 76%
rename from arch/arm/boot/dts/msm-pm8644.dtsi
rename to arch/arm/boot/dts/msm-pma8084.dtsi
index 17a6b0b..30525aa 100644
--- a/arch/arm/boot/dts/msm-pm8644.dtsi
+++ b/arch/arm/boot/dts/msm-pma8084.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,20 +16,20 @@
interrupt-controller;
#interrupt-cells = <3>;
- qcom,pm8644@0 {
+ qcom,pma8084@0 {
spmi-slave-container;
reg = <0x0>;
#address-cells = <1>;
#size-cells = <1>;
- pm8644_gpios: gpios {
+ pma8084_gpios: gpios {
spmi-dev-container;
compatible = "qcom,qpnp-pin";
gpio-controller;
#gpio-cells = <2>;
#address-cells = <1>;
#size-cells = <1>;
- label = "pm8644-gpio";
+ label = "pma8084-gpio";
gpio@c000 {
reg = <0xc000 0x100>;
@@ -140,121 +140,16 @@
reg = <0xd500 0x100>;
qcom,pin-num = <22>;
};
-
- gpio@d600 {
- reg = <0xd600 0x100>;
- qcom,pin-num = <23>;
- };
-
- gpio@d700 {
- reg = <0xd700 0x100>;
- qcom,pin-num = <24>;
- };
-
- gpio@d800 {
- reg = <0xd800 0x100>;
- qcom,pin-num = <25>;
- };
-
- gpio@d900 {
- reg = <0xd900 0x100>;
- qcom,pin-num = <26>;
- };
-
- gpio@da00 {
- reg = <0xda00 0x100>;
- qcom,pin-num = <27>;
- };
-
- gpio@db00 {
- reg = <0xdb00 0x100>;
- qcom,pin-num = <28>;
- };
-
- gpio@dc00 {
- reg = <0xdc00 0x100>;
- qcom,pin-num = <29>;
- };
-
- gpio@dd00 {
- reg = <0xdd00 0x100>;
- qcom,pin-num = <30>;
- };
-
- gpio@de00 {
- reg = <0xde00 0x100>;
- qcom,pin-num = <31>;
- };
-
- gpio@df00 {
- reg = <0xdf00 0x100>;
- qcom,pin-num = <32>;
- };
-
- gpio@e000 {
- reg = <0xe000 0x100>;
- qcom,pin-num = <33>;
- };
-
- gpio@e100 {
- reg = <0xe100 0x100>;
- qcom,pin-num = <34>;
- };
-
- gpio@e200 {
- reg = <0xe200 0x100>;
- qcom,pin-num = <35>;
- };
-
- gpio@e300 {
- reg = <0xe300 0x100>;
- qcom,pin-num = <36>;
- };
-
- gpio@e400 {
- reg = <0xe400 0x100>;
- qcom,pin-num = <37>;
- };
-
- gpio@e500 {
- reg = <0xe500 0x100>;
- qcom,pin-num = <38>;
- };
-
- gpio@e600 {
- reg = <0xe600 0x100>;
- qcom,pin-num = <39>;
- };
-
- gpio@e700 {
- reg = <0xe700 0x100>;
- qcom,pin-num = <40>;
- };
-
- gpio@e800 {
- reg = <0xe800 0x100>;
- qcom,pin-num = <41>;
- };
-
- gpio@e900 {
- reg = <0xe900 0x100>;
- qcom,pin-num = <42>;
- };
-
- gpio@ea00 {
- reg = <0xea00 0x100>;
- qcom,pin-num = <43>;
- };
};
- pm8644_mpps: mpps {
+ pma8084_mpps: mpps {
spmi-dev-container;
compatible = "qcom,qpnp-pin";
gpio-controller;
#gpio-cells = <2>;
#address-cells = <1>;
#size-cells = <1>;
- label = "pm8644-mpp";
+ label = "pma8084-mpp";
mpp@a000 {
reg = <0xa000 0x100>;
@@ -285,17 +180,27 @@
reg = <0xa500 0x100>;
qcom,pin-num = <6>;
};
+
+ mpp@a600 {
+ reg = <0xa600 0x100>;
+ qcom,pin-num = <7>;
+ };
+
+ mpp@a700 {
+ reg = <0xa700 0x100>;
+ qcom,pin-num = <8>;
+ };
};
};
- qcom,pm8644@1 {
+ qcom,pma8084@1 {
spmi-slave-container;
reg = <0x1>;
#address-cells = <1>;
#size-cells = <1>;
regulator@1400 {
- regulator-name = "8644_s1";
+ regulator-name = "8084_s1";
spmi-dev-container;
#address-cells = <1>;
#size-cells = <1>;
@@ -315,7 +220,7 @@
};
regulator@1700 {
- regulator-name = "8644_s2";
+ regulator-name = "8084_s2";
spmi-dev-container;
#address-cells = <1>;
#size-cells = <1>;
@@ -335,7 +240,7 @@
};
regulator@1a00 {
- regulator-name = "8644_s3";
+ regulator-name = "8084_s3";
spmi-dev-container;
#address-cells = <1>;
#size-cells = <1>;
@@ -355,7 +260,7 @@
};
regulator@1d00 {
- regulator-name = "8644_s4";
+ regulator-name = "8084_s4";
spmi-dev-container;
#address-cells = <1>;
#size-cells = <1>;
@@ -375,7 +280,7 @@
};
regulator@2000 {
- regulator-name = "8644_s5";
+ regulator-name = "8084_s5";
spmi-dev-container;
#address-cells = <1>;
#size-cells = <1>;
@@ -395,7 +300,7 @@
};
regulator@2300 {
- regulator-name = "8644_s6";
+ regulator-name = "8084_s6";
spmi-dev-container;
#address-cells = <1>;
#size-cells = <1>;
@@ -415,7 +320,7 @@
};
regulator@2600 {
- regulator-name = "8644_s7";
+ regulator-name = "8084_s7";
spmi-dev-container;
#address-cells = <1>;
#size-cells = <1>;
@@ -435,7 +340,7 @@
};
regulator@2900 {
- regulator-name = "8644_s8";
+ regulator-name = "8084_s8";
spmi-dev-container;
#address-cells = <1>;
#size-cells = <1>;
@@ -455,7 +360,7 @@
};
regulator@2c00 {
- regulator-name = "8644_s9";
+ regulator-name = "8084_s9";
spmi-dev-container;
#address-cells = <1>;
#size-cells = <1>;
@@ -475,7 +380,7 @@
};
regulator@2f00 {
- regulator-name = "8644_s10";
+ regulator-name = "8084_s10";
spmi-dev-container;
#address-cells = <1>;
#size-cells = <1>;
@@ -495,7 +400,7 @@
};
regulator@3200 {
- regulator-name = "8644_s11";
+ regulator-name = "8084_s11";
spmi-dev-container;
#address-cells = <1>;
#size-cells = <1>;
@@ -514,209 +419,248 @@
};
};
+ regulator@3500 {
+ regulator-name = "8084_s12";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,qpnp-regulator";
+ reg = <0x3500 0x300>;
+ status = "disabled";
+
+ qcom,ctl@3500 {
+ reg = <0x3500 0x100>;
+ };
+ qcom,ps@3600 {
+ reg = <0x3600 0x100>;
+ };
+ qcom,freq@3700 {
+ reg = <0x3700 0x100>;
+ };
+ };
+
regulator@4000 {
- regulator-name = "8644_l1";
+ regulator-name = "8084_l1";
reg = <0x4000 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@4100 {
- regulator-name = "8644_l2";
+ regulator-name = "8084_l2";
reg = <0x4100 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@4200 {
- regulator-name = "8644_l3";
+ regulator-name = "8084_l3";
reg = <0x4200 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@4300 {
- regulator-name = "8644_l4";
+ regulator-name = "8084_l4";
reg = <0x4300 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@4400 {
- regulator-name = "8644_l5";
+ regulator-name = "8084_l5";
reg = <0x4400 0x100>;
compatible = "qcom,qpnp-regulator";
- qcom,force-type = <0x04 0x10>;
status = "disabled";
};
regulator@4500 {
- regulator-name = "8644_l6";
+ regulator-name = "8084_l6";
reg = <0x4500 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@4600 {
- regulator-name = "8644_l7";
+ regulator-name = "8084_l7";
reg = <0x4600 0x100>;
compatible = "qcom,qpnp-regulator";
- qcom,force-type = <0x04 0x10>;
status = "disabled";
};
regulator@4700 {
- regulator-name = "8644_l8";
+ regulator-name = "8084_l8";
reg = <0x4700 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@4800 {
- regulator-name = "8644_l9";
+ regulator-name = "8084_l9";
reg = <0x4800 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@4900 {
- regulator-name = "8644_l10";
+ regulator-name = "8084_l10";
reg = <0x4900 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@4a00 {
- regulator-name = "8644_l11";
+ regulator-name = "8084_l11";
reg = <0x4a00 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@4b00 {
- regulator-name = "8644_l12";
+ regulator-name = "8084_l12";
reg = <0x4b00 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@4c00 {
- regulator-name = "8644_l13";
+ regulator-name = "8084_l13";
reg = <0x4c00 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@4d00 {
- regulator-name = "8644_l14";
+ regulator-name = "8084_l14";
reg = <0x4d00 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@4e00 {
- regulator-name = "8644_l15";
+ regulator-name = "8084_l15";
reg = <0x4e00 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@4f00 {
- regulator-name = "8644_l16";
+ regulator-name = "8084_l16";
reg = <0x4f00 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@5000 {
- regulator-name = "8644_l17";
+ regulator-name = "8084_l17";
reg = <0x5000 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@5100 {
- regulator-name = "8644_l18";
+ regulator-name = "8084_l18";
reg = <0x5100 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@5200 {
- regulator-name = "8644_l19";
+ regulator-name = "8084_l19";
reg = <0x5200 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@5300 {
- regulator-name = "8644_l20";
+ regulator-name = "8084_l20";
reg = <0x5300 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@5400 {
- regulator-name = "8644_l21";
+ regulator-name = "8084_l21";
reg = <0x5400 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@5500 {
- regulator-name = "8644_l22";
+ regulator-name = "8084_l22";
reg = <0x5500 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@5600 {
- regulator-name = "8644_l23";
+ regulator-name = "8084_l23";
reg = <0x5600 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@5700 {
- regulator-name = "8644_l24";
+ regulator-name = "8084_l24";
reg = <0x5700 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@5800 {
- regulator-name = "8644_l25";
+ regulator-name = "8084_l25";
reg = <0x5800 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
+ regulator@5900 {
+ regulator-name = "8084_l26";
+ reg = <0x5900 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@5a00 {
+ regulator-name = "8084_l27";
+ reg = <0x5a00 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
regulator@8000 {
- regulator-name = "8644_lvs1";
+ regulator-name = "8084_lvs1";
reg = <0x8000 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@8100 {
- regulator-name = "8644_lvs2";
+ regulator-name = "8084_lvs2";
reg = <0x8100 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@8200 {
- regulator-name = "8644_mvs1";
+ regulator-name = "8084_lvs3";
reg = <0x8200 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
regulator@8300 {
- regulator-name = "8644_mvs2";
+ regulator-name = "8084_lvs4";
reg = <0x8300 0x100>;
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
+
+ regulator@8400 {
+ regulator-name = "8084_mvs1";
+ reg = <0x8400 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8226-bus.dtsi b/arch/arm/boot/dts/msm8226-bus.dtsi
index 3c41e9e..d87aa3e 100644
--- a/arch/arm/boot/dts/msm8226-bus.dtsi
+++ b/arch/arm/boot/dts/msm8226-bus.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
msm-mmss-noc@fc478000 {
compatible = "msm-bus-fabric";
reg = <0xfc478000 0x00004000>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index c47d48d..07f16b9 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
led_flash0: qcom,camera-led-flash {
cell-index = <0>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index 1f7ba89..f06033e 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
led_flash0: qcom,camera-led-flash {
cell-index = <0>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index 5ea02b4..47f4049 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
led_flash0: qcom,camera-led-flash {
cell-index = <0>;
diff --git a/arch/arm/boot/dts/msm8226-camera.dtsi b/arch/arm/boot/dts/msm8226-camera.dtsi
index e94459e..0dae162 100644
--- a/arch/arm/boot/dts/msm8226-camera.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera.dtsi
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,msm-cam@fd8c0000 {
compatible = "qcom,msm-cam";
reg = <0xfd8c0000 0x10000>;
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index b203540..f887740 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -19,7 +19,9 @@
model = "Qualcomm MSM 8226 CDP";
compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
qcom,msm-id = <145 1 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index 993b4e6..7c19bc0 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
tmc_etr: tmc@fc322000 {
compatible = "arm,coresight-tmc";
reg = <0xfc322000 0x1000>,
@@ -355,4 +355,18 @@
coresight-name = "coresight-cti-cpu3";
coresight-nr-inports = <0>;
};
+
+ hwevent: hwevent@fd828018 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0xfd828018 0x80>,
+ <0xf9011080 0x80>,
+ <0xfd4ab160 0x80>;
+ reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+
+ coresight-id = <29>;
+ coresight-name = "coresight-hwevent";
+ coresight-nr-inports = <0>;
+
+ qcom,hwevent-clks = "core_mmss_clk";
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-fluid.dts b/arch/arm/boot/dts/msm8226-fluid.dts
index d70ef6e..7b11200 100644
--- a/arch/arm/boot/dts/msm8226-fluid.dts
+++ b/arch/arm/boot/dts/msm8226-fluid.dts
@@ -17,7 +17,9 @@
model = "Qualcomm MSM 8226 FLUID";
compatible = "qcom,msm8226-fluid", "qcom,msm8226", "qcom,fluid";
qcom,msm-id = <145 3 0>;
+};
+&soc {
serial@f991f000 {
status = "disabled";
};
diff --git a/arch/arm/boot/dts/msm8226-gpu.dtsi b/arch/arm/boot/dts/msm8226-gpu.dtsi
index bb2f0d4..d83df1e 100644
--- a/arch/arm/boot/dts/msm8226-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8226-gpu.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
msm_gpu: qcom,kgsl-3d0@fdb00000 {
label = "kgsl-3d0";
compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
@@ -22,8 +22,7 @@
qcom,chipid = <0x03000510>;
- qcom,initial-pwrlevel = <2>;
- qcom,step-pwrlevel = <2>;
+ qcom,initial-pwrlevel = <1>;
qcom,idle-timeout = <8>; //<HZ/12>
qcom,nap-allowed = <1>;
diff --git a/arch/arm/boot/dts/msm8226-iommu-domains.dtsi b/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
index 6ea5b9e..25fca2a 100644
--- a/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
+++ b/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,iommu-domains {
compatible = "qcom,iommu-domains";
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index f433a49..dee64e5 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,ion {
compatible = "qcom,msm-ion";
#address-cells = <1>;
@@ -38,9 +38,7 @@
qcom,ion-heap@27 { /* QSECOM HEAP */
compatible = "qcom,msm-ion-reserve";
reg = <27>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x780000>;
+ linux,contiguous-region = <&qsecom_mem>;
};
qcom,ion-heap@28 { /* AUDIO HEAP */
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 5aa39d3..f580897 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_mdp@fd900000 {
compatible = "qcom,mdss_mdp";
reg = <0xfd900000 0x22100>,
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index 1f8a773..589fe69 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -19,7 +19,9 @@
model = "Qualcomm MSM 8226 MTP";
compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
qcom,msm-id = <145 8 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
@@ -363,3 +365,10 @@
&pm8226_chg {
qcom,charging-disabled;
};
+
+&slim_msm {
+ tapan_codec {
+ qcom,cdc-micbias1-ext-cap;
+ qcom,cdc-micbias2-ext-cap;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 97b22aa..3240efb 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -12,7 +12,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
qcom,spm@f9089000 {
compatible = "qcom,spm-v2";
#address-cells = <1>;
@@ -114,7 +114,7 @@
qcom,type = <0x61706d73>; /* "smpa" */
qcom,id = <0x01>;
qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <5>; /* Super Turbo */
+ qcom,init-value = <3>; /* SVS SOC */
};
qcom,lpm-resources@1 {
@@ -123,7 +123,7 @@
qcom,type = <0x616F646C>; /* "ldoa" */
qcom,id = <0x03>;
qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <3>; /* Active */
+ qcom,init-value = <3>; /* SVS SOC */
};
qcom,lpm-resources@2 {
@@ -153,10 +153,10 @@
qcom,mode = "wfi";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <1>;
@@ -170,10 +170,10 @@
qcom,mode = "standalone_pc";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <3000>;
@@ -187,10 +187,10 @@
qcom,mode = "pc";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_retention";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <8000>;
@@ -204,10 +204,10 @@
qcom,mode = "pc";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <2>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <3>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <2>; /* SVS SOC */
+ qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <9000>;
@@ -221,10 +221,10 @@
qcom,mode = "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,latency-us = <16300>;
qcom,ss-power = <63>;
qcom,energy-overhead = <2128000>;
@@ -236,10 +236,10 @@
qcom,mode = "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <2>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <3>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <2>; /* SVS SOC */
+ qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
qcom,latency-us = <24000>;
qcom,ss-power = <10>;
qcom,energy-overhead = <3202600>;
@@ -251,10 +251,10 @@
qcom,mode = "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <2>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <0>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <2>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <0>; /* RETENTION */
+ qcom,vdd-mem-upper-bound = <3>; /* SVS SOC */
+ qcom,vdd-mem-lower-bound = <1>; /* RETENTION */
+ qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
qcom,latency-us = <26000>;
qcom,ss-power = <2>;
qcom,energy-overhead = <4252000>;
@@ -380,9 +380,9 @@
qcom,offset-page-indices = <56>;
};
- qcom,rpm-stats@0xfc19dbd0{
+ qcom,rpm-stats@fc19dba0 {
compatible = "qcom,rpm-stats";
- reg = <0xfc19dbd0 0x1000>;
+ reg = <0xfc19dba0 0x1000>;
reg-names = "phys_addr_base";
qcom,sleep-stats-version = <2>;
};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index 660fb3e..f917d45 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -19,7 +19,9 @@
model = "Qualcomm MSM 8226 QRD";
compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
qcom,msm-id = <145 11 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
@@ -329,3 +331,10 @@
mpp@a700 { /* MPP 8 */
};
};
+
+&slim_msm {
+ tapan_codec {
+ qcom,cdc-micbias1-ext-cap;
+ };
+
+};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 70731d2..6aeaf49 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -26,27 +26,41 @@
/* CPR controlled regulator */
-/ {
+&soc {
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
- reg = <0xf9018000 0x1000>,
- <0xfc4b80b0 8>;
- reg-names = "rbcpr", "efuse_phys";
+ reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
+ reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+ interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <4>;
+ regulator-max-microvolt = <3>;
qcom,num-efuse-bits = <5>;
- qcom,efuse-bit-pos = <6 7 8 9 10>;
- qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
- qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
- qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000 1200000>;
- qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000 1140000>;
+ qcom,pvs-corner-ceiling-slow = <1155000 1160000 1275000>;
+ qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000>;
vdd-apc-supply = <&pm8226_s2>;
+
vdd-mx-supply = <&pm8226_l3_ao>;
qcom,vdd-mx-vmax = <1350000>;
qcom,vdd-mx-vmin-method = <1>;
+
+ qcom,cpr-ref-clk = <19200>;
+ qcom,cpr-timer-delay = <5000>;
+ qcom,cpr-timer-cons-up = <1>;
+ qcom,cpr-timer-cons-down = <2>;
+ qcom,cpr-irq-line = <0>;
+ qcom,cpr-step-quotient = <15>;
+ qcom,cpr-up-threshold = <1>;
+ qcom,cpr-down-threshold = <2>;
+ qcom,cpr-idle-clocks = <5>;
+ qcom,cpr-gcnt-time = <1>;
+ qcom,vdd-apc-step-up-limit = <1>;
+ qcom,vdd-apc-step-down-limit = <1>;
+ qcom,cpr-apc-volt-step = <5000>;
};
};
@@ -67,7 +81,7 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
- qcom,consumer-supplies = "vdd_dig", "", "vdd_sr2_dig", "";
+ qcom,consumer-supplies = "vdd_dig", "";
};
pm8226_s1_corner_ao: regulator-s1-corner-ao {
compatible = "qcom,rpm-regulator-smd";
@@ -76,6 +90,7 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
+ qcom,consumer-supplies = "vdd_sr2_dig", "";
};
};
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 00c0e2e..3cca8b0 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -18,7 +18,9 @@
model = "Qualcomm MSM 8226 Simulator";
compatible = "qcom,msm8226-sim", "qcom,msm8226", "qcom,sim";
qcom,msm-id = <145 16 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-smp2p.dtsi b/arch/arm/boot/dts/msm8226-smp2p.dtsi
index 079e4ca..3921a68 100644
--- a/arch/arm/boot/dts/msm8226-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8226-smp2p.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,smp2p-modem {
compatible = "qcom,smp2p";
reg = <0xf9011008 0x4>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 5dedd93..b2933db 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -11,6 +11,35 @@
*/
/include/ "skeleton.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8226";
+ compatible = "qcom,msm8226";
+ interrupt-parent = <&intc>;
+
+ aliases {
+ spi0 = &spi_0;
+ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
+ sdhc2 = &sdhc_2; /* SDC2 SD card slot */
+ };
+
+ memory {
+ secure_mem: secure_region {
+ linux,contiguous-region;
+ reg = <0 0x3800000>;
+ label = "secure_mem";
+ };
+
+ qsecom_mem: qsecom_region {
+ linux,contiguous-region;
+ reg = <0 0x780000>;
+ label = "qsecom_mem";
+ };
+ };
+
+ soc: soc { };
+};
+
/include/ "msm8226-ion.dtsi"
/include/ "msm8226-camera.dtsi"
/include/ "msm-gdsc.dtsi"
@@ -22,10 +51,11 @@
/include/ "msm8226-mdss.dtsi"
/include/ "msm8226-coresight.dtsi"
/include/ "msm8226-iommu-domains.dtsi"
-/ {
- model = "Qualcomm MSM 8226";
- compatible = "qcom,msm8226";
- interrupt-parent = <&intc>;
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
intc: interrupt-controller@f9000000 {
compatible = "qcom,msm-qgic2";
@@ -47,18 +77,10 @@
qcom,direct-connect-irqs = <8>;
};
- aliases {
- spi0 = &spi_0;
- sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
- sdhc2 = &sdhc_2; /* SDC2 SD card slot */
- };
-
- memory {
- secure_mem: secure_region {
- linux,contiguous-region;
- reg = <0 0x3800000>;
- label = "secure_mem";
- };
+ qcom,mpm2-sleep-counter@fc4a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0xfc4a3000 0x1000>;
+ clock-frequency = <32768>;
};
timer {
@@ -248,6 +270,7 @@
android_usb@fe8050c8 {
compatible = "qcom,android-usb";
reg = <0xfe8050c8 0xc8>;
+ qcom,android-usb-cdrom;
};
wcd9xxx_intc: wcd9xxx-irq {
@@ -259,7 +282,7 @@
interrupt-names = "cdc-int";
};
- slim@fe12f000 {
+ slim_msm: slim@fe12f000 {
cell-index = <1>;
compatible = "qcom,slim-ngd";
reg = <0xfe12f000 0x35000>,
@@ -545,7 +568,7 @@
qcom,smem@fa00000 {
compatible = "qcom,smem";
- reg = <0xfa00000 0x200000>,
+ reg = <0xfa00000 0x100000>,
<0xf9011000 0x1000>,
<0xfc428000 0x4000>;
reg-names = "smem", "irq-reg-base", "aux-mem1";
@@ -706,7 +729,7 @@
reg = <0xf9927000 0x1000>;
interrupt-names = "qup_err_intr";
interrupts = <0 99 0>;
- qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-bus-freq = <384000>;
qcom,i2c-src-freq = <19200000>;
};
@@ -715,7 +738,6 @@
reg = <0xf9011050 0x8>;
reg-names = "rcg_base";
a7_cpu-supply = <&apc_vreg_corner>;
- a7_mem-supply = <&pm8226_l3>;
};
qcom,ocmem@fdd00000 {
@@ -764,6 +786,7 @@
/* GPIO inputs from wcnss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
/* GPIO output to wcnss */
@@ -788,6 +811,7 @@
/* GPIO inputs from lpass */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>;
/* GPIO output to lpass */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
@@ -804,7 +828,6 @@
"restart_reg", "cxrail_bhs_reg";
interrupts = <0 24 1>;
- vdd_mss-supply = <&pm8226_s1>;
vdd_cx-supply = <&pm8226_s1_corner>;
vdd_mx-supply = <&pm8226_l3>;
vdd_pll-supply = <&pm8226_l8>;
@@ -816,6 +839,7 @@
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
@@ -983,22 +1007,27 @@
};
&gdsc_venus {
+ qcom,clock-names = "core_clk";
status = "ok";
};
&gdsc_mdss {
+ qcom,clock-names = "core_clk", "lut_clk";
status = "ok";
};
&gdsc_jpeg {
+ qcom,clock-names = "core_clk";
status = "ok";
};
&gdsc_vfe {
+ qcom,clock-names = "core_clk", "csi_clk", "cpp_clk";
status = "ok";
};
&gdsc_oxili_cx {
+ qcom,clock-names = "core_clk";
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index 50066f3..2e7ba25 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
msm-mmss-noc@fc478000 {
compatible = "msm-bus-fabric";
reg = <0xfc478000 0x00004000>;
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 9b114cc..d3fc917 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -13,26 +13,193 @@
/dts-v1/;
/include/ "msm8610.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
/ {
model = "Qualcomm MSM 8610 CDP";
compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
qcom,msm-id = <147 1 0>, <165 1 0>, <161 1 0>, <162 1 0>,
<163 1 0>, <164 1 0>, <166 1 0>;
+};
+&soc {
serial@f991e000 {
status = "ok";
};
+
+ i2c@f9923000{
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <1 0x2>;
+ vdd_ana-supply = <&pm8110_l19>;
+ vcc_i2c-supply = <&pm8110_l14>;
+ atmel,reset-gpio = <&msmgpio 0 0x00>;
+ atmel,irq-gpio = <&msmgpio 1 0x00>;
+ atmel,panel-coords = <0 0 508 880>;
+ atmel,display-coords = <0 0 480 800>;
+ atmel,i2c-pull-up;
+ atmel,no-force-update;
+ atmel,cfg_1 {
+ atmel,family-id = <0x81>;
+ atmel,variant-id = <0x15>;
+ atmel,version = <0x11>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 6, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 38, Instance = 0 */
+ 1D 01 00 0C 04 0D 00 00
+ /* Object 7, Instance = 0 */
+ 20 08 32
+ /* Object 8, Instance = 0 */
+ 19 00 14 14 FF 00 FF 00 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 13 0B 00 20 32 01 03
+ 00 32 05 30 0A 05 0A 00 70 03
+ FC 01 00 36 2F 2C 00 00 40 00
+ 00 0A 00 00 02
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 03 00 18 79 A8 61
+ /* Object 58, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 04 03 08 10 00 00 00 00 00
+ /* Object 47, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 48, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00
+ /* Object 55, Instance = 0 */
+ 00 00 00 00
+ ];
+ };
+ };
+ };
+
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "atmel_mxt_ts";
+ qcom,disp-maxx = <480>;
+ qcom,disp-maxy = <800>;
+ qcom,panel-maxx = <508>;
+ qcom,panel-maxy = <880>;
+ qcom,key-codes = <158 102 139>;
+ qcom,y-offset = <35>;
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&msmgpio 73 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&msmgpio 74 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&msmgpio 72 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+};
+
+&i2c_cdc {
+ msm8x10_wcd_codec@0d{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x0d>;
+ cdc-vdda-cp-supply = <&pm8110_s4>;
+ qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+ qcom,cdc-vdda-cp-current = <650000>;
+
+ cdc-vdda-h-supply = <&pm8110_l6>;
+ qcom,cdc-vdda-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdda-h-current = <250000>;
+
+ cdc-vdd-px-supply = <&pm8110_l6>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+
+ cdc-vdd-1p2v-supply = <&pm8110_l4>;
+ qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
+ qcom,cdc-vdd-1p2v-current = <5000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8110_l20>;
+ qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+ qcom,cdc-vdd-mic-bias-current = <25000>;
+
+ qcom,cdc-micbias-cfilt-sel = <0x0>;
+ qcom,cdc-micbias-cfilt-mv = <1800000>;
+ qcom,cdc-mclk-clk-rate = <12288000>;
+ };
+
+ msm8x10_wcd_codec@77{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x77>;
+ };
+
+ msm8x10_wcd_codec@66{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x66>;
+ };
+
+ msm8x10_wcd_codec@55{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x55>;
+ };
};
&spmi_bus {
qcom,pm8110@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux-default-trigger = "hr-trigger";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,id = <6>;
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
qcom,leds@a200 {
status = "okay";
qcom,led_mpp_3 {
label = "mpp";
linux,name = "wled-backlight";
- linux-default-trigger = "none";
+ linux,default-trigger = "bkl-trigger";
qcom,default-state = "on";
qcom,max-current = <40>;
qcom,id = <6>;
@@ -43,6 +210,16 @@
};
};
+&spmi_bus {
+ qcom,pm8110@1 {
+ qcom,vibrator@c000 {
+ status = "okay";
+ qcom,vib-timeout-ms = <15000>;
+ qcom,vib-vtg-level-mV = <3100>;
+ };
+ };
+};
+
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
qcom,vdd-always-on;
@@ -120,3 +297,82 @@
status = "ok";
};
};
+
+&pm8110_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+};
+
+&pm8110_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ status = "disabled";
+ };
+
+ mpp@a200 { /* MPP 3 */
+ status = "disabled";
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+};
+
+/* CoreSight */
+&tpiu {
+ qcom,seta-gpios = <&msmgpio 4 0>,
+ <&msmgpio 5 0>,
+ <&msmgpio 6 0>,
+ <&msmgpio 7 0>,
+ <&msmgpio 22 0>,
+ <&msmgpio 23 0>,
+ <&msmgpio 24 0>,
+ <&msmgpio 25 0>,
+ <&msmgpio 26 0>,
+ <&msmgpio 27 0>,
+ <&msmgpio 28 0>,
+ <&msmgpio 29 0>,
+ <&msmgpio 30 0>,
+ <&msmgpio 31 0>,
+ <&msmgpio 94 0>,
+ <&msmgpio 95 0>,
+ <&msmgpio 96 0>,
+ <&msmgpio 97 0>;
+ qcom,seta-gpios-func = <9 9 8 11 2 2 2 2 2 2 3 2 3 3 4 4 4 4>;
+ qcom,seta-gpios-drv = <7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7>;
+ qcom,seta-gpios-pull = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+ qcom,seta-gpios-dir = <2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2>;
+
+ qcom,setb-gpios = <&msmgpio 8 0>,
+ <&msmgpio 10 0>,
+ <&msmgpio 11 0>,
+ <&msmgpio 13 0>,
+ <&msmgpio 14 0>,
+ <&msmgpio 15 0>,
+ <&msmgpio 16 0>,
+ <&msmgpio 17 0>,
+ <&msmgpio 18 0>,
+ <&msmgpio 19 0>,
+ <&msmgpio 20 0>,
+ <&msmgpio 21 0>,
+ <&msmgpio 42 0>,
+ <&msmgpio 80 0>,
+ <&msmgpio 81 0>,
+ <&msmgpio 82 0>,
+ <&msmgpio 83 0>,
+ <&msmgpio 84 0>;
+ qcom,setb-gpios-func = <10 8 8 6 9 9 9 9 9 9 9 9 5 7 7 8 8 8>;
+ qcom,setb-gpios-drv = <7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7>;
+ qcom,setb-gpios-pull = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+ qcom,setb-gpios-dir = <2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2>;
+};
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index a0a2c14..0d9ae9a 100644
--- a/arch/arm/boot/dts/msm8610-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
tmc_etr: tmc@fc326000 {
compatible = "arm,coresight-tmc";
reg = <0xfc326000 0x1000>,
@@ -34,6 +34,11 @@
coresight-id = <1>;
coresight-name = "coresight-tpiu";
coresight-nr-inports = <1>;
+
+ vdd-supply = <&pm8110_l18>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 400000>;
};
replicator: replicator@fc324000 {
diff --git a/arch/arm/boot/dts/msm8610-gpu.dtsi b/arch/arm/boot/dts/msm8610-gpu.dtsi
index 5580f73..d1b30ee 100644
--- a/arch/arm/boot/dts/msm8610-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8610-gpu.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
msm_gpu: qcom,kgsl-3d0@fdc00000 {
label = "kgsl-3d0";
compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
diff --git a/arch/arm/boot/dts/msm8610-iommu-domains.dtsi b/arch/arm/boot/dts/msm8610-iommu-domains.dtsi
index 0f48517..6f43897 100644
--- a/arch/arm/boot/dts/msm8610-iommu-domains.dtsi
+++ b/arch/arm/boot/dts/msm8610-iommu-domains.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,iommu-domains {
compatible = "qcom,iommu-domains";
diff --git a/arch/arm/boot/dts/msm8610-ion.dtsi b/arch/arm/boot/dts/msm8610-ion.dtsi
index 41b58da..456b60c 100644
--- a/arch/arm/boot/dts/msm8610-ion.dtsi
+++ b/arch/arm/boot/dts/msm8610-ion.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,ion {
compatible = "qcom,msm-ion";
#address-cells = <1>;
@@ -31,9 +31,7 @@
qcom,ion-heap@27 { /* QSECOM HEAP */
compatible = "qcom,msm-ion-reserve";
reg = <27>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x100000>;
+ linux,contiguous-region = <&qsecom_mem>;
};
};
};
diff --git a/arch/arm/boot/dts/msm8610-mdss.dtsi b/arch/arm/boot/dts/msm8610-mdss.dtsi
new file mode 100644
index 0000000..1766422
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-mdss.dtsi
@@ -0,0 +1,37 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ qcom,mdss_mdp@fd900000 {
+ compatible = "qcom,mdss_mdp3";
+ reg = <0xfd900000 0x100000>;
+ reg-names = "mdp_phys";
+ interrupts = <0 72 0>;
+
+ mdss_fb0: qcom,mdss_fb_primary {
+ cell-index = <0>;
+ compatible = "qcom,mdss-fb";
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x800000>;
+ };
+ };
+
+ mdss_dsi0: qcom,mdss_dsi@fdd00000 {
+ compatible = "qcom,msm-dsi-v2";
+ label = "MDSS DSI CTRL->0";
+ cell-index = <0>;
+ reg = <0xfdd00000 0x100000>;
+ interrupts = <0 30 0>;
+ vdda-supply = <&pm8110_l4>;
+ qcom,mdss-fb-map = <&mdss_fb0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index 3a26376..e1fe66a 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -13,26 +13,193 @@
/dts-v1/;
/include/ "msm8610.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
/ {
model = "Qualcomm MSM 8610 MTP";
compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
qcom,msm-id = <147 8 0>, <165 8 0>, <161 8 0>, <162 8 0>,
<163 8 0>, <164 8 0>, <166 8 0>;
+};
+&soc {
serial@f991e000 {
status = "ok";
};
+
+ i2c@f9923000{
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <1 0x2>;
+ vdd_ana-supply = <&pm8110_l19>;
+ vcc_i2c-supply = <&pm8110_l14>;
+ atmel,reset-gpio = <&msmgpio 0 0x00>;
+ atmel,irq-gpio = <&msmgpio 1 0x00>;
+ atmel,panel-coords = <0 0 508 880>;
+ atmel,display-coords = <0 0 480 800>;
+ atmel,i2c-pull-up;
+ atmel,no-force-update;
+ atmel,cfg_1 {
+ atmel,family-id = <0x81>;
+ atmel,variant-id = <0x15>;
+ atmel,version = <0x11>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 6, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 38, Instance = 0 */
+ 1D 01 00 0C 04 0D 00 00
+ /* Object 7, Instance = 0 */
+ 20 08 32
+ /* Object 8, Instance = 0 */
+ 19 00 14 14 FF 00 FF 00 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 13 0B 00 20 32 01 03
+ 00 32 05 30 0A 05 0A 00 70 03
+ FC 01 00 36 2F 2C 00 00 40 00
+ 00 0A 00 00 02
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 03 00 18 79 A8 61
+ /* Object 58, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 04 03 08 10 00 00 00 00 00
+ /* Object 47, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 48, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00
+ /* Object 55, Instance = 0 */
+ 00 00 00 00
+ ];
+ };
+ };
+ };
+
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "atmel_mxt_ts";
+ qcom,disp-maxx = <480>;
+ qcom,disp-maxy = <800>;
+ qcom,panel-maxx = <508>;
+ qcom,panel-maxy = <880>;
+ qcom,key-codes = <158 102 139>;
+ qcom,y-offset = <35>;
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&msmgpio 73 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&msmgpio 74 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&msmgpio 72 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+};
+
+&i2c_cdc {
+ msm8x10_wcd_codec@0d{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x0d>;
+ cdc-vdda-cp-supply = <&pm8110_s4>;
+ qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+ qcom,cdc-vdda-cp-current = <650000>;
+
+ cdc-vdda-h-supply = <&pm8110_l6>;
+ qcom,cdc-vdda-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdda-h-current = <250000>;
+
+ cdc-vdd-px-supply = <&pm8110_l6>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+
+ cdc-vdd-1p2v-supply = <&pm8110_l4>;
+ qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
+ qcom,cdc-vdd-1p2v-current = <5000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8110_l20>;
+ qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+ qcom,cdc-vdd-mic-bias-current = <25000>;
+
+ qcom,cdc-micbias-cfilt-sel = <0x0>;
+ qcom,cdc-micbias-cfilt-mv = <1800000>;
+ qcom,cdc-mclk-clk-rate = <12288000>;
+ };
+
+ msm8x10_wcd_codec@77{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x77>;
+ };
+
+ msm8x10_wcd_codec@66{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x66>;
+ };
+
+ msm8x10_wcd_codec@55{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x55>;
+ };
};
&spmi_bus {
qcom,pm8110@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux-default-trigger = "hr-trigger";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,id = <6>;
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
qcom,leds@a200 {
status = "okay";
qcom,led_mpp_3 {
label = "mpp";
linux,name = "wled-backlight";
- linux-default-trigger = "none";
+ linux,default-trigger = "bkl-trigger";
qcom,default-state = "on";
qcom,max-current = <40>;
qcom,id = <6>;
@@ -43,6 +210,16 @@
};
};
+&spmi_bus {
+ qcom,pm8110@1 {
+ qcom,vibrator@c000 {
+ status = "okay";
+ qcom,vib-timeout-ms = <15000>;
+ qcom,vib-vtg-level-mV = <3100>;
+ };
+ };
+};
+
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
qcom,vdd-always-on;
@@ -123,3 +300,37 @@
status = "ok";
};
};
+
+&pm8110_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+};
+
+&pm8110_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ status = "disabled";
+ };
+
+ mpp@a200 { /* MPP 3 */
+ status = "disabled";
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+};
+
+&pm8110_bms {
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index e8849f6..938b2aa 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -12,7 +12,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
qcom,spm@f9089000 {
compatible = "qcom,spm-v2";
#address-cells = <1>;
@@ -114,7 +114,7 @@
qcom,type = <0x61706d73>; /* "smpa" */
qcom,id = <0x01>;
qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <5>; /* Super Turbo */
+ qcom,init-value = <3>; /* SVS SOC */
};
qcom,lpm-resources@1 {
@@ -123,7 +123,7 @@
qcom,type = <0x616F646C>; /* "ldoa" */
qcom,id = <0x03>;
qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <3>; /* Active */
+ qcom,init-value = <3>; /* SVS SOC */
};
qcom,lpm-resources@2 {
@@ -153,10 +153,10 @@
qcom,mode = "wfi";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <1>;
@@ -170,10 +170,10 @@
qcom,mode = "standalone_pc";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <3000>;
@@ -187,10 +187,10 @@
qcom,mode = "pc";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_retention";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <8000>;
@@ -204,10 +204,10 @@
qcom,mode = "pc";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <2>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <3>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <2>; /* SVS SOC */
+ qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <9000>;
@@ -221,10 +221,10 @@
qcom,mode = "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,latency-us = <16300>;
qcom,ss-power = <63>;
qcom,energy-overhead = <2128000>;
@@ -236,10 +236,10 @@
qcom,mode = "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <2>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <3>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <2>; /* SVS SOC */
+ qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
qcom,latency-us = <24000>;
qcom,ss-power = <10>;
qcom,energy-overhead = <3202600>;
@@ -251,10 +251,10 @@
qcom,mode = "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <2>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <0>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <2>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <0>; /* RETENTION */
+ qcom,vdd-mem-upper-bound = <3>; /* SVS SOC */
+ qcom,vdd-mem-lower-bound = <1>; /* RETENTION */
+ qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
qcom,latency-us = <26000>;
qcom,ss-power = <2>;
qcom,energy-overhead = <4252000>;
@@ -382,9 +382,9 @@
qcom,offset-page-indices = <56>;
};
- qcom,rpm-stats@0xfc19dbd0{
+ qcom,rpm-stats@fc19dba0 {
compatible = "qcom,rpm-stats";
- reg = <0xfc19dbd0 0x1000>;
+ reg = <0xfc19dba0 0x1000>;
reg-names = "phys_addr_base";
qcom,sleep-stats-version = <2>;
};
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 67eee5c..a90f053 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -26,24 +26,41 @@
/* CPR controlled regulator */
-/ {
+&soc {
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
- reg = <0xf9018000 0x1000>,
- <0xfc4b80b0 8>;
- reg-names = "rbcpr", "efuse_phys";
+ reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
+ reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+ interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <4>;
+ regulator-max-microvolt = <3>;
qcom,num-efuse-bits = <5>;
- qcom,efuse-bit-pos = <6 7 8 9 10>;
- qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
- qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
- qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000 1200000>;
- qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000 1140000>;
+ qcom,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
+ qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000>;
vdd-apc-supply = <&pm8110_s2>;
+
+ vdd-mx-supply = <&pm8110_l3_ao>;
+ qcom,vdd-mx-vmax = <1350000>;
+ qcom,vdd-mx-vmin-method = <1>;
+
+ qcom,cpr-ref-clk = <19200>;
+ qcom,cpr-timer-delay = <5000>;
+ qcom,cpr-timer-cons-up = <1>;
+ qcom,cpr-timer-cons-down = <2>;
+ qcom,cpr-irq-line = <0>;
+ qcom,cpr-step-quotient = <15>;
+ qcom,cpr-up-threshold = <1>;
+ qcom,cpr-down-threshold = <2>;
+ qcom,cpr-idle-clocks = <5>;
+ qcom,cpr-gcnt-time = <1>;
+ qcom,vdd-apc-step-up-limit = <1>;
+ qcom,vdd-apc-step-down-limit = <1>;
+ qcom,cpr-apc-volt-step = <5000>;
};
};
@@ -66,7 +83,7 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
- qcom,consumer-supplies = "vdd_dig", "", "vdd_sr2_dig", "";
+ qcom,consumer-supplies = "vdd_dig", "";
};
pm8110_s1_corner_ao: regulator-s1-corner-ao {
@@ -76,6 +93,7 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
+ qcom,consumer-supplies = "vdd_sr2_dig", "";
};
};
diff --git a/arch/arm/boot/dts/msm8610-rumi.dts b/arch/arm/boot/dts/msm8610-rumi.dts
index cab7560..7f06485 100644
--- a/arch/arm/boot/dts/msm8610-rumi.dts
+++ b/arch/arm/boot/dts/msm8610-rumi.dts
@@ -18,7 +18,9 @@
model = "Qualcomm MSM 8610 Rumi";
compatible = "qcom,msm8610-rumi", "qcom,msm8610", "qcom,rumi";
qcom,msm-id = <147 15 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8610-sim.dts b/arch/arm/boot/dts/msm8610-sim.dts
index 1838b94..7c57fe6 100644
--- a/arch/arm/boot/dts/msm8610-sim.dts
+++ b/arch/arm/boot/dts/msm8610-sim.dts
@@ -18,8 +18,55 @@
model = "Qualcomm MSM 8610 Simulator";
compatible = "qcom,msm8610-sim", "qcom,msm8610", "qcom,sim";
qcom,msm-id = <147 16 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
};
+
+&i2c_cdc {
+ msm8x10_wcd_codec@0d{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x0d>;
+ cdc-vdda-cp-supply = <&pm8110_s4>;
+ qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+ qcom,cdc-vdda-cp-current = <650000>;
+
+ cdc-vdda-h-supply = <&pm8110_l6>;
+ qcom,cdc-vdda-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdda-h-current = <250000>;
+
+ cdc-vdd-px-supply = <&pm8110_l6>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+
+ cdc-vdd-1p2v-supply = <&pm8110_l4>;
+ qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
+ qcom,cdc-vdd-1p2v-current = <5000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8110_l20>;
+ qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+ qcom,cdc-vdd-mic-bias-current = <25000>;
+
+ qcom,cdc-micbias-cfilt-sel = <0x0>;
+ qcom,cdc-micbias-cfilt-mv = <1800000>;
+ qcom,cdc-mclk-clk-rate = <12288000>;
+ };
+
+ msm8x10_wcd_codec@77{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x77>;
+ };
+
+ msm8x10_wcd_codec@66{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x66>;
+ };
+
+ msm8x10_wcd_codec@55{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x55>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-smp2p.dtsi b/arch/arm/boot/dts/msm8610-smp2p.dtsi
index 079e4ca..3921a68 100644
--- a/arch/arm/boot/dts/msm8610-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8610-smp2p.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,smp2p-modem {
compatible = "qcom,smp2p";
reg = <0xf9011008 0x4>;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index e406ba8..9dbd71d 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -11,6 +11,28 @@
*/
/include/ "skeleton.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610";
+ compatible = "qcom,msm8610";
+ interrupt-parent = <&intc>;
+
+ memory {
+ qsecom_mem: qsecom_region {
+ linux,contiguous-region;
+ reg = <0 0x100000>;
+ label = "qsecom_mem";
+ };
+ };
+
+ aliases {
+ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
+ sdhc2 = &sdhc_2; /* SDC2 SD card slot */
+ };
+
+ soc: soc { };
+};
+
/include/ "msm-iommu-v0.dtsi"
/include/ "msm8610-ion.dtsi"
/include/ "msm8610-gpu.dtsi"
@@ -19,11 +41,12 @@
/include/ "msm8610-pm.dtsi"
/include/ "msm8610-smp2p.dtsi"
/include/ "msm8610-bus.dtsi"
+/include/ "msm8610-mdss.dtsi"
-/ {
- model = "Qualcomm MSM 8610";
- compatible = "qcom,msm8610";
- interrupt-parent = <&intc>;
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
intc: interrupt-controller@f9000000 {
compatible = "qcom,msm-qgic2";
@@ -45,10 +68,10 @@
qcom,direct-connect-irqs = <8>;
};
- aliases {
- spi0 = &spi_0;
- sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
- sdhc2 = &sdhc_2; /* SDC2 SD card slot */
+ qcom,mpm2-sleep-counter@fc4a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0xfc4a3000 0x1000>;
+ clock-frequency = <32768>;
};
timer {
@@ -121,6 +144,11 @@
qcom,adsp-state = <0>;
};
+ qcom,msm-audio-ion {
+ compatible = "qcom,msm-audio-ion";
+ qcom,smmu-enabled;
+ };
+
qcom,msm-imem@fe805000 {
compatible = "qcom,msm-imem";
reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
@@ -148,7 +176,7 @@
qcom,buffer-type-tz-usage-map = <0x1 0x1>,
<0x1fe 0x2>;
qcom,hfi = "q6";
- qcom,max-hw-load = <97200>; /* FWVGA @ 30 * 2 */
+ qcom,max-hw-load = <108000>; /* 720p @ 30 * 1 */
};
qcom,usbbam@f9a44000 {
@@ -309,7 +337,7 @@
qcom,smem@d900000 {
compatible = "qcom,smem";
- reg = <0xd900000 0x200000>,
+ reg = <0xd900000 0x100000>,
<0xf9011000 0x1000>,
<0xfc428000 0x4000>;
reg-names = "smem", "irq-reg-base", "aux-mem1";
@@ -401,7 +429,6 @@
reg = <0xf9011050 0x8>;
reg-names = "rcg_base";
a7_cpu-supply = <&apc_vreg_corner>;
- a7_mem-supply = <&pm8110_l3_ao>;
};
spmi_bus: qcom,spmi@fc4c0000 {
@@ -418,6 +445,48 @@
qcom,pmic-arb-channel = <0>;
};
+ i2c@f9923000 { /* BLSP-1 QUP-1 */
+ cell-index = <1>;
+ compatible = "qcom,i2c-qup";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0xf9923000 0x1000>;
+ interrupt-names = "qup_err_intr";
+ interrupts = <0 95 0>;
+ qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <19200000>;
+ qcom,sda-gpio = <&msmgpio 2 0>;
+ qcom,scl-gpio = <&msmgpio 3 0>;
+ };
+
+ i2c_cdc: i2c@f9927000 { /* BLSP1 QUP5 */
+ cell-index = <5>;
+ compatible = "qcom,i2c-qup";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0xf9927000 0x1000>;
+ interrupt-names = "qup_err_intr";
+ interrupts = <0 99 0>;
+ qcom,i2c-bus-freq = <100000>;
+ };
+
+ i2c@f9928000 { /* BLSP1 QUP6 */
+ cell-index = <6>;
+ compatible = "qcom,i2c-qup";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0xf9928000 0x1000>;
+ interrupt-names = "qup_err_intr";
+ interrupts = <0 100 0>;
+ qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <19200000>;
+ qcom,sda-gpio = <&msmgpio 16 0>;
+ qcom,scl-gpio = <&msmgpio 17 0>;
+ };
+
i2c@f9925000 { /* BLSP-1 QUP-3 */
cell-index = <0>;
compatible = "qcom,i2c-qup";
@@ -430,30 +499,6 @@
qcom,i2c-bus-freq = <100000>;
};
-
- spi_0: spi@f9923000 { /* BLSP1 QUP1 */
- compatible = "qcom,spi-qup-v2";
- #address-cells = <1>;
- #size-cells = <0>;
- reg-names = "spi_physical", "spi_bam_physical";
- reg = <0xf9923000 0x1000>,
- <0xf9904000 0xF000>;
- interrupt-names = "spi_irq", "spi_bam_irq";
- interrupts = <0 95 0>, <0 238 0>;
- spi-max-frequency = <19200000>;
-
- gpios = <&msmgpio 3 0>, /* CLK */
- <&msmgpio 1 0>, /* MISO */
- <&msmgpio 0 0>; /* MOSI */
- cs-gpios = <&msmgpio 2 0>;
-
- qcom,infinite-mode = <0>;
- qcom,use-bam;
- qcom,ver-reg-exists;
- qcom,bam-consumer-pipe-index = <12>;
- qcom,bam-producer-pipe-index = <13>;
- };
-
qcom,pronto@fb21b000 {
compatible = "qcom,pil-pronto";
reg = <0xfb21b000 0x3000>,
@@ -467,6 +512,7 @@
/* GPIO inputs from wcnss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
/* GPIO output to wcnss */
@@ -484,6 +530,13 @@
qcom,msm-pcm {
compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
};
qcom,msm-pcm-routing {
@@ -523,15 +576,15 @@
qcom,msm-dai-q6-mi2s-prim {
compatible = "qcom,msm-dai-q6-mi2s";
qcom,msm-dai-q6-mi2s-dev-id = <0>;
- qcom,msm-mi2s-rx-lines = <1>;
- qcom,msm-mi2s-tx-lines = <0>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
};
qcom,msm-dai-q6-mi2s-sec {
compatible = "qcom,msm-dai-q6-mi2s";
qcom,msm-dai-q6-mi2s-dev-id = <1>;
- qcom,msm-mi2s-rx-lines = <0>;
- qcom,msm-mi2s-tx-lines = <3>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
};
};
@@ -576,6 +629,21 @@
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <240>;
};
+
+ qcom,msm-dai-q6-incall-record-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32771>;
+ };
+
+ qcom,msm-dai-q6-incall-record-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32772>;
+ };
+
+ qcom,msm-dai-q6-incall-music-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32773>;
+ };
};
qcom,msm-pcm-hostless {
@@ -584,8 +652,9 @@
qcom,wcnss-wlan@fb000000 {
compatible = "qcom,wcnss_wlan";
- reg = <0xfb000000 0x280000>;
- reg-names = "wcnss_mmio";
+ reg = <0xfb000000 0x280000>,
+ <0xf9011008 0x04>;
+ reg-names = "wcnss_mmio", "wcnss_fiq";
interrupts = <0 145 0>, <0 146 0>;
interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
@@ -612,7 +681,6 @@
"restart_reg", "cxrail_bhs_reg";
interrupts = <0 24 1>;
- vdd_mss-supply = <&pm8110_s1>;
vdd_cx-supply = <&pm8110_s1_corner>;
vdd_mx-supply = <&pm8110_l3>;
vdd_pll-supply = <&pm8110_l10>;
@@ -623,6 +691,7 @@
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
@@ -642,6 +711,7 @@
/* GPIO inputs from lpass */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>;
/* GPIO output to lpass */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
@@ -656,14 +726,12 @@
qcom,sensors = <2>;
qcom,slope = <2901 2846>;
qcom,calib-mode = "fuse_map3";
- qcom,calibration-less-mode;
- qcom,tsens-local-init;
qcom,sensor-id = <0 5>;
};
qcom,msm-thermal {
compatible = "qcom,msm-thermal";
- qcom,sensor-id = <0>;
+ qcom,sensor-id = <5>;
qcom,poll-ms = <250>;
qcom,limit-temp = <60>;
qcom,temp-hysteresis = <10>;
@@ -706,6 +774,12 @@
qcom,msm-rng-iface-clk;
};
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+ };
+
jtag_mm0: jtagmm@fc34c000 {
compatible = "qcom,jtag-mm";
reg = <0xfc34c000 0x1000>,
@@ -794,7 +868,7 @@
label = "vchg_sns";
reg = <2>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <3>;
+ qcom,pre-div-channel-scaling = <2>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
diff --git a/arch/arm/boot/dts/msm8974-bus.dtsi b/arch/arm/boot/dts/msm8974-bus.dtsi
index 3e0ef04..bfe955e 100644
--- a/arch/arm/boot/dts/msm8974-bus.dtsi
+++ b/arch/arm/boot/dts/msm8974-bus.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
msm-mmss-noc@fc478000 {
compatible = "msm-bus-fabric";
reg = <0xfc478000 0x00004000>;
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 94a28f7..786e9e3 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -13,7 +13,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
qcom,msm-cam@fd8C0000 {
compatible = "qcom,msm-cam";
reg = <0xfd8C0000 0x10000>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 3c1711c..5fa7c08 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -15,7 +15,7 @@
/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor-cdp.dtsi"
-/ {
+&soc {
serial@f991e000 {
status = "ok";
};
@@ -195,6 +195,7 @@
qcom,model = "msm8974-taiko-cdp-snd-card";
qcom,hdmi-audio-rx;
qcom,us-euro-gpios = <&pm8941_gpios 20 0>;
+ qcom,cdc-micbias2-headset-only;
};
usb2_otg_sw: regulator-tpd4s214 {
@@ -499,7 +500,7 @@
qcom,output-type = <0>;
qcom,pull = <5>;
qcom,vin-sel = <2>;
- qcom,out-strength = <3>;
+ qcom,out-strength = <1>;
qcom,src-sel = <2>;
qcom,master-en = <1>;
};
@@ -710,5 +711,12 @@
qcom,cdc-micbias1-ext-cap;
qcom,cdc-micbias3-ext-cap;
qcom,cdc-micbias4-ext-cap;
+
+ /* If boot isn't available, vph_pwr_vreg can be used instead */
+ cdc-vdd-spkdrv-supply = <&pm8941_boost>;
+ qcom,cdc-vdd-spkdrv-voltage = <5000000 5000000>;
+ qcom,cdc-vdd-spkdrv-current = <1250000>;
+
+ qcom,cdc-on-demand-supplies = "cdc-vdd-spkdrv";
};
};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index c064b59..1610f1f 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
tmc_etr: tmc@fc322000 {
compatible = "arm,coresight-tmc";
reg = <0xfc322000 0x1000>,
@@ -364,4 +364,18 @@
coresight-name = "coresight-cti-cpu3";
coresight-nr-inports = <0>;
};
+
+ hwevent: hwevent@fdf30018 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0xfdf30018 0x80>,
+ <0xf9011080 0x80>,
+ <0xfd4ab160 0x80>;
+ reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+
+ coresight-id = <29>;
+ coresight-name = "coresight-hwevent";
+ coresight-nr-inports = <0>;
+
+ qcom,hwevent-clks = "core_mmss_clk";
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index eaf326e..ad5f175 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -14,7 +14,7 @@
/include/ "msm8974-camera-sensor-fluid.dtsi"
/include/ "msm8974-leds.dtsi"
-/ {
+&soc {
serial@f991e000 {
status = "ok";
};
@@ -202,7 +202,35 @@
sound {
qcom,model = "msm8974-taiko-fluid-snd-card";
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "AMIC1", "MIC BIAS1 Internal1",
+ "MIC BIAS1 Internal1", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
+ "DMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic1",
+ "DMIC2", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic2",
+ "DMIC3", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic3",
+ "DMIC4", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic4",
+ "DMIC5", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic5",
+ "DMIC6", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic6",
+ "Lineout_1 amp", "LINEOUT1",
+ "Lineout_3 amp", "LINEOUT3";
+
qcom,hdmi-audio-rx;
+ qcom,ext-ult-lo-amp-gpio = <&pm8941_gpios 6 0>;
+ qcom,cdc-micbias2-headset-only;
};
};
@@ -212,6 +240,13 @@
qcom,cdc-micbias2-ext-cap;
qcom,cdc-micbias3-ext-cap;
qcom,cdc-micbias4-ext-cap;
+
+ /* If boot isn't available, vph_pwr_vreg can be used instead */
+ cdc-vdd-spkdrv-supply = <&pm8941_boost>;
+ qcom,cdc-vdd-spkdrv-voltage = <5000000 5000000>;
+ qcom,cdc-vdd-spkdrv-current = <1250000>;
+
+ qcom,cdc-on-demand-supplies = "cdc-vdd-spkdrv";
};
};
@@ -471,7 +506,7 @@
qcom,output-type = <0>;
qcom,pull = <5>;
qcom,vin-sel = <2>;
- qcom,out-strength = <3>;
+ qcom,out-strength = <1>;
qcom,src-sel = <2>;
qcom,master-en = <1>;
};
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 3779dbd..669097e 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
msm_gpu: qcom,kgsl-3d0@fdb00000 {
label = "kgsl-3d0";
compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 31afd9c..ee8152d 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,ion {
compatible = "qcom,msm-ion";
#address-cells = <1>;
@@ -45,9 +45,7 @@
qcom,ion-heap@27 { /* QSECOM HEAP */
compatible = "qcom,msm-ion-reserve";
reg = <27>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x1100000>;
+ linux,contiguous-region = <&qsecom_mem>;
};
qcom,ion-heap@28 { /* AUDIO HEAP */
diff --git a/arch/arm/boot/dts/msm8974-leds.dtsi b/arch/arm/boot/dts/msm8974-leds.dtsi
index befd206..b39cc21 100644
--- a/arch/arm/boot/dts/msm8974-leds.dtsi
+++ b/arch/arm/boot/dts/msm8974-leds.dtsi
@@ -93,6 +93,20 @@
linux,name = "led:flash_1";
qcom,current = <625>;
};
+
+ pm8941_torch: qcom,flash_torch {
+ qcom,max-current = <200>;
+ qcom,default-state = "off";
+ qcom,headroom = <0>;
+ qcom,startup-dly = <1>;
+ linux,default-trigger =
+ "torch_trigger";
+ label = "flash";
+ qcom,id = <2>;
+ linux,name = "led:flash_torch";
+ qcom,current = <200>;
+ qcom,torch-enable;
+ };
};
qcom,leds@d400 {
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index d9acb81..e63b53b 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -13,7 +13,7 @@
/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor-liquid.dtsi"
-/ {
+&soc {
serial@f991e000 {
status = "ok";
};
@@ -318,6 +318,7 @@
"Lineout_3 amp", "LINEOUT3",
"Lineout_2 amp", "LINEOUT2",
"Lineout_4 amp", "LINEOUT4",
+ "SPK_ultrasound amp", "SPK_OUT",
"AMIC1", "MIC BIAS4 External",
"MIC BIAS4 External", "Analog Mic4",
"AMIC2", "MIC BIAS2 External",
@@ -346,6 +347,7 @@
qcom,ext-spk-amp-supply = <&ext_5v>;
qcom,ext-spk-amp-gpio = <&pm8841_mpps 1 0>;
qcom,dock-plug-det-irq = <&pm8841_mpps 2 0>;
+ qcom,ext-ult-spk-amp-gpio = <&pm8941_gpios 6 0>;
qcom,hdmi-audio-rx;
qcom,prim-auxpcm-gpio-clk = <&msmgpio 74 0>;
@@ -449,6 +451,14 @@
};
gpio@c500 { /* GPIO 6 */
+ /* ULTRASOUND_EN_1 PA AB enable */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,pull = <4>; /* PULL_DOWN */
+ qcom,vin-sel = <0>; /* VPH */
+ qcom,out-strength = <2>; /* STRENGTH_MED */
+ qcom,src-sel = <0>; /* CONSTANT */
+ qcom,master-en = <1>;
};
gpio@c600 { /* GPIO 7 */
@@ -501,7 +511,7 @@
qcom,output-type = <0>;
qcom,pull = <5>;
qcom,vin-sel = <2>;
- qcom,out-strength = <3>;
+ qcom,out-strength = <1>;
qcom,src-sel = <2>;
qcom,master-en = <1>;
};
@@ -701,10 +711,24 @@
};
};
+&vph_pwr_vreg {
+ status = "ok";
+};
+
&slim_msm {
taiko_codec {
qcom,cdc-micbias2-ext-cap;
qcom,cdc-micbias3-ext-cap;
+
+ /*
+ * Liquid has external spkrdrv supply. Give a dummy supply to
+ * make codec driver's happy.
+ */
+ cdc-vdd-spkdrv-supply = <&vph_pwr_vreg>;
+ qcom,cdc-vdd-spkdrv-voltage = <0 0>;
+ qcom,cdc-vdd-spkdrv-current = <0>;
+
+ qcom,cdc-on-demand-supplies = "cdc-vdd-spkdrv";
};
};
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 86f8141..6b8d600 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
mdss_mdp: qcom,mdss_mdp@fd900000 {
compatible = "qcom,mdss_mdp";
reg = <0xfd900000 0x22100>,
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index ca5f663..4d28a1d 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -14,7 +14,7 @@
/include/ "msm8974-camera-sensor-mtp.dtsi"
/include/ "msm8974-leds.dtsi"
-/ {
+&soc {
serial@f991e000 {
status = "ok";
};
@@ -187,6 +187,7 @@
sound {
qcom,model = "msm8974-taiko-mtp-snd-card";
+ qcom,cdc-micbias2-headset-only;
};
};
@@ -489,7 +490,7 @@
qcom,output-type = <0>;
qcom,pull = <5>;
qcom,vin-sel = <2>;
- qcom,out-strength = <3>;
+ qcom,out-strength = <1>;
qcom,src-sel = <2>;
qcom,master-en = <1>;
};
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index d1b3334..2cd3d24 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -458,7 +458,7 @@
};
};
-/ {
+&soc {
krait_pdn: krait-pdn@f9011000 {
reg = <0xf9011000 0x1000>;
reg-names = "apcs_gcc";
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
index c569e58..c01a4e5 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dtsi
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -13,7 +13,7 @@
/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor-cdp.dtsi"
-/ {
+&soc {
timer {
clock-frequency = <5000000>;
};
diff --git a/arch/arm/boot/dts/msm8974-sim.dtsi b/arch/arm/boot/dts/msm8974-sim.dtsi
index 786c50c..24b8d18 100644
--- a/arch/arm/boot/dts/msm8974-sim.dtsi
+++ b/arch/arm/boot/dts/msm8974-sim.dtsi
@@ -14,7 +14,7 @@
/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor-cdp.dtsi"
-/ {
+&soc {
qcom,mdss_dsi@fd922800 {
qcom,mdss_dsi_sim_video {
status = "ok";
diff --git a/arch/arm/boot/dts/msm8974-smp2p.dtsi b/arch/arm/boot/dts/msm8974-smp2p.dtsi
index 079e4ca..3921a68 100644
--- a/arch/arm/boot/dts/msm8974-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8974-smp2p.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,smp2p-modem {
compatible = "qcom,smp2p";
reg = <0xf9011008 0x4>;
diff --git a/arch/arm/boot/dts/msm8974-v1-cdp.dts b/arch/arm/boot/dts/msm8974-v1-cdp.dts
index cb58026..c3fd98d 100644
--- a/arch/arm/boot/dts/msm8974-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-cdp.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974 CDP";
compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
- qcom,msm-id = <126 1 0>;
+ qcom,msm-id = <126 1 0>,
+ <185 1 0>,
+ <186 1 0>;
};
&ehci {
diff --git a/arch/arm/boot/dts/msm8974-v1-fluid.dts b/arch/arm/boot/dts/msm8974-v1-fluid.dts
index 8ab24df..2b96ecb 100644
--- a/arch/arm/boot/dts/msm8974-v1-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v1-fluid.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974 FLUID";
compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
- qcom,msm-id = <126 3 0>;
+ qcom,msm-id = <126 3 0>,
+ <185 3 0>,
+ <186 3 0>;
};
diff --git a/arch/arm/boot/dts/msm8974-v1-iommu-domains.dtsi b/arch/arm/boot/dts/msm8974-v1-iommu-domains.dtsi
index 6ea5b9e..25fca2a 100644
--- a/arch/arm/boot/dts/msm8974-v1-iommu-domains.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-iommu-domains.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,iommu-domains {
compatible = "qcom,iommu-domains";
diff --git a/arch/arm/boot/dts/msm8974-v1-liquid.dts b/arch/arm/boot/dts/msm8974-v1-liquid.dts
index ccbd82f..29d6150 100644
--- a/arch/arm/boot/dts/msm8974-v1-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-v1-liquid.dts
@@ -18,5 +18,7 @@
/ {
model = "Qualcomm MSM 8974 LIQUID";
compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
- qcom,msm-id = <126 9 0>;
+ qcom,msm-id = <126 9 0>,
+ <185 9 0>,
+ <186 9 0>;
};
diff --git a/arch/arm/boot/dts/msm8974-v1-mtp.dts b/arch/arm/boot/dts/msm8974-v1-mtp.dts
index 09ea84b..8cbcca0 100644
--- a/arch/arm/boot/dts/msm8974-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-mtp.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974 MTP";
compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
- qcom,msm-id = <126 8 0>;
+ qcom,msm-id = <126 8 0>,
+ <185 8 0>,
+ <186 8 0>;
};
&pm8941_chg {
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index f9c0920..1a88749 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -12,7 +12,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
qcom,spm@f9089000 {
compatible = "qcom,spm-v2";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8974-v1-rumi.dts b/arch/arm/boot/dts/msm8974-v1-rumi.dts
index caf89ee..85aab17 100644
--- a/arch/arm/boot/dts/msm8974-v1-rumi.dts
+++ b/arch/arm/boot/dts/msm8974-v1-rumi.dts
@@ -18,5 +18,7 @@
/ {
model = "Qualcomm MSM 8974 RUMI";
compatible = "qcom,msm8974-rumi", "qcom,msm8974", "qcom,rumi";
- qcom,msm-id = <126 15 0>;
+ qcom,msm-id = <126 15 0>,
+ <185 15 0>,
+ <186 15 0>;
};
diff --git a/arch/arm/boot/dts/msm8974-v1-sim.dts b/arch/arm/boot/dts/msm8974-v1-sim.dts
index c4b29c2..fc9858d 100644
--- a/arch/arm/boot/dts/msm8974-v1-sim.dts
+++ b/arch/arm/boot/dts/msm8974-v1-sim.dts
@@ -18,5 +18,7 @@
/ {
model = "Qualcomm MSM 8974 Simulator";
compatible = "qcom,msm8974-sim", "qcom,msm8974", "qcom,sim";
- qcom,msm-id = <126 16 0>;
+ qcom,msm-id = <126 16 0>,
+ <185 16 0>,
+ <186 16 0>;
};
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index 62837a1..caec2dc 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -21,7 +21,7 @@
/include/ "msm8974-v1-iommu-domains.dtsi"
/include/ "msm8974-v1-pm.dtsi"
-/ {
+&soc {
android_usb@fc42b0c8 {
compatible = "qcom,android-usb";
reg = <0xfc42b0c8 0xc8>;
diff --git a/arch/arm/boot/dts/msm8974-v2-cdp.dts b/arch/arm/boot/dts/msm8974-v2-cdp.dts
index 4fa1f2a..85d478b 100644
--- a/arch/arm/boot/dts/msm8974-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v2-cdp.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974v2 CDP";
compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
- qcom,msm-id = <126 1 0x20000>;
+ qcom,msm-id = <126 1 0x20000>,
+ <185 1 0x20000>,
+ <186 1 0x20000>;
};
&usb3 {
diff --git a/arch/arm/boot/dts/msm8974-v2-fluid.dts b/arch/arm/boot/dts/msm8974-v2-fluid.dts
index c5779b1..d83d130 100644
--- a/arch/arm/boot/dts/msm8974-v2-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v2-fluid.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974v2 FLUID";
compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
- qcom,msm-id = <126 3 0x20000>;
+ qcom,msm-id = <126 3 0x20000>,
+ <185 3 0x20000>,
+ <186 3 0x20000>;
};
&usb3 {
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu-domains.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu-domains.dtsi
index a83815e..01c94d0 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu-domains.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu-domains.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,iommu-domains {
compatible = "qcom,iommu-domains";
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index c974884..b5652d1 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -76,6 +76,7 @@
};
venus_sec_pixel: qcom,iommu-ctx@fdc8f000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8f000 0x1000>;
interrupts = <0 42 0>;
qcom,iommu-ctx-sids = <0x85>;
@@ -84,6 +85,7 @@
};
venus_sec_non_pixel: qcom,iommu-ctx@fdc90000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc90000 0x1000>;
interrupts = <0 42 0>;
qcom,iommu-ctx-sids = <0x87 0xA0>;
diff --git a/arch/arm/boot/dts/msm8974-v2-liquid.dts b/arch/arm/boot/dts/msm8974-v2-liquid.dts
index 7132f43..53983dc 100644
--- a/arch/arm/boot/dts/msm8974-v2-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-v2-liquid.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974v2 LIQUID";
compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
- qcom,msm-id = <126 9 0x20000>;
+ qcom,msm-id = <126 9 0x20000>,
+ <185 9 0x20000>,
+ <186 9 0x20000>;
};
&usb3 {
diff --git a/arch/arm/boot/dts/msm8974-v2-mtp.dts b/arch/arm/boot/dts/msm8974-v2-mtp.dts
index d38e663..c25c385 100644
--- a/arch/arm/boot/dts/msm8974-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v2-mtp.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974v2 MTP";
compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
- qcom,msm-id = <126 8 0x20000>;
+ qcom,msm-id = <126 8 0x20000>,
+ <185 8 0x20000>,
+ <186 8 0x20000>;
};
&usb3 {
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index 5a1c047..f8492c0 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -12,7 +12,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
qcom,spm@f9089000 {
compatible = "qcom,spm-v2";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 494b12c..75dce17 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -21,7 +21,7 @@
/include/ "msm8974-v2-iommu-domains.dtsi"
/include/ "msm8974-v2-pm.dtsi"
-/ {
+&soc {
android_usb@fe8050c8 {
compatible = "qcom,android-usb";
reg = <0xfe8050c8 0xc8>;
@@ -65,6 +65,7 @@
qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>;
qcom,mdss-has-bwc;
qcom,mdss-has-decimation;
+ qcom,mdss-ad-off = <0x0013100 0x00013300>;
};
&mdss_hdmi_tx {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index f787cf5..a4a3efe 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -11,14 +11,6 @@
*/
/include/ "skeleton.dtsi"
-/include/ "msm8974-camera.dtsi"
-/include/ "msm8974-coresight.dtsi"
-/include/ "msm-gdsc.dtsi"
-/include/ "msm8974-ion.dtsi"
-/include/ "msm8974-gpu.dtsi"
-/include/ "msm8974-mdss.dtsi"
-/include/ "msm8974-smp2p.dtsi"
-/include/ "msm8974-bus.dtsi"
/ {
model = "Qualcomm MSM 8974";
@@ -35,7 +27,6 @@
};
memory {
-
secure_mem: secure_region {
linux,contiguous-region;
reg = <0 0xFC00000>;
@@ -47,8 +38,32 @@
reg = <0 0x2000000>;
label = "adsp_mem";
};
+
+ qsecom_mem: qsecom_region {
+ linux,contiguous-region;
+ reg = <0 0x1100000>;
+ label = "qseecom_mem";
+ };
+
};
+ soc: soc { };
+};
+
+/include/ "msm8974-camera.dtsi"
+/include/ "msm8974-coresight.dtsi"
+/include/ "msm-gdsc.dtsi"
+/include/ "msm8974-ion.dtsi"
+/include/ "msm8974-gpu.dtsi"
+/include/ "msm8974-mdss.dtsi"
+/include/ "msm8974-smp2p.dtsi"
+/include/ "msm8974-bus.dtsi"
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
intc: interrupt-controller@F9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
@@ -725,6 +740,22 @@
qcom,i2c-src-freq = <50000000>;
};
+ i2c_1: i2c@f9923000 {
+ cell-index = <1>;
+ compatible = "qcom,i2c-qup";
+ reg = <0xf9923000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ interrupts = <0 95 0>;
+ interrupt-names = "qup_err_intr";
+ qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <19200000>;
+ qcom,scl-gpio = <&msmgpio 3 0>;
+ qcom,sda-gpio = <&msmgpio 2 0>;
+ status = "disabled";
+ };
+
i2c_2: i2c@f9924000 {
cell-index = <2>;
compatible = "qcom,i2c-qup";
@@ -838,6 +869,7 @@
/* GPIO inputs from lpass */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>;
/* GPIO output to lpass */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
@@ -1096,12 +1128,12 @@
vdd_mx-supply = <&pm8841_s1>;
vdd_pll-supply = <&pm8941_l12>;
qcom,vdd_pll = <1800000>;
- qcom,is-loadable;
qcom,firmware-name = "mba";
qcom,pil-self-auth;
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
@@ -1121,6 +1153,7 @@
/* GPIO inputs from wcnss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
/* GPIO output to wcnss */
@@ -1162,7 +1195,7 @@
interrupts = <0 76 0 0 77 0>;
interrupt-names = "ocmem_irq", "dm_irq";
qcom,ocmem-num-regions = <0x3>;
- qcom,ocmem-num-macros = <0x8>;
+ qcom,ocmem-num-macros = <0x18>;
qcom,resource-type = <0x706d636f>;
#address-cells = <1>;
#size-cells = <1>;
@@ -1409,6 +1442,11 @@
qcom,min-level = <1>; /* No Request */
};
+ qcom,vdd-apps-rstr{
+ qcom,vdd-rstr-reg = "vdd_apps";
+ qcom,levels = <1881600 1958400 2265600>;
+ qcom,freq-req;
+ };
};
qcom,bam_dmux@fc834000 {
@@ -1544,22 +1582,28 @@
};
&gdsc_venus {
+ qcom,clock-names = "core_clk";
status = "ok";
};
&gdsc_mdss {
+ qcom,clock-names = "core_clk", "lut_clk";
status = "ok";
};
&gdsc_jpeg {
+ qcom,clock-names = "core0_clk", "core1_clk", "core2_clk";
status = "ok";
};
&gdsc_vfe {
+ qcom,clock-names = "core0_clk", "core1_clk", "csi0_clk", "csi1_clk",
+ "cpp_clk";
status = "ok";
};
&gdsc_oxili_gx {
+ qcom,clock-names = "core_clk";
qcom,retain-mems;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm9625-cdp.dtsi b/arch/arm/boot/dts/msm9625-cdp.dtsi
index 1f9cbb0..6ddb50b 100644
--- a/arch/arm/boot/dts/msm9625-cdp.dtsi
+++ b/arch/arm/boot/dts/msm9625-cdp.dtsi
@@ -13,7 +13,7 @@
/include/ "msm9625-display.dtsi"
/include/ "qpic-panel-ili-qvga.dtsi"
-/ {
+&soc {
i2c@f9925000 {
charger@57 {
compatible = "summit,smb137c";
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 69a1d7b..9b18b72 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
tmc_etr: tmc@fc322000 {
compatible = "arm,coresight-tmc";
reg = <0xfc322000 0x1000>,
@@ -243,4 +243,15 @@
coresight-name = "coresight-cti-cpu";
coresight-nr-inports = <0>;
};
+
+ hwevent: hwevent@f9011038 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0xf9011038 0x8>,
+ <0xfd4ab160 0x80>;
+ reg-names = "apcs-mux", "ppss-mux";
+
+ coresight-id = <20>;
+ coresight-name = "coresight-hwevent";
+ coresight-nr-inports = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm9625-display.dtsi b/arch/arm/boot/dts/msm9625-display.dtsi
index a160bae..287a63a 100644
--- a/arch/arm/boot/dts/msm9625-display.dtsi
+++ b/arch/arm/boot/dts/msm9625-display.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,msm_qpic@f9ac0000 {
compatible = "qcom,mdss_qpic";
reg = <0xf9ac0000 0x24000>;
diff --git a/arch/arm/boot/dts/msm9625-ion.dtsi b/arch/arm/boot/dts/msm9625-ion.dtsi
index 8183264..2a3e4b5 100644
--- a/arch/arm/boot/dts/msm9625-ion.dtsi
+++ b/arch/arm/boot/dts/msm9625-ion.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,ion {
compatible = "qcom,msm-ion";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm9625-mtp.dtsi b/arch/arm/boot/dts/msm9625-mtp.dtsi
index cc0bf5e..79c873f 100644
--- a/arch/arm/boot/dts/msm9625-mtp.dtsi
+++ b/arch/arm/boot/dts/msm9625-mtp.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
i2c@f9925000 {
charger@57 {
compatible = "summit,smb137c";
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 3e421a8..6c45f80 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -12,7 +12,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
qcom,spm@f9009000 {
compatible = "qcom,spm-v2";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm9625-regulator.dtsi b/arch/arm/boot/dts/msm9625-regulator.dtsi
index 24f616d..ee48b7f 100644
--- a/arch/arm/boot/dts/msm9625-regulator.dtsi
+++ b/arch/arm/boot/dts/msm9625-regulator.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -260,7 +260,7 @@
};
};
-/ {
+&soc {
ext_2p95v: regulator-isl80101 {
compatible = "regulator-fixed";
regulator-name = "ext_2p95v";
diff --git a/arch/arm/boot/dts/msm9625-smp2p.dtsi b/arch/arm/boot/dts/msm9625-smp2p.dtsi
index 46af1b2..f8ad351 100644
--- a/arch/arm/boot/dts/msm9625-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm9625-smp2p.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,smp2p-modem {
compatible = "qcom,smp2p";
reg = <0xf9011008 0x4>;
diff --git a/arch/arm/boot/dts/msm9625-v1.dtsi b/arch/arm/boot/dts/msm9625-v1.dtsi
index de88ff1..b238ba5 100644
--- a/arch/arm/boot/dts/msm9625-v1.dtsi
+++ b/arch/arm/boot/dts/msm9625-v1.dtsi
@@ -18,7 +18,7 @@
/include/ "msm9625.dtsi"
-/ {
+&soc {
qcom,msm-imem@fc42a800 {
compatible = "qcom,msm-imem";
reg = <0xfc42a800 0x1000>; /* Address and size of IMEM */
diff --git a/arch/arm/boot/dts/msm9625-v2-mtp.dts b/arch/arm/boot/dts/msm9625-v2-mtp.dts
index 5324e2c..27d0066 100644
--- a/arch/arm/boot/dts/msm9625-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-mtp.dts
@@ -21,7 +21,9 @@
qcom,msm-id = <134 7 0x20000>, <152 7 0x20000>, <149 7 0x20000>,
<150 7 0x20000>, <151 7 0x20000>, <148 7 0x20000>,
<173 7 0x20000>, <174 7 0x20000>, <175 7 0x20000>;
+};
+&soc {
i2c@f9925000 {
charger@57 {
compatible = "summit,smb137c";
diff --git a/arch/arm/boot/dts/msm9625-v2.1.dtsi b/arch/arm/boot/dts/msm9625-v2.1.dtsi
index c3c2c49..65ff96a 100644
--- a/arch/arm/boot/dts/msm9625-v2.1.dtsi
+++ b/arch/arm/boot/dts/msm9625-v2.1.dtsi
@@ -18,7 +18,7 @@
/include/ "msm9625.dtsi"
-/ {
+&soc {
qcom,msm-imem@fe807800 {
compatible = "qcom,msm-imem";
reg = <0xfe807800 0x1000>; /* Address and size of IMEM */
diff --git a/arch/arm/boot/dts/msm9625-v2.dtsi b/arch/arm/boot/dts/msm9625-v2.dtsi
index 81d8e00..b078309 100644
--- a/arch/arm/boot/dts/msm9625-v2.dtsi
+++ b/arch/arm/boot/dts/msm9625-v2.dtsi
@@ -18,7 +18,7 @@
/include/ "msm9625.dtsi"
-/ {
+&soc {
qcom,msm-imem@fe807800 {
compatible = "qcom,msm-imem";
reg = <0xfe807800 0x1000>; /* Address and size of IMEM */
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index a79f403..6e258b5 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -11,10 +11,6 @@
*/
/include/ "skeleton.dtsi"
-/include/ "msm9625-ion.dtsi"
-/include/ "msm9625-pm.dtsi"
-/include/ "msm9625-coresight.dtsi"
-/include/ "msm9625-smp2p.dtsi"
/ {
model = "Qualcomm MSM 9625";
@@ -25,6 +21,19 @@
spi0 = &spi_0;
};
+ soc: soc { };
+};
+
+/include/ "msm9625-ion.dtsi"
+/include/ "msm9625-pm.dtsi"
+/include/ "msm9625-coresight.dtsi"
+/include/ "msm9625-smp2p.dtsi"
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
intc: interrupt-controller@F9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
@@ -155,7 +164,7 @@
qcom,hsusb-otg-disable-reset;
qcom,hsusb-otg-lpm-on-dev-suspend;
qcom,hsusb-otg-clk-always-on-workaround;
- qcom,hsusb-otg-delay-lpm;
+ qcom,hsusb-otg-delay-lpm-hndshk-on-disconnect;
qcom,msm-bus,name = "usb2";
qcom,msm-bus,num-cases = <2>;
@@ -205,6 +214,7 @@
qcom,src-bam-pipe-index = <1>;
qcom,data-fifo-size = <0x8000>;
qcom,descriptor-fifo-size = <0x2000>;
+ qcom,reset-bam-on-connect;
};
qcom,pipe1 {
label = "hsusb-ipa-in-0";
@@ -217,6 +227,7 @@
qcom,dst-bam-pipe-index = <0>;
qcom,data-fifo-size = <0x8000>;
qcom,descriptor-fifo-size = <0x2000>;
+ qcom,reset-bam-on-connect;
};
qcom,pipe2 {
label = "hsusb-qdss-in-0";
@@ -752,9 +763,11 @@
qcom,mss {
compatible = "qcom,pil-q6v5-mss";
interrupts = <0 24 1>;
+ qcom,is-not-loadable;
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
@@ -955,3 +968,32 @@
qcom,fast-avg-setup = <0>;
};
};
+
+&pm8019_adc_tm {
+ /* Channel Node */
+ chan@33 {
+ label = "pa_therm0";
+ reg = <0x33>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x48>;
+ qcom,thermal-node;
+ };
+
+ chan@34 {
+ label = "pa_therm1";
+ reg = <0x34>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x68>;
+ qcom,thermal-node;
+ };
+};
diff --git a/arch/arm/boot/dts/msmkrypton.dtsi b/arch/arm/boot/dts/msmkrypton.dtsi
index 3f51659..4b032d8 100644
--- a/arch/arm/boot/dts/msmkrypton.dtsi
+++ b/arch/arm/boot/dts/msmkrypton.dtsi
@@ -17,6 +17,14 @@
compatible = "qcom,msmkrypton";
interrupt-parent = <&intc>;
+ soc: soc { };
+};
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
intc: interrupt-controller@f9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
diff --git a/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi b/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi
index a0c906e..089f112 100644
--- a/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi
+++ b/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_lcdc_ili9341_qvga {
compatible = "qcom,mdss-qpic-panel";
label = "ili qvga lcdc panel";
diff --git a/arch/arm/boot/dts/skeleton64.dtsi b/arch/arm/boot/dts/skeleton64.dtsi
new file mode 100644
index 0000000..5bf6a82
--- /dev/null
+++ b/arch/arm/boot/dts/skeleton64.dtsi
@@ -0,0 +1,18 @@
+/*
+ * Skeleton device tree; the bare minimum needed to boot; just include and
+ * add a compatible value. The bootloader will typically populate the memory
+ * node.
+ */
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ chosen { };
+ aliases { };
+ memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ device_type = "memory";
+ reg = <0 0 0 0>;
+ };
+};
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index f595188..a1fa53c 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -74,8 +74,6 @@
CONFIG_MSM_L2_ERP_PORT_PANIC=y
CONFIG_MSM_L2_ERP_1BIT_PANIC=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
-CONFIG_MSM_CACHE_DUMP=y
-CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_ARM_LPAE=y
CONFIG_NO_HZ=y
@@ -284,6 +282,7 @@
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
CONFIG_FB_MSM=y
# CONFIG_FB_MSM_BACKLIGHT is not set
CONFIG_FB_MSM_MDSS=y
@@ -326,6 +325,10 @@
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_MSM=y
CONFIG_MMC_SDHCI_MSM=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_DIAG_CHAR=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
diff --git a/arch/arm/configs/mpq8092_defconfig b/arch/arm/configs/mpq8092_defconfig
new file mode 100644
index 0000000..28ca32f
--- /dev/null
+++ b/arch/arm/configs/mpq8092_defconfig
@@ -0,0 +1,368 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_IOSCHED_TEST=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MPQ8092=y
+CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
+CONFIG_MSM_MPM_OF=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SECURITY=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_RUN_QUEUE_STATS=y
+CONFIG_MSM_SPM_V2=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_SENSORS_ADSP=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L1_RECOV_ERR_PANIC=y
+CONFIG_MSM_L1_ERR_LOG=y
+CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
+CONFIG_MSM_L2_ERP_PORT_PANIC=y
+CONFIG_MSM_L2_ERP_1BIT_PANIC=y
+CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_CACHE_DUMP=y
+CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
+CONFIG_USE_OF=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_CFG80211=y
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_HAPTIC_ISA1200=y
+CONFIG_USB_HSIC_SMSC_HUB=y
+CONFIG_TI_DRV2667=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_KS8851=m
+# CONFIG_MSM_RMNET is not set
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_USB_USBNET=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_SMB350_CHARGER=y
+CONFIG_BATTERY_BQ28400=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_BATTERY_BCL=y
+CONFIG_SENSORS_EPM_ADC=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
+CONFIG_FB_MSM_MDSS_HDMI_MHL_SII8334=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_USB=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_STORAGE_ENE_UB6250=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_SWITCH=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_QPNP_CLKDIV=y
+CONFIG_MSM_IOMMU=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_PSTORE=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
new file mode 100644
index 0000000..07a15d9
--- /dev/null
+++ b/arch/arm/configs/msm8226_defconfig
@@ -0,0 +1,383 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8226=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_PIL_LPASS_QDSP6V5=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_MSM_PIL_VENUS=y
+CONFIG_MSM_PIL_PRONTO=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_MSM_OCMEM_POWER_DISABLE=y
+CONFIG_SENSORS_ADSP=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_USE_OF=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_CMA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_QPNP_BMS=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_WCD9306_CODEC=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+# CONFIG_MSM_CAMERA is not set
+CONFIG_OV8825=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_CPP=y
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_ISPIF=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_OV9724=y
+CONFIG_MSMB_JPEG=y
+CONFIG_SWITCH=y
+CONFIG_MSM_WFD=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8226=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_MSM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SPS=y
+CONFIG_USB_BAM=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_MSM_IOMMU=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_TMC=y
+CONFIG_CORESIGHT_TPIU=y
+CONFIG_CORESIGHT_FUNNEL=y
+CONFIG_CORESIGHT_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_CORESIGHT_ETM=y
+CONFIG_CORESIGHT_EVENT=m
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_QPNP_VIBRATOR=y
+CONFIG_QSEECOM=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=m
\ No newline at end of file
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
new file mode 100644
index 0000000..b385669
--- /dev/null
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -0,0 +1,362 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCALVERSION="-perf"
+CONFIG_SYSVIPC=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8610=y
+CONFIG_ARCH_MSM8226=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_PIL_LPASS_QDSP6V5=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_MSM_PIL_VENUS=y
+CONFIG_MSM_PIL_PRONTO=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_MSM_OCMEM_POWER_DISABLE=y
+CONFIG_SENSORS_ADSP=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_USE_OF=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_CMA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_QPNP_BMS=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_WCD9306_CODEC=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+# CONFIG_MSM_CAMERA is not set
+CONFIG_OV8825=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_CPP=y
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_ISPIF=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_OV9724=y
+CONFIG_MSMB_JPEG=y
+CONFIG_SWITCH=y
+CONFIG_MSM_WFD=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8226=y
+CONFIG_SND_SOC_MSM8X10=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_MSM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SPS=y
+CONFIG_USB_BAM=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_MSM_IOMMU=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_QPNP_VIBRATOR=y
+CONFIG_QSEECOM=y
\ No newline at end of file
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 3291919..5e38ef1 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -59,7 +59,6 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_ADSP_LOADER=m
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
@@ -69,6 +68,8 @@
CONFIG_SENSORS_ADSP=y
CONFIG_MSM_RTB=y
CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_BOOT_STATS=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -214,6 +215,7 @@
CONFIG_INPUT_EVBUG=m
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
@@ -278,7 +280,6 @@
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_FB=y
-CONFIG_FB_VIRTUAL=y
CONFIG_FB_MSM=y
# CONFIG_FB_MSM_BACKLIGHT is not set
CONFIG_FB_MSM_MDSS=y
@@ -335,6 +336,7 @@
CONFIG_CORESIGHT_FUNNEL=y
CONFIG_CORESIGHT_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_ETM=y
CONFIG_CORESIGHT_EVENT=m
CONFIG_EXT2_FS=y
@@ -377,3 +379,7 @@
CONFIG_CRC_CCITT=y
CONFIG_QPNP_VIBRATOR=y
CONFIG_QSEECOM=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=m
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 59cafd1..bae4ee9 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -25,6 +25,7 @@
CONFIG_PANIC_TIMEOUT=5
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
@@ -442,15 +443,6 @@
CONFIG_IOMMU_PGTABLES_L2=y
CONFIG_MOBICORE_SUPPORT=m
CONFIG_MOBICORE_API=m
-CONFIG_CORESIGHT=y
-CONFIG_CORESIGHT_TMC=y
-CONFIG_CORESIGHT_TPIU=y
-CONFIG_CORESIGHT_FUNNEL=y
-CONFIG_CORESIGHT_REPLICATOR=y
-CONFIG_CORESIGHT_STM=y
-CONFIG_CORESIGHT_ETM=y
-CONFIG_CORESIGHT_ETM_PCSAVE_DEFAULT_ENABLE=y
-CONFIG_CORESIGHT_EVENT=m
CONFIG_BIF=y
CONFIG_BIF_QPNP=y
CONFIG_EXT2_FS=y
@@ -483,3 +475,4 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index fd8a639..8036a44 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -455,6 +455,7 @@
CONFIG_CORESIGHT_FUNNEL=y
CONFIG_CORESIGHT_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_ETM=y
CONFIG_CORESIGHT_ETM_PCSAVE_DEFAULT_ENABLE=y
CONFIG_CORESIGHT_EVENT=m
@@ -506,3 +507,4 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index ae73bad..662d555 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -25,6 +25,7 @@
CONFIG_PANIC_TIMEOUT=5
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
@@ -224,6 +225,7 @@
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_WCD9320_CODEC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -277,14 +279,6 @@
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_IPA=y
-CONFIG_CORESIGHT=y
-CONFIG_CORESIGHT_TMC=y
-CONFIG_CORESIGHT_TPIU=y
-CONFIG_CORESIGHT_FUNNEL=y
-CONFIG_CORESIGHT_REPLICATOR=y
-CONFIG_CORESIGHT_STM=y
-CONFIG_CORESIGHT_ETM=y
-CONFIG_CORESIGHT_EVENT=m
CONFIG_EXT3_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index f7c3bff..7891990 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -225,6 +225,7 @@
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_WCD9320_CODEC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -284,6 +285,7 @@
CONFIG_CORESIGHT_FUNNEL=y
CONFIG_CORESIGHT_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_ETM=y
CONFIG_CORESIGHT_EVENT=m
CONFIG_EXT3_FS=y
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index c1295c4..70d82ec 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -119,16 +119,16 @@
*/
extern void __iomem *__arm_ioremap_pfn_caller(unsigned long, unsigned long,
size_t, unsigned int, void *);
-extern void __iomem *__arm_ioremap_caller(unsigned long, size_t, unsigned int,
+extern void __iomem *__arm_ioremap_caller(phys_addr_t, size_t, unsigned int,
void *);
extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
-extern void __iomem *__arm_ioremap(unsigned long, size_t, unsigned int);
-extern void __iomem *__arm_ioremap_exec(unsigned long, size_t, bool cached);
+extern void __iomem *__arm_ioremap(phys_addr_t, size_t, unsigned int);
+extern void __iomem *__arm_ioremap_exec(phys_addr_t, size_t, bool cached);
extern void __iounmap(volatile void __iomem *addr);
extern void __arm_iounmap(volatile void __iomem *addr);
-extern void __iomem * (*arch_ioremap_caller)(unsigned long, size_t,
+extern void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
unsigned int, void *);
extern void (*arch_iounmap)(volatile void __iomem *);
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 84560dc..7b6f42a 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -313,6 +313,7 @@
* We provide our own arch_get_unmapped_area to cope with VIPT caches.
*/
#define HAVE_ARCH_UNMAPPED_AREA
+#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
/*
* remap a physical page `pfn' of size `size' with page protection `prot'
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index 8e2bb29..07209d7 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -126,6 +126,8 @@
#endif
+#define HAVE_ARCH_PICK_MMAP_LAYOUT
+
#endif
#endif /* __ASM_ARM_PROCESSOR_H */
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index a70e6c6..0eecffd 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -418,6 +418,7 @@
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
+ select ARM_TICKET_LOCKS
select GPIO_MSM_V3
select MSM_GPIOMUX
select MSM_NATIVE_RESTART
@@ -459,6 +460,7 @@
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
+ select ARM_TICKET_LOCKS
select GPIO_MSM_V3
select MSM_GPIOMUX
select MSM_NATIVE_RESTART
@@ -1113,14 +1115,14 @@
config KERNEL_PMEM_SMI_REGION
bool "Enable in-kernel PMEM region for SMI"
default y if ARCH_MSM8X60
- depends on ANDROID_PMEM && ((ARCH_QSD8X50 && !PMEM_GPU0) || (ARCH_MSM8X60 && !VCM))
+ depends on (ARCH_QSD8X50 && !PMEM_GPU0) || (ARCH_MSM8X60 && !VCM)
help
Enable the in-kernel PMEM allocator to use SMI memory.
config PMEM_GPU0
bool "Enable PMEM GPU0 region"
default y
- depends on ARCH_QSD8X50 && ANDROID_PMEM
+ depends on ARCH_QSD8X50
help
Enable the PMEM GPU0 device on SMI Memory.
@@ -1856,7 +1858,6 @@
config MSM_HW3D
tristate "MSM Hardware 3D Register Driver"
- depends on ANDROID_PMEM
help
Provides access to registers needed by the userspace OpenGL|ES
library.
@@ -1864,7 +1865,6 @@
config MSM_ADSP
depends on (ARCH_MSM7X01A || ARCH_MSM7X25 || ARCH_MSM7X27)
tristate "MSM ADSP driver"
- depends on ANDROID_PMEM
default y
help
Provides access to registers needed by the userspace aDSP library.
@@ -1890,7 +1890,7 @@
config MSM7KV2_AUDIO
bool "MSM7K v2 audio"
- depends on (ARCH_MSM7X30 && ANDROID_PMEM)
+ depends on ARCH_MSM7X30
default y
help
Enables QDSP5V2-based audio drivers for audio playbacks and
@@ -1906,14 +1906,14 @@
config MSM_QDSP6
tristate "QDSP6 support"
- depends on ARCH_QSD8X50 && ANDROID_PMEM
+ depends on ARCH_QSD8X50
default y
help
Enable support for qdsp6. This provides audio and video functionality.
config MSM8X60_AUDIO
tristate "MSM8X60 audio support"
- depends on ARCH_MSM8X60 && ANDROID_PMEM
+ depends on ARCH_MSM8X60
default y
help
Enable support for qdsp6v2. This provides audio functionality.
@@ -1972,7 +1972,7 @@
config QSD_AUDIO
bool "QSD audio"
- depends on ARCH_MSM_SCORPION && MSM_DALRPC && ANDROID_PMEM && !MSM_SMP
+ depends on ARCH_MSM_SCORPION && MSM_DALRPC && !MSM_SMP
default y
help
Provides PCM, MP3, and AAC audio playback.
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index a45f5ec..321040e 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -4,10 +4,9 @@
ifndef CONFIG_ARM_ARCH_TIMER
obj-y += timer.o
endif
-obj-y += clock.o clock-voter.o clock-dummy.o
+obj-y += clock.o clock-voter.o clock-dummy.o clock-generic.o
obj-y += modem_notifier.o
obj-$(CONFIG_USE_OF) += board-dt.o
-obj-$(CONFIG_CPU_FREQ_MSM) += cpufreq.o
obj-$(CONFIG_DEBUG_FS) += nohlt.o clock-debug.o
obj-$(CONFIG_KEXEC) += msm_kexec.o
@@ -298,6 +297,7 @@
obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o board-9615-display.o
obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o clock-pll.o
obj-$(CONFIG_ARCH_APQ8084) += board-8084.o board-8084-gpiomux.o
+obj-$(CONFIG_ARCH_APQ8084) += clock-8084.o
obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-8974-gpiomux.o
obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o
obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o clock-mdss-8974.o
@@ -316,6 +316,7 @@
obj-$(CONFIG_ARCH_MSM8226) += acpuclock-8226.o acpuclock-cortex.o
obj-$(CONFIG_ARCH_MSM8610) += board-8610.o board-8610-gpiomux.o
obj-$(CONFIG_ARCH_MSM8610) += clock-local2.o clock-pll.o clock-8610.o clock-rpm.o clock-voter.o
+obj-$(CONFIG_ARCH_MSM8610) += clock-dsi-8610.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -428,3 +429,4 @@
obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o
obj-$(CONFIG_MSM_CPR_REGULATOR) += cpr-regulator.o
+obj-$(CONFIG_CPU_FREQ_MSM) += cpufreq.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index d57709d..2827e65 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -58,6 +58,7 @@
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2-liquid.dtb
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2-mtp.dtb
dtb-$(CONFIG_ARCH_MSM8974) += apq8074-v2-liquid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += apq8074-v2-dragonboard.dtb
# APQ8084
zreladdr-$(CONFIG_ARCH_APQ8084) := 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index a0727b7..8262946 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -131,7 +131,6 @@
[12] = { { 1026000, HFPLL, 1, 0x26 }, 1150000, 1150000, 5 },
[13] = { { 1080000, HFPLL, 1, 0x28 }, 1150000, 1150000, 5 },
[14] = { { 1134000, HFPLL, 1, 0x2A }, 1150000, 1150000, 5 },
- [15] = { { 1188000, HFPLL, 1, 0x2C }, 1150000, 1150000, 5 },
{ }
};
@@ -149,15 +148,15 @@
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1100000 },
{ 0, { 972000, HFPLL, 1, 0x24 }, L2(5), 1125000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1125000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
- { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(14), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1175000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(14), 1200000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1200000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(14), 1225000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1225000 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(14), 1237500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1237500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1250000 },
{ 0, { 0 } }
};
@@ -175,15 +174,15 @@
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1050000 },
{ 0, { 972000, HFPLL, 1, 0x24 }, L2(5), 1075000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1075000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1125000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1125000 },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1150000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1150000 },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1175000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1175000 },
- { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1187500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1187500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1200000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(14), 1125000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1125000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(14), 1150000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1150000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(14), 1175000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1175000 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(14), 1187500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1187500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1200000 },
{ 0, { 0 } }
};
@@ -201,15 +200,15 @@
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1000000 },
{ 0, { 972000, HFPLL, 1, 0x24 }, L2(5), 1025000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1025000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1075000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1100000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1100000 },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1125000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 },
- { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1137500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1137500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1150000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(14), 1075000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1075000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(14), 1100000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1100000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(14), 1125000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1125000 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(14), 1137500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1137500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1150000 },
{ 0, { 0 } }
};
@@ -227,15 +226,15 @@
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 975000 },
{ 0, { 972000, HFPLL, 1, 0x24 }, L2(5), 1000000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1000000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1050000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1050000 },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1075000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1075000 },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1100000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1100000 },
- { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1112500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1112500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1125000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(14), 1050000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1050000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(14), 1075000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1075000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(14), 1100000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1100000 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(14), 1112500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1112500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1125000 },
{ 0, { 0 } }
};
@@ -247,11 +246,11 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 1000000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1025000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1037500 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1087500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1150000 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1162500 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1075000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1087500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1125000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1150000 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1162500 },
{ 0, { 0 } }
};
@@ -263,11 +262,11 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 975000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1000000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1012500 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1037500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1050000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1087500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1112500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1125000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1037500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1050000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1087500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1112500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1125000 },
{ 0, { 0 } }
};
@@ -279,11 +278,11 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 937500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 950000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 975000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1012500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1037500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1087500 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1000000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1012500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1037500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1075000 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1087500 },
{ 0, { 0 } }
};
@@ -295,11 +294,11 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 900000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 925000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 950000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 975000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 987500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1000000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1037500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1050000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 975000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 987500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1000000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1037500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1050000 },
{ 0, { 0 } }
};
@@ -311,11 +310,11 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 950000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 962500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 975000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1000000 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1012500 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 950000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 962500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 975000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1000000 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1012500 },
{ 0, { 0 } }
};
@@ -327,11 +326,11 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 987500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1000000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 987500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1000000 },
{ 0, { 0 } }
};
@@ -343,11 +342,11 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 975000 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 987500 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 975000 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 987500 },
{ 0, { 0 } }
};
@@ -359,13 +358,13 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 1000000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1025000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1037500 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1087500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1150000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1175000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1225000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1250000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1075000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1087500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1125000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1150000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1175000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1225000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1250000 },
{ 0, { 0 } }
};
@@ -377,13 +376,13 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 975000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1000000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1012500 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1037500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1050000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1087500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1112500 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1150000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1187500 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1200000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1037500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1050000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1087500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1112500 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1150000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1187500 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1200000 },
{ 0, { 0 } }
};
@@ -395,13 +394,13 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 937500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 950000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 975000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1012500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1037500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1100000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1137500 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1162500 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1000000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1012500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1037500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1075000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1100000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1137500 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1162500 },
{ 0, { 0 } }
};
@@ -413,13 +412,13 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 900000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 925000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 950000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 975000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 987500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1000000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1037500 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1062500 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1100000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1125000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 975000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 987500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1000000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1037500 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1062500 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1100000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1125000 },
{ 0, { 0 } }
};
@@ -431,13 +430,13 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 950000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 962500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 975000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1000000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1037500 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1075000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1100000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 950000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 962500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 975000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1000000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1037500 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1075000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1100000 },
{ 0, { 0 } }
};
@@ -449,13 +448,13 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 987500 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1012500 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1050000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1075000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 987500 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1012500 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1050000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1075000 },
{ 0, { 0 } }
};
@@ -467,13 +466,13 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 975000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1000000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1025000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1050000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 975000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1000000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1025000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1050000 },
{ 0, { 0 } }
};
@@ -485,14 +484,14 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 962500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 975000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1000000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1025000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1037500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1062500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1100000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1125000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1175000 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1225000 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1287500 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1025000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1037500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1062500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1100000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1125000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1175000 },
+ { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1225000 },
+ { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1287500 },
{ 0, { 0 } }
};
@@ -504,14 +503,14 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 937500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 950000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 975000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1012500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1037500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1100000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1137500 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1187500 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1250000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1000000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1012500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1037500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1075000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1100000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1137500 },
+ { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1187500 },
+ { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1250000 },
{ 0, { 0 } }
};
@@ -523,14 +522,14 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 912500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 925000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 950000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 975000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 987500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1012500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1050000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1075000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1112500 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1162500 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1212500 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 975000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 987500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1012500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1050000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1075000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1112500 },
+ { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1162500 },
+ { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1212500 },
{ 0, { 0 } }
};
@@ -542,14 +541,14 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 900000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 912500 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 937500 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 962500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 975000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1000000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1025000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1050000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1087500 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1137500 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 962500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 975000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1000000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1025000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1050000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1087500 },
+ { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1137500 },
+ { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1175000 },
{ 0, { 0 } }
};
@@ -561,14 +560,14 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 950000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 962500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 975000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1000000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1037500 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1075000 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1112500 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1150000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 950000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 962500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 975000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1000000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1037500 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1075000 },
+ { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1112500 },
+ { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1150000 },
{ 0, { 0 } }
};
@@ -580,14 +579,14 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 987500 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1012500 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1050000 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1087500 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1125000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 987500 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1012500 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1050000 },
+ { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1087500 },
+ { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1125000 },
{ 0, { 0 } }
};
@@ -599,14 +598,14 @@
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 975000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1000000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1025000 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1062500 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1100000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 975000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1000000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1025000 },
+ { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1062500 },
+ { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1100000 },
{ 0, { 0 } }
};
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 25bebd1..5793326 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -65,24 +65,23 @@
* 3) Depending on Frodo version, may need minimum of LVL_NOM
*/
static struct clkctl_acpu_speed acpu_freq_tbl_8226[] = {
- { 0, 19200, CXO, 0, 0, CPR_CORNER_SVS, 1150000, 0 },
- { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 1150000, 4 },
- { 1, 384000, ACPUPLL, 5, 0, CPR_CORNER_SVS, 1150000, 4 },
- { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 1150000, 6 },
- { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 1150000, 7 },
- { 0, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 1150000, 7 },
- { 0, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 1150000, 7 },
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
+ { 1, 384000, ACPUPLL, 5, 0, CPR_CORNER_SVS, 0, 4 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 7 },
+ { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 0, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
{ 0 }
};
static struct clkctl_acpu_speed acpu_freq_tbl_8610[] = {
- { 0, 19200, CXO, 0, 0, CPR_CORNER_SVS, 1150000, 0 },
- { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 1150000, 3 },
- { 1, 384000, ACPUPLL, 5, 0, CPR_CORNER_SVS, 1150000, 3 },
- { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 1150000, 4 },
- { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 1150000, 4 },
- { 0, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 1275000, 5 },
- { 0, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 1275000, 5 },
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 3 },
+ { 1, 384000, ACPUPLL, 5, 0, CPR_CORNER_SVS, 0, 3 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 4 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 4 },
+ { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 5 },
+ { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 5 },
{ 0 }
};
@@ -91,7 +90,6 @@
.current_speed = &(struct clkctl_acpu_speed){ 0 },
.bus_scale = &bus_client_pdata,
.vdd_max_cpu = CPR_CORNER_TURBO,
- .vdd_max_mem = 1150000,
.src_clocks = {
[PLL0].name = "gpll0",
[ACPUPLL].name = "a7sspll",
@@ -130,12 +128,6 @@
return PTR_ERR(drv_data.vdd_cpu);
}
- drv_data.vdd_mem = devm_regulator_get(&pdev->dev, "a7_mem");
- if (IS_ERR(drv_data.vdd_mem)) {
- dev_err(&pdev->dev, "regulator for %s get failed\n", "a7_mem");
- return PTR_ERR(drv_data.vdd_mem);
- }
-
for (i = 0; i < NUM_SRC; i++) {
if (!drv_data.src_clocks[i].name)
continue;
diff --git a/arch/arm/mach-msm/acpuclock-cortex.c b/arch/arm/mach-msm/acpuclock-cortex.c
index 47bf27a..0c80a56 100644
--- a/arch/arm/mach-msm/acpuclock-cortex.c
+++ b/arch/arm/mach-msm/acpuclock-cortex.c
@@ -66,11 +66,17 @@
{
int rc = 0;
- /* Increase vdd_mem before vdd_cpu. vdd_mem should be >= vdd_cpu. */
- rc = regulator_set_voltage(priv->vdd_mem, vdd_mem, priv->vdd_max_mem);
- if (rc) {
- pr_err("vdd_mem increase failed (%d)\n", rc);
- return rc;
+ if (priv->vdd_mem) {
+ /*
+ * Increase vdd_mem before vdd_cpu. vdd_mem should
+ * be >= vdd_cpu.
+ */
+ rc = regulator_set_voltage(priv->vdd_mem, vdd_mem,
+ priv->vdd_max_mem);
+ if (rc) {
+ pr_err("vdd_mem increase failed (%d)\n", rc);
+ return rc;
+ }
}
rc = regulator_set_voltage(priv->vdd_cpu, vdd_cpu, priv->vdd_max_cpu);
@@ -92,6 +98,9 @@
return;
}
+ if (!priv->vdd_mem)
+ return;
+
/* Decrease vdd_mem after vdd_cpu. vdd_mem should be >= vdd_cpu. */
ret = regulator_set_voltage(priv->vdd_mem, vdd_mem, priv->vdd_max_mem);
if (ret)
@@ -343,10 +352,12 @@
if (rc)
goto err_vdd;
- rc = regulator_enable(priv->vdd_mem);
- if (rc) {
- dev_err(&pdev->dev, "regulator_enable for mem failed\n");
- goto err_vdd;
+ if (priv->vdd_mem) {
+ rc = regulator_enable(priv->vdd_mem);
+ if (rc) {
+ dev_err(&pdev->dev, "regulator_enable for mem failed\n");
+ goto err_vdd;
+ }
}
rc = regulator_enable(priv->vdd_cpu);
@@ -369,7 +380,8 @@
return 0;
err_vdd_cpu:
- regulator_disable(priv->vdd_mem);
+ if (priv->vdd_mem)
+ regulator_disable(priv->vdd_mem);
err_vdd:
return rc;
}
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 0f88287..ede53bc 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -968,7 +968,6 @@
.pull = GPIOMUX_PULL_DOWN,
};
-
static struct gpiomux_setting ap2mdm_soft_reset_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_4MA,
diff --git a/arch/arm/mach-msm/board-8084.c b/arch/arm/mach-msm/board-8084.c
index 828ae9c..500c302 100644
--- a/arch/arm/mach-msm/board-8084.c
+++ b/arch/arm/mach-msm/board-8084.c
@@ -53,6 +53,14 @@
.paddr_to_memtype = apq8084_paddr_to_memtype,
};
+static struct of_dev_auxdata apq8084_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
+ "msm_sdcc.1", NULL),
+ OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
+ "msm_sdcc.2", NULL),
+ {}
+};
+
void __init apq8084_reserve(void)
{
reserve_info = &apq8084_reserve_info;
@@ -66,16 +74,6 @@
of_scan_flat_dt(dt_scan_for_memory_hole, apq8084_reserve_table);
}
-static struct clk_lookup msm_clocks_dummy[] = {
- CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
- CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
-};
-
-static struct clock_init_data msm_dummy_clock_init_data __initdata = {
- .table = msm_clocks_dummy,
- .size = ARRAY_SIZE(msm_clocks_dummy),
-};
-
/*
* Used to satisfy dependencies for devices that need to be
* run early or in a particular order. Most likely your device doesn't fall
@@ -85,7 +83,7 @@
void __init apq8084_add_drivers(void)
{
msm_smd_init();
- msm_clock_init(&msm_dummy_clock_init_data);
+ msm_clock_init(&msm8084_clock_init_data);
}
static void __init apq8084_map_io(void)
@@ -95,11 +93,13 @@
void __init apq8084_init(void)
{
+ struct of_dev_auxdata *adata = apq8084_auxdata_lookup;
+
if (socinfo_init() < 0)
pr_err("%s: socinfo_init() failed\n", __func__);
apq8084_init_gpiomux();
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ board_dt_populate(adata);
apq8084_add_drivers();
}
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index b4c63f9..6adff30 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -29,6 +29,7 @@
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <mach/clk-provider.h>
#include "board-dt.h"
#include "clock.h"
@@ -102,7 +103,7 @@
mpq8092_init_gpiomux();
msm_clock_init(&mpq8092_clock_init_data);
- of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
+ board_dt_populate(adata);
}
static const char *mpq8092_dt_match[] __initconst = {
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index a892e32..521898e 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -129,7 +129,7 @@
pr_err("%s: socinfo_init() failed\n", __func__);
msm8226_init_gpiomux();
- of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
+ board_dt_populate(adata);
msm8226_add_drivers();
}
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 4b435de..593e2b1 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -23,14 +23,32 @@
.pull = GPIOMUX_PULL_NONE,
};
-static struct gpiomux_setting gpio_spi_config = {
+static struct gpiomux_setting gpio_cam_i2c_config = {
.func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_6MA,
+ .drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_NONE,
};
-static struct gpiomux_setting gpio_spi_cs_config = {
- .func = GPIOMUX_FUNC_1,
+static struct gpiomux_setting atmel_int_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting atmel_int_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_reset_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting atmel_reset_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_6MA,
.pull = GPIOMUX_PULL_DOWN,
};
@@ -60,6 +78,18 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting gpio_keys_active = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting gpio_keys_suspend = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct msm_gpiomux_config msm_lcd_configs[] __initdata = {
{
.gpio = 41,
@@ -79,6 +109,18 @@
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
+ .gpio = 2, /* BLSP1 QUP1 I2C_SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
+ .gpio = 3, /* BLSP1 QUP1 I2C_SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
.gpio = 10, /* BLSP1 QUP3 I2C_SDA */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
@@ -91,27 +133,32 @@
},
},
{
- .gpio = 0, /* BLSP1 QUP1 SPI_DATA_MOSI */
+ .gpio = 16, /* BLSP1 QUP6 I2C_SDA */
.settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ [GPIOMUX_SUSPENDED] = &gpio_cam_i2c_config,
},
},
{
- .gpio = 1, /* BLSP1 QUP1 SPI_DATA_MISO */
+ .gpio = 17, /* BLSP1 QUP6 I2C_SCL */
.settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ [GPIOMUX_SUSPENDED] = &gpio_cam_i2c_config,
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm_atmel_configs[] __initdata = {
+ {
+ .gpio = 0, /* TOUCH RESET */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &atmel_reset_act_cfg,
+ [GPIOMUX_SUSPENDED] = &atmel_reset_sus_cfg,
},
},
{
- .gpio = 3, /* BLSP1 QUP1 SPI_CLK */
+ .gpio = 1, /* TOUCH INT */
.settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_config,
- },
- },
- {
- .gpio = 2, /* BLSP1 QUP1 SPI_CS1 */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+ [GPIOMUX_ACTIVE] = &atmel_int_act_cfg,
+ [GPIOMUX_SUSPENDED] = &atmel_int_sus_cfg,
},
},
};
@@ -154,6 +201,54 @@
},
};
+static struct msm_gpiomux_config msm_keypad_configs[] __initdata = {
+ {
+ .gpio = 72,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &gpio_keys_active,
+ [GPIOMUX_SUSPENDED] = &gpio_keys_suspend,
+ },
+ },
+ {
+ .gpio = 73,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &gpio_keys_active,
+ [GPIOMUX_SUSPENDED] = &gpio_keys_suspend,
+ },
+ },
+ {
+ .gpio = 74,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &gpio_keys_active,
+ [GPIOMUX_SUSPENDED] = &gpio_keys_suspend,
+ },
+ },
+};
+
+static struct gpiomux_setting sd_card_det_active_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting sd_card_det_suspend_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ .dir = GPIOMUX_IN,
+};
+
+static struct msm_gpiomux_config sd_card_det[] __initdata = {
+ {
+ .gpio = 42,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sd_card_det_active_config,
+ [GPIOMUX_SUSPENDED] = &sd_card_det_suspend_config,
+ },
+ },
+};
+
void __init msm8610_init_gpiomux(void)
{
int rc;
@@ -165,7 +260,12 @@
}
msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+ msm_gpiomux_install(msm_atmel_configs,
+ ARRAY_SIZE(msm_atmel_configs));
msm_gpiomux_install(wcnss_5wire_interface,
ARRAY_SIZE(wcnss_5wire_interface));
msm_gpiomux_install(msm_lcd_configs, ARRAY_SIZE(msm_lcd_configs));
+ msm_gpiomux_install(msm_keypad_configs,
+ ARRAY_SIZE(msm_keypad_configs));
+ msm_gpiomux_install(sd_card_det, ARRAY_SIZE(sd_card_det));
}
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index 2cd7134..962ed65 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -125,7 +125,7 @@
pr_err("%s: socinfo_init() failed\n", __func__);
msm8610_init_gpiomux();
- of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
+ board_dt_populate(adata);
msm8610_add_drivers();
}
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8038.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
index c34394e..8ed93ea 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8038.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -95,7 +95,7 @@
REGULATOR_SUPPLY("VDDIO_CDC", "sitar1p1-slim"),
REGULATOR_SUPPLY("CDC_VDDA_TX", "sitar1p1-slim"),
REGULATOR_SUPPLY("CDC_VDDA_RX", "sitar1p1-slim"),
- REGULATOR_SUPPLY("vddp", "0-0048"),
+ REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
REGULATOR_SUPPLY("mhl_iovcc18", "0-0039"),
REGULATOR_SUPPLY("vdd-io", "spi0.0"),
REGULATOR_SUPPLY("vdd-phy", "spi0.0"),
@@ -209,7 +209,6 @@
REGULATOR_SUPPLY("8038_lvs2", NULL),
REGULATOR_SUPPLY("vcc_i2c", "3-004a"),
REGULATOR_SUPPLY("vcc_i2c", "3-0024"),
- REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
REGULATOR_SUPPLY("vddio", "12-0018"),
REGULATOR_SUPPLY("vlogic", "12-0068"),
};
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8917.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
index 8f853a4..cdc419f 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8917.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -194,7 +194,7 @@
REGULATOR_SUPPLY("VDDIO_CDC", "sitar1p1-slim"),
REGULATOR_SUPPLY("CDC_VDDA_TX", "sitar1p1-slim"),
REGULATOR_SUPPLY("CDC_VDDA_RX", "sitar1p1-slim"),
- REGULATOR_SUPPLY("vddp", "0-0048"),
+ REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
REGULATOR_SUPPLY("mhl_iovcc18", "0-0039"),
REGULATOR_SUPPLY("CDC_VDD_CP", "sitar-slim"),
REGULATOR_SUPPLY("CDC_VDD_CP", "sitar1p1-slim"),
@@ -233,7 +233,6 @@
REGULATOR_SUPPLY("8917_lvs4", NULL),
REGULATOR_SUPPLY("vcc_i2c", "3-004a"),
REGULATOR_SUPPLY("vcc_i2c", "3-0024"),
- REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
REGULATOR_SUPPLY("vddio", "12-0018"),
REGULATOR_SUPPLY("vlogic", "12-0068"),
};
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 6ccaba6..ccea956 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1718,12 +1718,6 @@
static struct isa1200_regulator isa1200_reg_data[] = {
{
- .name = "vddp",
- .min_uV = ISA_I2C_VTG_MIN_UV,
- .max_uV = ISA_I2C_VTG_MAX_UV,
- .load_uA = ISA_I2C_CURR_UA,
- },
- {
.name = "vcc_i2c",
.min_uV = ISA_I2C_VTG_MIN_UV,
.max_uV = ISA_I2C_VTG_MAX_UV,
@@ -2356,6 +2350,7 @@
&msm_pcm_hostless,
&msm_multi_ch_pcm,
&msm_lowlatency_pcm,
+ &msm_fm_loopback,
};
static void __init msm8930_i2c_init(void)
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 705275c..76dbaef 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -20,6 +20,98 @@
#define KS8851_IRQ_GPIO 94
+static struct gpiomux_setting ap2mdm_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_status_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting mdm2ap_errfatal_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting mdm2ap_pblrdy = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_IN,
+};
+
+
+static struct gpiomux_setting ap2mdm_soft_reset_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting ap2mdm_wakeup = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config mdm_configs[] __initdata = {
+ /* AP2MDM_STATUS */
+ {
+ .gpio = 105,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+ }
+ },
+ /* MDM2AP_STATUS */
+ {
+ .gpio = 46,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
+ }
+ },
+ /* MDM2AP_ERRFATAL */
+ {
+ .gpio = 82,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg,
+ }
+ },
+ /* AP2MDM_ERRFATAL */
+ {
+ .gpio = 106,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+ }
+ },
+ /* AP2MDM_SOFT_RESET, aka AP2MDM_PON_RESET_N */
+ {
+ .gpio = 24,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_soft_reset_cfg,
+ }
+ },
+ /* AP2MDM_WAKEUP */
+ {
+ .gpio = 104,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_wakeup,
+ }
+ },
+ /* MDM2AP_PBL_READY*/
+ {
+ .gpio = 80,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mdm2ap_pblrdy,
+ }
+ },
+};
+
static struct gpiomux_setting gpio_uart_config = {
.func = GPIOMUX_FUNC_2,
.drv = GPIOMUX_DRV_16MA,
@@ -1079,6 +1171,23 @@
static void msm_gpiomux_sdc4_install(void) {}
#endif /* CONFIG_MMC_MSM_SDC4_SUPPORT */
+static struct msm_gpiomux_config apq8074_dragonboard_ts_config[] __initdata = {
+ {
+ /* BLSP1 QUP I2C_DATA */
+ .gpio = 2,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
+ /* BLSP1 QUP I2C_CLK */
+ .gpio = 3,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+};
+
void __init msm_8974_init_gpiomux(void)
{
int rc;
@@ -1140,4 +1249,12 @@
if (of_board_is_rumi())
msm_gpiomux_install(msm_rumi_blsp_configs,
ARRAY_SIZE(msm_rumi_blsp_configs));
+
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_MDM)
+ msm_gpiomux_install(mdm_configs,
+ ARRAY_SIZE(mdm_configs));
+
+ if (of_board_is_dragonboard() && machine_is_apq8074())
+ msm_gpiomux_install(apq8074_dragonboard_ts_config,
+ ARRAY_SIZE(apq8074_dragonboard_ts_config));
}
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 3eed219..35e46fc 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -163,7 +163,7 @@
msm_8974_init_gpiomux();
regulator_has_full_constraints();
- of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
+ board_dt_populate(adata);
msm8974_add_drivers();
}
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 3bb00bb..6bb5655 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -247,8 +247,7 @@
pr_err("%s: socinfo_init() failed\n", __func__);
msm9625_init_gpiomux();
- of_platform_populate(NULL, of_default_bus_match_table,
- msm9625_auxdata_lookup, NULL);
+ board_dt_populate(msm9625_auxdata_lookup);
msm9625_add_drivers();
}
diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c
index 5d2fdf9..1f77b4c 100644
--- a/arch/arm/mach-msm/board-dt.c
+++ b/arch/arm/mach-msm/board-dt.c
@@ -115,3 +115,14 @@
return 1;
}
+
+void __init board_dt_populate(struct of_dev_auxdata *adata)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+ /* Explicitly parent the /soc devices to the root node to preserve
+ * the kernel ABI (sysfs structure, etc) until userspace is updated
+ */
+ of_platform_populate(of_find_node_by_path("/soc"),
+ of_default_bus_match_table, adata, NULL);
+}
diff --git a/arch/arm/mach-msm/board-dt.h b/arch/arm/mach-msm/board-dt.h
index 03ffa0b..d79e414 100644
--- a/arch/arm/mach-msm/board-dt.h
+++ b/arch/arm/mach-msm/board-dt.h
@@ -10,9 +10,12 @@
* GNU General Public License for more details.
*/
+#include <linux/of_platform.h>
+
extern struct sys_timer msm_dt_timer;
void __init msm_dt_init_irq(void);
void __init msm_dt_init_irq_nompm(void);
void __init msm_dt_init_irq_l2x0(void);
int __init msm_scan_dt_map_imem(unsigned long node, const char *uname,
int depth, void *data);
+void __init board_dt_populate(struct of_dev_auxdata *adata);
diff --git a/arch/arm/mach-msm/board-krypton.c b/arch/arm/mach-msm/board-krypton.c
index aada3b0..7b7b7cd 100644
--- a/arch/arm/mach-msm/board-krypton.c
+++ b/arch/arm/mach-msm/board-krypton.c
@@ -64,7 +64,7 @@
pr_err("%s: socinfo_init() failed\n", __func__);
msmkrypton_init_gpiomux();
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ board_dt_populate(adata);
msmkrypton_add_drivers();
}
diff --git a/arch/arm/mach-msm/clock-8084.c b/arch/arm/mach-msm/clock-8084.c
new file mode 100644
index 0000000..424b694
--- /dev/null
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -0,0 +1,351 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/rpm-regulator-smd.h>
+#include <mach/socinfo.h>
+#include <mach/rpm-smd.h>
+
+#include "clock-local2.h"
+#include "clock-pll.h"
+#include "clock-rpm.h"
+#include "clock-voter.h"
+#include "clock.h"
+
+/*
+ * TODO: Drivers need to fill in the clock names and device names for the clocks
+ * they need to control.
+ */
+static struct clk_lookup msm_clocks_8084[] = {
+ CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("core_clk", SDC1_CLK, "msm_sdcc.1", OFF),
+ CLK_DUMMY("iface_clk", SDC1_P_CLK, "msm_sdcc.1", OFF),
+ CLK_DUMMY("core_clk", SDC2_CLK, "msm_sdcc.2", OFF),
+ CLK_DUMMY("iface_clk", SDC2_P_CLK, "msm_sdcc.2", OFF),
+ CLK_DUMMY("xo", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("core_clk", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("iface_clk", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("sleep_clk", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("sleep_a_clk", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("utmi_clk", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("ref_clk", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("", ufs_axi_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb30_master_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb30_sec_master_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hsic_ahb_clk_src.c, "", OFF),
+ CLK_DUMMY("", sata_asic0_clk_src.c, "", OFF),
+ CLK_DUMMY("", sata_pmalive_clk_src.c, "", OFF),
+ CLK_DUMMY("", sata_rx_clk_src.c, "", OFF),
+ CLK_DUMMY("", sata_rx_oob_clk_src.c, "", OFF),
+ CLK_DUMMY("", sdcc1_apps_clk_src.c, "", OFF),
+ CLK_DUMMY("", sdcc2_apps_clk_src.c, "", OFF),
+ CLK_DUMMY("", sdcc3_apps_clk_src.c, "", OFF),
+ CLK_DUMMY("", sdcc4_apps_clk_src.c, "", OFF),
+ CLK_DUMMY("", tsif_ref_clk_src.c, "", OFF),
+ CLK_DUMMY("", ufs_rx_cfg_postdiv_clk_src.c, "", OFF),
+ CLK_DUMMY("", ufs_tx_cfg_postdiv_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb30_mock_utmi_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb30_sec_mock_utmi_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hs_system_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hsic_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hsic_io_cal_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hsic_mock_utmi_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hsic_system_clk_src.c, "", OFF),
+ CLK_DUMMY("", gcc_bam_dma_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_bam_dma_inactivity_timers_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup1_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup1_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup2_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup2_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup3_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup3_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup4_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup4_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup5_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup5_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup6_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup6_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart1_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart2_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart3_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart4_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart5_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart6_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup1_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup1_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup2_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup2_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup3_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup3_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup4_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup4_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup5_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup5_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup6_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup6_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart1_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart2_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart3_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart4_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart5_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart6_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_boot_rom_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce1_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce1_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce1_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce2_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce2_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce2_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce3_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce3_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce3_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_copss_smmu_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_copss_smmu_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_dcd_xo_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_bimc_gfx_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_xo_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_xo_div4_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gp1_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gp2_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gp3_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_lpass_mport_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_lpass_q6_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_lpass_sway_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_mmss_bimc_gfx_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_mmss_vpu_maple_sys_noc_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ocmem_noc_cfg_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_msg_ram_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pdm2_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pdm_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pdm_xo4_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_periph_noc_usb_hsic_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_prng_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_asic0_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_cfg_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_pmalive_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_rx_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_rx_oob_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc1_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc1_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc1_cdccal_ff_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc1_cdccal_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc2_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc2_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc2_inactivity_timers_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc3_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc3_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc3_inactivity_timers_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc4_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc4_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc4_inactivity_timers_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_spss_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sys_noc_ufs_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sys_noc_usb3_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sys_noc_usb3_sec_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_tsif_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_tsif_inactivity_timers_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_tsif_ref_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_rx_cfg_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_rx_symbol_0_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_rx_symbol_1_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_tx_cfg_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_tx_symbol_0_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_tx_symbol_1_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb2a_phy_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb2b_phy_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_master_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_mock_utmi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_sec_master_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_sec_mock_utmi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_sec_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hs_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hs_inactivity_timers_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hs_system_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_io_cal_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_io_cal_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_mock_utmi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_system_clk.c, "", OFF),
+
+ CLK_DUMMY("", axi_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll0_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll1_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll2_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll3_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll4_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi0_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi1_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi2_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi3_clk_src.c, "", OFF),
+ CLK_DUMMY("", vcodec0_clk_src.c, "", OFF),
+ CLK_DUMMY("", vfe0_clk_src.c, "", OFF),
+ CLK_DUMMY("", vfe1_clk_src.c, "", OFF),
+ CLK_DUMMY("", edppixel_clk_src.c, "", OFF),
+ CLK_DUMMY("", extpclk_clk_src.c, "", OFF),
+ CLK_DUMMY("", mdp_clk_src.c, "", OFF),
+ CLK_DUMMY("", pclk0_clk_src.c, "", OFF),
+ CLK_DUMMY("", pclk1_clk_src.c, "", OFF),
+ CLK_DUMMY("", ocmemnoc_clk_src.c, "", OFF),
+ CLK_DUMMY("", gfx3d_clk_src.c, "", OFF),
+ CLK_DUMMY("", vp_clk_src.c, "", OFF),
+ CLK_DUMMY("", cci_clk_src.c, "", OFF),
+ CLK_DUMMY("", gp0_clk_src.c, "", OFF),
+ CLK_DUMMY("", gp1_clk_src.c, "", OFF),
+ CLK_DUMMY("", jpeg0_clk_src.c, "", OFF),
+ CLK_DUMMY("", jpeg1_clk_src.c, "", OFF),
+ CLK_DUMMY("", jpeg2_clk_src.c, "", OFF),
+ CLK_DUMMY("", mclk0_clk_src.c, "", OFF),
+ CLK_DUMMY("", mclk1_clk_src.c, "", OFF),
+ CLK_DUMMY("", mclk2_clk_src.c, "", OFF),
+ CLK_DUMMY("", mclk3_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi0phytimer_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi1phytimer_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi2phytimer_clk_src.c, "", OFF),
+ CLK_DUMMY("", cpp_clk_src.c, "", OFF),
+ CLK_DUMMY("", byte0_clk_src.c, "", OFF),
+ CLK_DUMMY("", byte1_clk_src.c, "", OFF),
+ CLK_DUMMY("", edpaux_clk_src.c, "", OFF),
+ CLK_DUMMY("", edplink_clk_src.c, "", OFF),
+ CLK_DUMMY("", esc0_clk_src.c, "", OFF),
+ CLK_DUMMY("", esc1_clk_src.c, "", OFF),
+ CLK_DUMMY("", hdmi_clk_src.c, "", OFF),
+ CLK_DUMMY("", vsync_clk_src.c, "", OFF),
+ CLK_DUMMY("", rbbmtimer_clk_src.c, "", OFF),
+ CLK_DUMMY("", maple_clk_src.c, "", OFF),
+ CLK_DUMMY("", vdp_clk_src.c, "", OFF),
+ CLK_DUMMY("", vpu_bus_clk_src.c, "", OFF),
+ CLK_DUMMY("", dsi0_phy_pll_out_byteclk.c, "", OFF),
+ CLK_DUMMY("", dsi0_phy_pll_out_dsiclk.c, "", OFF),
+ CLK_DUMMY("", dsi1_phy_pll_out_byteclk.c, "", OFF),
+ CLK_DUMMY("", dsi1_phy_pll_out_dsiclk.c, "", OFF),
+ CLK_DUMMY("", edpphy_cc_link_clk.c, "", OFF),
+ CLK_DUMMY("", edpphy_cc_vco_div_clk.c, "", OFF),
+ CLK_DUMMY("", hdmi_phy_pll_out.c, "", OFF),
+ CLK_DUMMY("", csiphy_bist_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_edppixel_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_extpclk_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_pclk0_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_pclk1_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_vp_clk.c, "", OFF),
+ CLK_DUMMY("", camss_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_cci_cci_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_cci_cci_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi0_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi0_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi0phy_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi0pix_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi0rdi_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi1_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi1_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi1phy_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi1pix_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi1rdi_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi2_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi2_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi2phy_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi2pix_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi2rdi_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi3_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi3_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi3phy_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi3pix_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi3rdi_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi_vfe0_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi_vfe1_clk.c, "", OFF),
+ CLK_DUMMY("", camss_gp0_clk.c, "", OFF),
+ CLK_DUMMY("", camss_gp1_clk.c, "", OFF),
+ CLK_DUMMY("", camss_ispif_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_jpeg_jpeg0_clk.c, "", OFF),
+ CLK_DUMMY("", camss_jpeg_jpeg1_clk.c, "", OFF),
+ CLK_DUMMY("", camss_jpeg_jpeg2_clk.c, "", OFF),
+ CLK_DUMMY("", camss_jpeg_jpeg_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_jpeg_jpeg_axi_clk.c, "", OFF),
+ CLK_DUMMY("", camss_mclk0_clk.c, "", OFF),
+ CLK_DUMMY("", camss_mclk1_clk.c, "", OFF),
+ CLK_DUMMY("", camss_mclk2_clk.c, "", OFF),
+ CLK_DUMMY("", camss_mclk3_clk.c, "", OFF),
+ CLK_DUMMY("", camss_micro_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_phy0_csi0phytimer_clk.c, "", OFF),
+ CLK_DUMMY("", camss_phy1_csi1phytimer_clk.c, "", OFF),
+ CLK_DUMMY("", camss_phy2_csi2phytimer_clk.c, "", OFF),
+ CLK_DUMMY("", camss_top_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_vfe_cpp_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_vfe_cpp_clk.c, "", OFF),
+ CLK_DUMMY("", camss_vfe_vfe0_clk.c, "", OFF),
+ CLK_DUMMY("", camss_vfe_vfe1_clk.c, "", OFF),
+ CLK_DUMMY("", camss_vfe_vfe_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_vfe_vfe_axi_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_axi_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_byte0_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_byte1_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_edpaux_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_edplink_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_edppixel_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_esc0_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_esc1_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_extpclk_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_hdmi_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_hdmi_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_mdp_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_mdp_lut_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_pclk0_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_pclk1_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_vsync_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_misc_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_mmssnoc_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_mmssnoc_axi_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_s0_axi_clk.c, "", OFF),
+ CLK_DUMMY("", ocmemcx_ocmemnoc_clk.c, "", OFF),
+ CLK_DUMMY("", oxili_ocmemgx_clk.c, "", OFF),
+ CLK_DUMMY("", oxili_gfx3d_clk.c, "", OFF),
+ CLK_DUMMY("", oxili_rbbmtimer_clk.c, "", OFF),
+ CLK_DUMMY("", oxilicx_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_axi_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_core0_vcodec_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_core1_vcodec_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_ocmemnoc_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_vcodec0_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_axi_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_bus_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_cxo_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_maple_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_vdp_clk.c, "", OFF),
+};
+
+struct clock_init_data msm8084_clock_init_data __initdata = {
+ .table = msm_clocks_8084,
+ .size = ARRAY_SIZE(msm_clocks_8084),
+};
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index af027f0..ac5efc1 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -169,14 +169,14 @@
VDD_DIG_NUM
};
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
[VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
[VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
[VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
};
-static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
#define RPM_MISC_CLK_TYPE 0x306b6c63
#define RPM_BUS_CLK_TYPE 0x316b6c63
@@ -2753,19 +2753,21 @@
VDD_SR2_PLL_NUM
};
-static const int *vdd_sr2_levels[] = {
+static int *vdd_sr2_levels[] = {
[VDD_SR2_PLL_OFF] = VDD_UV(0, RPM_REGULATOR_CORNER_NONE),
[VDD_SR2_PLL_SVS] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_SR2_PLL_NOM] = VDD_UV(1800000, RPM_REGULATOR_CORNER_NORMAL),
[VDD_SR2_PLL_TUR] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SUPER_TURBO),
};
-static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2, vdd_sr2_levels);
+static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2,
+ vdd_sr2_levels, NULL);
static struct pll_freq_tbl apcs_pll_freq[] = {
F_APCS_PLL( 384000000, 20, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 787200000, 41, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL(1094400000, 57, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL(1190400000, 62, 0x0, 0x1, 0x0, 0x0, 0x0),
PLL_F_END
};
@@ -3121,6 +3123,7 @@
CLK_LOOKUP("core_clk", qdss_clk.c, "fc342000.cti"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc343000.cti"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc344000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fd828018.hwevent"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
@@ -3136,10 +3139,10 @@
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33d000.etm"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33e000.etm"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33f000.etm"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33c000.jtagmm"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33d000.jtagmm"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33e000.jtagmm"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33f000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33c000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33d000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33e000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33f000.jtagmm"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc308000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc309000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30a000.cti"),
@@ -3154,6 +3157,9 @@
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc342000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc343000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc344000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fd828018.hwevent"),
+
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c, "fd828018.hwevent"),
/* HSUSB-OTG Clocks */
CLK_LOOKUP("xo", cxo_otg_clk.c, "f9a55000.usb"),
@@ -3277,6 +3283,15 @@
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
+ CLK_LOOKUP("core_clk", venus0_vcodec0_clk.c, "fd8c1024.qcom,gdsc"),
+ CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd8c2304.qcom,gdsc"),
+ CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd8c2304.qcom,gdsc"),
+ CLK_LOOKUP("core_clk", camss_jpeg_jpeg0_clk.c, "fd8c35a4.qcom,gdsc"),
+ CLK_LOOKUP("core_clk", camss_vfe_vfe0_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("csi_clk", camss_csi_vfe0_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("cpp_clk", camss_vfe_cpp_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fd8c4034.qcom,gdsc"),
+
/* MM sensor clocks */
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6f.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 3cb3ea4..aa9368d 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -30,6 +30,7 @@
#include "clock-rpm.h"
#include "clock-voter.h"
#include "clock.h"
+#include "clock-dsi-8610.h"
enum {
GCC_BASE,
@@ -255,6 +256,7 @@
#define MMSS_MMSSNOC_AXI_CBCR 0x506C
#define BIMC_GFX_BCR 0x5090
#define BIMC_GFX_CBCR 0x5094
+#define MMSS_CAMSS_MISC 0x3718
#define AUDIO_CORE_GDSCR 0x7000
#define SPDM_BCR 0x1000
@@ -432,14 +434,14 @@
VDD_DIG_NUM
};
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
[VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
[VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
[VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
};
-static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
#define RPM_MISC_CLK_TYPE 0x306b6c63
#define RPM_BUS_CLK_TYPE 0x316b6c63
@@ -531,14 +533,15 @@
VDD_SR2_PLL_NUM
};
-static const int *vdd_sr2_levels[] = {
+static int *vdd_sr2_levels[] = {
[VDD_SR2_PLL_OFF] = VDD_UV(0, RPM_REGULATOR_CORNER_NONE),
[VDD_SR2_PLL_SVS] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_SR2_PLL_NOM] = VDD_UV(1800000, RPM_REGULATOR_CORNER_NORMAL),
[VDD_SR2_PLL_TUR] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SUPER_TURBO),
};
-static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2, vdd_sr2_levels);
+static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2,
+ vdd_sr2_levels, NULL);
static struct pll_freq_tbl apcs_pll_freq[] = {
F_APCS_PLL( 384000000, 20, 0x0, 0x1, 0x0, 0x0, 0x0),
@@ -1560,21 +1563,85 @@
static DEFINE_CLK_VOTER(mdp_axi_clk_src, &axi_clk_src.c, 200000000);
static DEFINE_CLK_VOTER(mmssnoc_axi_clk_src, &axi_clk_src.c, 200000000);
-static struct clk_freq_tbl ftbl_dsi_pclk_clk[] = {
- F_MDSS( 50000000, dsipll, 10, 0, 0),
- F_MDSS(103330000, dsipll, 9, 0, 0),
- F_END,
+static struct clk_ops dsi_byte_clk_src_ops;
+static struct clk_ops dsi_pixel_clk_src_ops;
+static struct clk_ops dsi_dsi_clk_src_ops;
+
+static struct dsi_pll_vco_clk dsi_vco = {
+ .vco_clk_min = 600000000,
+ .vco_clk_max = 1200000000,
+ .pref_div_ratio = 26,
+ .c = {
+ .parent = &gcc_xo_clk_src.c,
+ .dbg_name = "dsi_vco",
+ .ops = &clk_ops_dsi_vco,
+ CLK_INIT(dsi_vco.c),
+ },
};
+static struct clk dsi_pll_byte = {
+ .parent = &dsi_vco.c,
+ .dbg_name = "dsi_pll_byte",
+ .ops = &clk_ops_dsi_byteclk,
+ CLK_INIT(dsi_pll_byte),
+};
+
+static struct clk dsi_pll_pixel = {
+ .parent = &dsi_vco.c,
+ .dbg_name = "dsi_pll_pixel",
+ .ops = &clk_ops_dsi_dsiclk,
+ CLK_INIT(dsi_pll_pixel),
+};
+
+static struct clk_freq_tbl pixel_freq_tbl[] = {
+ {
+ .src_clk = &dsi_pll_pixel,
+ .div_src_val = BVAL(10, 8, dsipll_mm_source_val),
+ },
+ F_END
+};
+
+#define CFG_RCGR_DIV_MASK BM(4, 0)
+
+static int set_rate_pixel_byte_clk(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk *pll = clk->parent;
+ unsigned long source_rate, div;
+ struct clk_freq_tbl *cur_freq = rcg->current_freq;
+ int rc;
+
+ if (rate == 0)
+ return clk_set_rate(pll, 0);
+
+ source_rate = clk_round_rate(pll, rate);
+ if (!source_rate || ((2 * source_rate) % rate))
+ return -EINVAL;
+
+ div = ((2 * source_rate)/rate) - 1;
+ if (div > CFG_RCGR_DIV_MASK)
+ return -EINVAL;
+
+ rc = clk_set_rate(pll, source_rate);
+ if (rc)
+ return rc;
+
+ cur_freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
+ cur_freq->div_src_val |= BVAL(4, 0, div);
+ rcg->set_rate(rcg, cur_freq);
+
+ return 0;
+}
+
static struct rcg_clk dsi_pclk_clk_src = {
.cmd_rcgr_reg = DSI_PCLK_CMD_RCGR,
.set_rate = set_rate_mnd,
- .freq_tbl = ftbl_dsi_pclk_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = pixel_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
+ .parent = &dsi_pll_pixel,
.dbg_name = "dsi_pclk_clk_src",
- .ops = &clk_ops_rcg_mnd,
+ .ops = &dsi_pixel_clk_src_ops,
VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 103330000),
CLK_INIT(dsi_pclk_clk_src.c),
},
@@ -1686,41 +1753,60 @@
},
};
-static struct clk_freq_tbl ftbl_dsi_clk[] = {
- F_MDSS(155000000, dsipll, 6, 0, 0),
- F_MDSS(310000000, dsipll, 3, 0, 0),
- F_END,
+/*
+ * The DSI clock will always use a divider of 1. However, we still
+ * need to set the right voltage and source.
+ */
+static int set_rate_dsi_clk(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk_freq_tbl *cur_freq = rcg->current_freq;
+
+ rcg->set_rate(rcg, cur_freq);
+
+ return 0;
+}
+
+static struct clk_freq_tbl dsi_freq_tbl[] = {
+ {
+ .src_clk = &dsi_pll_pixel,
+ .div_src_val = BVAL(4, 0, 0) |
+ BVAL(10, 8, dsipll_mm_source_val),
+ },
+ F_END
};
static struct rcg_clk dsi_clk_src = {
.cmd_rcgr_reg = DSI_CMD_RCGR,
.set_rate = set_rate_mnd,
- .freq_tbl = ftbl_dsi_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = dsi_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
+ .parent = &dsi_pll_pixel,
.dbg_name = "dsi_clk_src",
- .ops = &clk_ops_rcg_mnd,
+ .ops = &dsi_dsi_clk_src_ops,
VDD_DIG_FMAX_MAP2(LOW, 155000000, NOMINAL, 310000000),
CLK_INIT(dsi_clk_src.c),
},
};
-static struct clk_freq_tbl ftbl_dsi_byte_clk[] = {
- F_MDSS( 62500000, dsipll, 12, 0, 0),
- F_MDSS(125000000, dsipll, 6, 0, 0),
- F_END,
+static struct clk_freq_tbl byte_freq_tbl[] = {
+ {
+ .src_clk = &dsi_pll_byte,
+ .div_src_val = BVAL(10, 8, dsipll_mm_source_val),
+ },
+ F_END
};
static struct rcg_clk dsi_byte_clk_src = {
.cmd_rcgr_reg = DSI_BYTE_CMD_RCGR,
.set_rate = set_rate_hid,
- .freq_tbl = ftbl_dsi_byte_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = byte_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
+ .parent = &dsi_pll_byte,
.dbg_name = "dsi_byte_clk_src",
- .ops = &clk_ops_rcg,
+ .ops = &dsi_byte_clk_src_ops,
VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
CLK_INIT(dsi_byte_clk_src.c),
},
@@ -1932,6 +2018,115 @@
},
};
+static struct cam_mux_clk csi0phy_cam_mux_clk = {
+ .enable_reg = MMSS_CAMSS_MISC,
+ .enable_mask = BIT(11),
+ .select_reg = MMSS_CAMSS_MISC,
+ .select_mask = BIT(9),
+ .sources = (struct mux_source[]) {
+ { &csi0phy_clk.c, 0 },
+ { &csi1phy_clk.c, BIT(9) },
+ { 0 },
+ },
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "csi0phy_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(csi0phy_cam_mux_clk.c),
+ },
+};
+
+static struct cam_mux_clk csi1phy_cam_mux_clk = {
+ .enable_reg = MMSS_CAMSS_MISC,
+ .enable_mask = BIT(10),
+ .select_reg = MMSS_CAMSS_MISC,
+ .select_mask = BIT(8),
+ .sources = (struct mux_source[]) {
+ { &csi0phy_clk.c, 0 },
+ { &csi1phy_clk.c, BIT(8) },
+ { 0 },
+ },
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "csi1phy_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(csi1phy_cam_mux_clk.c),
+ },
+};
+
+static struct cam_mux_clk csi0pix_cam_mux_clk = {
+ .enable_reg = MMSS_CAMSS_MISC,
+ .enable_mask = BIT(7),
+ .select_reg = MMSS_CAMSS_MISC,
+ .select_mask = BIT(3),
+ .sources = (struct mux_source[]) {
+ { &csi0pix_clk.c, 0 },
+ { &csi1pix_clk.c, BIT(3) },
+ { 0 },
+ },
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "csi0pix_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(csi0pix_cam_mux_clk.c),
+ },
+};
+
+
+static struct cam_mux_clk rdi2_cam_mux_clk = {
+ .enable_reg = MMSS_CAMSS_MISC,
+ .enable_mask = BIT(6),
+ .select_reg = MMSS_CAMSS_MISC,
+ .select_mask = BIT(2),
+ .sources = (struct mux_source[]) {
+ { &csi0rdi_clk.c, 0 },
+ { &csi1rdi_clk.c, BIT(2) },
+ { 0 },
+ },
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "rdi2_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(rdi2_cam_mux_clk.c),
+ },
+};
+
+static struct cam_mux_clk rdi1_cam_mux_clk = {
+ .enable_reg = MMSS_CAMSS_MISC,
+ .enable_mask = BIT(5),
+ .select_reg = MMSS_CAMSS_MISC,
+ .select_mask = BIT(1),
+ .sources = (struct mux_source[]) {
+ { &csi0rdi_clk.c, 0 },
+ { &csi1rdi_clk.c, BIT(1) },
+ { 0 },
+ },
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "rdi1_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(rdi1_cam_mux_clk.c),
+ },
+};
+
+static struct cam_mux_clk rdi0_cam_mux_clk = {
+ .enable_reg = MMSS_CAMSS_MISC,
+ .enable_mask = BIT(4),
+ .select_reg = MMSS_CAMSS_MISC,
+ .select_mask = BIT(0),
+ .sources = (struct mux_source[]) {
+ { &csi0rdi_clk.c, 0 },
+ { &csi1rdi_clk.c, BIT(0) },
+ { 0 },
+ },
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "rdi0_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(rdi0_cam_mux_clk.c),
+ },
+};
+
static struct branch_clk csi_ahb_clk = {
.cbcr_reg = CSI_AHB_CBCR,
.has_sibling = 1,
@@ -2004,7 +2199,6 @@
static struct branch_clk dsi_pclk_clk = {
.cbcr_reg = DSI_PCLK_CBCR,
- .has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
.parent = &dsi_pclk_clk_src.c,
@@ -2302,7 +2496,7 @@
{ &gcc_ce1_axi_clk.c, GCC_BASE, 0x0139},
{ &gcc_ce1_ahb_clk.c, GCC_BASE, 0x013a},
{ &gcc_xo_clk_src.c, GCC_BASE, 0x0149},
- { &bimc_clk.c, GCC_BASE, 0x0154},
+ { &bimc_clk.c, GCC_BASE, 0x015d},
{ &gcc_bimc_smmu_clk.c, GCC_BASE, 0x015e},
{ &gcc_lpass_q6_axi_clk.c, GCC_BASE, 0x0160},
@@ -2346,11 +2540,11 @@
{ &q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
{ &q6ss_xo_clk.c, LPASS_BASE, 0x002b},
- {&apc0_m_clk, APCS_BASE, 0x10},
- {&apc1_m_clk, APCS_BASE, 0x11},
- {&apc2_m_clk, APCS_BASE, 0x12},
- {&apc3_m_clk, APCS_BASE, 0x13},
- {&l2_m_clk, APCS_BASE, 0x15},
+ {&apc0_m_clk, APCS_BASE, 0x00010},
+ {&apc1_m_clk, APCS_BASE, 0x00114},
+ {&apc2_m_clk, APCS_BASE, 0x00220},
+ {&apc3_m_clk, APCS_BASE, 0x00324},
+ {&l2_m_clk, APCS_BASE, 0x01000},
{&dummy_clk, N_BASES, 0x0000},
};
@@ -2417,6 +2611,8 @@
clk->multiplier = 4;
clk_sel = 0x16A;
regval = measure_mux[i].debug_mux;
+ /* Use a divider value of 4. */
+ regval |= BVAL(31, 30, 0x3);
writel_relaxed(regval, APCS_REG_BASE(GLB_CLK_DIAG));
break;
@@ -2679,19 +2875,21 @@
CLK_LOOKUP("core_clk_src", sdcc1_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", sdcc2_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", usb_hs_system_clk_src.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.i2c"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
- CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.spi"),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, "f9923000.spi"),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9927000.i2c"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, "f9923000.i2c"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, "f9927000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup5_spi_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9928000.i2c"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, "f9928000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup6_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_uart1_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, ""),
@@ -2773,6 +2971,13 @@
CLK_LOOKUP("core_clk", vfe_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", vfe_axi_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi0pix_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi0phy_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi1phy_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", rdi2_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", rdi1_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", rdi0_cam_mux_clk.c, ""),
+
CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fdc00000.qcom,kgsl-3d0"),
CLK_LOOKUP("iface_clk", oxili_ahb_clk.c, "fdc00000.qcom,kgsl-3d0"),
CLK_LOOKUP("mem_iface_clk", bimc_gfx_clk.c, "fdc00000.qcom,kgsl-3d0"),
@@ -2856,6 +3061,7 @@
CLK_DUMMY("core_clk", NULL, "fd870000.qcom,iommu", OFF),
CLK_DUMMY("iface_clk", NULL, "fd880000.qcom,iommu", OFF),
CLK_DUMMY("core_clk", NULL, "fd880000.qcom,iommu", OFF),
+ CLK_DUMMY("alt_core_clk", NULL, "fd880000.qcom,iommu", OFF),
CLK_DUMMY("iface_clk", NULL, "fd000000.qcom,iommu", OFF),
CLK_DUMMY("core_clk", NULL, "fd000000.qcom,iommu", OFF),
CLK_DUMMY("iface_clk", NULL, "fd010000.qcom,iommu", OFF),
@@ -2904,23 +3110,6 @@
.main_output_mask = BIT(0),
};
-#define PLL_AUX_OUTPUT_BIT 1
-#define PLL_AUX2_OUTPUT_BIT 2
-
-#define PWR_ON_MASK BIT(31)
-#define EN_REST_WAIT_MASK (0xF << 20)
-#define EN_FEW_WAIT_MASK (0xF << 16)
-#define CLK_DIS_WAIT_MASK (0xF << 12)
-#define SW_OVERRIDE_MASK BIT(2)
-#define HW_CONTROL_MASK BIT(1)
-#define SW_COLLAPSE_MASK BIT(0)
-
-/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
-#define EN_REST_WAIT_VAL (0x2 << 20)
-#define EN_FEW_WAIT_VAL (0x2 << 16)
-#define CLK_DIS_WAIT_VAL (0x2 << 12)
-#define GDSC_TIMEOUT_US 50000
-
static void __init reg_init(void)
{
u32 regval;
@@ -2957,6 +3146,26 @@
clk_set_rate(&mclk1_clk_src.c, mclk1_clk_src.freq_tbl[0].freq_hz);
}
+static void dsi_init(void)
+{
+ dsi_byte_clk_src_ops = clk_ops_rcg;
+ dsi_byte_clk_src_ops.set_rate = set_rate_pixel_byte_clk;
+ dsi_byte_clk_src_ops.handoff = byte_rcg_handoff;
+ dsi_byte_clk_src_ops.get_parent = NULL;
+
+ dsi_dsi_clk_src_ops = clk_ops_rcg_mnd;
+ dsi_dsi_clk_src_ops.set_rate = set_rate_dsi_clk;
+ dsi_dsi_clk_src_ops.handoff = pixel_rcg_handoff;
+ dsi_dsi_clk_src_ops.get_parent = NULL;
+
+ dsi_pixel_clk_src_ops = clk_ops_rcg_mnd;
+ dsi_pixel_clk_src_ops.set_rate = set_rate_pixel_byte_clk;
+ dsi_pixel_clk_src_ops.handoff = pixel_rcg_handoff;
+ dsi_pixel_clk_src_ops.get_parent = NULL;
+
+ dsi_clk_ctrl_init(&dsi_ahb_clk.c);
+}
+
#define GCC_CC_PHYS 0xFC400000
#define GCC_CC_SIZE SZ_16K
@@ -3016,6 +3225,8 @@
reg_init();
+ dsi_init();
+
/* Maintain the max nominal frequency on the MMSSNOC AHB bus. */
clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
clk_prepare_enable(&mmssnoc_ahb_a_clk.c);
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index be6d965..9ee4476 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -6406,79 +6406,14 @@
.main_output_mask = BIT(23),
};
-static void __init reg_init(void)
+
+static void __init init_mm_cc(void)
{
- void __iomem *imem_reg;
-
- /* Deassert MM SW_RESET_ALL signal. */
- writel_relaxed(0, SW_RESET_ALL_REG);
-
/*
- * Some bits are only used on 8960 or 8064 or 8930 and are marked as
- * reserved bits on the other SoCs. Writing to these reserved bits
- * should have no effect.
- */
- /*
- * Initialize MM AHB registers: Enable the FPB clock and disable HW
- * gating on 8627 and 8930ab for all clocks. Also set VFE_AHB's
- * FORCE_CORE_ON bit to prevent its memory from being collapsed when
- * the clock is halted. The sleep and wake-up delays are set to safe
- * values.
- */
- if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
- rmwreg(0x00000003, AHB_EN_REG, 0x6C000103);
- writel_relaxed(0x000007F9, AHB_EN2_REG);
- } else {
- rmwreg(0x40000000, AHB_EN_REG, 0x6C000103);
- writel_relaxed(0x3C7097F9, AHB_EN2_REG);
- }
-
- if (soc_class_is_apq8064())
- rmwreg(0x00000000, AHB_EN3_REG, 0x00000001);
-
- /* Deassert all locally-owned MM AHB resets. */
- rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
- rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
-
- /* Initialize MM AXI registers: Enable HW gating for all clocks that
- * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
- * delays to safe values. */
- if ((cpu_is_msm8960() &&
- SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 3) ||
- cpu_is_msm8627() || cpu_is_msm8930ab()) {
- rmwreg(0x000007F9, MAXI_EN_REG, 0x0803FFFF);
- rmwreg(0x3027FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
- } else {
- rmwreg(0x0003AFF9, MAXI_EN_REG, 0x0803FFFF);
- rmwreg(0x3A27FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
- }
-
- rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
- rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
-
- if (soc_class_is_apq8064())
- rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
- if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627() ||
- cpu_is_msm8930ab())
- rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
- if (cpu_is_msm8960ab())
- rmwreg(0x009FE000, MAXI_EN5_REG, 0x01FFE000);
-
- if (cpu_is_msm8627() || cpu_is_msm8930ab())
- rmwreg(0x000003C7, SAXI_EN_REG, 0x00003FFF);
- else
- rmwreg(0x00003C38, SAXI_EN_REG, 0x00003FFF);
-
- /* Enable IMEM's clk_on signal */
- imem_reg = ioremap(0x04b00040, 4);
- if (imem_reg) {
- writel_relaxed(0x3, imem_reg);
- iounmap(imem_reg);
- }
-
- /* Initialize MM CC registers: Set MM FORCE_CORE_ON bits so that core
+ * Initialize MM CC registers: Set MM FORCE_CORE_ON bits so that core
* memories retain state even when not clocked. Also, set sleep and
- * wake-up delays to safe values. */
+ * wake-up delays to safe values.
+ */
rmwreg(0x00000000, CSI0_CC_REG, 0x00000410);
rmwreg(0x00000000, CSI1_CC_REG, 0x00000410);
rmwreg(0x80FF0000, DSI1_BYTE_CC_REG, 0xE0FF0010);
@@ -6493,28 +6428,72 @@
rmwreg(0x80FF0000, VFE_CC_REG, 0xE0FF4010);
rmwreg(0x800000FF, VFE_CC2_REG, 0xE00000FF);
rmwreg(0x80FF0000, VPE_CC_REG, 0xE0FF0010);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || soc_class_is_apq8064()) {
- rmwreg(0x80FF0000, DSI2_BYTE_CC_REG, 0xE0FF0010);
- rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
- rmwreg(0x80FF0000, JPEGD_CC_REG, 0xE0FF0010);
- }
- if (cpu_is_msm8960ab())
- rmwreg(0x00000001, DSI2_PIXEL_CC2_REG, 0x00000001);
+}
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_msm8627() || cpu_is_msm8930ab())
- rmwreg(0x80FF0000, TV_CC_REG, 0xE1FFC010);
- if (cpu_is_msm8960ab())
- rmwreg(0x00000000, TV_CC_REG, 0x00004010);
+static void __init enable_imem_clk(unsigned long phys)
+{
+ void __iomem *imem_reg;
- if (cpu_is_msm8960()) {
- rmwreg(0x80FF0000, GFX2D0_CC_REG, 0xE0FF0010);
- rmwreg(0x80FF0000, GFX2D1_CC_REG, 0xE0FF0010);
+ /* Enable IMEM's clk_on signal */
+ imem_reg = ioremap(phys, SZ_4);
+ if (imem_reg) {
+ writel_relaxed(0x3, imem_reg);
+ iounmap(imem_reg);
}
- if (soc_class_is_apq8064()) {
- rmwreg(0x00000000, TV_CC_REG, 0x00004010);
- rmwreg(0x80FF0000, VCAP_CC_REG, 0xE0FF1010);
+}
+
+static void __init reg_init_8930(void)
+{
+ /* MM-AHB default values */
+ u32 en_reg = 0x40000000, en2_reg = 0x3C7097F9;
+ /* MM-AXI default values */
+ u32 aen_reg = 0x0003AFF9, aen2_reg = 0x3A27FCFF,
+ saen_reg = 0x00003C38;
+
+
+ /* Deassert MM SW_RESET_ALL signal. */
+ writel_relaxed(0, SW_RESET_ALL_REG);
+
+ /*
+ * Initialize MM AHB registers: Enable the FPB clock and disable HW
+ * gating on 8627 and 8930ab for all clocks. Also set VFE_AHB's
+ * FORCE_CORE_ON bit to prevent its memory from being collapsed when
+ * the clock is halted. The sleep and wake-up delays are set to safe
+ * values.
+ */
+ if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
+ en_reg = 0x00000003;
+ en2_reg = 0x000007F9;
}
+ rmwreg(en_reg, AHB_EN_REG, 0x6C000103);
+ writel_relaxed(en2_reg, AHB_EN2_REG);
+
+ /* Deassert all locally-owned MM AHB resets. */
+ rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+ rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
+
+ /*
+ * Initialize MM AXI registers: Enable HW gating for all clocks that
+ * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+ * delays to safe values.
+ */
+ if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
+ aen_reg = 0x000007F9;
+ aen2_reg = 0x3027FCFF;
+ }
+ rmwreg(aen_reg, MAXI_EN_REG, 0x0803FFFF);
+ rmwreg(aen2_reg, MAXI_EN2_REG, 0x3A3FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+ rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
+ if (cpu_is_msm8627() || cpu_is_msm8930ab())
+ saen_reg = 0x000003C7;
+ rmwreg(saen_reg, SAXI_EN_REG, 0x00003FFF);
+
+ enable_imem_clk(0x04b00040);
+
+ init_mm_cc();
+ rmwreg(0x80FF0000, TV_CC_REG, 0xE1FFC010);
/*
* Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
@@ -6522,10 +6501,6 @@
* and wake-up value to max.
*/
rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
- if (soc_class_is_apq8064()) {
- rmwreg(0x0000004F, USB_HS3_HCLK_FS_REG, 0x0000007F);
- rmwreg(0x0000004F, USB_HS4_HCLK_FS_REG, 0x0000007F);
- }
/* De-assert MM AXI resets to all hardware blocks. */
writel_relaxed(0, SW_RESET_AXI_REG);
@@ -6538,88 +6513,231 @@
writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
writel_relaxed(BIT(15), PDM_CLK_NS_REG);
- /* Source SLIMBus xo src from slimbus reference clock */
- if (cpu_is_msm8960ab() || cpu_is_msm8960())
- writel_relaxed(0x3, SLIMBUS_XO_SRC_CLK_CTL_REG);
-
- /* Source the dsi_byte_clks from the DSI PHY PLLs */
+ /* Source the dsi1_byte_clks/dsi1_esc_clk from the DSI PHY PLLs */
rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || soc_class_is_apq8064())
- rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
-
- /* Source the dsi1_esc_clk from the DSI1 PHY PLLs */
rmwreg(0x1, DSI1_ESC_NS_REG, 0x7);
/*
+ * Change PLL15 configuration based on the SoC we're running on.
+ *
+ * Default pll15 l, m, n values for 8930/8930aa/8627()
+ */
+ pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
+ pll15_config.m = 0x1;
+ pll15_config.n = 0x3;
+
+ if (cpu_is_msm8930ab()) {
+ pll15_config.l = 0x25 | BVAL(31, 7, 0x600);
+ pll15_config.m = 0x25;
+ pll15_config.n = 0x3E7;
+ }
+ configure_sr_pll(&pll15_config, &pll15_regs, 0);
+
+ /* Disable AUX and BIST outputs */
+ writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
+}
+
+static void __init reg_init_8064(void)
+{
+ u32 is_pll_enabled;
+
+ /* Deassert MM SW_RESET_ALL signal. */
+ writel_relaxed(0, SW_RESET_ALL_REG);
+
+ /*
+ * Initialize MM AHB registers:
+ * Also set VFE_AHB's FORCE_CORE_ON bit to prevent its memory
+ * from being collapsed when the clock is halted. The sleep and
+ * wake-up delays are set to safe values.
+ */
+ rmwreg(0x40000000, AHB_EN_REG, 0x6C000103);
+ writel_relaxed(0x3C7097F9, AHB_EN2_REG);
+ rmwreg(0x00000000, AHB_EN3_REG, 0x00000001);
+
+ /* Deassert all locally-owned MM AHB resets. */
+ rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+ rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
+
+ /*
+ * Initialize MM AXI registers: Enable HW gating for all clocks that
+ * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+ * delays to safe values.
+ */
+ rmwreg(0x0003AFF9, MAXI_EN_REG, 0x0803FFFF);
+ rmwreg(0x3A27FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+ rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
+ rmwreg(0x00003C38, SAXI_EN_REG, 0x00003FFF);
+
+ enable_imem_clk(0x04b00040);
+
+ init_mm_cc();
+ rmwreg(0x80FF0000, DSI2_BYTE_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, JPEGD_CC_REG, 0xE0FF0010);
+ rmwreg(0x00000000, TV_CC_REG, 0x00004010);
+ rmwreg(0x80FF0000, VCAP_CC_REG, 0xE0FF1010);
+
+ /*
+ * Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
+ * core remain active during halt state of the clk. Also, set sleep
+ * and wake-up value to max.
+ */
+ rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
+ rmwreg(0x0000004F, USB_HS3_HCLK_FS_REG, 0x0000007F);
+ rmwreg(0x0000004F, USB_HS4_HCLK_FS_REG, 0x0000007F);
+
+ /* De-assert MM AXI resets to all hardware blocks. */
+ writel_relaxed(0, SW_RESET_AXI_REG);
+
+ /* Deassert all MM core resets. */
+ writel_relaxed(0, SW_RESET_CORE_REG);
+ writel_relaxed(0, SW_RESET_CORE2_REG);
+
+ /* Enable TSSC and PDM PXO sources. */
+ writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
+ writel_relaxed(BIT(15), PDM_CLK_NS_REG);
+
+ /* Source the dsi1_byte_clks/dsi1_esc_clk from the DSI PHY PLLs */
+ rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
+ rmwreg(0x1, DSI1_ESC_NS_REG, 0x7);
+
+ /* Source the dsi2_byte_clks from the DSI PHY PLLs */
+ rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
+
+ /*
* Source the sata_phy_ref_clk from PXO and set predivider of
* sata_pmalive_clk to 1.
*/
- if (soc_class_is_apq8064()) {
- rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
- rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
- }
+ rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
+ rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
/*
* TODO: Programming below PLLs and prng_clk is temporary and
* needs to be removed after bootloaders program them.
*/
- if (soc_class_is_apq8064()) {
- u32 is_pll_enabled;
- /* Program pxo_src_clk to source from PXO */
- rmwreg(0x1, PXO_SRC_CLK_CTL_REG, 0x7);
+ /* Program pxo_src_clk to source from PXO */
+ rmwreg(0x1, PXO_SRC_CLK_CTL_REG, 0x7);
- /* Check if PLL14 is active */
- is_pll_enabled = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
- if (!is_pll_enabled)
- /* Ref clk = 27MHz and program pll14 to 480MHz */
- configure_sr_pll(&pll14_config, &pll14_regs, 1);
+ /* Check if PLL14 is active */
+ is_pll_enabled = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
+ if (!is_pll_enabled)
+ /* Ref clk = 27MHz and program pll14 to 480MHz */
+ configure_sr_pll(&pll14_config, &pll14_regs, 1);
- /* Check if PLL4 is active */
- is_pll_enabled = readl_relaxed(LCC_PLL0_STATUS_REG) & BIT(16);
- if (!is_pll_enabled)
- /* Ref clk = 27MHz and program pll4 to 393.2160MHz */
- configure_sr_pll(&pll4_config_393, &pll4_regs, 1);
+ /* Check if PLL4 is active */
+ is_pll_enabled = readl_relaxed(LCC_PLL0_STATUS_REG) & BIT(16);
+ if (!is_pll_enabled)
+ /* Ref clk = 27MHz and program pll4 to 393.2160MHz */
+ configure_sr_pll(&pll4_config_393, &pll4_regs, 1);
- /* Enable PLL4 source on the LPASS Primary PLL Mux */
- writel_relaxed(0x1, LCC_PRI_PLL_CLK_CTL_REG);
+ /* Enable PLL4 source on the LPASS Primary PLL Mux */
+ writel_relaxed(0x1, LCC_PRI_PLL_CLK_CTL_REG);
- /* Program prng_clk to 64MHz if it isn't configured */
- if (!readl_relaxed(PRNG_CLK_NS_REG))
- writel_relaxed(0x2B, PRNG_CLK_NS_REG);
- }
+ /* Program prng_clk to 64MHz if it isn't configured */
+ if (!readl_relaxed(PRNG_CLK_NS_REG))
+ writel_relaxed(0x2B, PRNG_CLK_NS_REG);
- if (cpu_is_apq8064() || cpu_is_apq8064aa()) {
- /* Program PLL15 to 975MHz with ref clk = 27MHz */
- configure_sr_pll(&pll15_config, &pll15_regs, 0);
- } else if (cpu_is_apq8064ab()) {
+ if (cpu_is_apq8064ab()) {
/* Program PLL15 to 900MHZ */
pll15_config.l = 0x21 | BVAL(31, 7, 0x620);
pll15_config.m = 0x1;
pll15_config.n = 0x3;
- configure_sr_pll(&pll15_config, &pll15_regs, 0);
- } else if (cpu_is_msm8960ab()) {
- pll3_clk.c.rate = 880000000;
- configure_sr_pll(&pll3_config, &pll3_regs, 0);
+ }
+ /*
+ * Default Program PLL15 to 975MHz with ref clk = 27MHz
+ * In case of apq8064ab PLL15 is set to 900MHZ
+ */
+ configure_sr_pll(&pll15_config, &pll15_regs, 0);
+}
+
+static void __init reg_init_8960(void)
+{
+ u32 aen_reg = 0x0003AFF9, aen2_reg = 0x3A27FCFF;
+
+ /* Deassert MM SW_RESET_ALL signal. */
+ writel_relaxed(0, SW_RESET_ALL_REG);
+
+ /*
+ * Initialize MM AHB registers:
+ * Also set VFE_AHB's FORCE_CORE_ON bit to prevent its memory
+ * from being collapsed when the clock is halted. The sleep and
+ * wake-up delays are set to safe values.
+ */
+ rmwreg(0x40000000, AHB_EN_REG, 0x6C000103);
+ writel_relaxed(0x3C7097F9, AHB_EN2_REG);
+
+ /* Deassert all locally-owned MM AHB resets. */
+ rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+ rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
+
+ /*
+ * Initialize MM AXI registers: Enable HW gating for all clocks that
+ * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+ * delays to safe values.
+ */
+ if (cpu_is_msm8960() &&
+ SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 3) {
+ aen_reg = 0x000007F9;
+ aen2_reg = 0x3027FCFF;
+ }
+ rmwreg(aen_reg, MAXI_EN_REG, 0x0803FFFF);
+ rmwreg(aen2_reg, MAXI_EN2_REG, 0x3A3FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+ if (cpu_is_msm8960ab())
+ rmwreg(0x009FE000, MAXI_EN5_REG, 0x01FFE000);
+ rmwreg(0x00003C38, SAXI_EN_REG, 0x00003FFF);
+
+ enable_imem_clk(0x04b00040);
+
+ init_mm_cc();
+ rmwreg(0x80FF0000, DSI2_BYTE_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, JPEGD_CC_REG, 0xE0FF0010);
+ if (cpu_is_msm8960ab()) {
+ rmwreg(0x00000001, DSI2_PIXEL_CC2_REG, 0x00000001);
+ rmwreg(0x00000000, TV_CC_REG, 0x00004010);
+ }
+ if (cpu_is_msm8960()) {
+ rmwreg(0x80FF0000, TV_CC_REG, 0xE1FFC010);
+ rmwreg(0x80FF0000, GFX2D0_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, GFX2D1_CC_REG, 0xE0FF0010);
}
/*
- * Change PLL15 configuration based on the SoC we're running on.
+ * Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
+ * core remain active during halt state of the clk. Also, set sleep
+ * and wake-up value to max.
*/
- if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
- pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
- pll15_config.m = 0x1;
- pll15_config.n = 0x3;
- configure_sr_pll(&pll15_config, &pll15_regs, 0);
- /* Disable AUX and BIST outputs */
- writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
- } else if (cpu_is_msm8930ab()) {
- pll15_config.l = 0x25 | BVAL(31, 7, 0x600);
- pll15_config.m = 0x25;
- pll15_config.n = 0x3E7;
- configure_sr_pll(&pll15_config, &pll15_regs, 0);
- /* Disable AUX and BIST outputs */
- writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
+ rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
+
+ /* De-assert MM AXI resets to all hardware blocks. */
+ writel_relaxed(0, SW_RESET_AXI_REG);
+
+ /* Deassert all MM core resets. */
+ writel_relaxed(0, SW_RESET_CORE_REG);
+ writel_relaxed(0, SW_RESET_CORE2_REG);
+
+ /* Enable TSSC and PDM PXO sources. */
+ writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
+ writel_relaxed(BIT(15), PDM_CLK_NS_REG);
+
+ /* Source the dsi1_byte_clks/dsi1_esc_clk from the DSI PHY PLLs */
+ rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
+ rmwreg(0x1, DSI1_ESC_NS_REG, 0x7);
+
+ /* Source SLIMBus xo src from slimbus reference clock */
+ writel_relaxed(0x3, SLIMBUS_XO_SRC_CLK_CTL_REG);
+
+ /* Source the dsi2_byte_clks from the DSI PHY PLLs */
+ rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
+
+ if (cpu_is_msm8960ab()) {
+ pll3_clk.c.rate = 880000000;
+ configure_sr_pll(&pll3_config, &pll3_regs, 0);
}
}
@@ -6645,13 +6763,15 @@
}
struct clock_init_data msm8960_clock_init_data __initdata;
+
static void __init msm8960_clock_pre_init(void)
{
- /* Initialize clock registers. */
- reg_init();
+ struct clk_lookup *clk_lkup;
+ size_t clk_size;
+ struct clk_freq_tbl *tbl;
- if (soc_class_is_apq8064())
- vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
+ /* Initialize clock registers. */
+ reg_init_8960();
/* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
@@ -6665,73 +6785,120 @@
pcm_clk.freq_tbl = clk_tbl_pcm_492;
}
- if (cpu_is_msm8960() || cpu_is_msm8960ab())
- memcpy(msm_clocks_8960, msm_clocks_8960_common,
- sizeof(msm_clocks_8960_common));
- if (cpu_is_msm8960ab()) {
- gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8960ab;
- mdp_clk.c.fmax = fmax_mdp_8960ab;
-
- gfx3d_clk.c.fmax = select_gfx_fmax_plan(fmax_gfx3d_8960ab,
- ARRAY_SIZE(fmax_gfx3d_8960ab));
-
- memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
- msm_clocks_8960ab_only, sizeof(msm_clocks_8960ab_only));
- msm8960_clock_init_data.size -=
- ARRAY_SIZE(msm_clocks_8960_only);
-
- gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
- } else if (cpu_is_msm8960()) {
- gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8960;
- memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
- msm_clocks_8960_only, sizeof(msm_clocks_8960_only));
+ if (cpu_is_msm8960()) {
+ tbl = clk_tbl_gfx3d_8960;
+ clk_lkup = msm_clocks_8960_only;
+ clk_size = sizeof(msm_clocks_8960_only);
msm8960_clock_init_data.size -=
ARRAY_SIZE(msm_clocks_8960ab_only);
}
- /*
- * Change the freq tables for and voltage requirements for
- * clocks which differ between chips.
- */
- if (cpu_is_apq8064() || cpu_is_apq8064aa())
- gfx3d_clk.c.fmax = fmax_gfx3d_8064;
+
+ if (cpu_is_msm8960ab()) {
+ mdp_clk.c.fmax = fmax_mdp_8960ab;
+ gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
+ tbl = clk_tbl_gfx3d_8960ab;
+ gfx3d_clk.c.fmax = select_gfx_fmax_plan(fmax_gfx3d_8960ab,
+ ARRAY_SIZE(fmax_gfx3d_8960ab));
+
+ clk_lkup = msm_clocks_8960ab_only;
+ clk_size = sizeof(msm_clocks_8960ab_only);
+ msm8960_clock_init_data.size -=
+ ARRAY_SIZE(msm_clocks_8960_only);
+ }
+
+ gfx3d_clk.freq_tbl = tbl;
+
+ memcpy(msm_clocks_8960, msm_clocks_8960_common,
+ sizeof(msm_clocks_8960_common));
+ memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
+ clk_lkup, clk_size);
+
+ if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
+ prng_clk.freq_tbl = clk_tbl_prng_64;
+
+ clk_ops_local_pll.enable = sr_pll_clk_enable;
+}
+
+static void __init msm8064_clock_pre_init(void)
+{
+ unsigned long *fmax = fmax_gfx3d_8064;
+
+ /* Initialize clock registers. */
+ reg_init_8064();
+
+ vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
+
+ /* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
+ if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
+ pll4_clk.c.rate = 491520000;
+ audio_slimbus_clk.freq_tbl = clk_tbl_aif_osr_492;
+ mi2s_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ pcm_clk.freq_tbl = clk_tbl_pcm_492;
+ }
if (cpu_is_apq8064ab())
- gfx3d_clk.c.fmax = fmax_gfx3d_8064ab;
+ fmax = fmax_gfx3d_8064ab;
if ((cpu_is_apq8064() &&
SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) ||
cpu_is_apq8064ab() || cpu_is_apq8064aa()) {
-
vcodec_clk.c.fmax = fmax_vcodec_8064v2;
ce3_src_clk.c.fmax = fmax_ce3_8064v2;
sdc1_clk.c.fmax = fmax_sdc1_8064v2;
}
- if (soc_class_is_apq8064()) {
- ijpeg_clk.c.fmax = fmax_ijpeg_8064;
- mdp_clk.c.fmax = fmax_mdp_8064;
- tv_src_clk.c.fmax = fmax_tv_src_8064;
- vfe_clk.c.fmax = fmax_vfe_8064;
- gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
+
+ gfx3d_clk.c.fmax = fmax;
+ ijpeg_clk.c.fmax = fmax_ijpeg_8064;
+ mdp_clk.c.fmax = fmax_mdp_8064;
+ tv_src_clk.c.fmax = fmax_tv_src_8064;
+ vfe_clk.c.fmax = fmax_vfe_8064;
+
+ gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
+
+ if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
+ prng_clk.freq_tbl = clk_tbl_prng_64;
+
+ clk_ops_local_pll.enable = sr_pll_clk_enable;
+}
+
+static void __init __msm8930_clock_pre_init(void)
+{
+ unsigned long rate = 900000000;
+ unsigned long *fmax = fmax_gfx3d_8930;
+
+ /* Initialize clock registers. */
+ reg_init_8930();
+
+ /* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
+ if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
+ pll4_clk.c.rate = 491520000;
+ audio_slimbus_clk.freq_tbl = clk_tbl_aif_osr_492;
+ mi2s_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ pcm_clk.freq_tbl = clk_tbl_pcm_492;
}
- /*
- * Change the freq tables and voltage requirements for
- * clocks which differ between 8960 and 8930.
- */
- if (cpu_is_msm8930() || cpu_is_msm8627())
- gfx3d_clk.c.fmax = fmax_gfx3d_8930;
- else if (cpu_is_msm8930aa())
- gfx3d_clk.c.fmax = fmax_gfx3d_8930aa;
- if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
- pll15_clk.c.rate = 900000000;
- gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
- } else if (cpu_is_msm8930ab()) {
+ if (cpu_is_msm8930aa())
+ fmax = fmax_gfx3d_8930aa;
+
+ if (cpu_is_msm8930ab()) {
+ rate = 1000000000;
+ fmax = fmax_gfx3d_8930ab;
gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930ab;
- pll15_clk.c.rate = 1000000000;
- gfx3d_clk.c.fmax = fmax_gfx3d_8930ab;
- gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
vcodec_clk.c.fmax = fmax_vcodec_8930ab;
}
+
+ pll15_clk.c.rate = rate;
+ gfx3d_clk.c.fmax = fmax;
+ gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
+
if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
prng_clk.freq_tbl = clk_tbl_prng_64;
@@ -6746,7 +6913,7 @@
rpm_vreg_dig_8930 = RPM_VREG_ID_PM8917_VDD_DIG_CORNER;
vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930_pm8917;
- msm8960_clock_pre_init();
+ __msm8930_clock_pre_init();
}
static void __init msm8930_clock_pre_init(void)
@@ -6754,10 +6921,10 @@
vdd_dig.set_vdd = set_vdd_dig_8930;
vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930;
- msm8960_clock_pre_init();
+ __msm8930_clock_pre_init();
}
-static void __init msm8960_clock_post_init(void)
+static void __init common_clock_post_init(void)
{
/* Keep PXO on whenever APPS cpu is active */
clk_prepare_enable(&pxo_a_clk.c);
@@ -6777,18 +6944,12 @@
clk_set_rate(&tsif_ref_clk.c, 105000);
clk_set_rate(&tssc_clk.c, 27000000);
clk_set_rate(&usb_hs1_xcvr_clk.c, 60000000);
- if (soc_class_is_apq8064()) {
- clk_set_rate(&usb_hs3_xcvr_clk.c, 60000000);
- clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
- }
clk_set_rate(&usb_fs1_src_clk.c, 60000000);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_msm8930() ||
- cpu_is_msm8930aa() || cpu_is_msm8627() || cpu_is_msm8930ab())
- clk_set_rate(&usb_fs2_src_clk.c, 60000000);
clk_set_rate(&usb_hsic_xcvr_fs_clk.c, 60000000);
clk_set_rate(&usb_hsic_hsic_src_clk.c, 480000000);
clk_set_rate(&usb_hsic_hsio_cal_clk.c, 9000000);
clk_set_rate(&usb_hsic_system_clk.c, 60000000);
+
/*
* Set the CSI rates to a safe default to avoid warnings when
* switching csi pix and rdi clocks.
@@ -6817,6 +6978,19 @@
clk_prepare_enable(&sfab_tmr_a_clk.c);
}
+static void __init msm8960_clock_post_init(void)
+{
+ common_clock_post_init();
+ clk_set_rate(&usb_fs2_src_clk.c, 60000000);
+}
+
+static void __init msm8064_clock_post_init(void)
+{
+ common_clock_post_init();
+ clk_set_rate(&usb_hs3_xcvr_clk.c, 60000000);
+ clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
+}
+
static int __init msm8960_clock_late_init(void)
{
int rc;
@@ -6859,8 +7033,8 @@
struct clock_init_data apq8064_clock_init_data __initdata = {
.table = msm_clocks_8064,
.size = ARRAY_SIZE(msm_clocks_8064),
- .pre_init = msm8960_clock_pre_init,
- .post_init = msm8960_clock_post_init,
+ .pre_init = msm8064_clock_pre_init,
+ .post_init = msm8064_clock_post_init,
.late_init = msm8960_clock_late_init,
};
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 707e6b6..ec94f00 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -638,14 +638,14 @@
VDD_DIG_NUM
};
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
[VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
[VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
[VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
};
-static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
#define RPM_MISC_CLK_TYPE 0x306b6c63
#define RPM_BUS_CLK_TYPE 0x316b6c63
@@ -920,6 +920,7 @@
};
static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk[] = {
+ F(19200000, cxo, 1, 0, 0),
F(50000000, gpll0, 12, 0, 0),
F_END
};
@@ -3193,7 +3194,9 @@
F_HDMI( 25200000, hdmipll, 1, 0, 0),
F_HDMI( 27000000, hdmipll, 1, 0, 0),
F_HDMI( 27030000, hdmipll, 1, 0, 0),
+ F_HDMI( 65000000, hdmipll, 1, 0, 0),
F_HDMI( 74250000, hdmipll, 1, 0, 0),
+ F_HDMI(108000000, hdmipll, 1, 0, 0),
F_HDMI(148500000, hdmipll, 1, 0, 0),
F_HDMI(268500000, hdmipll, 1, 0, 0),
F_HDMI(297000000, hdmipll, 1, 0, 0),
@@ -4894,6 +4897,7 @@
CLK_LOOKUP("alt_iface_clk", mdss_hdmi_ahb_clk.c,
"fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, "fd922100.qcom,hdmi_tx"),
+ CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("extp_clk", mdss_extpclk_clk.c, "fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "mdp.0"),
CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "mdp.0"),
@@ -5121,6 +5125,17 @@
CLK_LOOKUP("bus_clk", venus0_axi_clk.c, "fdc00000.qcom,vidc"),
CLK_LOOKUP("mem_clk", venus0_ocmemnoc_clk.c, "fdc00000.qcom,vidc"),
+ CLK_LOOKUP("core_clk", venus0_vcodec0_clk.c, "fd8c1024.qcom,gdsc"),
+ CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd8c2304.qcom,gdsc"),
+ CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd8c2304.qcom,gdsc"),
+ CLK_LOOKUP("core0_clk", camss_jpeg_jpeg0_clk.c, "fd8c35a4.qcom,gdsc"),
+ CLK_LOOKUP("core1_clk", camss_jpeg_jpeg1_clk.c, "fd8c35a4.qcom,gdsc"),
+ CLK_LOOKUP("core2_clk", camss_jpeg_jpeg2_clk.c, "fd8c35a4.qcom,gdsc"),
+ CLK_LOOKUP("core0_clk", camss_vfe_vfe0_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("core1_clk", camss_vfe_vfe1_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("csi0_clk", camss_csi_vfe0_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("csi1_clk", camss_csi_vfe1_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("cpp_clk", camss_vfe_cpp_clk.c, "fd8c36a4.qcom,gdsc"),
CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fd8c4024.qcom,gdsc"),
/* LPASS clocks */
@@ -5194,6 +5209,7 @@
CLK_LOOKUP("core_clk", qdss_clk.c, "fc342000.cti"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc343000.cti"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc344000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fdf30018.hwevent"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
@@ -5223,6 +5239,9 @@
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc342000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc343000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc344000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fdf30018.hwevent"),
+
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c, "fdf30018.hwevent"),
CLK_LOOKUP("l2_m_clk", l2_m_clk, ""),
CLK_LOOKUP("krait0_m_clk", krait0_m_clk, ""),
@@ -5343,20 +5362,6 @@
.main_output_mask = BIT(0),
};
-#define PWR_ON_MASK BIT(31)
-#define EN_REST_WAIT_MASK (0xF << 20)
-#define EN_FEW_WAIT_MASK (0xF << 16)
-#define CLK_DIS_WAIT_MASK (0xF << 12)
-#define SW_OVERRIDE_MASK BIT(2)
-#define HW_CONTROL_MASK BIT(1)
-#define SW_COLLAPSE_MASK BIT(0)
-
-/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
-#define EN_REST_WAIT_VAL (0x2 << 20)
-#define EN_FEW_WAIT_VAL (0x2 << 16)
-#define CLK_DIS_WAIT_VAL (0x2 << 12)
-#define GDSC_TIMEOUT_US 50000
-
static void __init reg_init(void)
{
u32 regval;
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 4984255..5bfc4bb 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -280,14 +280,14 @@
VDD_DIG_NUM
};
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
[VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
[VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
[VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
};
-static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
/* TODO: Needs to confirm the below values */
#define RPM_MISC_CLK_TYPE 0x306b6c63
@@ -1620,11 +1620,6 @@
{&gcc_sdcc2_ahb_clk.c, GCC_BASE, 0x0071},
{&gcc_ce1_clk.c, GCC_BASE, 0x0138},
{&gcc_sys_noc_ipa_axi_clk.c, GCC_BASE, 0x0007},
- {&gcc_ipa_clk.c, GCC_BASE, 0x01E0},
- {&gcc_ipa_cnoc_clk.c, GCC_BASE, 0x01E1},
- {&gcc_ipa_sleep_clk.c, GCC_BASE, 0x01E2},
- {&gcc_qpic_clk.c, GCC_BASE, 0x01D8},
- {&gcc_qpic_ahb_clk.c, GCC_BASE, 0x01D9},
{&a5_m_clk, APCS_BASE, 0x3},
@@ -1929,6 +1924,7 @@
CLK_LOOKUP("core_clk", qdss_clk.c, "fc30f000.cti"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc310000.cti"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc333000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "f9011038.hwevent"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
@@ -1950,7 +1946,7 @@
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30f000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc333000.cti"),
-
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "f9011038.hwevent"),
};
#define PLL_AUX_OUTPUT_BIT 1
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index d540f2b..fe43b72 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -21,10 +21,23 @@
#include <linux/clk.h>
#include <linux/list.h>
#include <linux/clkdev.h>
+#include <linux/uaccess.h>
#include <mach/clk-provider.h>
#include "clock.h"
+static LIST_HEAD(clk_list);
+static DEFINE_SPINLOCK(clk_list_lock);
+
+static struct dentry *debugfs_base;
+static u32 debug_suspend;
+
+struct clk_table {
+ struct list_head node;
+ struct clk_lookup *clocks;
+ size_t num_clocks;
+};
+
static int clock_debug_rate_set(void *data, u64 val)
{
struct clk *clock = data;
@@ -218,35 +231,68 @@
.release = seq_release,
};
-static int clock_parent_show(struct seq_file *m, void *unused)
+static ssize_t clock_parent_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
{
- struct clk *clock = m->private;
- struct clk *parent = clk_get_parent(clock);
+ struct clk *clock = filp->private_data;
+ struct clk *p = clock->parent;
+ char name[256] = {0};
- seq_printf(m, "%s\n", (parent ? parent->dbg_name : "None"));
+ snprintf(name, sizeof(name), "%s\n", p ? p->dbg_name : "None\n");
- return 0;
+ return simple_read_from_buffer(ubuf, cnt, ppos, name, strlen(name));
}
-static int clock_parent_open(struct inode *inode, struct file *file)
+
+static ssize_t clock_parent_write(struct file *filp,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
{
- return single_open(file, clock_parent_show, inode->i_private);
+ struct clk *clock = filp->private_data;
+ char buf[256];
+ char *cmp;
+ unsigned long flags;
+ struct clk_table *table;
+ int i, ret;
+ struct clk *parent = NULL;
+
+ cnt = min(cnt, sizeof(buf) - 1);
+ if (copy_from_user(&buf, ubuf, cnt))
+ return -EFAULT;
+ buf[cnt] = '\0';
+ cmp = strstrip(buf);
+
+ spin_lock_irqsave(&clk_list_lock, flags);
+ list_for_each_entry(table, &clk_list, node) {
+ for (i = 0; i < table->num_clocks; i++)
+ if (!strcmp(cmp, table->clocks[i].clk->dbg_name)) {
+ parent = table->clocks[i].clk;
+ break;
+ }
+ if (parent)
+ break;
+ }
+
+ if (!parent) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ spin_unlock_irqrestore(&clk_list_lock, flags);
+ ret = clk_set_parent(clock, table->clocks[i].clk);
+ if (ret)
+ return ret;
+
+ return cnt;
+err:
+ spin_unlock_irqrestore(&clk_list_lock, flags);
+ return ret;
}
+
static const struct file_operations clock_parent_fops = {
- .open = clock_parent_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-static struct dentry *debugfs_base;
-static u32 debug_suspend;
-
-struct clk_table {
- struct list_head node;
- struct clk_lookup *clocks;
- size_t num_clocks;
+ .open = simple_open,
+ .read = clock_parent_read,
+ .write = clock_parent_write,
};
static int clock_debug_add(struct clk *clock)
@@ -305,8 +351,6 @@
debugfs_remove_recursive(clk_dir);
return -ENOMEM;
}
-static LIST_HEAD(clk_list);
-static DEFINE_SPINLOCK(clk_list_lock);
/**
* clock_debug_register() - Add additional clocks to clock debugfs hierarchy
diff --git a/arch/arm/mach-msm/clock-dsi-8610.c b/arch/arm/mach-msm/clock-dsi-8610.c
new file mode 100644
index 0000000..44b332e
--- /dev/null
+++ b/arch/arm/mach-msm/clock-dsi-8610.c
@@ -0,0 +1,408 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/iopoll.h>
+#include <linux/clk.h>
+
+#include <asm/processor.h>
+#include <mach/msm_iomap.h>
+#include <mach/clk-provider.h>
+
+#include "clock-dsi-8610.h"
+
+#define DSI_PHY_PHYS 0xFDD00000
+#define DSI_PHY_SIZE 0x00100000
+
+#define DSI_CTRL 0x0000
+#define DSI_DSIPHY_PLL_CTRL_0 0x0200
+#define DSI_DSIPHY_PLL_CTRL_1 0x0204
+#define DSI_DSIPHY_PLL_CTRL_2 0x0208
+#define DSI_DSIPHY_PLL_CTRL_3 0x020C
+#define DSI_DSIPHY_PLL_RDY 0x0280
+#define DSI_DSIPHY_PLL_CTRL_8 0x0220
+#define DSI_DSIPHY_PLL_CTRL_9 0x0224
+#define DSI_DSIPHY_PLL_CTRL_10 0x0228
+
+#define DSI_BPP 3
+#define DSI_PLL_RDY_BIT 0x01
+#define DSI_PLL_RDY_LOOP_COUNT 80000
+#define DSI_MAX_DIVIDER 256
+
+static unsigned char *dsi_base;
+static struct clk *dsi_ahb_clk;
+
+int __init dsi_clk_ctrl_init(struct clk *ahb_clk)
+{
+ dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
+ if (!dsi_base) {
+ pr_err("unable to remap dsi base\n");
+ return -ENODEV;
+ }
+
+ dsi_ahb_clk = ahb_clk;
+ return 0;
+}
+
+static int dsi_pll_vco_enable(struct clk *c)
+{
+ u32 status;
+ int i = 0, ret = 0;
+
+ ret = clk_enable(dsi_ahb_clk);
+ if (ret) {
+ pr_err("fail to enable dsi ahb clk\n");
+ return ret;
+ }
+
+ writel_relaxed(0x01, dsi_base + DSI_DSIPHY_PLL_CTRL_0);
+
+ do {
+ status = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_RDY);
+ } while (!(status & DSI_PLL_RDY_BIT) && (i++ < DSI_PLL_RDY_LOOP_COUNT));
+
+ if (!(status & DSI_PLL_RDY_BIT)) {
+ pr_err("DSI PLL not ready, polling time out!\n");
+ ret = -ETIMEDOUT;
+ }
+
+ clk_disable(dsi_ahb_clk);
+
+ return ret;
+}
+
+static void dsi_pll_vco_disable(struct clk *c)
+{
+ int ret;
+
+ ret = clk_enable(dsi_ahb_clk);
+ if (ret) {
+ pr_err("fail to enable dsi ahb clk\n");
+ return;
+ }
+
+ writel_relaxed(0x00, dsi_base + DSI_DSIPHY_PLL_CTRL_0);
+ clk_disable(dsi_ahb_clk);
+}
+
+static int dsi_pll_vco_set_rate(struct clk *c, unsigned long rate)
+{
+ int ret;
+ u32 temp, val;
+ unsigned long fb_divider;
+ struct clk *parent = c->parent;
+ struct dsi_pll_vco_clk *vco_clk =
+ container_of(c, struct dsi_pll_vco_clk, c);
+
+ if (!rate)
+ return 0;
+
+ ret = clk_prepare_enable(dsi_ahb_clk);
+ if (ret) {
+ pr_err("fail to enable dsi ahb clk\n");
+ return ret;
+ }
+
+ temp = rate / 10;
+ val = parent->rate / 10;
+ fb_divider = (temp * vco_clk->pref_div_ratio) / val;
+ fb_divider = fb_divider / 2 - 1;
+
+ temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_1);
+ val = (temp & 0xFFFFFF00) | (fb_divider & 0xFF);
+ writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_1);
+
+ temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_2);
+ val = (temp & 0xFFFFFFF8) | ((fb_divider >> 8) & 0x07);
+ writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_2);
+
+ temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_3);
+ val = (temp & 0xFFFFFFC0) | (vco_clk->pref_div_ratio - 1);
+ writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_3);
+
+ clk_disable_unprepare(dsi_ahb_clk);
+
+ return 0;
+}
+
+/* rate is the bit clk rate */
+static long dsi_pll_vco_round_rate(struct clk *c, unsigned long rate)
+{
+ long vco_rate;
+ struct dsi_pll_vco_clk *vco_clk =
+ container_of(c, struct dsi_pll_vco_clk, c);
+
+
+ vco_rate = rate;
+ if (rate < vco_clk->vco_clk_min)
+ vco_rate = vco_clk->vco_clk_min;
+ else if (rate > vco_clk->vco_clk_max)
+ vco_rate = vco_clk->vco_clk_max;
+
+ return vco_rate;
+}
+
+static unsigned long dsi_pll_vco_get_rate(struct clk *c)
+{
+ u32 fb_divider, ref_divider, vco_rate;
+ u32 temp, status;
+ struct clk *parent = c->parent;
+
+ status = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_RDY);
+ if (status & DSI_PLL_RDY_BIT) {
+ fb_divider = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_1);
+ fb_divider &= 0xFF;
+ temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_2) & 0x07;
+ fb_divider = (temp << 8) | fb_divider;
+ fb_divider += 1;
+
+ ref_divider = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_3);
+ ref_divider &= 0x3F;
+ ref_divider += 1;
+
+ vco_rate = (parent->rate / ref_divider) * fb_divider;
+ } else {
+ vco_rate = 0;
+ }
+ return vco_rate;
+}
+
+static enum handoff dsi_pll_vco_handoff(struct clk *c)
+{
+ u32 status;
+
+ if (clk_prepare_enable(dsi_ahb_clk)) {
+ pr_err("fail to enable dsi ahb clk\n");
+ return HANDOFF_DISABLED_CLK;
+ }
+
+ status = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_0);
+ if (!status & DSI_PLL_RDY_BIT) {
+ pr_err("DSI PLL not ready\n");
+ clk_disable(dsi_ahb_clk);
+ return HANDOFF_DISABLED_CLK;
+ }
+
+ c->rate = dsi_pll_vco_get_rate(c);
+
+ clk_disable_unprepare(dsi_ahb_clk);
+
+ return HANDOFF_ENABLED_CLK;
+}
+
+static int dsi_byteclk_set_rate(struct clk *c, unsigned long rate)
+{
+ int div, ret;
+ long vco_rate;
+ unsigned long bitclk_rate;
+ u32 temp, val;
+ struct clk *parent = clk_get_parent(c);
+
+ if (rate == 0) {
+ ret = clk_set_rate(parent, 0);
+ return ret;
+ }
+
+ bitclk_rate = rate * 8;
+ for (div = 1; div < DSI_MAX_DIVIDER; div++) {
+ vco_rate = clk_round_rate(parent, bitclk_rate * div);
+
+ if (vco_rate == bitclk_rate * div)
+ break;
+
+ if (vco_rate < bitclk_rate * div)
+ return -EINVAL;
+ }
+
+ if (vco_rate != bitclk_rate * div)
+ return -EINVAL;
+
+ ret = clk_set_rate(parent, vco_rate);
+ if (ret) {
+ pr_err("fail to set vco rate\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(dsi_ahb_clk);
+ if (ret) {
+ pr_err("fail to enable dsi ahb clk\n");
+ return ret;
+ }
+
+ /* set the bit clk divider */
+ temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_8);
+ val = (temp & 0xFFFFFFF0) | (div - 1);
+ writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_8);
+
+ /* set the byte clk divider */
+ temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_9);
+ val = (temp & 0xFFFFFF00) | (vco_rate / rate - 1);
+ writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_9);
+ clk_disable_unprepare(dsi_ahb_clk);
+
+ return 0;
+}
+
+static long dsi_byteclk_round_rate(struct clk *c, unsigned long rate)
+{
+ int div;
+ long vco_rate;
+ unsigned long bitclk_rate;
+ struct clk *parent = clk_get_parent(c);
+
+ if (rate == 0)
+ return -EINVAL;
+
+ bitclk_rate = rate * 8;
+ for (div = 1; div < DSI_MAX_DIVIDER; div++) {
+ vco_rate = clk_round_rate(parent, bitclk_rate * div);
+ if (vco_rate == bitclk_rate * div)
+ break;
+ if (vco_rate < bitclk_rate * div)
+ return -EINVAL;
+ }
+
+ if (vco_rate != bitclk_rate * div)
+ return -EINVAL;
+
+ return rate;
+}
+
+static enum handoff dsi_byteclk_handoff(struct clk *c)
+{
+ struct clk *parent = clk_get_parent(c);
+ unsigned long vco_rate = clk_get_rate(parent);
+ u32 out_div2;
+
+ if (vco_rate == 0)
+ return HANDOFF_DISABLED_CLK;
+
+ if (clk_prepare_enable(dsi_ahb_clk)) {
+ pr_err("fail to enable dsi ahb clk\n");
+ return HANDOFF_DISABLED_CLK;
+ }
+
+ out_div2 = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_9);
+ out_div2 &= 0xFF;
+ c->rate = vco_rate / (out_div2 + 1);
+ clk_disable_unprepare(dsi_ahb_clk);
+
+ return HANDOFF_ENABLED_CLK;
+}
+
+static int dsi_dsiclk_set_rate(struct clk *c, unsigned long rate)
+{
+ u32 temp, val;
+ int ret;
+ struct clk *parent = clk_get_parent(c);
+ unsigned long vco_rate = clk_get_rate(parent);
+
+ if (rate == 0)
+ return 0;
+
+ if (vco_rate % rate != 0) {
+ pr_err("dsiclk_set_rate invalid rate\n");
+ return -EINVAL;
+ }
+
+ ret = clk_prepare_enable(dsi_ahb_clk);
+ if (ret) {
+ pr_err("fail to enable dsi ahb clk\n");
+ return ret;
+ }
+ temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_10);
+ val = (temp & 0xFFFFFF00) | (vco_rate / rate - 1);
+ writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_10);
+ clk_disable_unprepare(dsi_ahb_clk);
+
+ return 0;
+}
+
+static long dsi_dsiclk_round_rate(struct clk *c, unsigned long rate)
+{
+ /* rate is the pixel clk rate, translate into dsi clk rate*/
+ struct clk *parent = clk_get_parent(c);
+ unsigned long vco_rate = clk_get_rate(parent);
+
+ rate *= DSI_BPP;
+
+ if (vco_rate < rate)
+ return -EINVAL;
+
+ if (vco_rate % rate != 0)
+ return -EINVAL;
+
+ return rate;
+}
+
+static enum handoff dsi_dsiclk_handoff(struct clk *c)
+{
+ struct clk *parent = clk_get_parent(c);
+ unsigned long vco_rate = clk_get_rate(parent);
+ u32 out_div3;
+
+ if (vco_rate == 0)
+ return HANDOFF_DISABLED_CLK;
+
+ if (clk_prepare_enable(dsi_ahb_clk)) {
+ pr_err("fail to enable dsi ahb clk\n");
+ return HANDOFF_DISABLED_CLK;
+ }
+
+ out_div3 = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_10);
+ out_div3 &= 0xFF;
+ c->rate = vco_rate / (out_div3 + 1);
+ clk_disable_unprepare(dsi_ahb_clk);
+
+ return HANDOFF_ENABLED_CLK;
+}
+
+int dsi_prepare(struct clk *clk)
+{
+ return clk_prepare(dsi_ahb_clk);
+}
+
+void dsi_unprepare(struct clk *clk)
+{
+ clk_unprepare(dsi_ahb_clk);
+}
+
+struct clk_ops clk_ops_dsi_dsiclk = {
+ .prepare = dsi_prepare,
+ .unprepare = dsi_unprepare,
+ .set_rate = dsi_dsiclk_set_rate,
+ .round_rate = dsi_dsiclk_round_rate,
+ .handoff = dsi_dsiclk_handoff,
+};
+
+struct clk_ops clk_ops_dsi_byteclk = {
+ .prepare = dsi_prepare,
+ .unprepare = dsi_unprepare,
+ .set_rate = dsi_byteclk_set_rate,
+ .round_rate = dsi_byteclk_round_rate,
+ .handoff = dsi_byteclk_handoff,
+};
+
+struct clk_ops clk_ops_dsi_vco = {
+ .prepare = dsi_prepare,
+ .unprepare = dsi_unprepare,
+ .enable = dsi_pll_vco_enable,
+ .disable = dsi_pll_vco_disable,
+ .set_rate = dsi_pll_vco_set_rate,
+ .round_rate = dsi_pll_vco_round_rate,
+ .handoff = dsi_pll_vco_handoff,
+};
+
diff --git a/arch/arm/mach-msm/clock-dsi-8610.h b/arch/arm/mach-msm/clock-dsi-8610.h
new file mode 100644
index 0000000..4c09790
--- /dev/null
+++ b/arch/arm/mach-msm/clock-dsi-8610.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_DSI_8610
+#define __ARCH_ARM_MACH_MSM_CLOCK_DSI_8610
+
+#include <mach/clk-provider.h>
+
+struct dsi_pll_vco_clk {
+ const unsigned long vco_clk_min;
+ const unsigned long vco_clk_max;
+ const unsigned pref_div_ratio;
+ int factor;
+ struct clk c;
+};
+
+extern struct clk_ops clk_ops_dsi_vco;
+extern struct clk_ops clk_ops_dsi_byteclk;
+extern struct clk_ops clk_ops_dsi_dsiclk;
+
+int dsi_clk_ctrl_init(struct clk *ahb_clk);
+
+#endif
diff --git a/arch/arm/mach-msm/clock-generic.c b/arch/arm/mach-msm/clock-generic.c
new file mode 100644
index 0000000..4d74533
--- /dev/null
+++ b/arch/arm/mach-msm/clock-generic.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <linux/clk.h>
+#include <mach/clk-provider.h>
+#include <mach/clock-generic.h>
+
+/* ==================== Mux clock ==================== */
+
+static int parent_to_src_sel(struct mux_clk *mux, struct clk *p)
+{
+ int i;
+
+ for (i = 0; i < mux->num_parents; i++) {
+ if (mux->parents[i].src == p)
+ return mux->parents[i].sel;
+ }
+
+ return -EINVAL;
+}
+
+static int mux_set_parent(struct clk *c, struct clk *p)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ int sel = parent_to_src_sel(mux, p);
+ struct clk *old_parent;
+ int rc = 0;
+ unsigned long flags;
+
+ if (sel < 0)
+ return sel;
+
+ rc = __clk_pre_reparent(c, p, &flags);
+ if (rc)
+ goto out;
+
+ rc = mux->ops->set_mux_sel(mux, sel);
+ if (rc)
+ goto set_fail;
+
+ old_parent = c->parent;
+ c->parent = p;
+ __clk_post_reparent(c, old_parent, &flags);
+
+ return 0;
+
+set_fail:
+ __clk_post_reparent(c, p, &flags);
+out:
+ return rc;
+}
+
+static long mux_round_rate(struct clk *c, unsigned long rate)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ int i;
+ long prate, max_prate = 0, rrate = LONG_MAX;
+
+ for (i = 0; i < mux->num_parents; i++) {
+ prate = clk_round_rate(mux->parents[i].src, rate);
+ if (prate < rate) {
+ max_prate = max(prate, max_prate);
+ continue;
+ }
+
+ rrate = min(rrate, prate);
+ }
+ if (rrate == LONG_MAX)
+ rrate = max_prate;
+
+ return rrate ? rrate : -EINVAL;
+}
+
+static int mux_set_rate(struct clk *c, unsigned long rate)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ struct clk *new_parent = NULL;
+ int rc = 0, i;
+ unsigned long new_par_curr_rate;
+
+ for (i = 0; i < mux->num_parents; i++) {
+ if (clk_round_rate(mux->parents[i].src, rate) == rate) {
+ new_parent = mux->parents[i].src;
+ break;
+ }
+ }
+ if (new_parent == NULL)
+ return -EINVAL;
+
+ /*
+ * Switch to safe parent since the old and new parent might be the
+ * same and the parent might temporarily turn off while switching
+ * rates.
+ */
+ if (mux->safe_sel >= 0)
+ rc = mux->ops->set_mux_sel(mux, mux->safe_sel);
+ if (rc)
+ return rc;
+
+ new_par_curr_rate = clk_get_rate(new_parent);
+ rc = clk_set_rate(new_parent, rate);
+ if (rc)
+ goto set_rate_fail;
+
+ rc = mux_set_parent(c, new_parent);
+ if (rc)
+ goto set_par_fail;
+
+ return 0;
+
+set_par_fail:
+ clk_set_rate(new_parent, new_par_curr_rate);
+set_rate_fail:
+ WARN(mux->ops->set_mux_sel(mux, parent_to_src_sel(mux, c->parent)),
+ "Set rate failed for %s. Also in bad state!\n", c->dbg_name);
+ return rc;
+}
+
+static int mux_enable(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ if (mux->ops->enable)
+ return mux->ops->enable(mux);
+ return 0;
+}
+
+static void mux_disable(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ if (mux->ops->disable)
+ return mux->ops->disable(mux);
+}
+
+static struct clk *mux_get_parent(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ int sel = mux->ops->get_mux_sel(mux);
+ int i;
+
+ for (i = 0; i < mux->num_parents; i++) {
+ if (mux->parents[i].sel == sel)
+ return mux->parents[i].src;
+ }
+
+ /* Unfamiliar parent. */
+ return NULL;
+}
+
+static enum handoff mux_handoff(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+
+ c->rate = clk_get_rate(c->parent);
+ mux->safe_sel = parent_to_src_sel(mux, mux->safe_parent);
+
+ if (mux->en_mask && mux->ops && mux->ops->is_enabled)
+ return mux->ops->is_enabled(mux)
+ ? HANDOFF_ENABLED_CLK
+ : HANDOFF_DISABLED_CLK;
+
+ /*
+ * If this function returns 'enabled' even when the clock downstream
+ * of this clock is disabled, then handoff code will unnecessarily
+ * enable the current parent of this clock. If this function always
+ * returns 'disabled' and a clock downstream is on, the clock handoff
+ * code will bump up the ref count for this clock and its current
+ * parent as necessary. So, clocks without an actual HW gate can
+ * always return disabled.
+ */
+ return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_gen_mux = {
+ .enable = mux_enable,
+ .disable = mux_disable,
+ .set_parent = mux_set_parent,
+ .round_rate = mux_round_rate,
+ .set_rate = mux_set_rate,
+ .handoff = mux_handoff,
+ .get_parent = mux_get_parent,
+};
+
+
+/* ==================== Divider clock ==================== */
+
+static long __div_round_rate(struct clk *c, unsigned long rate, int *best_div)
+{
+ struct div_clk *d = to_div_clk(c);
+ unsigned int div, min_div, max_div;
+ long p_rrate, rrate = LONG_MAX;
+
+ rate = max(rate, 1UL);
+
+ if (!d->ops || !d->ops->set_div)
+ min_div = max_div = d->div;
+ else {
+ min_div = max(d->min_div, 1U);
+ max_div = min(d->max_div, (unsigned int) (LONG_MAX / rate));
+ }
+
+ for (div = min_div; div <= max_div; div++) {
+ p_rrate = clk_round_rate(c->parent, rate * div);
+ if (p_rrate < 0)
+ break;
+
+ p_rrate /= div;
+ /*
+ * Trying higher dividers is only going to ask the parent for
+ * a higher rate. If it can't even output a rate higher than
+ * the one we request for this divider, the parent is not
+ * going to be able to output an even higher rate required
+ * for a higher divider. So, stop trying higher dividers.
+ */
+ if (p_rrate < rate) {
+ if (rrate == LONG_MAX) {
+ rrate = p_rrate;
+ if (best_div)
+ *best_div = div;
+ }
+ break;
+ }
+ if (p_rrate < rrate) {
+ rrate = p_rrate;
+ if (best_div)
+ *best_div = div;
+ }
+
+ if (rrate <= rate + d->rate_margin)
+ break;
+ }
+
+ if (rrate == LONG_MAX)
+ return -EINVAL;
+
+ return rrate;
+}
+
+static long div_round_rate(struct clk *c, unsigned long rate)
+{
+ return __div_round_rate(c, rate, NULL);
+}
+
+static int div_set_rate(struct clk *c, unsigned long rate)
+{
+ struct div_clk *d = to_div_clk(c);
+ int div, rc = 0;
+ long rrate, old_prate;
+
+ rrate = __div_round_rate(c, rate, &div);
+ if (rrate != rate)
+ return -EINVAL;
+
+ if (div > d->div)
+ rc = d->ops->set_div(d, div);
+ if (rc)
+ return rc;
+
+ old_prate = clk_get_rate(c->parent);
+ rc = clk_set_rate(c->parent, rate * div);
+ if (rc)
+ goto set_rate_fail;
+
+ if (div < d->div)
+ rc = d->ops->set_div(d, div);
+ if (rc)
+ goto div_dec_fail;
+
+ d->div = div;
+
+ return 0;
+
+div_dec_fail:
+ WARN(clk_set_rate(c->parent, old_prate),
+ "Set rate failed for %s. Also in bad state!\n", c->dbg_name);
+set_rate_fail:
+ if (div > d->div)
+ WARN(d->ops->set_div(d, d->div),
+ "Set rate failed for %s. Also in bad state!\n",
+ c->dbg_name);
+ return rc;
+}
+
+static int div_enable(struct clk *c)
+{
+ struct div_clk *d = to_div_clk(c);
+ if (d->ops->enable)
+ return d->ops->enable(d);
+ return 0;
+}
+
+static void div_disable(struct clk *c)
+{
+ struct div_clk *d = to_div_clk(c);
+ if (d->ops->disable)
+ return d->ops->disable(d);
+}
+
+static enum handoff div_handoff(struct clk *c)
+{
+ struct div_clk *d = to_div_clk(c);
+
+ if (d->ops->get_div)
+ d->div = max(d->ops->get_div(d), 1);
+ d->div = max(d->div, 1U);
+ c->rate = clk_get_rate(c->parent) / d->div;
+
+ if (d->en_mask && d->ops && d->ops->is_enabled)
+ return d->ops->is_enabled(d)
+ ? HANDOFF_ENABLED_CLK
+ : HANDOFF_DISABLED_CLK;
+
+ /*
+ * If this function returns 'enabled' even when the clock downstream
+ * of this clock is disabled, then handoff code will unnecessarily
+ * enable the current parent of this clock. If this function always
+ * returns 'disabled' and a clock downstream is on, the clock handoff
+ * code will bump up the ref count for this clock and its current
+ * parent as necessary. So, clocks without an actual HW gate can
+ * always return disabled.
+ */
+ return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_div = {
+ .enable = div_enable,
+ .disable = div_disable,
+ .round_rate = div_round_rate,
+ .set_rate = div_set_rate,
+ .handoff = div_handoff,
+};
+
+static long __slave_div_round_rate(struct clk *c, unsigned long rate,
+ int *best_div)
+{
+ struct div_clk *d = to_div_clk(c);
+ unsigned int div, min_div, max_div;
+ long p_rate;
+
+ rate = max(rate, 1UL);
+
+ if (!d->ops || !d->ops->set_div)
+ min_div = max_div = d->div;
+ else {
+ min_div = d->min_div;
+ max_div = d->max_div;
+ }
+
+ p_rate = clk_get_rate(c->parent);
+ div = p_rate / rate;
+ div = max(div, min_div);
+ div = min(div, max_div);
+ if (best_div)
+ *best_div = div;
+
+ return p_rate / div;
+}
+
+static long slave_div_round_rate(struct clk *c, unsigned long rate)
+{
+ return __slave_div_round_rate(c, rate, NULL);
+}
+
+static int slave_div_set_rate(struct clk *c, unsigned long rate)
+{
+ struct div_clk *d = to_div_clk(c);
+ int div, rc = 0;
+ long rrate;
+
+ rrate = __slave_div_round_rate(c, rate, &div);
+ if (rrate != rate)
+ return -EINVAL;
+
+ if (div == d->div)
+ return 0;
+
+ if (d->ops->set_div)
+ rc = d->ops->set_div(d, div);
+ if (rc)
+ return rc;
+
+ d->div = div;
+
+ return 0;
+}
+
+struct clk_ops clk_ops_slave_div = {
+ .enable = div_enable,
+ .disable = div_disable,
+ .round_rate = slave_div_round_rate,
+ .set_rate = slave_div_set_rate,
+ .handoff = div_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 0d1104e..e67d973 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -476,10 +476,7 @@
if (branch->max_div)
return branch->c.rate;
- if (!branch->has_sibling)
- return clk_get_rate(c->parent);
-
- return 0;
+ return clk_get_rate(c->parent);
}
static int branch_clk_list_rate(struct clk *c, unsigned n)
@@ -670,7 +667,7 @@
return HANDOFF_ENABLED_CLK;
}
-static enum handoff byte_rcg_handoff(struct clk *clk)
+enum handoff byte_rcg_handoff(struct clk *clk)
{
struct rcg_clk *rcg = to_rcg_clk(clk);
u32 div_val;
@@ -721,7 +718,7 @@
return 0;
}
-static enum handoff pixel_rcg_handoff(struct clk *clk)
+enum handoff pixel_rcg_handoff(struct clk *clk)
{
struct rcg_clk *rcg = to_rcg_clk(clk);
u32 div_val, mval, nval, cfg_regval;
@@ -812,6 +809,155 @@
}
+#define ENABLE_REG(x) (*(x)->base + (x)->enable_reg)
+#define SELECT_REG(x) (*(x)->base + (x)->select_reg)
+
+/*
+ * mux clock functions
+ */
+static void cam_mux_clk_halt_check(void)
+{
+ /* Ensure that the delay starts after the mux disable/enable. */
+ mb();
+ udelay(HALT_CHECK_DELAY_US);
+}
+
+static int cam_mux_clk_enable(struct clk *c)
+{
+ unsigned long flags;
+ u32 regval;
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ regval = readl_relaxed(ENABLE_REG(mux));
+ regval |= mux->enable_mask;
+ writel_relaxed(regval, ENABLE_REG(mux));
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+ /* Wait for clock to enable before continuing. */
+ cam_mux_clk_halt_check();
+
+ return 0;
+}
+
+static void cam_mux_clk_disable(struct clk *c)
+{
+ unsigned long flags;
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
+ u32 regval;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ regval = readl_relaxed(ENABLE_REG(mux));
+ regval &= ~mux->enable_mask;
+ writel_relaxed(regval, ENABLE_REG(mux));
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+ /* Wait for clock to disable before continuing. */
+ cam_mux_clk_halt_check();
+}
+
+static int mux_source_switch(struct cam_mux_clk *mux, struct mux_source *dest)
+{
+ unsigned long flags;
+ u32 regval;
+ int ret = 0;
+
+ ret = __clk_pre_reparent(&mux->c, dest->clk, &flags);
+ if (ret)
+ goto out;
+
+ regval = readl_relaxed(SELECT_REG(mux));
+ regval &= ~mux->select_mask;
+ regval |= dest->select_val;
+ writel_relaxed(regval, SELECT_REG(mux));
+
+ /* Make sure switch request goes through before proceeding. */
+ mb();
+
+ __clk_post_reparent(&mux->c, mux->c.parent, &flags);
+out:
+ return ret;
+}
+
+static int cam_mux_clk_set_parent(struct clk *c, struct clk *parent)
+{
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
+ struct mux_source *dest = NULL;
+ int ret;
+
+ if (!mux->sources || !parent)
+ return -EPERM;
+
+ dest = mux->sources;
+
+ while (dest->clk) {
+ if (dest->clk == parent)
+ break;
+ dest++;
+ }
+
+ if (!dest->clk)
+ return -EPERM;
+
+ ret = mux_source_switch(mux, dest);
+ if (ret)
+ return ret;
+
+ mux->c.rate = clk_get_rate(dest->clk);
+
+ return 0;
+}
+
+static enum handoff cam_mux_clk_handoff(struct clk *c)
+{
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
+ u32 mask = mux->enable_mask;
+ u32 regval = readl_relaxed(ENABLE_REG(mux));
+
+ c->rate = clk_get_rate(c->parent);
+
+ if (mask == (regval & mask))
+ return HANDOFF_ENABLED_CLK;
+
+ return HANDOFF_DISABLED_CLK;
+}
+
+static struct clk *cam_mux_clk_get_parent(struct clk *c)
+{
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
+ struct mux_source *parent = NULL;
+ u32 regval = readl_relaxed(SELECT_REG(mux));
+
+ if (!mux->sources)
+ return ERR_PTR(-EPERM);
+
+ parent = mux->sources;
+
+ while (parent->clk) {
+ if ((regval & mux->select_mask) == parent->select_val)
+ return parent->clk;
+
+ parent++;
+ }
+
+ return ERR_PTR(-EPERM);
+}
+
+static int cam_mux_clk_list_rate(struct clk *c, unsigned n)
+{
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
+ int i;
+
+ for (i = 0; i < n; i++)
+ if (!mux->sources[i].clk)
+ break;
+
+ if (!mux->sources[i].clk)
+ return -ENXIO;
+
+ return clk_get_rate(mux->sources[i].clk);
+}
+
struct clk_ops clk_ops_empty;
struct clk_ops clk_ops_rcg = {
@@ -875,3 +1021,14 @@
.reset = local_vote_clk_reset,
.handoff = local_vote_clk_handoff,
};
+
+struct clk_ops clk_ops_cam_mux = {
+ .enable = cam_mux_clk_enable,
+ .disable = cam_mux_clk_disable,
+ .set_parent = cam_mux_clk_set_parent,
+ .get_parent = cam_mux_clk_get_parent,
+ .handoff = cam_mux_clk_handoff,
+ .list_rate = cam_mux_clk_list_rate,
+};
+
+
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index 7ac7bd3..f307a2f 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -157,6 +157,38 @@
return container_of(clk, struct measure_clk, c);
}
+struct mux_source {
+ struct clk *const clk;
+ const u32 select_val;
+};
+
+/**
+ * struct cam_mux_clk - branch clock
+ * @c: clk
+ * @enable_reg: register that contains the enable bit(s) for the mux
+ * @select_reg: register that contains the source selection bits for the mux
+ * @enable_mask: mask that enables the mux
+ * @select_mask: mask for the source selection bits
+ * @sources: list of mux sources
+ * @base: pointer to base address of ioremapped registers.
+ */
+struct cam_mux_clk {
+ struct clk c;
+ const u32 enable_reg;
+ const u32 select_reg;
+ const u32 enable_mask;
+ const u32 select_mask;
+
+ struct mux_source *sources;
+
+ void *const __iomem *base;
+};
+
+static inline struct cam_mux_clk *to_cam_mux_clk(struct clk *clk)
+{
+ return container_of(clk, struct cam_mux_clk, c);
+}
+
/*
* Generic set-rate implementations
*/
@@ -168,6 +200,7 @@
*/
extern spinlock_t local_clock_reg_lock;
+extern struct clk_ops clk_ops_cam_mux;
extern struct clk_ops clk_ops_empty;
extern struct clk_ops clk_ops_rcg;
extern struct clk_ops clk_ops_rcg_mnd;
@@ -177,6 +210,9 @@
extern struct clk_ops clk_ops_byte;
extern struct clk_ops clk_ops_pixel;
+enum handoff pixel_rcg_handoff(struct clk *clk);
+enum handoff byte_rcg_handoff(struct clk *clk);
+
/*
* Clock definition macros
*/
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index d866874..bf95615 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -648,7 +648,49 @@
REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
udelay(200);
break;
+ case 65000000:
+ REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+ REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+ REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x4F, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+ REG_W(0x55, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+ REG_W(0xED, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+ REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+ REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
+ REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+ REG_W(0x8A, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+ REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+ udelay(50);
+ REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+ REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+ REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+ REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+ REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+ udelay(200);
+ break;
case 74250000:
/*
* 720p60/720p50/1080i60/1080i50
@@ -697,6 +739,50 @@
udelay(200);
break;
+ case 108000000:
+ REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+ REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+ REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x5B, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+ REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+ REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
+ REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+ REG_W(0x38, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+ udelay(50);
+
+ REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+ REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+ REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+ REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+ REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+ udelay(200);
+ break;
+
case 148500000:
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 044fc2c..08817c0 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -62,7 +62,8 @@
{
int level, rc = 0, i;
struct regulator **r = vdd_class->regulator;
- const int **vdd_uv = vdd_class->vdd_uv;
+ int **vdd_uv = vdd_class->vdd_uv;
+ int **vdd_ua = vdd_class->vdd_ua;
int max_level = vdd_class->num_levels - 1;
for (level = max_level; level > 0; level--)
@@ -77,20 +78,36 @@
vdd_uv[max_level][i]);
if (rc)
goto set_voltage_fail;
+
+ if (!vdd_ua)
+ continue;
+
+ rc = regulator_set_optimum_mode(r[i], vdd_ua[level][i]);
+ if (rc < 0)
+ goto set_mode_fail;
}
if (vdd_class->set_vdd && !vdd_class->num_regulators)
rc = vdd_class->set_vdd(vdd_class, level);
- if (!rc)
+ if (rc < 0)
vdd_class->cur_level = level;
- return rc;
+ return 0;
+
+set_mode_fail:
+ regulator_set_voltage(r[i], vdd_uv[vdd_class->cur_level][i],
+ vdd_uv[max_level][i]);
set_voltage_fail:
- level = vdd_class->cur_level;
- for (i--; i >= 0; i--)
- regulator_set_voltage(r[i], vdd_uv[level][i],
- vdd_uv[max_level][i]);
+ for (i--; i >= 0; i--) {
+ regulator_set_voltage(r[i], vdd_uv[vdd_class->cur_level][i],
+ vdd_uv[max_level][i]);
+
+ if (!vdd_ua)
+ continue;
+ regulator_set_optimum_mode(r[i],
+ vdd_ua[vdd_class->cur_level][i]);
+ }
return rc;
}
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 9ca1965..674ef77 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -53,6 +53,7 @@
extern struct clock_init_data msm8610_rumi_clock_init_data;
extern struct clock_init_data msm8226_clock_init_data;
extern struct clock_init_data msm8226_rumi_clock_init_data;
+extern struct clock_init_data msm8084_clock_init_data;
int msm_clock_init(struct clock_init_data *data);
int find_vdd_level(struct clk *clk, unsigned long rate);
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index 08923e4..e51a1f5 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -24,26 +24,139 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/interrupt.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/cpr-regulator.h>
+/* Register Offsets for RB-CPR and Bit Definitions */
+
+/* RBCPR Gate Count and Target Registers */
+#define REG_RBCPR_GCNT_TARGET(n) (0x60 + 4 * n)
+
+#define RBCPR_GCNT_TARGET_GCNT_BITS 10
+#define RBCPR_GCNT_TARGET_GCNT_SHIFT 12
+#define RBCPR_GCNT_TARGET_GCNT_MASK ((1<<RBCPR_GCNT_TARGET_GCNT_BITS)-1)
+
+/* RBCPR Timer Control */
+#define REG_RBCPR_TIMER_INTERVAL 0x44
+#define REG_RBIF_TIMER_ADJUST 0x4C
+
+#define RBIF_TIMER_ADJ_CONS_UP_BITS 4
+#define RBIF_TIMER_ADJ_CONS_UP_MASK ((1<<RBIF_TIMER_ADJ_CONS_UP_BITS)-1)
+#define RBIF_TIMER_ADJ_CONS_DOWN_BITS 4
+#define RBIF_TIMER_ADJ_CONS_DOWN_MASK ((1<<RBIF_TIMER_ADJ_CONS_DOWN_BITS)-1)
+#define RBIF_TIMER_ADJ_CONS_DOWN_SHIFT 4
+
+/* RBCPR Config Register */
+#define REG_RBIF_LIMIT 0x48
+#define REG_RBCPR_STEP_QUOT 0x80
+#define REG_RBIF_SW_VLEVEL 0x94
+
+#define RBIF_LIMIT_CEILING_BITS 6
+#define RBIF_LIMIT_CEILING_MASK ((1<<RBIF_LIMIT_CEILING_BITS)-1)
+#define RBIF_LIMIT_CEILING_SHIFT 6
+#define RBIF_LIMIT_FLOOR_BITS 6
+#define RBIF_LIMIT_FLOOR_MASK ((1<<RBIF_LIMIT_FLOOR_BITS)-1)
+
+#define RBIF_LIMIT_CEILING_DEFAULT RBIF_LIMIT_CEILING_MASK
+#define RBIF_LIMIT_FLOOR_DEFAULT 0
+#define RBIF_SW_VLEVEL_DEFAULT 0x20
+
+#define RBCPR_STEP_QUOT_STEPQUOT_BITS 8
+#define RBCPR_STEP_QUOT_STEPQUOT_MASK ((1<<RBCPR_STEP_QUOT_STEPQUOT_BITS)-1)
+#define RBCPR_STEP_QUOT_IDLE_CLK_BITS 4
+#define RBCPR_STEP_QUOT_IDLE_CLK_MASK ((1<<RBCPR_STEP_QUOT_IDLE_CLK_BITS)-1)
+#define RBCPR_STEP_QUOT_IDLE_CLK_SHIFT 8
+
+/* RBCPR Control Register */
+#define REG_RBCPR_CTL 0x90
+
+#define RBCPR_CTL_LOOP_EN BIT(0)
+#define RBCPR_CTL_TIMER_EN BIT(3)
+#define RBCPR_CTL_SW_AUTO_CONT_ACK_EN BIT(5)
+#define RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN BIT(6)
+#define RBCPR_CTL_COUNT_MODE BIT(10)
+#define RBCPR_CTL_UP_THRESHOLD_BITS 4
+#define RBCPR_CTL_UP_THRESHOLD_MASK ((1<<RBCPR_CTL_UP_THRESHOLD_BITS)-1)
+#define RBCPR_CTL_UP_THRESHOLD_SHIFT 24
+#define RBCPR_CTL_DN_THRESHOLD_BITS 4
+#define RBCPR_CTL_DN_THRESHOLD_MASK ((1<<RBCPR_CTL_DN_THRESHOLD_BITS)-1)
+#define RBCPR_CTL_DN_THRESHOLD_SHIFT 28
+
+/* RBCPR Ack/Nack Response */
+#define REG_RBIF_CONT_ACK_CMD 0x98
+#define REG_RBIF_CONT_NACK_CMD 0x9C
+
+/* RBCPR Result status Register */
+#define REG_RBCPR_RESULT_0 0xA0
+
+#define RBCPR_RESULT0_ERROR_STEPS_SHIFT 2
+#define RBCPR_RESULT0_ERROR_STEPS_BITS 4
+#define RBCPR_RESULT0_ERROR_STEPS_MASK ((1<<RBCPR_RESULT0_ERROR_STEPS_BITS)-1)
+
+/* RBCPR Interrupt Control Register */
+#define REG_RBIF_IRQ_EN(n) (0x100 + 4 * n)
+#define REG_RBIF_IRQ_CLEAR 0x110
+#define REG_RBIF_IRQ_STATUS 0x114
+
+#define CPR_INT_DONE BIT(0)
+#define CPR_INT_MIN BIT(1)
+#define CPR_INT_DOWN BIT(2)
+#define CPR_INT_MID BIT(3)
+#define CPR_INT_UP BIT(4)
+#define CPR_INT_MAX BIT(5)
+#define CPR_INT_CLAMP BIT(6)
+#define CPR_INT_ALL (CPR_INT_DONE | CPR_INT_MIN | CPR_INT_DOWN | \
+ CPR_INT_MID | CPR_INT_UP | CPR_INT_MAX | CPR_INT_CLAMP)
+#define CPR_INT_DEFAULT (CPR_INT_UP | CPR_INT_DOWN)
+
+#define CPR_NUM_RING_OSC 8
+#define CPR_NUM_SAVE_REGS 10
+
+/* CPR eFuse parameters */
+#define CPR_FUSE_TARGET_QUOT_BITS 12
+#define CPR_FUSE_TARGET_QUOT_BITS_MASK ((1<<CPR_FUSE_TARGET_QUOT_BITS)-1)
+#define CPR_FUSE_RO_SEL_BITS 3
+#define CPR_FUSE_RO_SEL_BITS_MASK ((1<<CPR_FUSE_RO_SEL_BITS)-1)
+
+#define CPR_FUSE_TARGET_QUOT_TURBO_SHIFT 0
+#define CPR_FUSE_TARGET_QUOT_NOMINAL_SHIFT 12
+#define CPR_FUSE_TARGET_QUOT_SVS_SHIFT 24
+
+#define CPR_FUSE_DISABLE_CPR_SHIFT 36
+#define CPR_FUSE_LOCAL_APPROACH_SHIFT 37
+#define CPR_FUSE_REDUNDANT_SHIFT 57
+
+/* PVS eFuse parameters */
+#define PVS_FUSE_REDUNDANT_SHIFT 24
+#define PVS_FUSE_REDUNDANT_BITS 3
+#define PVS_FUSE_REDUNDANT_MASK ((1<<PVS_FUSE_REDUNDANT_BITS)-1)
+
+#define PVS_FUSE_BINS_SHIFT 6
+#define PVS_FUSE_BINS_REDUNDANT_SHIFT 27
+
+enum voltage_change_dir {
+ NO_CHANGE,
+ DOWN,
+ UP,
+};
+
struct cpr_regulator {
struct regulator_desc rdesc;
struct regulator_dev *rdev;
- bool enabled;
+ bool vreg_enabled;
int corner;
+ int ceiling_max;
/* Process voltage parameters */
- phys_addr_t efuse_phys;
+ phys_addr_t pvs_efuse;
u32 num_efuse_bits;
- u32 efuse_bit_pos[CPR_PVS_EFUSE_BITS_MAX];
u32 pvs_bin_process[CPR_PVS_EFUSE_BINS_MAX];
- u32 pvs_corner_ceiling[NUM_APC_PVS][CPR_CORNER_MAX];
+ u32 pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
/* Process voltage variables */
u32 pvs_bin;
- u32 pvs_process;
- u32 *corner_ceiling;
+ u32 process;
/* APC voltage regulator */
struct regulator *vdd_apc;
@@ -53,13 +166,499 @@
int vdd_mx_vmax;
int vdd_mx_vmin_method;
int vdd_mx_vmin;
+
+ /* CPR parameters */
+ phys_addr_t cpr_fuse_addr;
+ u64 cpr_fuse_bits;
+ u64 cpr_fuse_bits_2;
+ bool cpr_fuse_disable;
+ bool cpr_fuse_local;
+ bool cpr_fuse_redundancy;
+ int cpr_fuse_target_quot[CPR_CORNER_MAX];
+ int cpr_fuse_ro_sel[CPR_CORNER_MAX];
+ int gcnt;
+
+ unsigned int cpr_irq;
+ void __iomem *rbcpr_base;
+ struct mutex cpr_mutex;
+
+ int ceiling_volt[CPR_CORNER_MAX];
+ int floor_volt[CPR_CORNER_MAX];
+ int last_volt[CPR_CORNER_MAX];
+ int step_volt;
+
+ int save_ctl[CPR_CORNER_MAX];
+ int save_irq[CPR_CORNER_MAX];
+
+ u32 save_regs[CPR_NUM_SAVE_REGS];
+ u32 save_reg_val[CPR_NUM_SAVE_REGS];
+
+ /* Config parameters */
+ bool enable;
+ u32 ref_clk_khz;
+ u32 timer_delay_us;
+ u32 timer_cons_up;
+ u32 timer_cons_down;
+ u32 irq_line;
+ u32 step_quotient;
+ u32 up_threshold;
+ u32 down_threshold;
+ u32 idle_clocks;
+ u32 gcnt_time_us;
+ u32 vdd_apc_step_up_limit;
+ u32 vdd_apc_step_down_limit;
};
+static int cpr_debug_enable;
+static int cpr_enable;
+static struct cpr_regulator *the_cpr;
+
+module_param_named(debug_enable, cpr_debug_enable, int, S_IRUGO | S_IWUSR);
+#define cpr_debug(message, ...) \
+ do { \
+ if (cpr_debug_enable) \
+ pr_info(message, ##__VA_ARGS__); \
+ } while (0)
+
+static bool cpr_is_allowed(struct cpr_regulator *cpr_vreg)
+{
+ if (cpr_vreg->cpr_fuse_disable || !cpr_enable)
+ return false;
+ else
+ return true;
+}
+
+static void cpr_write(struct cpr_regulator *cpr_vreg, u32 offset, u32 value)
+{
+ writel_relaxed(value, cpr_vreg->rbcpr_base + offset);
+}
+
+static u32 cpr_read(struct cpr_regulator *cpr_vreg, u32 offset)
+{
+ return readl_relaxed(cpr_vreg->rbcpr_base + offset);
+}
+
+static void cpr_masked_write(struct cpr_regulator *cpr_vreg, u32 offset,
+ u32 mask, u32 value)
+{
+ u32 reg_val;
+
+ reg_val = readl_relaxed(cpr_vreg->rbcpr_base + offset);
+ reg_val &= ~mask;
+ reg_val |= value & mask;
+ writel_relaxed(reg_val, cpr_vreg->rbcpr_base + offset);
+}
+
+static void cpr_irq_clr(struct cpr_regulator *cpr_vreg)
+{
+ cpr_write(cpr_vreg, REG_RBIF_IRQ_CLEAR, CPR_INT_ALL);
+}
+
+static void cpr_irq_clr_nack(struct cpr_regulator *cpr_vreg)
+{
+ cpr_irq_clr(cpr_vreg);
+ cpr_write(cpr_vreg, REG_RBIF_CONT_NACK_CMD, 1);
+}
+
+static void cpr_irq_clr_ack(struct cpr_regulator *cpr_vreg)
+{
+ cpr_irq_clr(cpr_vreg);
+ cpr_write(cpr_vreg, REG_RBIF_CONT_ACK_CMD, 1);
+}
+
+static void cpr_irq_set(struct cpr_regulator *cpr_vreg, u32 int_bits)
+{
+ cpr_write(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line), int_bits);
+}
+
+static void cpr_ctl_modify(struct cpr_regulator *cpr_vreg, u32 mask, u32 value)
+{
+ cpr_masked_write(cpr_vreg, REG_RBCPR_CTL, mask, value);
+}
+
+static void cpr_ctl_enable(struct cpr_regulator *cpr_vreg)
+{
+ u32 val;
+
+ if (cpr_is_allowed(cpr_vreg))
+ val = RBCPR_CTL_LOOP_EN;
+ else
+ val = 0;
+ cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, val);
+}
+
+static void cpr_ctl_disable(struct cpr_regulator *cpr_vreg)
+{
+ cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, 0);
+}
+
+static void cpr_regs_save(struct cpr_regulator *cpr_vreg)
+{
+ int i, offset;
+
+ for (i = 0; i < CPR_NUM_SAVE_REGS; i++) {
+ offset = cpr_vreg->save_regs[i];
+ cpr_vreg->save_reg_val[i] = cpr_read(cpr_vreg, offset);
+ }
+}
+
+static void cpr_regs_restore(struct cpr_regulator *cpr_vreg)
+{
+ int i, offset;
+ u32 val;
+
+ for (i = 0; i < CPR_NUM_SAVE_REGS; i++) {
+ offset = cpr_vreg->save_regs[i];
+ val = cpr_vreg->save_reg_val[i];
+ cpr_write(cpr_vreg, offset, val);
+ }
+}
+
+static void cpr_corner_save(struct cpr_regulator *cpr_vreg, int corner)
+{
+ cpr_vreg->save_ctl[corner] = cpr_read(cpr_vreg, REG_RBCPR_CTL);
+ cpr_vreg->save_irq[corner] =
+ cpr_read(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line));
+}
+
+static void cpr_corner_restore(struct cpr_regulator *cpr_vreg, int corner)
+{
+ u32 gcnt, ctl, irq, ro_sel;
+
+ ro_sel = cpr_vreg->cpr_fuse_ro_sel[corner];
+ gcnt = cpr_vreg->gcnt | cpr_vreg->cpr_fuse_target_quot[corner];
+ cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(ro_sel), gcnt);
+ ctl = cpr_vreg->save_ctl[corner];
+ cpr_write(cpr_vreg, REG_RBCPR_CTL, ctl);
+ irq = cpr_vreg->save_irq[corner];
+ cpr_irq_set(cpr_vreg, irq);
+ cpr_debug("gcnt = 0x%08x, ctl = 0x%08x, irq = 0x%08x\n",
+ gcnt, ctl, irq);
+}
+
+static void cpr_corner_switch(struct cpr_regulator *cpr_vreg, int corner)
+{
+ if (cpr_vreg->corner == corner)
+ return;
+
+ cpr_corner_restore(cpr_vreg, corner);
+}
+
+/* Module parameter ops */
+static int cpr_enable_param_set(const char *val, const struct kernel_param *kp)
+{
+ int rc;
+ int old_cpr_enable;
+
+ if (!the_cpr) {
+ pr_err("the_cpr = NULL\n");
+ return -ENXIO;
+ }
+
+ mutex_lock(&the_cpr->cpr_mutex);
+
+ old_cpr_enable = cpr_enable;
+ rc = param_set_int(val, kp);
+ if (rc) {
+ pr_err("param_set_int: rc = %d\n", rc);
+ goto _exit;
+ }
+
+ cpr_debug("%d -> %d [corner=%d]\n",
+ old_cpr_enable, cpr_enable, the_cpr->corner);
+
+ if (the_cpr->cpr_fuse_disable) {
+ /* Already disabled */
+ pr_info("CPR disabled by fuse\n");
+ goto _exit;
+ }
+
+ if ((old_cpr_enable != cpr_enable) && the_cpr->corner) {
+ if (cpr_enable) {
+ cpr_ctl_disable(the_cpr);
+ cpr_irq_clr(the_cpr);
+ cpr_corner_restore(the_cpr, the_cpr->corner);
+ cpr_ctl_enable(the_cpr);
+ } else {
+ cpr_ctl_disable(the_cpr);
+ cpr_irq_set(the_cpr, 0);
+ }
+ }
+
+_exit:
+ mutex_unlock(&the_cpr->cpr_mutex);
+ return 0;
+}
+
+static struct kernel_param_ops cpr_enable_ops = {
+ .set = cpr_enable_param_set,
+ .get = param_get_int,
+};
+
+module_param_cb(cpr_enable, &cpr_enable_ops, &cpr_enable, S_IRUGO | S_IWUSR);
+
+static int cpr_apc_set(struct cpr_regulator *cpr_vreg, u32 new_volt)
+{
+ int max_volt, rc;
+
+ max_volt = cpr_vreg->ceiling_max;
+ rc = regulator_set_voltage(cpr_vreg->vdd_apc, new_volt, max_volt);
+ if (rc)
+ pr_err("set: vdd_apc = %d uV: rc=%d\n", new_volt, rc);
+ return rc;
+}
+
+static int cpr_mx_get(struct cpr_regulator *cpr_vreg, int corner, int apc_volt)
+{
+ int vdd_mx;
+
+ switch (cpr_vreg->vdd_mx_vmin_method) {
+ case VDD_MX_VMIN_APC:
+ vdd_mx = apc_volt;
+ break;
+ case VDD_MX_VMIN_APC_CORNER_CEILING:
+ vdd_mx = cpr_vreg->ceiling_volt[corner];
+ break;
+ case VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
+ vdd_mx = cpr_vreg->pvs_corner_v[APC_PVS_SLOW]
+ [CPR_CORNER_TURBO];
+ break;
+ case VDD_MX_VMIN_MX_VMAX:
+ vdd_mx = cpr_vreg->vdd_mx_vmax;
+ break;
+ default:
+ vdd_mx = 0;
+ break;
+ }
+
+ return vdd_mx;
+}
+
+static int cpr_mx_set(struct cpr_regulator *cpr_vreg, int corner,
+ int vdd_mx_vmin)
+{
+ int rc;
+
+ rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
+ cpr_vreg->vdd_mx_vmax);
+ cpr_debug("[corner:%d] %d uV\n", corner, vdd_mx_vmin);
+ if (!rc)
+ cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
+ else
+ pr_err("set: vdd_mx [%d] = %d uV: rc=%d\n",
+ corner, vdd_mx_vmin, rc);
+ return rc;
+}
+
+static int cpr_scale_voltage(struct cpr_regulator *cpr_vreg, int corner,
+ int new_apc_volt, enum voltage_change_dir dir)
+{
+ int rc = 0, vdd_mx_vmin = 0;
+
+ /* No MX scaling if no vdd_mx */
+ if (cpr_vreg->vdd_mx == NULL)
+ dir = NO_CHANGE;
+
+ if (dir != NO_CHANGE) {
+ /* Determine the vdd_mx voltage */
+ vdd_mx_vmin = cpr_mx_get(cpr_vreg, corner, new_apc_volt);
+ }
+
+ if (vdd_mx_vmin && dir == UP) {
+ if (vdd_mx_vmin != cpr_vreg->vdd_mx_vmin)
+ rc = cpr_mx_set(cpr_vreg, corner, vdd_mx_vmin);
+ }
+
+ if (!rc)
+ rc = cpr_apc_set(cpr_vreg, new_apc_volt);
+
+ if (!rc && vdd_mx_vmin && dir == DOWN) {
+ if (vdd_mx_vmin != cpr_vreg->vdd_mx_vmin)
+ rc = cpr_mx_set(cpr_vreg, corner, vdd_mx_vmin);
+ }
+
+ return rc;
+}
+
+static void cpr_scale(struct cpr_regulator *cpr_vreg,
+ enum voltage_change_dir dir)
+{
+ u32 reg_val, error_steps, reg_mask;
+ int last_volt, new_volt, corner;
+
+ corner = cpr_vreg->corner;
+
+ reg_val = cpr_read(cpr_vreg, REG_RBCPR_RESULT_0);
+
+ error_steps = (reg_val >> RBCPR_RESULT0_ERROR_STEPS_SHIFT)
+ & RBCPR_RESULT0_ERROR_STEPS_MASK;
+ last_volt = cpr_vreg->last_volt[corner];
+
+ cpr_debug("last_volt[corner:%d] = %d uV\n", corner, last_volt);
+
+ if (dir == UP) {
+ cpr_debug("Up: cpr status = 0x%08x (error_steps=%d)\n",
+ reg_val, error_steps);
+
+ if (last_volt >= cpr_vreg->ceiling_volt[corner]) {
+ cpr_debug("[corn:%d] @ ceiling: %d >= %d: NACK\n",
+ corner, last_volt,
+ cpr_vreg->ceiling_volt[corner]);
+ cpr_irq_clr_nack(cpr_vreg);
+
+ /* Maximize the UP threshold */
+ reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK <<
+ RBCPR_CTL_UP_THRESHOLD_SHIFT;
+ reg_val = reg_mask;
+ cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
+ return;
+ }
+
+ if (error_steps > cpr_vreg->vdd_apc_step_up_limit) {
+ cpr_debug("%d is over up-limit(%d): Clamp\n",
+ error_steps,
+ cpr_vreg->vdd_apc_step_up_limit);
+ error_steps = cpr_vreg->vdd_apc_step_up_limit;
+ }
+
+ /* Calculate new voltage */
+ new_volt = last_volt + (error_steps * cpr_vreg->step_volt);
+ if (new_volt > cpr_vreg->ceiling_volt[corner]) {
+ cpr_debug("new_volt(%d) >= ceiling_volt(%d): Clamp\n",
+ new_volt, cpr_vreg->ceiling_volt[corner]);
+ new_volt = cpr_vreg->ceiling_volt[corner];
+ }
+
+ if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
+ cpr_irq_clr_nack(cpr_vreg);
+ return;
+ }
+ cpr_vreg->last_volt[corner] = new_volt;
+
+ /* Restore default threshold for DOWN */
+ reg_mask = RBCPR_CTL_DN_THRESHOLD_MASK <<
+ RBCPR_CTL_DN_THRESHOLD_SHIFT;
+ reg_val = cpr_vreg->down_threshold <<
+ RBCPR_CTL_DN_THRESHOLD_SHIFT;
+ /* and disable auto nack down */
+ reg_mask |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+
+ cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
+
+ /* Re-enable default interrupts */
+ cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
+
+ /* Ack */
+ cpr_irq_clr_ack(cpr_vreg);
+
+ cpr_debug("UP: -> new_volt = %d uV\n", new_volt);
+ } else if (dir == DOWN) {
+ cpr_debug("Down: cpr status = 0x%08x (error_steps=%d)\n",
+ reg_val, error_steps);
+
+ if (last_volt <= cpr_vreg->floor_volt[corner]) {
+ cpr_debug("[corn:%d] @ floor: %d <= %d: NACK\n",
+ corner, last_volt,
+ cpr_vreg->floor_volt[corner]);
+ cpr_irq_clr_nack(cpr_vreg);
+
+ /* Maximize the DOWN threshold */
+ reg_mask = RBCPR_CTL_DN_THRESHOLD_MASK <<
+ RBCPR_CTL_DN_THRESHOLD_SHIFT;
+ reg_val = reg_mask;
+
+ /* Enable auto nack down */
+ reg_mask |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+ reg_val |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+
+ cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
+
+ /* Disable DOWN interrupt */
+ cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT & ~CPR_INT_DOWN);
+
+ return;
+ }
+
+ if (error_steps > cpr_vreg->vdd_apc_step_down_limit) {
+ cpr_debug("%d is over down-limit(%d): Clamp\n",
+ error_steps,
+ cpr_vreg->vdd_apc_step_down_limit);
+ error_steps = cpr_vreg->vdd_apc_step_down_limit;
+ }
+
+ /* Calculte new voltage */
+ new_volt = last_volt - (error_steps * cpr_vreg->step_volt);
+ if (new_volt < cpr_vreg->floor_volt[corner]) {
+ cpr_debug("new_volt(%d) < floor_volt(%d): Clamp\n",
+ new_volt, cpr_vreg->floor_volt[corner]);
+ new_volt = cpr_vreg->floor_volt[corner];
+ }
+
+ if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
+ cpr_irq_clr_nack(cpr_vreg);
+ return;
+ }
+ cpr_vreg->last_volt[corner] = new_volt;
+
+ /* Restore default threshold for UP */
+ reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK <<
+ RBCPR_CTL_UP_THRESHOLD_SHIFT;
+ reg_val = cpr_vreg->up_threshold <<
+ RBCPR_CTL_UP_THRESHOLD_SHIFT;
+ cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
+
+ /* Ack */
+ cpr_irq_clr_ack(cpr_vreg);
+
+ cpr_debug("DOWN: -> new_volt = %d uV\n", new_volt);
+ }
+}
+
+static irqreturn_t cpr_irq_handler(int irq, void *dev)
+{
+ struct cpr_regulator *cpr_vreg = dev;
+ u32 reg_val;
+
+ mutex_lock(&cpr_vreg->cpr_mutex);
+
+ reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
+ cpr_debug("IRQ_STATUS = 0x%02X\n", reg_val);
+
+ if (!cpr_is_allowed(cpr_vreg)) {
+ reg_val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
+ pr_err("Interrupt broken? RBCPR_CTL = 0x%02X\n", reg_val);
+ goto _exit;
+ }
+
+ /* Following sequence of handling is as per each IRQ's priority */
+ if (reg_val & CPR_INT_UP) {
+ cpr_scale(cpr_vreg, UP);
+ } else if (reg_val & CPR_INT_DOWN) {
+ cpr_scale(cpr_vreg, DOWN);
+ } else if (reg_val & CPR_INT_MIN) {
+ cpr_irq_clr_nack(cpr_vreg);
+ } else if (reg_val & CPR_INT_MAX) {
+ cpr_irq_clr_nack(cpr_vreg);
+ } else if (reg_val & CPR_INT_MID) {
+ /* RBCPR_CTL_SW_AUTO_CONT_ACK_EN is enabled */
+ cpr_debug("IRQ occured for Mid Flag\n");
+ } else {
+ pr_err("IRQ occured for unknown flag (0x%08x)\n", reg_val);
+ }
+
+ /* Save register values for the corner */
+ cpr_corner_save(cpr_vreg, cpr_vreg->corner);
+
+_exit:
+ mutex_unlock(&cpr_vreg->cpr_mutex);
+ return IRQ_HANDLED;
+}
+
static int cpr_regulator_is_enabled(struct regulator_dev *rdev)
{
struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
- return cpr_vreg->enabled;
+ return cpr_vreg->vreg_enabled;
}
static int cpr_regulator_enable(struct regulator_dev *rdev)
@@ -78,7 +677,7 @@
rc = regulator_enable(cpr_vreg->vdd_apc);
if (!rc)
- cpr_vreg->enabled = true;
+ cpr_vreg->vreg_enabled = true;
else
pr_err("regulator_enable: vdd_apc: rc=%d\n", rc);
@@ -98,7 +697,7 @@
if (rc)
pr_err("regulator_disable: vdd_mx: rc=%d\n", rc);
else
- cpr_vreg->enabled = false;
+ cpr_vreg->vreg_enabled = false;
} else {
pr_err("regulator_disable: vdd_apc: rc=%d\n", rc);
}
@@ -107,90 +706,44 @@
}
static int cpr_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+ int corner, int corner_max, unsigned *selector)
{
struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
int rc;
- int vdd_apc_min, vdd_apc_max, vdd_mx_vmin = 0;
- int change_dir = 0;
+ int new_volt;
+ enum voltage_change_dir change_dir = NO_CHANGE;
- if (cpr_vreg->vdd_mx) {
- if (min_uV > cpr_vreg->corner)
- change_dir = 1;
- else if (min_uV < cpr_vreg->corner)
- change_dir = -1;
- }
+ mutex_lock(&cpr_vreg->cpr_mutex);
- vdd_apc_min = cpr_vreg->corner_ceiling[min_uV];
- vdd_apc_max = cpr_vreg->corner_ceiling[CPR_CORNER_SUPER_TURBO];
-
- if (change_dir) {
- /* Determine the vdd_mx voltage */
- switch (cpr_vreg->vdd_mx_vmin_method) {
- case VDD_MX_VMIN_APC:
- vdd_mx_vmin = vdd_apc_min;
- break;
- case VDD_MX_VMIN_APC_CORNER_CEILING:
- vdd_mx_vmin = vdd_apc_min;
- break;
- case VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
- vdd_mx_vmin = cpr_vreg->pvs_corner_ceiling
- [APC_PVS_SLOW][min_uV];
- break;
- case VDD_MX_VMIN_MX_VMAX:
- default:
- vdd_mx_vmin = cpr_vreg->vdd_mx_vmax;
- break;
- }
- }
-
- if (change_dir > 0) {
- if (vdd_mx_vmin < cpr_vreg->vdd_mx_vmin) {
- /* Check and report the value in case */
- pr_err("Up: but new %d < old %d uV\n", vdd_mx_vmin,
- cpr_vreg->vdd_mx_vmin);
- }
-
- rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
- cpr_vreg->vdd_mx_vmax);
- if (!rc) {
- cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
- } else {
- pr_err("set: vdd_mx [%d] = %d uV: rc=%d\n",
- min_uV, vdd_mx_vmin, rc);
- return rc;
- }
- }
-
- rc = regulator_set_voltage(cpr_vreg->vdd_apc,
- vdd_apc_min, vdd_apc_max);
- if (!rc) {
- cpr_vreg->corner = min_uV;
+ if (cpr_is_allowed(cpr_vreg)) {
+ cpr_ctl_disable(cpr_vreg);
+ new_volt = cpr_vreg->last_volt[corner];
} else {
- pr_err("set: vdd_apc [%d] = %d uV: rc=%d\n",
- min_uV, vdd_apc_min, rc);
- return rc;
+ new_volt = cpr_vreg->pvs_corner_v[cpr_vreg->process][corner];
}
- if (change_dir < 0) {
- if (vdd_mx_vmin > cpr_vreg->vdd_mx_vmin) {
- /* Check and report the value in case */
- pr_err("Down: but new %d >= old %d uV\n", vdd_mx_vmin,
- cpr_vreg->vdd_mx_vmin);
- }
+ cpr_debug("[corner:%d] = %d uV\n", corner, new_volt);
- rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
- cpr_vreg->vdd_mx_vmax);
- if (!rc) {
- cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
- } else {
- pr_err("set: vdd_mx [%d] = %d uV: rc=%d\n",
- min_uV, vdd_mx_vmin, rc);
- return rc;
- }
+ if (corner > cpr_vreg->corner)
+ change_dir = UP;
+ else if (corner < cpr_vreg->corner)
+ change_dir = DOWN;
+
+ rc = cpr_scale_voltage(cpr_vreg, corner, new_volt, change_dir);
+ if (rc)
+ goto _exit;
+
+ if (cpr_is_allowed(cpr_vreg)) {
+ cpr_irq_clr(cpr_vreg);
+ cpr_corner_switch(cpr_vreg, corner);
+ cpr_ctl_enable(cpr_vreg);
}
- pr_debug("set [corner:%d] = %d uV: rc=%d\n", min_uV, vdd_apc_min, rc);
+ cpr_vreg->corner = corner;
+
+_exit:
+ mutex_unlock(&cpr_vreg->cpr_mutex);
+
return rc;
}
@@ -209,56 +762,202 @@
.get_voltage = cpr_regulator_get_voltage,
};
-static int __init cpr_regulator_pvs_init(struct cpr_regulator *cpr_vreg)
+#ifdef CONFIG_PM
+static int cpr_suspend(struct cpr_regulator *cpr_vreg)
+{
+ cpr_debug("suspend\n");
+
+ cpr_ctl_disable(cpr_vreg);
+ disable_irq(cpr_vreg->cpr_irq);
+
+ cpr_irq_clr(cpr_vreg);
+ cpr_regs_save(cpr_vreg);
+
+ return 0;
+}
+
+static int cpr_resume(struct cpr_regulator *cpr_vreg)
+
+{
+ cpr_debug("resume\n");
+
+ cpr_regs_restore(cpr_vreg);
+ cpr_irq_clr(cpr_vreg);
+
+ enable_irq(cpr_vreg->cpr_irq);
+ cpr_ctl_enable(cpr_vreg);
+
+ return 0;
+}
+
+static int cpr_regulator_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct cpr_regulator *cpr_vreg = platform_get_drvdata(pdev);
+
+ if (cpr_is_allowed(cpr_vreg))
+ return cpr_suspend(cpr_vreg);
+ else
+ return 0;
+}
+
+static int cpr_regulator_resume(struct platform_device *pdev)
+{
+ struct cpr_regulator *cpr_vreg = platform_get_drvdata(pdev);
+
+ if (cpr_is_allowed(cpr_vreg))
+ return cpr_resume(cpr_vreg);
+ else
+ return 0;
+}
+#else
+#define cpr_regulator_suspend NULL
+#define cpr_regulator_resume NULL
+#endif
+
+static void cpr_config(struct cpr_regulator *cpr_vreg)
+{
+ int i;
+ u32 val, gcnt;
+
+ /* Disable interrupt and CPR */
+ cpr_write(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line), 0);
+ cpr_write(cpr_vreg, REG_RBCPR_CTL, 0);
+
+ /* Program the default HW Ceiling, Floor and vlevel */
+ val = ((RBIF_LIMIT_CEILING_DEFAULT & RBIF_LIMIT_CEILING_MASK)
+ << RBIF_LIMIT_CEILING_SHIFT)
+ | (RBIF_LIMIT_FLOOR_DEFAULT & RBIF_LIMIT_FLOOR_MASK);
+ cpr_write(cpr_vreg, REG_RBIF_LIMIT, val);
+ cpr_write(cpr_vreg, REG_RBIF_SW_VLEVEL, RBIF_SW_VLEVEL_DEFAULT);
+
+ /* Clear the target quotient value and gate count of all ROs */
+ for (i = 0; i < CPR_NUM_RING_OSC; i++)
+ cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(i), 0);
+
+ /* Init and save gcnt */
+ gcnt = (cpr_vreg->ref_clk_khz * cpr_vreg->gcnt_time_us) / 1000;
+ gcnt = (gcnt & RBCPR_GCNT_TARGET_GCNT_MASK) <<
+ RBCPR_GCNT_TARGET_GCNT_SHIFT;
+ cpr_vreg->gcnt = gcnt;
+
+ /* Program the step quotient and idle clocks */
+ val = ((cpr_vreg->idle_clocks & RBCPR_STEP_QUOT_IDLE_CLK_MASK)
+ << RBCPR_STEP_QUOT_IDLE_CLK_SHIFT) |
+ (cpr_vreg->step_quotient & RBCPR_STEP_QUOT_STEPQUOT_MASK);
+ cpr_write(cpr_vreg, REG_RBCPR_STEP_QUOT, val);
+
+ /* Program the delay count for the timer */
+ val = (cpr_vreg->ref_clk_khz * cpr_vreg->timer_delay_us) / 1000;
+ cpr_write(cpr_vreg, REG_RBCPR_TIMER_INTERVAL, val);
+ pr_info("Timer count: 0x%0x (for %d us)\n", val,
+ cpr_vreg->timer_delay_us);
+
+ /* Program Consecutive Up & Down */
+ val = ((cpr_vreg->timer_cons_down & RBIF_TIMER_ADJ_CONS_DOWN_MASK)
+ << RBIF_TIMER_ADJ_CONS_DOWN_SHIFT) |
+ (cpr_vreg->timer_cons_up & RBIF_TIMER_ADJ_CONS_UP_MASK);
+ cpr_write(cpr_vreg, REG_RBIF_TIMER_ADJUST, val);
+
+ /* Program the control register */
+ cpr_vreg->up_threshold &= RBCPR_CTL_UP_THRESHOLD_MASK;
+ cpr_vreg->down_threshold &= RBCPR_CTL_DN_THRESHOLD_MASK;
+ val = (cpr_vreg->up_threshold << RBCPR_CTL_UP_THRESHOLD_SHIFT)
+ | (cpr_vreg->down_threshold << RBCPR_CTL_DN_THRESHOLD_SHIFT);
+ val |= RBCPR_CTL_TIMER_EN | RBCPR_CTL_COUNT_MODE;
+ val |= RBCPR_CTL_SW_AUTO_CONT_ACK_EN;
+ cpr_write(cpr_vreg, REG_RBCPR_CTL, val);
+
+ /* Registers to save & restore for suspend */
+ cpr_vreg->save_regs[0] = REG_RBCPR_TIMER_INTERVAL;
+ cpr_vreg->save_regs[1] = REG_RBCPR_STEP_QUOT;
+ cpr_vreg->save_regs[2] = REG_RBIF_TIMER_ADJUST;
+ cpr_vreg->save_regs[3] = REG_RBIF_LIMIT;
+ cpr_vreg->save_regs[4] = REG_RBIF_SW_VLEVEL;
+ cpr_vreg->save_regs[5] = REG_RBIF_IRQ_EN(cpr_vreg->irq_line);
+ cpr_vreg->save_regs[6] = REG_RBCPR_CTL;
+ cpr_vreg->save_regs[7] = REG_RBCPR_GCNT_TARGET
+ (cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_SVS]);
+ cpr_vreg->save_regs[8] = REG_RBCPR_GCNT_TARGET
+ (cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_NORMAL]);
+ cpr_vreg->save_regs[9] = REG_RBCPR_GCNT_TARGET
+ (cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_TURBO]);
+
+ cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
+
+ cpr_corner_save(cpr_vreg, CPR_CORNER_SVS);
+ cpr_corner_save(cpr_vreg, CPR_CORNER_NORMAL);
+ cpr_corner_save(cpr_vreg, CPR_CORNER_TURBO);
+}
+
+static int __init cpr_pvs_init(struct cpr_regulator *cpr_vreg)
{
void __iomem *efuse_base;
- u32 efuse_bits;
- int i, bit_pos;
- u32 vmax;
+ u32 efuse_bits, redundant, shift, mask;
+ int i, process;
- efuse_base = ioremap(cpr_vreg->efuse_phys, 4);
+ efuse_base = ioremap(cpr_vreg->pvs_efuse, 4);
if (!efuse_base) {
- pr_err("Unable to map efuse_phys 0x%x\n",
- cpr_vreg->efuse_phys);
+ pr_err("Unable to map pvs_efuse 0x%08x\n",
+ cpr_vreg->pvs_efuse);
return -EINVAL;
}
efuse_bits = readl_relaxed(efuse_base);
/* Construct PVS process # from the efuse bits */
- for (i = 0; i < cpr_vreg->num_efuse_bits; i++) {
- bit_pos = cpr_vreg->efuse_bit_pos[i];
- cpr_vreg->pvs_bin |= (efuse_bits & BIT(bit_pos)) ? BIT(i) : 0;
- }
+ redundant = (efuse_bits >> PVS_FUSE_REDUNDANT_SHIFT)
+ & PVS_FUSE_REDUNDANT_MASK;
+ if (redundant == 2)
+ shift = PVS_FUSE_BINS_REDUNDANT_SHIFT;
+ else
+ shift = PVS_FUSE_BINS_SHIFT;
+ mask = (1 << cpr_vreg->num_efuse_bits) - 1;
+ cpr_vreg->pvs_bin = (efuse_bits >> shift) & mask;
- cpr_vreg->pvs_process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
- if (cpr_vreg->pvs_process >= NUM_APC_PVS)
- cpr_vreg->pvs_process = APC_PVS_NO;
-
- /* Use ceiling voltage of Turbo@Slow for all corners of APC_PVS_NO
- but use SuperTurbo@Slow for its SuperTurbo */
- vmax = cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW][CPR_CORNER_TURBO];
- for (i = CPR_CORNER_SVS; i <= CPR_CORNER_TURBO; i++)
- cpr_vreg->pvs_corner_ceiling[APC_PVS_NO][i] = vmax;
- cpr_vreg->pvs_corner_ceiling[APC_PVS_NO][CPR_CORNER_SUPER_TURBO]
- = cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW]
- [CPR_CORNER_SUPER_TURBO];
-
- cpr_vreg->corner_ceiling =
- cpr_vreg->pvs_corner_ceiling[cpr_vreg->pvs_process];
+ /* Set ceiling max and use it for APC_PVS_NO */
+ cpr_vreg->ceiling_max =
+ cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_TURBO];
iounmap(efuse_base);
- pr_info("PVS Info: efuse_phys=0x%08X, n_bits=%d\n",
- cpr_vreg->efuse_phys, cpr_vreg->num_efuse_bits);
- pr_info("PVS Info: efuse=0x%08X, bin=%d, process=%d\n",
- efuse_bits, cpr_vreg->pvs_bin, cpr_vreg->pvs_process);
+ process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
+ pr_info("[0x%08X] = 0x%08X, n_bits=%d, bin=%d (%d) [redundant=%d]\n",
+ cpr_vreg->pvs_efuse, efuse_bits, cpr_vreg->num_efuse_bits,
+ cpr_vreg->pvs_bin, process, redundant);
+ for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++) {
+ pr_info("[%d] [%d %d %d] uV\n", i,
+ cpr_vreg->pvs_corner_v[i][CPR_CORNER_SVS],
+ cpr_vreg->pvs_corner_v[i][CPR_CORNER_NORMAL],
+ cpr_vreg->pvs_corner_v[i][CPR_CORNER_TURBO]);
+ }
+
+ if (process == APC_PVS_NO || process >= NUM_APC_PVS) {
+ pr_err("Bin=%d (%d) is out of spec. Assume SLOW.\n",
+ cpr_vreg->pvs_bin, process);
+ process = APC_PVS_SLOW;
+ }
+
+ cpr_vreg->process = process;
return 0;
}
-static int __init cpr_regulator_apc_init(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
+#define CPR_PROP_READ_U32(of_node, cpr_property, cpr_config, rc) \
+do { \
+ if (!rc) { \
+ rc = of_property_read_u32(of_node, \
+ "qcom," cpr_property, \
+ cpr_config); \
+ if (rc) { \
+ pr_err("Missing " #cpr_property \
+ ": rc = %d\n", rc); \
+ } \
+ } \
+} while (0)
+
+static int __init cpr_apc_init(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
{
struct device_node *of_node = pdev->dev.of_node;
int rc;
@@ -308,9 +1007,9 @@
return 0;
}
-static void cpr_regulator_apc_exit(struct cpr_regulator *cpr_vreg)
+static void cpr_apc_exit(struct cpr_regulator *cpr_vreg)
{
- if (cpr_vreg->enabled) {
+ if (cpr_vreg->vreg_enabled) {
regulator_disable(cpr_vreg->vdd_apc);
if (cpr_vreg->vdd_mx)
@@ -318,8 +1017,231 @@
}
}
-static int __init cpr_regulator_parse_dt(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
+static int __init cpr_init_cpr_efuse(struct cpr_regulator *cpr_vreg)
+{
+ void __iomem *efuse_base;
+ u32 ro_sel, val;
+ u64 fuse_bits;
+ int ro_sel_shift[CPR_CORNER_MAX];
+
+ efuse_base = ioremap(cpr_vreg->cpr_fuse_addr, 16);
+ if (!efuse_base) {
+ pr_err("Unable to map cpr_fuse_addr 0x%08x\n",
+ cpr_vreg->cpr_fuse_addr);
+ return -EINVAL;
+ }
+
+ cpr_vreg->cpr_fuse_bits = readll_relaxed(efuse_base);
+ cpr_vreg->cpr_fuse_bits_2 = readll_relaxed(efuse_base + 8);
+
+ iounmap(efuse_base);
+
+ /* Read the control bits of eFuse */
+ cpr_vreg->cpr_fuse_disable = (cpr_vreg->cpr_fuse_bits >>
+ CPR_FUSE_DISABLE_CPR_SHIFT) & 0x01;
+ cpr_vreg->cpr_fuse_local = (cpr_vreg->cpr_fuse_bits >>
+ CPR_FUSE_LOCAL_APPROACH_SHIFT) & 0x01;
+ cpr_vreg->cpr_fuse_redundancy = (cpr_vreg->cpr_fuse_bits >>
+ CPR_FUSE_REDUNDANT_SHIFT) & 0x01;
+
+ pr_info("[0x%08X] = 0x%llx\n", cpr_vreg->cpr_fuse_addr,
+ cpr_vreg->cpr_fuse_bits);
+ pr_info("disable = %d, local = %d, redundancy = %d\n",
+ cpr_vreg->cpr_fuse_disable,
+ cpr_vreg->cpr_fuse_local,
+ cpr_vreg->cpr_fuse_redundancy);
+ pr_info("[0x%08X] = 0x%llx\n", cpr_vreg->cpr_fuse_addr + 8,
+ cpr_vreg->cpr_fuse_bits_2);
+
+ if (cpr_vreg->cpr_fuse_redundancy == 0) {
+ fuse_bits = cpr_vreg->cpr_fuse_bits;
+ ro_sel_shift[CPR_CORNER_SVS] = 54;
+ ro_sel_shift[CPR_CORNER_NORMAL] = 38;
+ ro_sel_shift[CPR_CORNER_TURBO] = 41;
+ } else {
+ fuse_bits = cpr_vreg->cpr_fuse_bits_2;
+ ro_sel_shift[CPR_CORNER_SVS] = 46;
+ ro_sel_shift[CPR_CORNER_NORMAL] = 36;
+ ro_sel_shift[CPR_CORNER_TURBO] = 39;
+ }
+
+ /* SVS */
+ ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_SVS])
+ & CPR_FUSE_RO_SEL_BITS_MASK;
+ val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_SVS_SHIFT)
+ & CPR_FUSE_TARGET_QUOT_BITS_MASK;
+ cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_SVS] = val;
+ cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_SVS] = ro_sel;
+ pr_info("SVS: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
+
+ /* Nominal */
+ ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_NORMAL])
+ & CPR_FUSE_RO_SEL_BITS_MASK;
+ val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_NOMINAL_SHIFT)
+ & CPR_FUSE_TARGET_QUOT_BITS_MASK;
+ cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_NORMAL] = val;
+ cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_NORMAL] = ro_sel;
+ pr_info("Nominal: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
+
+ /* Turbo */
+ ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_TURBO])
+ & CPR_FUSE_RO_SEL_BITS_MASK;
+ val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_TURBO_SHIFT)
+ & CPR_FUSE_TARGET_QUOT_BITS_MASK;
+ cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_TURBO] = val;
+ cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_TURBO] = ro_sel;
+ pr_info("Turbo: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
+
+ if (!cpr_vreg->cpr_fuse_bits) {
+ cpr_vreg->cpr_fuse_disable = 1;
+ pr_err("cpr_fuse_bits = 0: set cpr_fuse_disable = 1\n");
+ }
+
+ return 0;
+}
+
+static int __init cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg)
+{
+ int i;
+
+ /* Construct CPR voltage limits */
+ for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+ cpr_vreg->floor_volt[i] =
+ cpr_vreg->pvs_corner_v[APC_PVS_FAST][i];
+ cpr_vreg->ceiling_volt[i] =
+ cpr_vreg->pvs_corner_v[APC_PVS_SLOW][i];
+ cpr_vreg->last_volt[i] =
+ cpr_vreg->pvs_corner_v[cpr_vreg->process][i];
+ }
+
+ return 0;
+}
+
+static int __init cpr_init_cpr_parameters(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
+{
+ struct device_node *of_node = pdev->dev.of_node;
+ int rc = 0;
+
+ CPR_PROP_READ_U32(of_node, "cpr-ref-clk",
+ &cpr_vreg->ref_clk_khz, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-timer-delay",
+ &cpr_vreg->timer_delay_us, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-timer-cons-up",
+ &cpr_vreg->timer_cons_up, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-timer-cons-down",
+ &cpr_vreg->timer_cons_down, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-irq-line",
+ &cpr_vreg->irq_line, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-step-quotient",
+ &cpr_vreg->step_quotient, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-up-threshold",
+ &cpr_vreg->up_threshold, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-down-threshold",
+ &cpr_vreg->down_threshold, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-idle-clocks",
+ &cpr_vreg->idle_clocks, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-gcnt-time",
+ &cpr_vreg->gcnt_time_us, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "vdd-apc-step-up-limit",
+ &cpr_vreg->vdd_apc_step_up_limit, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "vdd-apc-step-down-limit",
+ &cpr_vreg->vdd_apc_step_down_limit, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-apc-volt-step",
+ &cpr_vreg->step_volt, rc);
+ if (rc)
+ return rc;
+
+ /* Init module parameter with the DT value */
+ cpr_vreg->enable = of_property_read_bool(of_node, "qcom,cpr-enable");
+ cpr_enable = (int) cpr_vreg->enable;
+ pr_info("CPR is %s by default.\n",
+ cpr_vreg->enable ? "enabled" : "disabled");
+
+ return rc;
+}
+
+static int __init cpr_init_cpr(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
+{
+ struct resource *res;
+ int rc = 0;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "cpr_efuse");
+ if (!res || !res->start) {
+ pr_err("cpr_efuse missing: res=%p\n", res);
+ return -EINVAL;
+ }
+ cpr_vreg->cpr_fuse_addr = res->start;
+
+ rc = cpr_init_cpr_efuse(cpr_vreg);
+ if (rc)
+ return rc;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rbcpr");
+ if (!res || !res->start) {
+ pr_err("missing rbcpr address: res=%p\n", res);
+ return -EINVAL;
+ }
+ cpr_vreg->rbcpr_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+
+ /* Init all voltage set points of APC regulator for CPR */
+ cpr_init_cpr_voltages(cpr_vreg);
+
+ /* Init CPR configuration parameters */
+ rc = cpr_init_cpr_parameters(pdev, cpr_vreg);
+ if (rc)
+ return rc;
+
+ /* Get and Init interrupt */
+ cpr_vreg->cpr_irq = platform_get_irq(pdev, 0);
+ if (!cpr_vreg->cpr_irq) {
+ pr_err("missing CPR IRQ\n");
+ return -EINVAL;
+ }
+
+ /* Configure CPR HW but keep it disabled */
+ cpr_config(cpr_vreg);
+
+ rc = request_threaded_irq(cpr_vreg->cpr_irq, NULL, cpr_irq_handler,
+ IRQF_TRIGGER_RISING, "cpr", cpr_vreg);
+ if (rc) {
+ pr_err("CPR: request irq failed for IRQ %d\n",
+ cpr_vreg->cpr_irq);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int __init cpr_pvs_parse_dt(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
{
struct device_node *of_node = pdev->dev.of_node;
struct resource *res;
@@ -327,13 +1249,12 @@
size_t pvs_bins;
/* Parse process voltage parameters */
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "efuse_phys");
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pvs_efuse");
if (!res || !res->start) {
- pr_err("efuse_phys missing: res=%p\n", res);
+ pr_err("pvs_efuse missing: res=%p\n", res);
return -EINVAL;
}
- cpr_vreg->efuse_phys = res->start;
+ cpr_vreg->pvs_efuse = res->start;
rc = of_property_read_u32(of_node, "qcom,num-efuse-bits",
&cpr_vreg->num_efuse_bits);
@@ -349,14 +1270,6 @@
return -EINVAL;
}
- rc = of_property_read_u32_array(of_node, "qcom,efuse-bit-pos",
- cpr_vreg->efuse_bit_pos,
- cpr_vreg->num_efuse_bits);
- if (rc < 0) {
- pr_err("efuse-bit-pos missing: rc=%d\n", rc);
- return rc;
- }
-
pvs_bins = 1 << cpr_vreg->num_efuse_bits;
rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
cpr_vreg->pvs_bin_process,
@@ -368,7 +1281,7 @@
rc = of_property_read_u32_array(of_node,
"qcom,pvs-corner-ceiling-slow",
- &cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW][CPR_CORNER_SVS],
+ &cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_SVS],
CPR_CORNER_MAX - CPR_CORNER_SVS);
if (rc < 0) {
pr_err("pvs-corner-ceiling-slow missing: rc=%d\n", rc);
@@ -377,7 +1290,7 @@
rc = of_property_read_u32_array(of_node,
"qcom,pvs-corner-ceiling-nom",
- &cpr_vreg->pvs_corner_ceiling[APC_PVS_NOM][CPR_CORNER_SVS],
+ &cpr_vreg->pvs_corner_v[APC_PVS_NOM][CPR_CORNER_SVS],
CPR_CORNER_MAX - CPR_CORNER_SVS);
if (rc < 0) {
pr_err("pvs-corner-ceiling-norm missing: rc=%d\n", rc);
@@ -386,7 +1299,7 @@
rc = of_property_read_u32_array(of_node,
"qcom,pvs-corner-ceiling-fast",
- &cpr_vreg->pvs_corner_ceiling[APC_PVS_FAST][CPR_CORNER_SVS],
+ &cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS],
CPR_CORNER_MAX - CPR_CORNER_SVS);
if (rc < 0) {
pr_err("pvs-corner-ceiling-fast missing: rc=%d\n", rc);
@@ -426,25 +1339,33 @@
return -ENOMEM;
}
- rc = cpr_regulator_parse_dt(pdev, cpr_vreg);
+ rc = cpr_pvs_parse_dt(pdev, cpr_vreg);
if (rc) {
pr_err("Wrong DT parameter specified: rc=%d\n", rc);
return rc;
}
- rc = cpr_regulator_pvs_init(cpr_vreg);
+ rc = cpr_pvs_init(cpr_vreg);
if (rc) {
pr_err("Initialize PVS wrong: rc=%d\n", rc);
return rc;
}
- rc = cpr_regulator_apc_init(pdev, cpr_vreg);
+ rc = cpr_apc_init(pdev, cpr_vreg);
if (rc) {
if (rc != -EPROBE_DEFER)
pr_err("Initialize APC wrong: rc=%d\n", rc);
return rc;
}
+ rc = cpr_init_cpr(pdev, cpr_vreg);
+ if (rc) {
+ pr_err("Initialize CPR failed: rc=%d\n", rc);
+ return rc;
+ }
+
+ mutex_init(&cpr_vreg->cpr_mutex);
+
rdesc = &cpr_vreg->rdesc;
rdesc->owner = THIS_MODULE;
rdesc->type = REGULATOR_VOLTAGE;
@@ -457,17 +1378,12 @@
rc = PTR_ERR(cpr_vreg->rdev);
pr_err("regulator_register failed: rc=%d\n", rc);
- cpr_regulator_apc_exit(cpr_vreg);
+ cpr_apc_exit(cpr_vreg);
return rc;
}
platform_set_drvdata(pdev, cpr_vreg);
-
- pr_info("PVS [%d %d %d %d] uV\n",
- cpr_vreg->corner_ceiling[CPR_CORNER_SVS],
- cpr_vreg->corner_ceiling[CPR_CORNER_NORMAL],
- cpr_vreg->corner_ceiling[CPR_CORNER_TURBO],
- cpr_vreg->corner_ceiling[CPR_CORNER_SUPER_TURBO]);
+ the_cpr = cpr_vreg;
return 0;
}
@@ -478,7 +1394,13 @@
cpr_vreg = platform_get_drvdata(pdev);
if (cpr_vreg) {
- cpr_regulator_apc_exit(cpr_vreg);
+ /* Disable CPR */
+ if (cpr_is_allowed(cpr_vreg)) {
+ cpr_ctl_disable(cpr_vreg);
+ cpr_irq_set(cpr_vreg, 0);
+ }
+
+ cpr_apc_exit(cpr_vreg);
regulator_unregister(cpr_vreg->rdev);
}
@@ -498,6 +1420,8 @@
},
.probe = cpr_regulator_probe,
.remove = __devexit_p(cpr_regulator_remove),
+ .suspend = cpr_regulator_suspend,
+ .resume = cpr_regulator_resume,
};
/**
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index d02ab66..d5084e4 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -3,7 +3,7 @@
* MSM architecture cpufreq driver
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
* Author: Mike A. Chan <mikechan@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -261,6 +261,7 @@
{
int cur_freq;
int index;
+ int ret = 0;
struct cpufreq_frequency_table *table;
struct cpufreq_work_struct *cpu_work = NULL;
@@ -296,19 +297,16 @@
policy->cpu, cur_freq);
return -EINVAL;
}
-
- if (cur_freq != table[index].frequency) {
- int ret = 0;
- ret = acpuclk_set_rate(policy->cpu, table[index].frequency,
- SETRATE_CPUFREQ);
- if (ret)
- return ret;
- pr_info("cpufreq: cpu%d init at %d switching to %d\n",
- policy->cpu, cur_freq, table[index].frequency);
- cur_freq = table[index].frequency;
- }
-
- policy->cur = cur_freq;
+ /*
+ * Call set_cpu_freq unconditionally so that when cpu is set to
+ * online, frequency limit will always be updated.
+ */
+ ret = set_cpu_freq(policy, table[index].frequency);
+ if (ret)
+ return ret;
+ pr_debug("cpufreq: cpu%d init at %d switching to %d\n",
+ policy->cpu, cur_freq, table[index].frequency);
+ policy->cur = table[index].frequency;
policy->cpuinfo.transition_latency =
acpuclk_get_switch_time() * NSEC_PER_USEC;
@@ -410,4 +408,4 @@
return cpufreq_register_driver(&msm_cpufreq_driver);
}
-late_initcall(msm_cpufreq_register);
+device_initcall(msm_cpufreq_register);
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 837aef3..cb8ffc1 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2510,6 +2510,11 @@
.id = -1,
};
+struct platform_device msm_fm_loopback = {
+ .name = "msm-pcm-loopback",
+ .id = -1,
+};
+
static struct fs_driver_data gfx2d0_fs_data = {
.clks = (struct fs_clk_data[]){
{ .name = "core_clk" },
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 327c11d..eb12383 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -260,6 +260,7 @@
extern struct platform_device msm_i2s_cpudai4;
extern struct platform_device msm_i2s_cpudai5;
extern struct platform_device msm_cpudai_stub;
+extern struct platform_device msm_fm_loopback;
extern struct platform_device msm_pil_q6v3;
extern struct platform_device msm_pil_modem;
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 6665d66..30a034e 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -22,6 +22,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
#include <linux/clk.h>
#include <mach/clk.h>
@@ -44,7 +45,9 @@
struct regulator_dev *rdev;
struct regulator_desc rdesc;
void __iomem *gdscr;
- struct clk *core_clk;
+ struct clk **clocks;
+ int clock_count;
+ bool toggle_mems;
};
static int gdsc_is_enabled(struct regulator_dev *rdev)
@@ -58,7 +61,7 @@
{
struct gdsc *sc = rdev_get_drvdata(rdev);
uint32_t regval;
- int ret;
+ int i, ret;
regval = readl_relaxed(sc->gdscr);
regval &= ~SW_COLLAPSE_MASK;
@@ -71,9 +74,18 @@
return ret;
}
+ if (sc->toggle_mems) {
+ for (i = 0; i < sc->clock_count; i++) {
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+ }
+ }
+
/*
* If clocks to this power domain were already on, they will take an
* additional 4 clock cycles to re-enable after the rail is enabled.
+ * Delay to account for this. A delay is also needed to ensure clocks
+ * are not enabled within 400ns of enabling power to the memories.
*/
udelay(1);
@@ -84,7 +96,7 @@
{
struct gdsc *sc = rdev_get_drvdata(rdev);
uint32_t regval;
- int ret;
+ int i, ret;
regval = readl_relaxed(sc->gdscr);
regval |= SW_COLLAPSE_MASK;
@@ -95,6 +107,13 @@
if (ret)
dev_err(&rdev->dev, "%s disable timed out\n", sc->rdesc.name);
+ if (sc->toggle_mems) {
+ for (i = 0; i < sc->clock_count; i++) {
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+ }
+ }
+
return ret;
}
@@ -112,7 +131,7 @@
struct gdsc *sc;
uint32_t regval;
bool retain_mems;
- int ret;
+ int i, ret;
sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
if (sc == NULL)
@@ -137,6 +156,34 @@
if (sc->gdscr == NULL)
return -ENOMEM;
+ sc->clock_count = of_property_count_strings(pdev->dev.of_node,
+ "qcom,clock-names");
+ if (sc->clock_count == -EINVAL) {
+ sc->clock_count = 0;
+ } else if (IS_ERR_VALUE(sc->clock_count)) {
+ dev_err(&pdev->dev, "Failed to get clock names\n");
+ return -EINVAL;
+ }
+
+ sc->clocks = devm_kzalloc(&pdev->dev,
+ sizeof(struct clk *) * sc->clock_count, GFP_KERNEL);
+ if (!sc->clocks)
+ return -ENOMEM;
+ for (i = 0; i < sc->clock_count; i++) {
+ const char *clock_name;
+ of_property_read_string_index(pdev->dev.of_node,
+ "qcom,clock-names", i,
+ &clock_name);
+ sc->clocks[i] = devm_clk_get(&pdev->dev, clock_name);
+ if (IS_ERR(sc->clocks[i])) {
+ int rc = PTR_ERR(sc->clocks[i]);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get %s\n",
+ clock_name);
+ return rc;
+ }
+ }
+
sc->rdesc.id = atomic_inc_return(&gdsc_count);
sc->rdesc.ops = &gdsc_ops;
sc->rdesc.type = REGULATOR_VOLTAGE;
@@ -157,13 +204,16 @@
retain_mems = of_property_read_bool(pdev->dev.of_node,
"qcom,retain-mems");
- if (retain_mems) {
- sc->core_clk = devm_clk_get(&pdev->dev, "core_clk");
- if (IS_ERR(sc->core_clk))
- return PTR_ERR(sc->core_clk);
- clk_set_flags(sc->core_clk, CLKFLAG_RETAIN_MEM);
- clk_set_flags(sc->core_clk, CLKFLAG_RETAIN_PERIPH);
+ for (i = 0; i < sc->clock_count; i++) {
+ if (retain_mems || (regval & PWR_ON_MASK)) {
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+ } else {
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+ }
}
+ sc->toggle_mems = !retain_mems;
sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
pdev->dev.of_node);
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 2a33228..0dd4957 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -49,6 +49,8 @@
* @set_vdd: function to call when applying a new voltage setting.
* @vdd_uv: sorted 2D array of legal voltage settings. Indexed by level, then
regulator.
+ * @vdd_ua: sorted 2D array of legal cureent settings. Indexed by level, then
+ regulator. Optional parameter.
* @level_votes: array of votes for each level.
* @num_levels: specifies the size of level_votes array.
* @cur_level: the currently set voltage level
@@ -59,7 +61,8 @@
struct regulator **regulator;
int num_regulators;
int (*set_vdd)(struct clk_vdd_class *v_class, int level);
- const int **vdd_uv;
+ int **vdd_uv;
+ int **vdd_ua;
int *level_votes;
int num_levels;
unsigned long cur_level;
@@ -76,10 +79,12 @@
.lock = __MUTEX_INITIALIZER(_name.lock) \
}
-#define DEFINE_VDD_REGULATORS(_name, _num_levels, _num_regulators, _vdd_uv) \
+#define DEFINE_VDD_REGULATORS(_name, _num_levels, _num_regulators, _vdd_uv, \
+ _vdd_ua) \
struct clk_vdd_class _name = { \
.class_name = #_name, \
.vdd_uv = _vdd_uv, \
+ .vdd_ua = _vdd_ua, \
.regulator = (struct regulator * [_num_regulators]) {}, \
.num_regulators = _num_regulators, \
.level_votes = (int [_num_levels]) {}, \
@@ -89,6 +94,7 @@
}
#define VDD_UV(...) ((int []){__VA_ARGS__})
+#define VDD_UA(...) ((int []){__VA_ARGS__})
enum handoff {
HANDOFF_ENABLED_CLK,
diff --git a/arch/arm/mach-msm/include/mach/clock-generic.h b/arch/arm/mach-msm/include/mach/clock-generic.h
new file mode 100644
index 0000000..0f689f1
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/clock-generic.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MACH_CLOCK_GENERIC_H
+#define __MACH_CLOCK_GENERIC_H
+
+#include <mach/clk-provider.h>
+
+/* ==================== Mux clock ==================== */
+
+struct clk_src {
+ struct clk *src;
+ int sel;
+};
+
+struct mux_clk;
+
+struct clk_mux_ops {
+ int (*set_mux_sel)(struct mux_clk *clk, int sel);
+ int (*get_mux_sel)(struct mux_clk *clk);
+
+ /* Optional */
+ bool (*is_enabled)(struct mux_clk *clk);
+ int (*enable)(struct mux_clk *clk);
+ void (*disable)(struct mux_clk *clk);
+};
+
+#define MUX_SRC_LIST(...) \
+ .parents = (struct clk_src[]){__VA_ARGS__}, \
+ .num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__}))
+
+struct mux_clk {
+ /* Parents in decreasing order of preference for obtaining rates. */
+ struct clk_src *parents;
+ int num_parents;
+ struct clk *safe_parent;
+ int safe_sel;
+ struct clk_mux_ops *ops;
+
+ /* Fields not used by helper function. */
+ void *const __iomem *base;
+ u32 offset;
+ u32 mask;
+ u32 shift;
+ u32 en_mask;
+ void *priv;
+
+ struct clk c;
+};
+
+static inline struct mux_clk *to_mux_clk(struct clk *c)
+{
+ return container_of(c, struct mux_clk, c);
+}
+
+extern struct clk_ops clk_ops_gen_mux;
+
+/* ==================== Divider clock ==================== */
+
+struct div_clk;
+
+struct clk_div_ops {
+ int (*set_div)(struct div_clk *clk, int div);
+ int (*get_div)(struct div_clk *clk);
+
+ /* Optional */
+ bool (*is_enabled)(struct div_clk *clk);
+ int (*enable)(struct div_clk *clk);
+ void (*disable)(struct div_clk *clk);
+};
+
+struct div_clk {
+ unsigned int div;
+ unsigned int min_div;
+ unsigned int max_div;
+ unsigned long rate_margin;
+ struct clk_div_ops *ops;
+
+ /* Fields not used by helper function. */
+ void *const __iomem *base;
+ u32 offset;
+ u32 mask;
+ u32 shift;
+ u32 en_mask;
+ void *priv;
+ struct clk c;
+};
+
+static inline struct div_clk *to_div_clk(struct clk *c)
+{
+ return container_of(c, struct div_clk, c);
+}
+
+extern struct clk_ops clk_ops_div;
+extern struct clk_ops clk_ops_slave_div;
+
+#define DEFINE_FIXED_DIV_CLK(clk_name, _div, _parent) \
+static struct div_clk clk_name = { \
+ .div = _div, \
+ .c = { \
+ .parent = _parent, \
+ .dbg_name = #clk_name, \
+ .ops = &clk_ops_div, \
+ CLK_INIT(clk_name.c), \
+ } \
+}
+
+#define DEFINE_FIXED_SLAVE_DIV_CLK(clk_name, _div, _parent) \
+static struct div_clk clk_name = { \
+ .div = _div, \
+ .c = { \
+ .parent = _parent, \
+ .dbg_name = #clk_name, \
+ .ops = &clk_ops_slave_div, \
+ CLK_INIT(clk_name.c), \
+ } \
+}
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/ecm_ipa.h b/arch/arm/mach-msm/include/mach/ecm_ipa.h
index 008a659..f6afb2a 100644
--- a/arch/arm/mach-msm/include/mach/ecm_ipa.h
+++ b/arch/arm/mach-msm/include/mach/ecm_ipa.h
@@ -24,15 +24,35 @@
enum ipa_dp_evt_type evt,
unsigned long data);
+/*
+ * struct ecm_ipa_params - parameters for ecm_ipa initialization API
+ *
+ * @ecm_ipa_rx_dp_notify: ecm_ipa will set this callback (out parameter).
+ * this callback shall be supplied for ipa_connect upon pipe
+ * connection (USB->IPA), once IPA driver receive data packets
+ * from USB pipe destined for Apps this callback will be called.
+ * @ecm_ipa_tx_dp_notify: ecm_ipa will set this callback (out parameter).
+ * this callback shall be supplied for ipa_connect upon pipe
+ * connection (IPA->USB), once IPA driver send packets destined
+ * for USB, IPA BAM will notify for Tx-complete.
+ * @priv: ecm_ipa will set this pointer (out parameter).
+ * This pointer will hold the network device for later interaction
+ * with ecm_ipa APIs
+ * @host_ethaddr: host Ethernet address in network order
+ * @device_ethaddr: device Ethernet address in network order
+ */
+struct ecm_ipa_params {
+ ecm_ipa_callback ecm_ipa_rx_dp_notify;
+ ecm_ipa_callback ecm_ipa_tx_dp_notify;
+ u8 host_ethaddr[ETH_ALEN];
+ u8 device_ethaddr[ETH_ALEN];
+ void *private;
+};
+
#ifdef CONFIG_ECM_IPA
-int ecm_ipa_init(ecm_ipa_callback * ecm_ipa_rx_dp_notify,
- ecm_ipa_callback * ecm_ipa_tx_dp_notify,
- void **priv);
-
-int ecm_ipa_configure(u8 host_ethaddr[], u8 device_ethaddr[],
- void *priv);
+int ecm_ipa_init(struct ecm_ipa_params *params);
int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
void *priv);
@@ -43,15 +63,7 @@
#else /* CONFIG_ECM_IPA*/
-static inline int ecm_ipa_init(ecm_ipa_callback *ecm_ipa_rx_dp_notify,
- ecm_ipa_callback *ecm_ipa_tx_dp_notify,
- void **priv)
-{
- return 0;
-}
-
-static inline int ecm_ipa_configure(u8 host_ethaddr[], u8 device_ethaddr[],
- void *priv)
+int ecm_ipa_init(struct ecm_ipa_params *params)
{
return 0;
}
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index 9a89508..7157d12 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -122,6 +122,7 @@
unsigned long size);
extern int msm_register_domain(struct msm_iova_layout *layout);
+extern int msm_unregister_domain(struct iommu_domain *domain);
#else
static inline void msm_iommu_set_client_name(struct iommu_domain *domain,
@@ -195,6 +196,11 @@
{
return -ENODEV;
}
+
+static inline int msm_unregister_domain(struct iommu_domain *domain)
+{
+ return -ENODEV;
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index 90757b6..db5e126 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -464,6 +464,13 @@
int ipa_disconnect(u32 clnt_hdl);
/*
+ * Resume / Suspend
+ */
+int ipa_resume(u32 clnt_hdl);
+
+int ipa_suspend(u32 clnt_hdl);
+
+/*
* Configuration
*/
int ipa_cfg_ep(u32 clnt_hdl, const struct ipa_ep_cfg *ipa_ep_cfg);
@@ -583,6 +590,8 @@
*/
int ipa_rm_create_resource(struct ipa_rm_create_params *create_params);
+int ipa_rm_delete_resource(enum ipa_rm_resource_name resource_name);
+
int ipa_rm_register(enum ipa_rm_resource_name resource_name,
struct ipa_rm_register_params *reg_params);
@@ -694,6 +703,19 @@
}
/*
+ * Resume / Suspend
+ */
+static inline int ipa_resume(u32 clnt_hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_suspend(u32 clnt_hdl)
+{
+ return -EPERM;
+}
+
+/*
* Configuration
*/
static inline int ipa_cfg_ep(u32 clnt_hdl,
@@ -955,6 +977,12 @@
return -EPERM;
}
+static inline int ipa_rm_delete_resource(
+ enum ipa_rm_resource_name resource_name)
+{
+ return -EPERM;
+}
+
static inline int ipa_rm_register(enum ipa_rm_resource_name resource_name,
struct ipa_rm_register_params *reg_params)
{
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8610.h b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
index 2a62460..18e448d 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
@@ -24,6 +24,9 @@
#define MSM8610_MSM_SHARED_RAM_PHYS 0x0D900000
+#define MSM8610_QGIC_DIST_PHYS 0xF9000000
+#define MSM8610_QGIC_DIST_SIZE SZ_4K
+
#define MSM8610_APCS_GCC_PHYS 0xF9011000
#define MSM8610_APCS_GCC_SIZE SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index a90e78a..8f48e94 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -115,7 +115,8 @@
#if defined(CONFIG_ARCH_MSM9615) || defined(CONFIG_ARCH_MSM7X27) \
- || defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM9625)
+ || defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM9625) \
+ || defined(CONFIG_ARCH_MSM8610) || defined(CONFIG_ARCH_MSM8226)
#define MSM_SHARED_RAM_SIZE SZ_1M
#else
#define MSM_SHARED_RAM_SIZE SZ_2M
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_router.h b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
index c68c783..894379e 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_router.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -31,6 +31,11 @@
MSM_IPC_ROUTER_WRITE_DONE,
};
+struct comm_mode_info {
+ int mode;
+ void *xprt_info;
+};
+
struct msm_ipc_port {
struct list_head list;
@@ -39,6 +44,7 @@
uint32_t type;
unsigned flags;
spinlock_t port_lock;
+ struct comm_mode_info mode_info;
struct list_head incomplete;
struct mutex incomplete_lock;
diff --git a/arch/arm/mach-msm/include/mach/qseecomi.h b/arch/arm/mach-msm/include/mach/qseecomi.h
index e889242..3a997be 100644
--- a/arch/arm/mach-msm/include/mach/qseecomi.h
+++ b/arch/arm/mach-msm/include/mach/qseecomi.h
@@ -67,9 +67,9 @@
};
enum qseecom_pipe_type {
- QSEOS_PIPE_ENC = 0,
- QSEOS_PIPE_ENC_XTS,
- QSEOS_PIPE_AUTH,
+ QSEOS_PIPE_ENC = 0x1,
+ QSEOS_PIPE_ENC_XTS = 0x2,
+ QSEOS_PIPE_AUTH = 0x4,
QSEOS_PIPE_ENUM_FILL = 0x7FFFFFFF
};
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index d4ea4ac..64531f0 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -36,11 +36,14 @@
#define of_board_is_rumi() of_machine_is_compatible("qcom,rumi")
#define of_board_is_fluid() of_machine_is_compatible("qcom,fluid")
#define of_board_is_liquid() of_machine_is_compatible("qcom,liquid")
+#define of_board_is_dragonboard() \
+ of_machine_is_compatible("qcom,dragonboard")
#define machine_is_msm8974() of_machine_is_compatible("qcom,msm8974")
#define machine_is_msm9625() of_machine_is_compatible("qcom,msm9625")
#define machine_is_msm8610() of_machine_is_compatible("qcom,msm8610")
#define machine_is_msm8226() of_machine_is_compatible("qcom,msm8226")
+#define machine_is_apq8074() of_machine_is_compatible("qcom,apq8074")
#define early_machine_is_msm8610() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8610")
@@ -55,11 +58,13 @@
#define of_board_is_rumi() 0
#define of_board_is_fluid() 0
#define of_board_is_liquid() 0
+#define of_board_is_dragonboard() 0
#define machine_is_msm8974() 0
#define machine_is_msm9625() 0
#define machine_is_msm8610() 0
#define machine_is_msm8226() 0
+#define machine_is_apq8074() 0
#define early_machine_is_msm8610() 0
#define early_machine_is_mpq8092() 0
@@ -67,6 +72,7 @@
#define early_machine_is_msmkrypton() 0
#endif
+#define PLATFORM_SUBTYPE_MDM 1
#define PLATFORM_SUBTYPE_SGLTE 6
enum msm_cpu {
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 67f643e..35b1f76 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -41,6 +41,8 @@
* @powerup: Start a subsystem
* @crash_shutdown: Shutdown a subsystem when the system crashes (can't sleep)
* @ramdump: Collect a ramdump of the subsystem
+ * @is_not_loadable: Indicate if subsystem firmware is not loadable via pil
+ * framework
*/
struct subsys_desc {
const char *name;
@@ -55,6 +57,8 @@
int (*powerup)(const struct subsys_desc *desc);
void (*crash_shutdown)(const struct subsys_desc *desc);
int (*ramdump)(int, const struct subsys_desc *desc);
+ unsigned int err_ready_irq;
+ int is_not_loadable;
};
#if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index 68313c5..da7c039 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -42,6 +42,12 @@
OCI_MEM, /* Shared memory among peripherals */
};
+enum usb_bam_event_type {
+ USB_BAM_EVENT_WAKEUP_PIPE = 0, /* Wake a pipe */
+ USB_BAM_EVENT_WAKEUP, /* Wake a bam (first pipe waked) */
+ USB_BAM_EVENT_INACTIVITY, /* Inactivity on all pipes */
+};
+
struct usb_bam_connect_ipa_params {
u8 src_idx;
u8 dst_idx;
@@ -57,16 +63,20 @@
void *priv;
void (*notify)(void *priv, enum ipa_dp_evt_type evt,
unsigned long data);
+ int (*activity_notify)(void *priv);
+ int (*inactivity_notify)(void *priv);
};
/**
* struct usb_bam_event_info: suspend/resume event information.
+* @type: usb bam event type.
* @event: holds event data.
* @callback: suspend/resume callback.
* @param: port num (for suspend) or NULL (for resume).
* @event_w: holds work queue parameters.
*/
struct usb_bam_event_info {
+ enum usb_bam_event_type type;
struct sps_register_event event;
int (*callback)(void *);
void *param;
@@ -89,8 +99,12 @@
* @desc_fifo_size: descriptor fifo size.
* @data_mem_buf: data fifo buffer.
* @desc_mem_buf: descriptor fifo buffer.
-* @wake_event: event for wakeup.
+* @event: event for wakeup.
* @enabled: true if pipe is enabled.
+* @priv: private data to return upon activity_notify
+* or inactivity_notify callbacks.
+* @activity_notify: callback to invoke on activity on one of the in pipes.
+* @inactivity_notify: callback to invoke on inactivity on all pipes.
*/
struct usb_bam_pipe_connect {
const char *name;
@@ -109,8 +123,11 @@
u32 desc_fifo_size;
struct sps_mem_buffer data_mem_buf;
struct sps_mem_buffer desc_mem_buf;
- struct usb_bam_event_info wake_event;
+ struct usb_bam_event_info event;
bool enabled;
+ void *priv;
+ int (*activity_notify)(void *priv);
+ int (*inactivity_notify)(void *priv);
};
/**
@@ -154,7 +171,10 @@
/**
* Connect USB-to-IPA SPS connection.
*
- * This function returns the allocated pipes number and clnt handles.
+ * This function returns the allocated pipes number and clnt
+ * handles. Assumes that the user first connects producer pipes
+ * and only after that consumer pipes, since that's the correct
+ * sequence for the handshake with the IPA.
*
* @ipa_params - in/out parameters
*
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 37dbbab..1c4a317 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -574,6 +574,7 @@
#ifdef CONFIG_ARCH_MSM8610
static struct map_desc msm8610_io_desc[] __initdata = {
+ MSM_CHIP_DEVICE(QGIC_DIST, MSM8610),
MSM_CHIP_DEVICE(APCS_GCC, MSM8610),
MSM_CHIP_DEVICE(TLMM, MSM8610),
MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8610),
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 18562a3..f4ac37e 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/idr.h>
#include <asm/sizes.h>
#include <asm/page.h>
#include <mach/iommu.h>
@@ -36,9 +37,14 @@
int domain_num;
};
+struct msm_iommu_data_entry {
+ struct list_head list;
+ void *data;
+};
+
static struct rb_root domain_root;
DEFINE_MUTEX(domain_mutex);
-static atomic_t domain_nums = ATOMIC_INIT(-1);
+static DEFINE_IDA(domain_nums);
void msm_iommu_set_client_name(struct iommu_domain *domain, char const *name)
{
@@ -273,6 +279,27 @@
return 0;
}
+static int remove_domain(struct iommu_domain *domain)
+{
+ struct rb_root *root = &domain_root;
+ struct rb_node *n;
+ struct msm_iova_data *node;
+ int ret = -EINVAL;
+
+ mutex_lock(&domain_mutex);
+
+ for (n = rb_first(root); n; n = rb_next(n)) {
+ node = rb_entry(n, struct msm_iova_data, node);
+ if (node->domain == domain) {
+ rb_erase(&node->node, &domain_root);
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&domain_mutex);
+ return ret;
+}
+
struct iommu_domain *msm_get_iommu_domain(int domain_num)
{
struct msm_iova_data *data;
@@ -307,6 +334,27 @@
}
EXPORT_SYMBOL(msm_find_domain_no);
+static struct msm_iova_data *msm_domain_to_iova_data(struct iommu_domain
+ const *domain)
+{
+ struct rb_root *root = &domain_root;
+ struct rb_node *n;
+ struct msm_iova_data *node;
+ struct msm_iova_data *iova_data = ERR_PTR(-EINVAL);
+
+ mutex_lock(&domain_mutex);
+
+ for (n = rb_first(root); n; n = rb_next(n)) {
+ node = rb_entry(n, struct msm_iova_data, node);
+ if (node->domain == domain) {
+ iova_data = node;
+ break;
+ }
+ }
+ mutex_unlock(&domain_mutex);
+ return iova_data;
+}
+
int msm_allocate_iova_address(unsigned int iommu_domain,
unsigned int partition_no,
unsigned long size,
@@ -330,7 +378,9 @@
if (!pool->gpool)
return -EINVAL;
+ mutex_lock(&pool->pool_mutex);
va = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
+ mutex_unlock(&pool->pool_mutex);
if (va) {
pool->free -= size;
/* Offset because genpool can't handle 0 addresses */
@@ -375,7 +425,9 @@
if (pool->paddr == 0)
iova += SZ_4K;
+ mutex_lock(&pool->pool_mutex);
gen_pool_free(pool->gpool, iova, size);
+ mutex_unlock(&pool->pool_mutex);
}
int msm_register_domain(struct msm_iova_layout *layout)
@@ -393,11 +445,11 @@
if (!data)
return -ENOMEM;
- pools = kmalloc(sizeof(struct mem_pool) * layout->npartitions,
+ pools = kzalloc(sizeof(struct mem_pool) * layout->npartitions,
GFP_KERNEL);
if (!pools)
- goto out;
+ goto free_data;
for (i = 0; i < layout->npartitions; i++) {
if (layout->partitions[i].size == 0)
@@ -410,6 +462,7 @@
pools[i].paddr = layout->partitions[i].start;
pools[i].size = layout->partitions[i].size;
+ mutex_init(&pools[i].pool_mutex);
/*
* genalloc can't handle a pool starting at address 0.
@@ -435,10 +488,13 @@
data->pools = pools;
data->npools = layout->npartitions;
- data->domain_num = atomic_inc_return(&domain_nums);
+ data->domain_num = ida_simple_get(&domain_nums, 0, 0, GFP_KERNEL);
+ if (data->domain_num < 0)
+ goto free_pools;
+
data->domain = iommu_domain_alloc(bus, layout->domain_flags);
if (!data->domain)
- goto out;
+ goto free_domain_num;
msm_iommu_set_client_name(data->domain, layout->client_name);
@@ -446,13 +502,50 @@
return data->domain_num;
-out:
+free_domain_num:
+ ida_simple_remove(&domain_nums, data->domain_num);
+
+free_pools:
+ for (i = 0; i < layout->npartitions; i++) {
+ if (pools[i].gpool)
+ gen_pool_destroy(pools[i].gpool);
+ }
+ kfree(pools);
+free_data:
kfree(data);
return -EINVAL;
}
EXPORT_SYMBOL(msm_register_domain);
+int msm_unregister_domain(struct iommu_domain *domain)
+{
+ unsigned int i;
+ struct msm_iova_data *data = msm_domain_to_iova_data(domain);
+
+ if (IS_ERR_OR_NULL(data)) {
+ pr_err("%s: Could not find iova_data\n", __func__);
+ return -EINVAL;
+ }
+
+ if (remove_domain(data->domain)) {
+ pr_err("%s: Domain not found. Failed to remove domain\n",
+ __func__);
+ }
+
+ iommu_domain_free(domain);
+
+ ida_simple_remove(&domain_nums, data->domain_num);
+
+ for (i = 0; i < data->npools; ++i)
+ gen_pool_destroy(data->pools[i].gpool);
+
+ kfree(data->pools);
+ kfree(data);
+ return 0;
+}
+EXPORT_SYMBOL(msm_unregister_domain);
+
static int find_and_add_contexts(struct iommu_group *group,
const struct device_node *node,
unsigned int num_contexts)
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 0d617a6..a328b2b 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -133,15 +133,21 @@
struct msm_ipc_router_xprt_info *xprt_info;
};
+struct msm_ipc_resume_tx_port {
+ struct list_head list;
+ uint32_t port_id;
+ uint32_t node_id;
+};
+
#define RP_HASH_SIZE 32
struct msm_ipc_router_remote_port {
struct list_head list;
uint32_t node_id;
uint32_t port_id;
uint32_t restart_state;
- wait_queue_head_t quota_wait;
uint32_t tx_quota_cnt;
struct mutex quota_lock;
+ struct list_head resume_tx_port_list;
void *sec_rule;
};
@@ -657,8 +663,8 @@
rport_ptr->restart_state = RESTART_NORMAL;
rport_ptr->sec_rule = NULL;
rport_ptr->tx_quota_cnt = 0;
- init_waitqueue_head(&rport_ptr->quota_wait);
mutex_init(&rport_ptr->quota_lock);
+ INIT_LIST_HEAD(&rport_ptr->resume_tx_port_list);
list_add_tail(&rport_ptr->list,
&rt_entry->remote_port_list[key]);
mutex_unlock(&rt_entry->lock);
@@ -666,6 +672,97 @@
return rport_ptr;
}
+/**
+ * msm_ipc_router_free_resume_tx_port() - Free the resume_tx ports
+ * @rport_ptr: Pointer to the remote port.
+ *
+ * This function deletes all the resume_tx ports associated with a remote port
+ * and frees the memory allocated to each resume_tx port.
+ *
+ * Must be called with rport_ptr->quota_lock locked.
+ */
+static void msm_ipc_router_free_resume_tx_port(
+ struct msm_ipc_router_remote_port *rport_ptr)
+{
+ struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
+
+ list_for_each_entry_safe(rtx_port, tmp_rtx_port,
+ &rport_ptr->resume_tx_port_list, list) {
+ list_del(&rtx_port->list);
+ kfree(rtx_port);
+ }
+}
+
+/**
+ * msm_ipc_router_lookup_resume_tx_port() - Lookup resume_tx port list
+ * @rport_ptr: Remote port whose resume_tx port list needs to be looked.
+ * @port_id: Port ID which needs to be looked from the list.
+ *
+ * return 1 if the port_id is found in the list, else 0.
+ *
+ * This function is used to lookup the existence of a local port in
+ * remote port's resume_tx list. This function is used to ensure that
+ * the same port is not added to the remote_port's resume_tx list repeatedly.
+ *
+ * Must be called with rport_ptr->quota_lock locked.
+ */
+static int msm_ipc_router_lookup_resume_tx_port(
+ struct msm_ipc_router_remote_port *rport_ptr, uint32_t port_id)
+{
+ struct msm_ipc_resume_tx_port *rtx_port;
+
+ list_for_each_entry(rtx_port, &rport_ptr->resume_tx_port_list, list) {
+ if (port_id == rtx_port->port_id)
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * post_resume_tx() - Post the resume_tx event
+ * @rport_ptr: Pointer to the remote port
+ * @pkt : The data packet that is received on a resume_tx event
+ *
+ * This function informs about the reception of the resume_tx message from a
+ * remote port pointed by rport_ptr to all the local ports that are in the
+ * resume_tx_ports_list of this remote port. On posting the information, this
+ * function sequentially deletes each entry in the resume_tx_port_list of the
+ * remote port.
+ *
+ * Must be called with rport_ptr->quota_lock locked.
+ */
+static void post_resume_tx(struct msm_ipc_router_remote_port *rport_ptr,
+ struct rr_packet *pkt)
+{
+ struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
+ struct msm_ipc_port *local_port;
+ struct rr_packet *cloned_pkt;
+
+ list_for_each_entry_safe(rtx_port, tmp_rtx_port,
+ &rport_ptr->resume_tx_port_list, list) {
+ mutex_lock(&local_ports_lock);
+ local_port =
+ msm_ipc_router_lookup_local_port(rtx_port->port_id);
+ if (local_port) {
+ cloned_pkt = clone_pkt(pkt);
+ if (cloned_pkt) {
+ mutex_lock(&local_port->port_rx_q_lock);
+ list_add_tail(&cloned_pkt->list,
+ &local_port->port_rx_q);
+ wake_up(&local_port->port_rx_wait_q);
+ mutex_unlock(&local_port->port_rx_q_lock);
+ } else {
+ pr_err("%s: Clone_pkt failed for %08x:%08x\n",
+ __func__, local_port->this_port.node_id,
+ local_port->this_port.port_id);
+ }
+ }
+ mutex_unlock(&local_ports_lock);
+ list_del(&rtx_port->list);
+ kfree(rtx_port);
+ }
+}
+
static void msm_ipc_router_destroy_remote_port(
struct msm_ipc_router_remote_port *rport_ptr)
{
@@ -683,7 +780,9 @@
pr_err("%s: Node %d is not up\n", __func__, node_id);
return;
}
-
+ mutex_lock(&rport_ptr->quota_lock);
+ msm_ipc_router_free_resume_tx_port(rport_ptr);
+ mutex_unlock(&rport_ptr->quota_lock);
mutex_lock(&rt_entry->lock);
list_del(&rport_ptr->list);
kfree(rport_ptr);
@@ -1146,6 +1245,67 @@
return 0;
}
+static int msm_ipc_router_send_remove_client(struct comm_mode_info *mode_info,
+ uint32_t node_id, uint32_t port_id)
+{
+ union rr_control_msg msg;
+ struct msm_ipc_router_xprt_info *tmp_xprt_info;
+ int mode;
+ void *xprt_info;
+ int rc = 0;
+
+ if (!mode_info) {
+ pr_err("%s: NULL mode_info\n", __func__);
+ return -EINVAL;
+ }
+ mode = mode_info->mode;
+ xprt_info = mode_info->xprt_info;
+
+ msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
+ msg.cli.node_id = node_id;
+ msg.cli.port_id = port_id;
+
+ if ((mode == SINGLE_LINK_MODE) && xprt_info) {
+ mutex_lock(&xprt_info_list_lock);
+ list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
+ if (tmp_xprt_info != xprt_info)
+ continue;
+ msm_ipc_router_send_control_msg(tmp_xprt_info, &msg);
+ break;
+ }
+ mutex_unlock(&xprt_info_list_lock);
+ } else if ((mode == SINGLE_LINK_MODE) && !xprt_info) {
+ broadcast_ctl_msg_locally(&msg);
+ } else if (mode == MULTI_LINK_MODE) {
+ broadcast_ctl_msg(&msg);
+ broadcast_ctl_msg_locally(&msg);
+ } else if (mode != NULL_MODE) {
+ pr_err("%s: Invalid mode(%d) + xprt_inf(%p) for %08x:%08x\n",
+ __func__, mode, xprt_info, node_id, port_id);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static void update_comm_mode_info(struct comm_mode_info *mode_info,
+ struct msm_ipc_router_xprt_info *xprt_info)
+{
+ if (!mode_info) {
+ pr_err("%s: NULL mode_info\n", __func__);
+ return;
+ }
+
+ if (mode_info->mode == NULL_MODE) {
+ mode_info->xprt_info = xprt_info;
+ mode_info->mode = SINGLE_LINK_MODE;
+ } else if (mode_info->mode == SINGLE_LINK_MODE &&
+ mode_info->xprt_info != xprt_info) {
+ mode_info->mode = MULTI_LINK_MODE;
+ }
+
+ return;
+}
+
static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
{
struct msm_ipc_router_remote_port *rport_ptr;
@@ -1158,7 +1318,7 @@
}
mutex_lock(&rport_ptr->quota_lock);
rport_ptr->restart_state = RESTART_PEND;
- wake_up(&rport_ptr->quota_wait);
+ msm_ipc_router_free_resume_tx_port(rport_ptr);
mutex_unlock(&rport_ptr->quota_lock);
return;
}
@@ -1240,7 +1400,8 @@
continue;
mutex_lock(&rport_ptr->quota_lock);
rport_ptr->restart_state = RESTART_PEND;
- wake_up(&rport_ptr->quota_wait);
+ msm_ipc_router_free_resume_tx_port(
+ rport_ptr);
mutex_unlock(&rport_ptr->quota_lock);
ctl.cli.node_id = rport_ptr->node_id;
ctl.cli.port_id = rport_ptr->port_id;
@@ -1531,8 +1692,8 @@
}
mutex_lock(&rport_ptr->quota_lock);
rport_ptr->tx_quota_cnt = 0;
+ post_resume_tx(rport_ptr, pkt);
mutex_unlock(&rport_ptr->quota_lock);
- wake_up(&rport_ptr->quota_wait);
break;
case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
@@ -1815,6 +1976,7 @@
broadcast_ctl_msg(&ctl);
spin_lock_irqsave(&port_ptr->port_lock, flags);
port_ptr->type = SERVER_PORT;
+ port_ptr->mode_info.mode = MULTI_LINK_MODE;
port_ptr->port_name.service = server->name.service;
port_ptr->port_name.instance = server->name.instance;
spin_unlock_irqrestore(&port_ptr->port_lock, flags);
@@ -1926,6 +2088,7 @@
ret_len = pkt->length;
wake_up(&port_ptr->port_rx_wait_q);
mutex_unlock(&port_ptr->port_rx_q_lock);
+ update_comm_mode_info(&src->mode_info, NULL);
mutex_unlock(&local_ports_lock);
return ret_len;
@@ -1939,8 +2102,8 @@
struct rr_header *hdr;
struct msm_ipc_router_xprt_info *xprt_info;
struct msm_ipc_routing_table_entry *rt_entry;
+ struct msm_ipc_resume_tx_port *resume_tx_port;
int ret;
- DEFINE_WAIT(__wait);
if (!rport_ptr || !src || !pkt)
return -EINVAL;
@@ -1965,29 +2128,33 @@
hdr->dst_port_id = rport_ptr->port_id;
pkt->length += IPC_ROUTER_HDR_SIZE;
- for (;;) {
- prepare_to_wait(&rport_ptr->quota_wait, &__wait,
- TASK_INTERRUPTIBLE);
- mutex_lock(&rport_ptr->quota_lock);
- if (rport_ptr->restart_state != RESTART_NORMAL)
- break;
- if (rport_ptr->tx_quota_cnt <
- IPC_ROUTER_DEFAULT_RX_QUOTA)
- break;
- if (signal_pending(current))
- break;
- mutex_unlock(&rport_ptr->quota_lock);
- schedule();
- }
- finish_wait(&rport_ptr->quota_wait, &__wait);
-
+ mutex_lock(&rport_ptr->quota_lock);
if (rport_ptr->restart_state != RESTART_NORMAL) {
mutex_unlock(&rport_ptr->quota_lock);
return -ENETRESET;
}
- if (signal_pending(current)) {
+ if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
+ if (msm_ipc_router_lookup_resume_tx_port(
+ rport_ptr, src->this_port.port_id)) {
+ mutex_unlock(&rport_ptr->quota_lock);
+ return -EAGAIN;
+ }
+ resume_tx_port =
+ kzalloc(sizeof(struct msm_ipc_resume_tx_port),
+ GFP_KERNEL);
+ if (!resume_tx_port) {
+ pr_err("%s: Resume_Tx port allocation failed\n",
+ __func__);
+ mutex_unlock(&rport_ptr->quota_lock);
+ return -ENOMEM;
+ }
+ INIT_LIST_HEAD(&resume_tx_port->list);
+ resume_tx_port->port_id = src->this_port.port_id;
+ resume_tx_port->node_id = src->this_port.node_id;
+ list_add_tail(&resume_tx_port->list,
+ &rport_ptr->resume_tx_port_list);
mutex_unlock(&rport_ptr->quota_lock);
- return -ERESTARTSYS;
+ return -EAGAIN;
}
rport_ptr->tx_quota_cnt++;
if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
@@ -2014,6 +2181,7 @@
pr_err("%s: Write on XPRT failed\n", __func__);
return ret;
}
+ update_comm_mode_info(&src->mode_info, xprt_info);
RAW_HDR("[w rr_h] "
"ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
@@ -2303,13 +2471,11 @@
* Server port could have been a client port earlier.
* Send REMOVE_CLIENT message in either case.
*/
- msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
- msg.cli.node_id = port_ptr->this_port.node_id;
- msg.cli.port_id = port_ptr->this_port.port_id;
RR("x REMOVE_CLIENT id=%d:%08x\n",
- msg.cli.node_id, msg.cli.port_id);
- broadcast_ctl_msg(&msg);
- broadcast_ctl_msg_locally(&msg);
+ port_ptr->this_port.node_id, port_ptr->this_port.port_id);
+ msm_ipc_router_send_remove_client(&port_ptr->mode_info,
+ port_ptr->this_port.node_id,
+ port_ptr->this_port.port_id);
} else if (port_ptr->type == CONTROL_PORT) {
mutex_lock(&control_ports_lock);
list_del(&port_ptr->list);
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index cafcdd2..32832dd 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -62,6 +62,12 @@
IRSC_PORT,
};
+enum {
+ NULL_MODE,
+ SINGLE_LINK_MODE,
+ MULTI_LINK_MODE,
+};
+
union rr_control_msg {
uint32_t cmd;
struct {
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 342663e..64d8fed 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -197,6 +197,7 @@
struct sockaddr_msm_ipc *addr;
struct rr_header *hdr;
struct sk_buff *temp;
+ union rr_control_msg *ctl_msg;
int offset = 0, data_len = 0, copy_len;
if (!m || !msg_head) {
@@ -207,6 +208,16 @@
temp = skb_peek(msg_head);
hdr = (struct rr_header *)(temp->data);
+ if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)) {
+ skb_pull(temp, IPC_ROUTER_HDR_SIZE);
+ ctl_msg = (union rr_control_msg *)(temp->data);
+ addr->family = AF_MSM_IPC;
+ addr->address.addrtype = MSM_IPC_ADDR_ID;
+ addr->address.addr.port_addr.node_id = ctl_msg->cli.node_id;
+ addr->address.addr.port_addr.port_id = ctl_msg->cli.port_id;
+ m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
+ return offset;
+ }
if (addr && (hdr->src_port_id != IPC_ROUTER_ADDRESS)) {
addr->family = AF_MSM_IPC;
addr->address.addrtype = MSM_IPC_ADDR_ID;
@@ -415,8 +426,10 @@
return -EFAULT;
}
- if (timeout == 0)
+ if (timeout == 0) {
+ m->msg_namelen = 0;
return 0;
+ }
lock_sock(sk);
mutex_lock(&port_ptr->port_rx_q_lock);
}
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 52d20e3..9014f37 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -133,6 +133,7 @@
#define LDO_DELTA_MIN 10000
#define LDO_DELTA_MAX 100000
+#define MSM_L2_SAW_PHYS 0xf9012000
/**
* struct pmic_gang_vreg -
* @name: the string used to represent the gang
@@ -550,9 +551,15 @@
if (kvreg->mode == HS_MODE)
return 0;
/* enable bhs */
+ krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_EN_MASK, BHS_EN_MASK);
+ /* complete the above write before the delay */
+ mb();
+ /* wait for the bhs to settle */
+ udelay(BHS_SETTLING_DELAY_US);
+
+ /* Turn on BHS segments */
krait_masked_write(kvreg, APC_PWR_GATE_CTL,
- BHS_SEG_EN_MASK | BHS_EN_MASK,
- BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS | BHS_EN_MASK);
+ BHS_SEG_EN_MASK, BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS);
/* complete the above write before the delay */
mb();
@@ -1329,35 +1336,53 @@
void secondary_cpu_hs_init(void *base_ptr)
{
+ uint32_t reg_val;
+ void *l2_saw_base;
+
/* Turn on the BHS, turn off LDO Bypass and power down LDO */
- writel_relaxed(
- BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
+ reg_val = BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
| LDO_PWR_DWN_MASK
| CLK_SRC_DEFAULT << CLK_SRC_SEL_BIT_POS
- | BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS
- | BHS_EN_MASK,
- base_ptr + APC_PWR_GATE_CTL);
+ | BHS_EN_MASK;
+ writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
/* complete the above write before the delay */
mb();
+ /* wait for the bhs to settle */
+ udelay(BHS_SETTLING_DELAY_US);
- /*
- * wait for the bhs to settle
- */
+ /* Turn on BHS segments */
+ reg_val |= BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS;
+ writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
+
+ /* complete the above write before the delay */
+ mb();
+ /* wait for the bhs to settle */
udelay(BHS_SETTLING_DELAY_US);
/* Finally turn on the bypass so that BHS supplies power */
- writel_relaxed(
- BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
- | LDO_PWR_DWN_MASK
- | CLK_SRC_DEFAULT << CLK_SRC_SEL_BIT_POS
- | LDO_BYP_MASK
- | BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS
- | BHS_EN_MASK,
- base_ptr + APC_PWR_GATE_CTL);
+ reg_val |= LDO_BYP_MASK;
+ writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
+
+ if (the_gang && the_gang->manage_phases)
+ return;
+
+ /*
+ * If the driver has not yet started to manage phases then enable
+ * max phases.
+ */
+ l2_saw_base = ioremap_nocache(MSM_L2_SAW_PHYS, SZ_4K);
+ if (!l2_saw_base) {
+ __WARN();
+ return;
+ }
+ writel_relaxed(0x10003, l2_saw_base + 0x1c);
+ mb();
+ udelay(PHASE_SETTLING_TIME_US);
+
+ iounmap(l2_saw_base);
}
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("KRAIT POWER regulator driver");
-MODULE_VERSION("1.0");
MODULE_ALIAS("platform:"KRAIT_REGULATOR_DRIVER_NAME);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 4adfe4d..eddf017 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -247,6 +247,11 @@
struct msm_bus_fabric_device *gwfab =
msm_bus_get_fabric_device(fabnodeinfo->
info->node_info->priv_id);
+ if (!gwfab) {
+ MSM_BUS_ERR("Err: No gateway found\n");
+ return -ENXIO;
+ }
+
if (!gwfab->visited) {
MSM_BUS_DBG("VISITED ID: %d\n",
gwfab->id);
@@ -314,12 +319,18 @@
struct msm_bus_inode_info *info;
int next_pnode;
int64_t add_bw = req_bw - curr_bw;
- unsigned bwsum = 0;
+ uint64_t bwsum = 0;
uint64_t req_clk_hz, curr_clk_hz, bwsum_hz;
int *master_tiers;
struct msm_bus_fabric_device *fabdev = msm_bus_get_fabric_device
(GET_FABID(curr));
+ if (!fabdev) {
+ MSM_BUS_ERR("Bus device for bus ID: %d not found!\n",
+ GET_FABID(curr));
+ return -ENXIO;
+ }
+
MSM_BUS_DBG("args: %d %d %d %llu %llu %llu %llu %u\n",
curr, GET_NODE(pnode), GET_INDEX(pnode), req_clk, req_bw,
curr_clk, curr_bw, ctx);
@@ -398,7 +409,7 @@
/* Update Bandwidth */
fabdev->algo->update_bw(fabdev, hop, info, add_bw,
master_tiers, ctx);
- bwsum = (uint16_t)*hop->link_info.sel_bw;
+ bwsum = *hop->link_info.sel_bw;
/* Update Fabric clocks */
curr_clk_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth,
curr_clk);
@@ -525,6 +536,11 @@
goto err;
}
srcfab = msm_bus_get_fabric_device(GET_FABID(src));
+ if (!srcfab) {
+ MSM_BUS_ERR("Fabric not found\n");
+ goto err;
+ }
+
srcfab->visited = true;
pnode[i] = getpath(src, dest);
bus_for_each_dev(&msm_bus_type, NULL, NULL, clearvisitedflag);
@@ -574,6 +590,10 @@
curr = client->curr;
pdata = client->pdata;
+ if (!pdata) {
+ MSM_BUS_ERR("Null pdata passed to update-request\n");
+ return -ENXIO;
+ }
if (index >= pdata->num_usecases) {
MSM_BUS_ERR("Client %u passed invalid index: %d\n",
@@ -657,6 +677,12 @@
struct msm_bus_fabric_device *fabdev;
int index, next_pnode;
fabdev = msm_bus_get_fabric_device(GET_FABID(curr));
+ if (!fabdev) {
+ MSM_BUS_ERR("Fabric not found for: %d\n",
+ (GET_FABID(curr)));
+ return -ENXIO;
+ }
+
index = GET_INDEX(pnode);
info = fabdev->algo->find_node(fabdev, curr);
if (!info) {
@@ -718,7 +744,7 @@
{
int i, src, pnode, index;
struct msm_bus_client *client = (struct msm_bus_client *)(cl);
- if (IS_ERR(client)) {
+ if (IS_ERR_OR_NULL(client)) {
MSM_BUS_ERR("msm_bus_scale_reset_pnodes error\n");
return;
}
@@ -739,7 +765,7 @@
void msm_bus_scale_unregister_client(uint32_t cl)
{
struct msm_bus_client *client = (struct msm_bus_client *)(cl);
- if (IS_ERR(client) || (!client))
+ if (IS_ERR_OR_NULL(client))
return;
if (client->curr != 0)
msm_bus_scale_client_update_request(cl, 0);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index cd6693e..f05b381 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1769,8 +1769,13 @@
}
}
+ if (fab_pdata->virt) {
+ MSM_BUS_DBG("Don't get memory regions for virtual fabric\n");
+ goto skip_mem;
+ }
+
bimc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!bimc_mem && !fab_pdata->virt) {
+ if (!bimc_mem) {
MSM_BUS_ERR("Cannot get BIMC Base address\n");
kfree(binfo);
return NULL;
@@ -1792,6 +1797,7 @@
return NULL;
}
+skip_mem:
fab_pdata->hw_data = (void *)binfo;
return (void *)binfo;
}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
index b45efad..ff3dc21 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
@@ -437,10 +437,7 @@
},
};
-static int mport_mdp[] = {
- MSM_BUS_MASTER_PORT_MDP_PORT0,
- MSM_BUS_MASTER_PORT_MDP_PORT1,
-};
+static int mport_mdp[] = {MSM_BUS_MASTER_PORT_MDP_PORT0,};
static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
static int mport_graphics_3d_port0[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT0,};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
index 91d106e..af51355 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
@@ -377,10 +377,7 @@
},
};
-static int mport_mdp[] = {
- MSM_BUS_MASTER_PORT_MDP_PORT0,
- MSM_BUS_MASTER_PORT_MDP_PORT1,
-};
+static int mport_mdp[] = {MSM_BUS_MASTER_PORT_MDP_PORT0,};
static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
static int mport_graphics_3d[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D,};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
index 158dee3..295b91b 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
@@ -440,10 +440,7 @@
},
};
-static int mport_mdp[] = {
- MSM_BUS_MASTER_PORT_MDP_PORT0,
- MSM_BUS_MASTER_PORT_MDP_PORT1,
-};
+static int mport_mdp[] = {MSM_BUS_MASTER_PORT_MDP_PORT0,};
static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
static int mport_graphics_3d[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D,};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_config.c b/arch/arm/mach-msm/msm_bus/msm_bus_config.c
index c6fa250..858b15e 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_config.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_config.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -39,7 +39,7 @@
MSM_BUS_DBG("master_port: %d iid: %d fabid%d\n",
master_port, priv_id, GET_FABID(priv_id));
fabdev = msm_bus_get_fabric_device(GET_FABID(priv_id));
- if (IS_ERR(fabdev)) {
+ if (IS_ERR_OR_NULL(fabdev)) {
MSM_BUS_ERR("Fabric device not found for mport: %d\n",
master_port);
return -ENODEV;
@@ -65,7 +65,7 @@
MSM_BUS_DBG("master_port: %d iid: %d fabid: %d\n",
master_port, priv_id, GET_FABID(priv_id));
fabdev = msm_bus_get_fabric_device(GET_FABID(priv_id));
- if (IS_ERR(fabdev)) {
+ if (IS_ERR_OR_NULL(fabdev)) {
MSM_BUS_ERR("Fabric device not found for mport: %d\n",
master_port);
return -ENODEV;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_of.c b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
index af3537c..4e25637 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_of.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
@@ -103,6 +103,11 @@
}
vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len);
+ if (vec_arr == NULL) {
+ pr_err("Error: Vector array not found\n");
+ goto err;
+ }
+
if (len != num_usecases * num_paths * sizeof(uint32_t) * 4) {
pr_err("Error: Length-error on getting vectors\n");
goto err;
@@ -432,7 +437,7 @@
struct msm_bus_fabric_registration
*msm_bus_of_get_fab_data(struct platform_device *pdev)
{
- struct device_node *of_node = pdev->dev.of_node;
+ struct device_node *of_node;
struct msm_bus_fabric_registration *pdata;
bool mem_err = false;
int ret = 0;
@@ -443,6 +448,7 @@
return NULL;
}
+ of_node = pdev->dev.of_node;
pdata = devm_kzalloc(&pdev->dev,
sizeof(struct msm_bus_fabric_registration), GFP_KERNEL);
if (!pdata) {
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 9e0be63..1a919fc 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1026,6 +1026,9 @@
uint32_t ret1;
uint32_t ret2;
+ if (!msm_dcvs_enabled)
+ return ret;
+
offset = get_core_offset(type, type_core_num);
if (offset < 0)
return ret;
@@ -1277,6 +1280,9 @@
struct kobject *module_kobj = NULL;
int ret = 0;
+ if (!msm_dcvs_enabled)
+ return ret;
+
module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
if (!module_kobj) {
pr_err("%s: cannot find kobject for module %s\n",
@@ -1343,6 +1349,7 @@
ret = msm_dcvs_scm_init(SZ_32K);
if (ret) {
__err("Unable to initialize DCVS err=%d\n", ret);
+ msm_dcvs_enabled = 0;
goto done;
}
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index 4ea1de9..9b18c59 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -66,7 +66,7 @@
#define NUM_PORTS_SHIFT (0)
#define GFX_MPU_SHIFT (12)
-#define NUM_MACROS_MASK (0xF << 8)
+#define NUM_MACROS_MASK (0x3F << 8)
#define NUM_MACROS_SHIFT (8)
#define INTERLEAVING_MASK (0x1 << 17)
@@ -97,9 +97,12 @@
#define REGION_SLEEP_PERI_ON 0x00007777
#define REGION_DEFAULT_OFF REGION_SLEEP_NO_RETENTION
-#define REGION_DEFAULT_ON REGION_NORMAL_PASSTHROUGH
+#define REGION_DEFAULT_ON REGION_FORCE_CORE_ON
#define REGION_DEFAULT_RETENTION REGION_SLEEP_PERI_OFF
+#define REGION_STAGING_SET(x) (REGION_SLEEP_PERI_OFF & (0xF << (x * 0x4)))
+#define REGION_ON_SET(x) (REGION_DEFAULT_OFF & (0xF << (x * 0x4)))
+
enum rpm_macro_state {
rpm_macro_off = 0x0,
rpm_macro_retain,
@@ -195,6 +198,51 @@
return state;
}
+#ifndef CONFIG_MSM_OCMEM_POWER_DISABLE
+static int commit_region_staging(unsigned region_num, unsigned start_m,
+ unsigned new_state)
+{
+ int rc = -1;
+ unsigned state = 0x0;
+ unsigned read_state = 0x0;
+ unsigned curr_state = 0x0;
+
+ if (region_num >= num_regions)
+ return -EINVAL;
+
+ if (rpm_power_control)
+ return 0;
+ else {
+ if (new_state != REGION_DEFAULT_OFF) {
+ curr_state = read_region_state(region_num);
+ state = curr_state | REGION_STAGING_SET(start_m);
+ rc = ocmem_write(state,
+ ocmem_base + PSCGC_CTL_n(region_num));
+ /* Barrier to commit the region state */
+ mb();
+ read_state = read_region_state(region_num);
+ if (new_state == REGION_DEFAULT_ON) {
+ curr_state = read_region_state(region_num);
+ state = curr_state ^ REGION_ON_SET(start_m);
+ rc = ocmem_write(state,
+ ocmem_base + PSCGC_CTL_n(region_num));
+ /* Barrier to commit the region state */
+ mb();
+ read_state = read_region_state(region_num);
+ }
+ } else {
+ curr_state = read_region_state(region_num);
+ state = curr_state ^ REGION_STAGING_SET(start_m);
+ rc = ocmem_write(state,
+ ocmem_base + PSCGC_CTL_n(region_num));
+ /* Barrier to commit the region state */
+ mb();
+ read_state = read_region_state(region_num);
+ }
+ }
+ return 0;
+}
+#endif
/* Returns the current state of a OCMEM macro that belongs to a region */
static int read_macro_state(unsigned region_num, unsigned macro_num)
@@ -948,9 +996,11 @@
apply_macro_vote(id, i, j,
hw_macro_state(new_state));
aggregate_macro_state(i, j);
+ commit_region_staging(i, j, new_state);
}
aggregate_region_state(i);
- commit_region_state(i);
+ if (rpm_power_control)
+ commit_region_state(i);
len -= region_size;
/* If we voted ON/retain the banks must never be OFF */
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 8afe695..a14b960 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -1515,6 +1515,18 @@
pr_err("ocmem: Failed to unmap %p\n", req);
goto free_fail;
}
+ /* Turn off the memory */
+ if (req->req_sz != 0) {
+
+ offset = phys_to_offset(req->req_start);
+ rc = ocmem_memory_off(req->owner, offset,
+ req->req_sz);
+
+ if (rc < 0) {
+ pr_err("Failed to switch OFF memory macros\n");
+ goto free_fail;
+ }
+ }
rc = do_free(req);
if (rc < 0) {
@@ -1525,21 +1537,19 @@
pr_debug("request %p was already shrunk to 0\n", req);
}
- /* Turn off the memory */
- if (req->req_sz != 0) {
+ if (!TEST_STATE(req, R_FREE)) {
+ /* Turn off the memory */
+ if (req->req_sz != 0) {
- offset = phys_to_offset(req->req_start);
+ offset = phys_to_offset(req->req_start);
+ rc = ocmem_memory_off(req->owner, offset, req->req_sz);
- rc = ocmem_memory_off(req->owner, offset, req->req_sz);
-
- if (rc < 0) {
- pr_err("Failed to switch OFF memory macros\n");
- goto free_fail;
+ if (rc < 0) {
+ pr_err("Failed to switch OFF memory macros\n");
+ goto free_fail;
+ }
}
- }
-
- if (!TEST_STATE(req, R_FREE)) {
/* free the allocation */
rc = do_free(req);
if (rc < 0)
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index cf29cf1..b186a4d 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -515,6 +515,17 @@
drv->subsys_desc.start = pronto_start;
drv->subsys_desc.stop = pronto_stop;
+ ret = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,gpio-err-ready", 0);
+ if (ret < 0)
+ return ret;
+
+ ret = gpio_to_irq(ret);
+ if (ret < 0)
+ return ret;
+
+ drv->subsys_desc.err_ready_irq = ret;
+
INIT_DELAYED_WORK(&drv->cancel_vote_work, wcnss_post_bootup);
drv->subsys = subsys_register(&drv->subsys_desc);
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 04c1be3..6e8e79e 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -409,6 +409,12 @@
drv->err_fatal_irq = ret;
ret = gpio_to_irq(of_get_named_gpio(pdev->dev.of_node,
+ "qcom,gpio-err-ready", 0));
+ if (ret < 0)
+ return ret;
+ drv->subsys_desc.err_ready_irq = ret;
+
+ ret = gpio_to_irq(of_get_named_gpio(pdev->dev.of_node,
"qcom,gpio-proxy-unvote", 0));
if (ret < 0)
return ret;
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index c1c3100..979458e 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -92,7 +92,6 @@
void *smem_ramdump_dev;
bool crash_shutdown;
bool ignore_errors;
- int is_loadable;
int err_fatal_irq;
int force_stop_gpio;
};
@@ -105,13 +104,15 @@
static int pil_mss_power_up(struct q6v5_data *drv)
{
- int ret;
+ int ret = 0;
struct device *dev = drv->desc.dev;
u32 regval;
- ret = regulator_enable(drv->vreg);
- if (ret)
- dev_err(dev, "Failed to enable modem regulator.\n");
+ if (drv->vreg) {
+ ret = regulator_enable(drv->vreg);
+ if (ret)
+ dev_err(dev, "Failed to enable modem regulator.\n");
+ }
if (drv->cxrail_bhs) {
regval = readl_relaxed(drv->cxrail_bhs);
@@ -135,7 +136,10 @@
writel_relaxed(regval, drv->cxrail_bhs);
}
- return regulator_disable(drv->vreg);
+ if (drv->vreg)
+ return regulator_disable(drv->vreg);
+
+ return 0;
}
static int pil_mss_enable_clks(struct q6v5_data *drv)
@@ -502,7 +506,7 @@
{
struct mba_data *drv = subsys_to_drv(subsys);
- if (!drv->is_loadable)
+ if (subsys->is_not_loadable)
return 0;
pil_shutdown(&drv->desc);
pil_shutdown(&drv->q6->desc);
@@ -514,7 +518,7 @@
struct mba_data *drv = subsys_to_drv(subsys);
int ret;
- if (!drv->is_loadable)
+ if (subsys->is_not_loadable)
return 0;
/*
* At this time, the modem is shutdown. Therefore this function cannot
@@ -601,7 +605,7 @@
int ret;
struct mba_data *drv = subsys_to_drv(desc);
- if (!drv->is_loadable)
+ if (desc->is_not_loadable)
return 0;
ret = pil_boot(&drv->q6->desc);
@@ -624,7 +628,7 @@
{
struct mba_data *drv = subsys_to_drv(desc);
- if (!drv->is_loadable)
+ if (desc->is_not_loadable)
return;
pil_shutdown(&drv->desc);
@@ -650,6 +654,17 @@
drv->subsys_desc.start = mss_start;
drv->subsys_desc.stop = mss_stop;
+ ret = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,gpio-err-ready", 0);
+ if (ret < 0)
+ return ret;
+
+ ret = gpio_to_irq(ret);
+ if (ret < 0)
+ return ret;
+
+ drv->subsys_desc.err_ready_irq = ret;
+
drv->subsys = subsys_register(&drv->subsys_desc);
if (IS_ERR(drv->subsys)) {
ret = PTR_ERR(drv->subsys);
@@ -714,6 +729,7 @@
struct q6v5_data *q6;
struct pil_desc *q6_desc, *mba_desc;
struct resource *res;
+ struct property *prop;
int ret;
int clk_ready = of_get_named_gpio(pdev->dev.of_node,
@@ -751,31 +767,36 @@
if (!q6->restart_reg)
return -ENOMEM;
- q6->vreg = devm_regulator_get(&pdev->dev, "vdd_mss");
- if (IS_ERR(q6->vreg))
- return PTR_ERR(q6->vreg);
+ q6->vreg = NULL;
+
+ prop = of_find_property(pdev->dev.of_node, "vdd_mss-supply", NULL);
+ if (prop) {
+ q6->vreg = devm_regulator_get(&pdev->dev, "vdd_mss");
+ if (IS_ERR(q6->vreg))
+ return PTR_ERR(q6->vreg);
+
+ ret = regulator_set_voltage(q6->vreg, VDD_MSS_UV,
+ MAX_VDD_MSS_UV);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to set vreg voltage.\n");
+
+ ret = regulator_set_optimum_mode(q6->vreg, 100000);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to set vreg mode.\n");
+ return ret;
+ }
+ }
q6->vreg_mx = devm_regulator_get(&pdev->dev, "vdd_mx");
if (IS_ERR(q6->vreg_mx))
return PTR_ERR(q6->vreg_mx);
- ret = regulator_set_voltage(q6->vreg, VDD_MSS_UV, MAX_VDD_MSS_UV);
- if (ret)
- dev_err(&pdev->dev, "Failed to set regulator's voltage.\n");
-
- ret = regulator_set_optimum_mode(q6->vreg, 100000);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to set regulator's mode.\n");
- return ret;
- }
-
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"cxrail_bhs_reg");
if (res)
q6->cxrail_bhs = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
-
q6->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
if (IS_ERR(q6->ahb_clk))
return PTR_ERR(q6->ahb_clk);
@@ -815,16 +836,18 @@
static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
{
struct mba_data *drv;
- int ret, err_fatal_gpio;
+ int ret, err_fatal_gpio, is_not_loadable;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;
platform_set_drvdata(pdev, drv);
- drv->is_loadable = of_property_read_bool(pdev->dev.of_node,
- "qcom,is-loadable");
- if (drv->is_loadable) {
+ is_not_loadable = of_property_read_bool(pdev->dev.of_node,
+ "qcom,is-not-loadable");
+ if (is_not_loadable) {
+ drv->subsys_desc.is_not_loadable = 1;
+ } else {
ret = pil_mss_loadable_init(drv, pdev);
if (ret)
return ret;
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index a39e38b..33ad83f 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -1248,24 +1248,19 @@
static void setup_broadcast_timer(void *arg)
{
- unsigned long reason = (unsigned long)arg;
int cpu = smp_processor_id();
- reason = reason ?
- CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
-
- clockevents_notify(reason, &cpu);
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
}
static int setup_broadcast_cpuhp_notify(struct notifier_block *n,
unsigned long action, void *hcpu)
{
- int hotcpu = (unsigned long)hcpu;
+ int cpu = (unsigned long)hcpu;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
- smp_call_function_single(hotcpu, setup_broadcast_timer,
- (void *)true, 1);
+ smp_call_function_single(cpu, setup_broadcast_timer, NULL, 1);
break;
}
@@ -1292,10 +1287,7 @@
msm_cpuidle_init();
if (msm_pm_pc_reset_timer) {
- get_cpu();
- smp_call_function_many(cpu_online_mask, setup_broadcast_timer,
- (void *)true, 1);
- put_cpu();
+ on_each_cpu(setup_broadcast_timer, NULL, 1);
register_cpu_notifier(&setup_broadcast_notifier);
}
@@ -1368,7 +1360,7 @@
if (!data)
return -EINVAL;
- if (!bufu || count < 0)
+ if (!bufu)
return -EINVAL;
if (!access_ok(VERIFY_WRITE, bufu, count))
diff --git a/arch/arm/mach-msm/pm-data.c b/arch/arm/mach-msm/pm-data.c
index 249032f..f41c569 100644
--- a/arch/arm/mach-msm/pm-data.c
+++ b/arch/arm/mach-msm/pm-data.c
@@ -125,4 +125,11 @@
.idle_enabled = 1,
.suspend_enabled = 0,
},
+
+ [MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_NR)] = {
+ .idle_supported = 0,
+ .suspend_supported = 0,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
};
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index ea22c12..b5ccc31 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -786,7 +786,7 @@
goto done;
}
- if (size <= 0) {
+ if ((size <= 0) || (size > sizeof(data))) {
pr_err("%s: Invalid size sent to driver: %d\n",
__func__, size);
result = -EFAULT;
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
index c9bc3d7..5303009 100644
--- a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
+++ b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
@@ -22,10 +22,15 @@
#include <linux/of_device.h>
#include <linux/msm_audio_ion.h>
+#include <linux/iommu.h>
+#include <mach/iommu_domains.h>
+
struct msm_audio_ion_private {
bool smmu_enabled;
- /*u32 group_id;*/
- /*u32 domain_id;*/
+ bool audioheap_enabled;
+ struct iommu_group *group;
+ u32 domain_id;
+ struct iommu_domain *domain;
};
static struct msm_audio_ion_private msm_audio_ion_data = {0,};
@@ -49,10 +54,22 @@
goto err;
}
- *handle = ion_alloc(*client, bufsz, SZ_4K, (0x1<<ION_AUDIO_HEAP_ID), 0);
+ *handle = ion_alloc(*client, bufsz, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL((void *) (*handle))) {
- pr_err("%s: ION memory allocation for AUDIO failed\n",
- __func__);
+ pr_debug("system heap is used");
+ msm_audio_ion_data.audioheap_enabled = 0;
+ *handle = ion_alloc(*client, bufsz, SZ_4K,
+ ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
+
+ } else {
+ pr_debug("audio heap is used");
+ msm_audio_ion_data.audioheap_enabled = 1;
+ }
+
+ if (IS_ERR_OR_NULL((void *) (*handle))) {
+ pr_err("%s: ION memory allocation for AUDIO failed rc=%d, smmu_enabled=%d\n",
+ __func__, rc, msm_audio_ion_data.smmu_enabled);
goto err_ion_client;
}
@@ -63,15 +80,17 @@
goto err_ion_handle;
}
- /*Need to add condition SMMU enable or not */
*vaddr = ion_map_kernel(*client, *handle);
if (IS_ERR_OR_NULL((void *)*vaddr)) {
pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
goto err_ion_handle;
}
+ pr_debug("%s: mapped address = %p, size=%d\n", __func__, *vaddr, bufsz);
- if (bufsz != 0)
+ if (bufsz != 0) {
+ pr_debug("%s: memset to 0 %p %d\n", __func__, *vaddr, bufsz);
memset((void *)*vaddr, 0, bufsz);
+ }
return 0;
@@ -81,7 +100,6 @@
msm_audio_ion_client_destroy(*client);
err:
return -EINVAL;
-
}
int msm_audio_ion_import(const char *name, struct ion_client **client,
@@ -125,13 +143,6 @@
goto err_ion_handle;
}
- /*Need to add condition SMMU enable or not */
- *vaddr = ion_map_kernel(*client, *handle);
- if (IS_ERR_OR_NULL((void *)*vaddr)) {
- pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
- goto err_ion_handle;
- }
-
if (bufsz != 0)
memset((void *)*vaddr, 0, bufsz);
@@ -142,12 +153,20 @@
msm_audio_ion_client_destroy(*client);
err:
return -EINVAL;
-
}
int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle)
{
- /* add condition for SMMU enabled */
+ if (msm_audio_ion_data.smmu_enabled) {
+ /* Need to populate book kept infomation */
+ pr_debug("client=%p, domain=%p, domain_id=%d, group=%p",
+ client, msm_audio_ion_data.domain,
+ msm_audio_ion_data.domain_id, msm_audio_ion_data.group);
+
+ ion_unmap_iommu(client, handle,
+ msm_audio_ion_data.domain_id, 0);
+ }
+
ion_unmap_kernel(client, handle);
ion_free(client, handle);
@@ -155,6 +174,91 @@
return 0;
}
+int msm_audio_ion_mmap(struct audio_buffer *ab,
+ struct vm_area_struct *vma)
+{
+ struct sg_table *table;
+ unsigned long addr = vma->vm_start;
+ unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
+ struct scatterlist *sg;
+ unsigned int i;
+ struct page *page;
+ int ret;
+
+ pr_debug("%s\n", __func__);
+
+ table = ion_sg_table(ab->client, ab->handle);
+
+ if (IS_ERR(table)) {
+ pr_err("%s: Unable to get sg_table from ion: %ld\n",
+ __func__, PTR_ERR(table));
+ return PTR_ERR(table);
+ } else if (!table) {
+ pr_err("%s: sg_list is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ /* uncached */
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ /* We need to check if a page is associated with this sg list because:
+ * If the allocation came from a carveout we currently don't have
+ * pages associated with carved out memory. This might change in the
+ * future and we can remove this check and the else statement.
+ */
+ page = sg_page(table->sgl);
+ if (page) {
+ pr_debug("%s: page is NOT null\n", __func__);
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ unsigned long remainder = vma->vm_end - addr;
+ unsigned long len = sg_dma_len(sg);
+
+ page = sg_page(sg);
+
+ if (offset >= sg_dma_len(sg)) {
+ offset -= sg_dma_len(sg);
+ continue;
+ } else if (offset) {
+ page += offset / PAGE_SIZE;
+ len = sg_dma_len(sg) - offset;
+ offset = 0;
+ }
+ len = min(len, remainder);
+ pr_debug("vma=%p, addr=%x len=%ld vm_start=%x vm_end=%x vm_page_prot=%ld\n",
+ vma, (unsigned int)addr, len,
+ (unsigned int)vma->vm_start,
+ (unsigned int)vma->vm_end,
+ (unsigned long int)vma->vm_page_prot);
+ remap_pfn_range(vma, addr, page_to_pfn(page), len,
+ vma->vm_page_prot);
+ addr += len;
+ if (addr >= vma->vm_end)
+ return 0;
+ }
+ } else {
+ ion_phys_addr_t phys_addr;
+ size_t phys_len;
+ pr_debug("%s: page is NULL\n", __func__);
+
+ ret = ion_phys(ab->client, ab->handle, &phys_addr, &phys_len);
+ if (ret) {
+ pr_err("%s: Unable to get phys address from ION buffer: %d\n"
+ , __func__ , ret);
+ return ret;
+ }
+ pr_debug("phys=%x len=%d\n", (unsigned int)phys_addr, phys_len);
+ pr_debug("vma=%p, vm_start=%x vm_end=%x vm_pgoff=%ld vm_page_prot=%ld\n",
+ vma, (unsigned int)vma->vm_start,
+ (unsigned int)vma->vm_end, vma->vm_pgoff,
+ (unsigned long int)vma->vm_page_prot);
+ ret = remap_pfn_range(vma, vma->vm_start,
+ __phys_to_pfn(phys_addr) + vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+ }
+ return 0;
+}
+
bool msm_audio_ion_is_smmu_available(void)
{
@@ -165,18 +269,17 @@
struct ion_client *msm_audio_ion_client_create(unsigned int heap_mask,
const char *name)
{
- pr_debug("%s: smmu_enabled = %d\n", __func__,
- msm_audio_ion_data.smmu_enabled);
-
-
- return msm_ion_client_create(heap_mask, name);
+ struct ion_client *pclient = NULL;
+ /*IOMMU group and domain are moved to probe()*/
+ pclient = msm_ion_client_create(heap_mask, name);
+ return pclient;
}
void msm_audio_ion_client_destroy(struct ion_client *client)
{
- pr_debug("%s: smmu_enabled = %d\n", __func__,
- msm_audio_ion_data.smmu_enabled);
+ pr_debug("%s: client = %p smmu_enabled = %d\n", __func__,
+ client, msm_audio_ion_data.smmu_enabled);
ion_client_destroy(client);
}
@@ -192,9 +295,9 @@
bufsz should be 0 and fd shouldn't be 0 as of now
*/
*handle = ion_import_dma_buf(client, fd);
- pr_err("%s: DMA Buf name=%s, fd=%d handle=%p\n", __func__,
+ pr_debug("%s: DMA Buf name=%s, fd=%d handle=%p\n", __func__,
name, fd, *handle);
- if (IS_ERR_OR_NULL((void *) (*handle))) {
+ if (IS_ERR_OR_NULL((void *)(*handle))) {
pr_err("%s: ion import dma buffer failed\n",
__func__);
goto err_ion_handle;
@@ -245,6 +348,41 @@
return 0;
}
+int msm_audio_ion_cache_operations(struct audio_buffer *abuff, int cache_op)
+{
+ unsigned long ionflag = 0;
+ int rc = 0;
+ int msm_cache_ops = 0;
+
+ if (!abuff) {
+ pr_err("Invalid params: %p, %p\n", __func__, abuff);
+ return -EINVAL;
+ }
+ rc = ion_handle_get_flags(abuff->client, abuff->handle,
+ &ionflag);
+ if (rc) {
+ pr_err("ion_handle_get_flags failed: %d\n", rc);
+ goto cache_op_failed;
+ }
+
+ /* has to be CACHED */
+ if (ION_IS_CACHED(ionflag)) {
+ /* ION_IOC_INV_CACHES or ION_IOC_CLEAN_CACHES */
+ msm_cache_ops = cache_op;
+ rc = msm_ion_do_cache_op(abuff->client,
+ abuff->handle,
+ (unsigned long *) abuff->data,
+ (unsigned long)abuff->size,
+ msm_cache_ops);
+ if (rc) {
+ pr_err("cache operation failed %d\n", rc);
+ goto cache_op_failed;
+ }
+ }
+cache_op_failed:
+ return rc;
+}
+
static int msm_audio_ion_get_phys(struct ion_client *client,
struct ion_handle *handle,
@@ -255,18 +393,25 @@
msm_audio_ion_data.smmu_enabled);
if (msm_audio_ion_data.smmu_enabled) {
- /* SMMU enabled case ion_map_iommu()*/
+ rc = ion_map_iommu(client, handle, msm_audio_ion_data.domain_id,
+ 0 /*partition_num*/, SZ_4K /*align*/, 0/*iova_length*/,
+ addr, (unsigned long *)len,
+ 0, 0);
+ if (rc) {
+ pr_err("%s: ION map iommu failed %d\n", __func__, rc);
+ return rc;
+ }
+ pr_debug("client=%p, domain=%p, domain_id=%d, group=%p",
+ client, msm_audio_ion_data.domain,
+ msm_audio_ion_data.domain_id, msm_audio_ion_data.group);
} else {
/* SMMU is disabled*/
rc = ion_phys(client, handle, addr, len);
}
- pr_debug("%s: addr= 0x%p, len= %d\n", __func__, addr, *len);
+ pr_debug("phys=%x, len=%d, rc=%d\n", (unsigned int)*addr, *len, rc);
return rc;
}
-
-
-
static int msm_audio_ion_probe(struct platform_device *pdev)
{
int rc = 0;
@@ -283,13 +428,53 @@
msm_audio_ion_dt);
msm_audio_ion_data.smmu_enabled = smmu_enabled;
+ if (smmu_enabled) {
+ msm_audio_ion_data.group = iommu_group_find("lpass_audio");
+ if (!msm_audio_ion_data.group) {
+ pr_debug("Failed to find group lpass_audio deferred\n");
+ goto fail_group;
+ }
+ msm_audio_ion_data.domain =
+ iommu_group_get_iommudata(msm_audio_ion_data.group);
+ if (IS_ERR_OR_NULL(msm_audio_ion_data.domain)) {
+ pr_err("Failed to get domain data for group %p",
+ msm_audio_ion_data.group);
+ goto fail_group;
+ }
+ msm_audio_ion_data.domain_id =
+ msm_find_domain_no(msm_audio_ion_data.domain);
+ if (msm_audio_ion_data.domain_id < 0) {
+ pr_err("Failed to get domain index for domain %p",
+ msm_audio_ion_data.domain);
+ goto fail_group;
+ }
+ pr_debug("domain=%p, domain_id=%d, group=%p",
+ msm_audio_ion_data.domain,
+ msm_audio_ion_data.domain_id, msm_audio_ion_data.group);
+
+ /* iommu_attach_group() will make AXI clock ON. For future PL
+ this will require to be called in once per session */
+ rc = iommu_attach_group(msm_audio_ion_data.domain,
+ msm_audio_ion_data.group);
+ if (rc) {
+ pr_err("%s:ION attach group failed %d\n", __func__, rc);
+ return rc;
+ }
+
+ }
+
pr_debug("%s: SMMU-Enabled = %d\n", __func__, smmu_enabled);
return rc;
+
+fail_group:
+ return -EPROBE_DEFER;
}
static int msm_audio_ion_remove(struct platform_device *pdev)
{
- pr_debug("%s: msm audio ion is unloaded\n", __func__);
+ pr_debug("%s: msm audio ion is unloaded, domain=%p, group=%p\n",
+ __func__, msm_audio_ion_data.domain, msm_audio_ion_data.group);
+ iommu_detach_group(msm_audio_ion_data.domain, msm_audio_ion_data.group);
return 0;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
index ff7ba33..a3af3e78 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
@@ -17,7 +17,7 @@
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/msm_audio.h>
-#include <sound/apr_audio.h>
+#include <sound/apr_audio-v2.h>
#include <mach/qdsp6v2/apr_us_b.h>
#include "q6usm.h"
diff --git a/arch/arm/mach-msm/rpm_log.c b/arch/arm/mach-msm/rpm_log.c
index 53d5752..58e8588 100644
--- a/arch/arm/mach-msm/rpm_log.c
+++ b/arch/arm/mach-msm/rpm_log.c
@@ -213,7 +213,7 @@
return -EINVAL;
if (!buf->data)
return -ENOMEM;
- if (!bufu || count < 0)
+ if (!bufu || count == 0)
return -EINVAL;
if (!access_ok(VERIFY_WRITE, bufu, count))
return -EFAULT;
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 424d310..20a6165 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -41,7 +41,7 @@
#ifdef CONFIG_ARCH_FSM9XXX
#define NUM_SMD_PKT_PORTS 4
#else
-#define NUM_SMD_PKT_PORTS 27
+#define NUM_SMD_PKT_PORTS 28
#endif
#define PDRIVER_NAME_MAX_SIZE 32
@@ -729,6 +729,7 @@
"smd_test_framework",
"smd_logging_0",
"smd_data_0",
+ "apr",
"smd_pkt_loopback",
};
@@ -759,6 +760,7 @@
"TESTFRAMEWORK",
"LOGGING",
"DATA",
+ "apr",
"LOOPBACK",
};
@@ -789,6 +791,7 @@
SMD_APPS_QDSP,
SMD_APPS_QDSP,
SMD_APPS_QDSP,
+ SMD_APPS_QDSP,
SMD_APPS_MODEM,
};
#endif
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 12a3ceb..d316496 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -279,6 +279,8 @@
/* 8974 IDs */
[126] = MSM_CPU_8974,
[184] = MSM_CPU_8974,
+ [185] = MSM_CPU_8974,
+ [186] = MSM_CPU_8974,
/* 8625 IDs */
[127] = MSM_CPU_8625,
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 174d444..8e94b3a 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -76,7 +76,7 @@
info.vlevel = vlevel;
info.err = -ENODEV;
- if (cpu_online(cpu)) {
+ if ((smp_processor_id() != cpu) && cpu_online(cpu)) {
/**
* We do not want to set the voltage of another core from
* this core, as its possible that we may race the vdd change
@@ -404,21 +404,28 @@
memset(&modes, 0,
(MSM_SPM_MODE_NR - 2) * sizeof(struct msm_spm_seq_entry));
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- goto fail;
-
- spm_data.reg_base_addr = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!spm_data.reg_base_addr)
- return -ENOMEM;
-
key = "qcom,core-id";
ret = of_property_read_u32(node, key, &val);
if (ret)
goto fail;
cpu = val;
+ /*
+ * Device with id 0..NR_CPUS are SPM for apps cores
+ * Device with id 0xFFFF is for L2 SPM.
+ */
+ if (cpu >= 0 && cpu < num_possible_cpus()) {
+ mode_of_data = of_cpu_modes;
+ num_modes = ARRAY_SIZE(of_cpu_modes);
+ dev = &per_cpu(msm_cpu_spm_device, cpu);
+
+ } else if (cpu == 0xffff) {
+ mode_of_data = of_l2_modes;
+ num_modes = ARRAY_SIZE(of_l2_modes);
+ dev = &msm_spm_l2_device;
+ } else
+ return ret;
+
key = "qcom,saw2-ver-reg";
ret = of_property_read_u32(node, key, &val);
if (ret)
@@ -429,21 +436,17 @@
ret = of_property_read_u32(node, key, &val);
if (!ret)
spm_data.vctl_timeout_us = val;
+ else if (cpu == 0xffff)
+ goto fail;
- /*
- * Device with id 0..NR_CPUS are SPM for apps cores
- * Device with id 0xFFFF is for L2 SPM.
- */
- if (cpu >= 0 && cpu < num_possible_cpus()) {
- mode_of_data = of_cpu_modes;
- num_modes = ARRAY_SIZE(of_cpu_modes);
- dev = &per_cpu(msm_cpu_spm_device, cpu);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ goto fail;
- } else {
- mode_of_data = of_l2_modes;
- num_modes = ARRAY_SIZE(of_l2_modes);
- dev = &msm_spm_l2_device;
- }
+ spm_data.reg_base_addr = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!spm_data.reg_base_addr)
+ return -ENOMEM;
spm_data.vctl_port = -1;
spm_data.phase_port = -1;
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 5fe7a29..26f0210 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -31,6 +31,7 @@
#include <linux/idr.h>
#include <linux/debugfs.h>
#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
#include <asm/current.h>
@@ -132,6 +133,7 @@
* @restart_order: order of other devices this devices restarts with
* @dentry: debugfs directory for this device
* @do_ramdump_on_put: ramdump on subsystem_put() if true
+ * @err_ready: completion variable to record error ready from subsystem
*/
struct subsys_device {
struct subsys_desc *desc;
@@ -154,6 +156,7 @@
bool do_ramdump_on_put;
struct miscdevice misc_dev;
char miscdevice_name[32];
+ struct completion err_ready;
};
static struct subsys_device *to_subsys(struct device *d)
@@ -412,6 +415,21 @@
}
}
+static int wait_for_err_ready(struct subsys_device *subsys)
+{
+ int ret;
+
+ if (!subsys->desc->err_ready_irq)
+ return 0;
+
+ ret = wait_for_completion_timeout(&subsys->err_ready,
+ msecs_to_jiffies(10000));
+ if (!ret)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
static void subsystem_shutdown(struct subsys_device *dev, void *data)
{
const char *name = dev->desc->name;
@@ -436,10 +454,17 @@
static void subsystem_powerup(struct subsys_device *dev, void *data)
{
const char *name = dev->desc->name;
+ int ret;
pr_info("[%p]: Powering up %s\n", current, name);
+ init_completion(&dev->err_ready);
if (dev->desc->powerup(dev->desc) < 0)
- panic("[%p]: Failed to powerup %s!", current, name);
+ panic("[%p]: Powerup error: %s!", current, name);
+
+ ret = wait_for_err_ready(dev);
+ if (ret)
+ panic("[%p]: Timed out waiting for error ready: %s!",
+ current, name);
subsys_set_state(dev, SUBSYS_ONLINE);
}
@@ -465,8 +490,21 @@
{
int ret;
+ init_completion(&subsys->err_ready);
ret = subsys->desc->start(subsys->desc);
- if (!ret)
+ if (ret)
+ return ret;
+
+ if (subsys->desc->is_not_loadable)
+ return 0;
+
+ ret = wait_for_err_ready(subsys);
+ if (ret)
+ /* pil-boot succeeded but we need to shutdown
+ * the device because error ready timed out.
+ */
+ subsys->desc->stop(subsys->desc);
+ else
subsys_set_state(subsys, SUBSYS_ONLINE);
return ret;
@@ -895,6 +933,14 @@
ida_simple_remove(&subsys_ida, subsys->id);
kfree(subsys);
}
+static irqreturn_t subsys_err_ready_intr_handler(int irq, void *subsys)
+{
+ struct subsys_device *subsys_dev = subsys;
+ pr_info("Error ready interrupt occured for %s\n",
+ subsys_dev->desc->name);
+ complete(&subsys_dev->err_ready);
+ return IRQ_HANDLED;
+}
static int subsys_misc_device_add(struct subsys_device *subsys_dev)
{
@@ -971,8 +1017,24 @@
goto err_register;
}
+ if (subsys->desc->err_ready_irq) {
+ ret = devm_request_irq(&subsys->dev,
+ subsys->desc->err_ready_irq,
+ subsys_err_ready_intr_handler,
+ IRQF_TRIGGER_RISING,
+ "error_ready_interrupt", subsys);
+ if (ret < 0) {
+ dev_err(&subsys->dev,
+ "[%s]: Unable to register err ready handler\n",
+ subsys->desc->name);
+ goto err_misc_device;
+ }
+ }
+
return subsys;
+err_misc_device:
+ subsys_misc_device_remove(subsys);
err_register:
subsys_debugfs_remove(subsys);
err_debugfs:
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 8df41e2..07b6f6c 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -280,11 +280,11 @@
return (void __iomem *) (offset + addr);
}
-void __iomem *__arm_ioremap_caller(unsigned long phys_addr, size_t size,
+void __iomem *__arm_ioremap_caller(phys_addr_t phys_addr, size_t size,
unsigned int mtype, void *caller)
{
- unsigned long last_addr;
- unsigned long offset = phys_addr & ~PAGE_MASK;
+ phys_addr_t last_addr;
+ phys_addr_t offset = phys_addr & ~PAGE_MASK;
unsigned long pfn = __phys_to_pfn(phys_addr);
/*
@@ -316,12 +316,12 @@
}
EXPORT_SYMBOL(__arm_ioremap_pfn);
-void __iomem * (*arch_ioremap_caller)(unsigned long, size_t,
+void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
unsigned int, void *) =
__arm_ioremap_caller;
void __iomem *
-__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
+__arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype)
{
return arch_ioremap_caller(phys_addr, size, mtype,
__builtin_return_address(0));
@@ -336,7 +336,7 @@
* CONFIG_GENERIC_ALLOCATOR for allocating external memory.
*/
void __iomem *
-__arm_ioremap_exec(unsigned long phys_addr, size_t size, bool cached)
+__arm_ioremap_exec(phys_addr_t phys_addr, size_t size, bool cached)
{
unsigned int mtype;
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index 06262c5..ce8cb19 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -11,10 +11,49 @@
#include <linux/random.h>
#include <asm/cachetype.h>
+static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr,
+ unsigned long pgoff)
+{
+ unsigned long base = addr & ~(SHMLBA-1);
+ unsigned long off = (pgoff << PAGE_SHIFT) & (SHMLBA-1);
+
+ if (base + off <= addr)
+ return base + off;
+
+ return base - off;
+}
+
#define COLOUR_ALIGN(addr,pgoff) \
((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \
(((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
+/* gap between mmap and stack */
+#define MIN_GAP (128*1024*1024UL)
+#define MAX_GAP ((TASK_SIZE)/6*5)
+
+static int mmap_is_legacy(void)
+{
+ if (current->personality & ADDR_COMPAT_LAYOUT)
+ return 1;
+
+ if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
+ return 1;
+
+ return sysctl_legacy_va_layout;
+}
+
+static unsigned long mmap_base(unsigned long rnd)
+{
+ unsigned long gap = rlimit(RLIMIT_STACK);
+
+ if (gap < MIN_GAP)
+ gap = MIN_GAP;
+ else if (gap > MAX_GAP)
+ gap = MAX_GAP;
+
+ return PAGE_ALIGN(TASK_SIZE - gap - rnd);
+}
+
/*
* We need to ensure that shared mappings are correctly aligned to
* avoid aliasing issues with VIPT caches. We need to ensure that
@@ -68,13 +107,9 @@
if (len > mm->cached_hole_size) {
start_addr = addr = mm->free_area_cache;
} else {
- start_addr = addr = TASK_UNMAPPED_BASE;
+ start_addr = addr = mm->mmap_base;
mm->cached_hole_size = 0;
}
- /* 8 bits of randomness in 20 address space bits */
- if ((current->flags & PF_RANDOMIZE) &&
- !(current->personality & ADDR_NO_RANDOMIZE))
- addr += (get_random_int() % (1 << 8)) << PAGE_SHIFT;
full_search:
if (do_align)
@@ -111,6 +146,134 @@
}
}
+unsigned long
+arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
+ const unsigned long len, const unsigned long pgoff,
+ const unsigned long flags)
+{
+ struct vm_area_struct *vma;
+ struct mm_struct *mm = current->mm;
+ unsigned long addr = addr0;
+ int do_align = 0;
+ int aliasing = cache_is_vipt_aliasing();
+
+ /*
+ * We only need to do colour alignment if either the I or D
+ * caches alias.
+ */
+ if (aliasing)
+ do_align = filp || (flags & MAP_SHARED);
+
+ /* requested length too big for entire address space */
+ if (len > TASK_SIZE)
+ return -ENOMEM;
+
+ if (flags & MAP_FIXED) {
+ if (aliasing && flags & MAP_SHARED &&
+ (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
+ return -EINVAL;
+ return addr;
+ }
+
+ /* requesting a specific address */
+ if (addr) {
+ if (do_align)
+ addr = COLOUR_ALIGN(addr, pgoff);
+ else
+ addr = PAGE_ALIGN(addr);
+ vma = find_vma(mm, addr);
+ if (TASK_SIZE - len >= addr &&
+ (!vma || addr + len <= vma->vm_start))
+ return addr;
+ }
+
+ /* check if free_area_cache is useful for us */
+ if (len <= mm->cached_hole_size) {
+ mm->cached_hole_size = 0;
+ mm->free_area_cache = mm->mmap_base;
+ }
+
+ /* either no address requested or can't fit in requested address hole */
+ addr = mm->free_area_cache;
+ if (do_align) {
+ unsigned long base = COLOUR_ALIGN_DOWN(addr - len, pgoff);
+ addr = base + len;
+ }
+
+ /* make sure it can fit in the remaining address space */
+ if (addr > len) {
+ vma = find_vma(mm, addr-len);
+ if (!vma || addr <= vma->vm_start)
+ /* remember the address as a hint for next time */
+ return (mm->free_area_cache = addr-len);
+ }
+
+ if (mm->mmap_base < len)
+ goto bottomup;
+
+ addr = mm->mmap_base - len;
+ if (do_align)
+ addr = COLOUR_ALIGN_DOWN(addr, pgoff);
+
+ do {
+ /*
+ * Lookup failure means no vma is above this address,
+ * else if new region fits below vma->vm_start,
+ * return with success:
+ */
+ vma = find_vma(mm, addr);
+ if (!vma || addr+len <= vma->vm_start)
+ /* remember the address as a hint for next time */
+ return (mm->free_area_cache = addr);
+
+ /* remember the largest hole we saw so far */
+ if (addr + mm->cached_hole_size < vma->vm_start)
+ mm->cached_hole_size = vma->vm_start - addr;
+
+ /* try just below the current vma->vm_start */
+ addr = vma->vm_start - len;
+ if (do_align)
+ addr = COLOUR_ALIGN_DOWN(addr, pgoff);
+ } while (len < vma->vm_start);
+
+bottomup:
+ /*
+ * A failed mmap() very likely causes application failure,
+ * so fall back to the bottom-up function here. This scenario
+ * can happen with large stack limits and large mmap()
+ * allocations.
+ */
+ mm->cached_hole_size = ~0UL;
+ mm->free_area_cache = TASK_UNMAPPED_BASE;
+ addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
+ /*
+ * Restore the topdown base:
+ */
+ mm->free_area_cache = mm->mmap_base;
+ mm->cached_hole_size = ~0UL;
+
+ return addr;
+}
+
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+ unsigned long random_factor = 0UL;
+
+ /* 8 bits of randomness in 20 address space bits */
+ if ((current->flags & PF_RANDOMIZE) &&
+ !(current->personality & ADDR_NO_RANDOMIZE))
+ random_factor = (get_random_int() % (1 << 8)) << PAGE_SHIFT;
+
+ if (mmap_is_legacy()) {
+ mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
+ mm->get_unmapped_area = arch_get_unmapped_area;
+ mm->unmap_area = arch_unmap_area;
+ } else {
+ mm->mmap_base = mmap_base(random_factor);
+ mm->get_unmapped_area = arch_get_unmapped_area_topdown;
+ mm->unmap_area = arch_unmap_area_topdown;
+ }
+}
/*
* You really shouldn't be using read() or write() on /dev/mem. This
diff --git a/block/blk-core.c b/block/blk-core.c
index 69764df..2b6595c 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1123,7 +1123,7 @@
* urgent requests. We want to be able to track this
* down.
*/
- pr_err("%s(): requeueing an URGENT request", __func__);
+ pr_err("%s(): reinserting an URGENT request", __func__);
WARN_ON(!q->dispatched_urgent);
q->dispatched_urgent = false;
}
@@ -2018,6 +2018,10 @@
* not be passed by new incoming requests
*/
rq->cmd_flags |= REQ_STARTED;
+ if (rq->cmd_flags & REQ_URGENT) {
+ WARN_ON(q->dispatched_urgent);
+ q->dispatched_urgent = true;
+ }
trace_block_rq_issue(q, rq);
}
@@ -2151,13 +2155,8 @@
struct request *rq;
rq = blk_peek_request(q);
- if (rq) {
- if (rq->cmd_flags & REQ_URGENT) {
- WARN_ON(q->dispatched_urgent);
- q->dispatched_urgent = true;
- }
+ if (rq)
blk_start_request(rq);
- }
return rq;
}
EXPORT_SYMBOL(blk_fetch_request);
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 9e36e1e..04c3300 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -481,6 +481,7 @@
driver->feature_mask->ctrl_pkt_data_len = 4 + FEATURE_MASK_LEN_BYTES;
driver->feature_mask->feature_mask_len = FEATURE_MASK_LEN_BYTES;
memcpy(buf, driver->feature_mask, header_size);
+ feature_byte |= F_DIAG_INT_FEATURE_MASK;
feature_byte |= APPS_RESPOND_LOG_ON_DEMAND;
memcpy(buf+header_size, &feature_byte, FEATURE_MASK_LEN_BYTES);
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 2ebae71..7022a6f 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -2071,6 +2071,7 @@
diagchar_cleanup();
diagfwd_exit();
diagfwd_cntl_exit();
+ diag_dci_exit();
diag_masks_exit();
diag_sdio_fn(EXIT);
diagfwd_bridge_fn(EXIT);
@@ -2085,6 +2086,7 @@
diagmem_exit(driver, POOL_TYPE_ALL);
diagfwd_exit();
diagfwd_cntl_exit();
+ diag_dci_exit();
diag_masks_exit();
diag_sdio_fn(EXIT);
diagfwd_bridge_fn(EXIT);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index c3ff7dc..2776c58 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -69,7 +69,7 @@
type = *(uint32_t *)(buf);
data_len = *(uint32_t *)(buf + 4);
if (type < DIAG_CTRL_MSG_REG ||
- type > DIAG_CTRL_MSG_F3_MASK_V2) {
+ type > DIAG_CTRL_MSG_LAST) {
pr_alert("diag: In %s, Invalid Msg type %d proc %d",
__func__, type, smd_info->peripheral);
break;
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index 7cd1866..f58ab24 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -29,6 +29,15 @@
#define DIAG_CTRL_MSG_EVENT_MASK_V2 10
/* Send Diag F3 mask */
#define DIAG_CTRL_MSG_F3_MASK_V2 11
+#define DIAG_CTRL_MSG_NUM_PRESETS 12
+#define DIAG_CTRL_MSG_SET_PRESET_ID 13
+#define DIAG_CTRL_MSG_LOG_MASK_WITH_PRESET_ID 14
+#define DIAG_CTRL_MSG_EVENT_MASK_WITH_PRESET_ID 15
+#define DIAG_CTRL_MSG_F3_MASK_WITH_PRESET_ID 16
+#define DIAG_CTRL_MSG_LAST DIAG_CTRL_MSG_F3_MASK_WITH_PRESET_ID
+
+/* Denotes that we support sending/receiving the feature mask */
+#define F_DIAG_INT_FEATURE_MASK 0x01
struct cmd_code_range {
uint16_t cmd_code_lo;
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index 5e00570..7ec83dd 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -105,6 +105,16 @@
If unsure, say 'N' here to avoid potential power and performance
penalty.
+config CORESIGHT_HWEVENT
+ bool "CoreSight Hardware Event driver"
+ depends on CORESIGHT_STM
+ select CORESIGHT_CSR
+ help
+ This driver provides support for monitoring and tracing CoreSight
+ Hardware Event across STM interface. It configures Coresight
+ Hardware Event mux control registers to select hardware events
+ based on user input.
+
config CORESIGHT_ETM
bool "CoreSight Embedded Trace Macrocell driver"
help
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 0595064..0e2e2d9 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -11,5 +11,6 @@
obj-$(CONFIG_CORESIGHT_FUNNEL) += coresight-funnel.o
obj-$(CONFIG_CORESIGHT_REPLICATOR) += coresight-replicator.o
obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o
+obj-$(CONFIG_CORESIGHT_HWEVENT) += coresight-hwevent.o
obj-$(CONFIG_CORESIGHT_ETM) += coresight-etm.o coresight-etm-cp14.o
obj-$(CONFIG_CORESIGHT_EVENT) += coresight-event.o
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
index 1c2ab25..8195184 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.c
@@ -73,6 +73,7 @@
struct csr_drvdata {
void __iomem *base;
+ phys_addr_t pbase;
struct device *dev;
struct coresight_device *csdev;
uint32_t blksize;
@@ -134,6 +135,30 @@
}
EXPORT_SYMBOL(msm_qdss_csr_disable_flush);
+int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val)
+{
+ struct csr_drvdata *drvdata = csrdrvdata;
+ int ret = 0;
+
+ CSR_UNLOCK(drvdata);
+
+ if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL0))
+ csr_writel(drvdata, val, CSR_STMEXTHWCTRL0);
+ else if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL1))
+ csr_writel(drvdata, val, CSR_STMEXTHWCTRL1);
+ else if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL2))
+ csr_writel(drvdata, val, CSR_STMEXTHWCTRL2);
+ else if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL3))
+ csr_writel(drvdata, val, CSR_STMEXTHWCTRL3);
+ else
+ ret = -EINVAL;
+
+ CSR_LOCK(drvdata);
+
+ return ret;
+}
+EXPORT_SYMBOL(coresight_csr_hwctrl_set);
+
static int __devinit csr_probe(struct platform_device *pdev)
{
int ret;
@@ -161,6 +186,7 @@
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr-base");
if (!res)
return -ENODEV;
+ drvdata->pbase = res->start;
drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
if (!drvdata->base)
diff --git a/drivers/coresight/coresight-hwevent.c b/drivers/coresight/coresight-hwevent.c
new file mode 100644
index 0000000..777484d
--- /dev/null
+++ b/drivers/coresight/coresight-hwevent.c
@@ -0,0 +1,341 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+#include <linux/of.h>
+
+#include "coresight-priv.h"
+
+struct hwevent_mux {
+ phys_addr_t start;
+ phys_addr_t end;
+};
+
+struct hwevent_drvdata {
+ struct device *dev;
+ struct coresight_device *csdev;
+ struct clk *clk;
+ struct mutex mutex;
+ int nr_hclk;
+ struct clk **hclk;
+ int nr_hmux;
+ struct hwevent_mux *hmux;
+ bool enable;
+};
+
+static int hwevent_enable(struct hwevent_drvdata *drvdata)
+{
+ int ret, i;
+
+ mutex_lock(&drvdata->mutex);
+
+ if (drvdata->enable)
+ goto out;
+
+ ret = clk_prepare_enable(drvdata->clk);
+ if (ret)
+ goto err0;
+ for (i = 0; i < drvdata->nr_hclk; i++) {
+ ret = clk_prepare_enable(drvdata->hclk[i]);
+ if (ret)
+ goto err1;
+ }
+ drvdata->enable = true;
+ dev_info(drvdata->dev, "Hardware Event driver enabled\n");
+out:
+ mutex_unlock(&drvdata->mutex);
+ return 0;
+err1:
+ clk_disable_unprepare(drvdata->clk);
+ for (i--; i >= 0; i--)
+ clk_disable_unprepare(drvdata->hclk[i]);
+err0:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+
+static void hwevent_disable(struct hwevent_drvdata *drvdata)
+{
+ int i;
+
+ mutex_lock(&drvdata->mutex);
+
+ if (!drvdata->enable)
+ goto out;
+
+ drvdata->enable = false;
+ clk_disable_unprepare(drvdata->clk);
+ for (i = 0; i < drvdata->nr_hclk; i++)
+ clk_disable_unprepare(drvdata->hclk[i]);
+ dev_info(drvdata->dev, "Hardware Event driver disabled\n");
+out:
+ mutex_unlock(&drvdata->mutex);
+}
+
+static ssize_t hwevent_show_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hwevent_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val = drvdata->enable;
+
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t hwevent_store_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct hwevent_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+ int ret = 0;
+
+ if (sscanf(buf, "%lx", &val) != 1)
+ return -EINVAL;
+
+ if (val)
+ ret = hwevent_enable(drvdata);
+ else
+ hwevent_disable(drvdata);
+
+ if (ret)
+ return ret;
+ return size;
+}
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, hwevent_show_enable,
+ hwevent_store_enable);
+
+static ssize_t hwevent_store_setreg(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct hwevent_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ void *hwereg;
+ phys_addr_t addr;
+ uint32_t val;
+ int ret, i;
+
+ if (sscanf(buf, "%x %x", &addr, &val) != 2)
+ return -EINVAL;
+
+ mutex_lock(&drvdata->mutex);
+
+ if (!drvdata->enable) {
+ dev_err(dev, "Hardware Event driver not enabled\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ for (i = 0; i < drvdata->nr_hmux; i++) {
+ if ((addr >= drvdata->hmux[i].start) &&
+ (addr < drvdata->hmux[i].end)) {
+ hwereg = devm_ioremap(dev,
+ drvdata->hmux[i].start,
+ drvdata->hmux[i].end -
+ drvdata->hmux[i].start);
+ if (!hwereg) {
+ dev_err(dev, "unable to map address 0x%x\n",
+ addr);
+ ret = -ENOMEM;
+ goto err;
+ }
+ writel_relaxed(val, hwereg + addr -
+ drvdata->hmux[i].start);
+ /* Ensure writes to hwevent control registers
+ are completed before unmapping the address
+ */
+ mb();
+ devm_iounmap(dev, hwereg);
+ break;
+ }
+ }
+
+ if (i == drvdata->nr_hmux) {
+ ret = coresight_csr_hwctrl_set(addr, val);
+ if (ret) {
+ dev_err(dev, "invalid mux control register address\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ mutex_unlock(&drvdata->mutex);
+ return size;
+err:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+static DEVICE_ATTR(setreg, S_IWUSR, NULL, hwevent_store_setreg);
+
+static struct attribute *hwevent_attrs[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_setreg.attr,
+ NULL,
+};
+
+static struct attribute_group hwevent_attr_grp = {
+ .attrs = hwevent_attrs,
+};
+
+static const struct attribute_group *hwevent_attr_grps[] = {
+ &hwevent_attr_grp,
+ NULL,
+};
+
+static int __devinit hwevent_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct hwevent_drvdata *drvdata;
+ struct coresight_desc *desc;
+ struct coresight_platform_data *pdata;
+ struct resource *res;
+ int ret, i;
+ const char *hmux_name, *hclk_name;
+
+ if (pdev->dev.of_node) {
+ pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ pdev->dev.platform_data = pdata;
+ }
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+ drvdata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ if (pdev->dev.of_node)
+ drvdata->nr_hmux = of_property_count_strings(pdev->dev.of_node,
+ "reg-names");
+
+ if (drvdata->nr_hmux > 0) {
+ drvdata->hmux = devm_kzalloc(dev, drvdata->nr_hmux *
+ sizeof(*drvdata->hmux),
+ GFP_KERNEL);
+ if (!drvdata->hmux)
+ return -ENOMEM;
+ for (i = 0; i < drvdata->nr_hmux; i++) {
+ ret = of_property_read_string_index(pdev->dev.of_node,
+ "reg-names", i,
+ &hmux_name);
+ if (ret)
+ return ret;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ hmux_name);
+ if (!res)
+ return -ENODEV;
+ drvdata->hmux[i].start = res->start;
+ drvdata->hmux[i].end = res->end;
+ }
+ } else if (drvdata->nr_hmux < 0) {
+ return drvdata->nr_hmux;
+ } else {
+ /* return error if reg-names in dt node is empty string */
+ return -ENODEV;
+ }
+
+ mutex_init(&drvdata->mutex);
+
+ drvdata->clk = devm_clk_get(dev, "core_clk");
+ if (IS_ERR(drvdata->clk))
+ return PTR_ERR(drvdata->clk);
+
+ ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+ if (ret)
+ return ret;
+
+ if (pdev->dev.of_node)
+ drvdata->nr_hclk = of_property_count_strings(pdev->dev.of_node,
+ "qcom,hwevent-clks");
+ if (drvdata->nr_hclk > 0) {
+ drvdata->hclk = devm_kzalloc(dev, drvdata->nr_hclk *
+ sizeof(*drvdata->hclk),
+ GFP_KERNEL);
+ if (!drvdata->hclk)
+ return -ENOMEM;
+ for (i = 0; i < drvdata->nr_hclk; i++) {
+ ret = of_property_read_string_index(pdev->dev.of_node,
+ "qcom,hwevent-clks",
+ i, &hclk_name);
+ if (ret)
+ return ret;
+ drvdata->hclk[i] = devm_clk_get(dev, hclk_name);
+ if (IS_ERR(drvdata->hclk[i]))
+ return PTR_ERR(drvdata->hclk[i]);
+ }
+ }
+
+ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->type = CORESIGHT_DEV_TYPE_NONE;
+ desc->pdata = pdev->dev.platform_data;
+ desc->dev = &pdev->dev;
+ desc->groups = hwevent_attr_grps;
+ desc->owner = THIS_MODULE;
+ drvdata->csdev = coresight_register(desc);
+ if (IS_ERR(drvdata->csdev))
+ return PTR_ERR(drvdata->csdev);
+
+ dev_info(dev, "Hardware Event driver initialized\n");
+ return 0;
+}
+
+static int __devexit hwevent_remove(struct platform_device *pdev)
+{
+ struct hwevent_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ coresight_unregister(drvdata->csdev);
+ return 0;
+}
+
+static struct of_device_id hwevent_match[] = {
+ {.compatible = "qcom,coresight-hwevent"},
+ {}
+};
+
+static struct platform_driver hwevent_driver = {
+ .probe = hwevent_probe,
+ .remove = __devexit_p(hwevent_remove),
+ .driver = {
+ .name = "coresight-hwevent",
+ .owner = THIS_MODULE,
+ .of_match_table = hwevent_match,
+ },
+};
+
+static int __init hwevent_init(void)
+{
+ return platform_driver_register(&hwevent_driver);
+}
+module_init(hwevent_init);
+
+static void __exit hwevent_exit(void)
+{
+ platform_driver_unregister(&hwevent_driver);
+}
+module_exit(hwevent_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Hardware Event driver");
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index 258ff09..f208185 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -40,10 +40,13 @@
extern void msm_qdss_csr_enable_bam_to_usb(void);
extern void msm_qdss_csr_disable_bam_to_usb(void);
extern void msm_qdss_csr_disable_flush(void);
+extern int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val);
#else
static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
static inline void msm_qdss_csr_disable_flush(void) {}
+static inline int coresight_csr_hwctrl_set(phys_addr_t addr,
+ uint32_t val) { return -ENOSYS; }
#endif
#ifdef CONFIG_CORESIGHT_ETM
extern unsigned int etm_readl_cp14(uint32_t off);
diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c
index 7ea71d3..8597e29 100644
--- a/drivers/coresight/coresight-tpiu.c
+++ b/drivers/coresight/coresight-tpiu.c
@@ -218,6 +218,24 @@
return 0;
}
+static int tpiu_reg_set_optimum_mode(struct regulator *reg,
+ unsigned int reg_hpm)
+{
+ if (regulator_count_voltages(reg) <= 0)
+ return 0;
+
+ return regulator_set_optimum_mode(reg, reg_hpm);
+}
+
+static int tpiu_reg_set_voltage(struct regulator *reg, unsigned int reg_low,
+ unsigned int reg_high)
+{
+ if (regulator_count_voltages(reg) <= 0)
+ return 0;
+
+ return regulator_set_voltage(reg, reg_low, reg_high);
+}
+
static int __tpiu_enable_to_sdc(struct tpiu_drvdata *drvdata)
{
int ret;
@@ -225,11 +243,11 @@
if (!drvdata->reg)
return -EINVAL;
- ret = regulator_set_optimum_mode(drvdata->reg, drvdata->reg_hpm);
+ ret = tpiu_reg_set_optimum_mode(drvdata->reg, drvdata->reg_hpm);
if (ret < 0)
return ret;
- ret = regulator_set_voltage(drvdata->reg, drvdata->reg_low,
- drvdata->reg_high);
+ ret = tpiu_reg_set_voltage(drvdata->reg, drvdata->reg_low,
+ drvdata->reg_high);
if (ret)
goto err0;
ret = regulator_enable(drvdata->reg);
@@ -248,9 +266,9 @@
return 0;
err1:
- regulator_set_voltage(drvdata->reg, 0, drvdata->reg_high);
+ tpiu_reg_set_voltage(drvdata->reg, 0, drvdata->reg_high);
err0:
- regulator_set_optimum_mode(drvdata->reg, 0);
+ tpiu_reg_set_optimum_mode(drvdata->reg, 0);
return ret;
}
@@ -325,8 +343,8 @@
msm_tlmm_misc_reg_write(TLMM_ETM_MODE_REG, 0);
regulator_disable(drvdata->reg);
- regulator_set_optimum_mode(drvdata->reg, 0);
- regulator_set_voltage(drvdata->reg, 0, drvdata->reg_high);
+ tpiu_reg_set_optimum_mode(drvdata->reg, 0);
+ tpiu_reg_set_voltage(drvdata->reg, 0, drvdata->reg_high);
}
static void tpiu_disable(struct coresight_device *csdev)
@@ -531,7 +549,7 @@
prop = of_get_property(node, "qcom,vdd-voltage-level", &len);
if (!prop || (len != (2 * sizeof(__be32)))) {
of_node_put(reg_node);
- return -EINVAL;
+ dev_err(dev, "sdc voltage levels not specified\n");
} else {
drvdata->reg_low = be32_to_cpup(&prop[0]);
drvdata->reg_high = be32_to_cpup(&prop[1]);
@@ -540,7 +558,7 @@
prop = of_get_property(node, "qcom,vdd-current-level", &len);
if (!prop || (len != (2 * sizeof(__be32)))) {
of_node_put(reg_node);
- return -EINVAL;
+ dev_err(dev, "sdc current levels not specified\n");
} else {
drvdata->reg_lpm = be32_to_cpup(&prop[0]);
drvdata->reg_hpm = be32_to_cpup(&prop[1]);
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 245272b..58fa5c9 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -62,6 +62,7 @@
dma_addr_t coh_pmem; /* Allocated coherent physical memory */
int memsize; /* Memory allocated */
int is_shared; /* CE HW is shared */
+ bool support_cmd_dscr;
void __iomem *iobase; /* Virtual io base of CE HW */
unsigned int phy_iobase; /* Physical io base of CE HW */
@@ -84,6 +85,7 @@
int dir;
void *areq;
enum qce_cipher_mode_enum mode;
+ struct qce_ce_cfg_reg_setting reg;
struct ce_sps_data ce_sps;
};
@@ -494,25 +496,17 @@
for (i = 0; i < noncelen32; i++, pce++)
pce->data = nonce32[i];
- /* TBD NEW FEATURE partial AES CCM pkt support set last bit */
- auth_cfg |= ((1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST));
+ if (creq->authklen == AES128_KEY_SIZE)
+ auth_cfg = pce_dev->reg.auth_cfg_aes_ccm_128;
+ else {
+ if (creq->authklen == AES256_KEY_SIZE)
+ auth_cfg = pce_dev->reg.auth_cfg_aes_ccm_256;
+ }
if (creq->dir == QCE_ENCRYPT)
auth_cfg |= (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
else
auth_cfg |= (CRYPTO_AUTH_POS_AFTER << CRYPTO_AUTH_POS);
auth_cfg |= ((creq->authsize - 1) << CRYPTO_AUTH_SIZE);
- auth_cfg |= (CRYPTO_AUTH_MODE_CCM << CRYPTO_AUTH_MODE);
- if (creq->authklen == AES128_KEY_SIZE)
- auth_cfg |= (CRYPTO_AUTH_KEY_SZ_AES128 <<
- CRYPTO_AUTH_KEY_SIZE);
- else {
- if (creq->authklen == AES256_KEY_SIZE)
- auth_cfg |= (CRYPTO_AUTH_KEY_SZ_AES256 <<
- CRYPTO_AUTH_KEY_SIZE);
- }
- auth_cfg |= (CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG);
- auth_cfg |= ((MAX_NONCE/sizeof(uint32_t)) <<
- CRYPTO_AUTH_NONCE_NUM_WORDS);
if (use_hw_key == true) {
auth_cfg |= (1 << CRYPTO_USE_HW_KEY_AUTH);
@@ -542,21 +536,37 @@
}
switch (creq->mode) {
case QCE_MODE_ECB:
- encr_cfg |= (CRYPTO_ENCR_MODE_ECB << CRYPTO_ENCR_MODE);
+ if (key_size == AES128_KEY_SIZE)
+ encr_cfg = pce_dev->reg.encr_cfg_aes_ecb_128;
+ else
+ encr_cfg = pce_dev->reg.encr_cfg_aes_ecb_256;
break;
case QCE_MODE_CBC:
- encr_cfg |= (CRYPTO_ENCR_MODE_CBC << CRYPTO_ENCR_MODE);
+ if (key_size == AES128_KEY_SIZE)
+ encr_cfg = pce_dev->reg.encr_cfg_aes_cbc_128;
+ else
+ encr_cfg = pce_dev->reg.encr_cfg_aes_cbc_256;
break;
case QCE_MODE_XTS:
- encr_cfg |= (CRYPTO_ENCR_MODE_XTS << CRYPTO_ENCR_MODE);
+ if (key_size == AES128_KEY_SIZE)
+ encr_cfg = pce_dev->reg.encr_cfg_aes_xts_128;
+ else
+ encr_cfg = pce_dev->reg.encr_cfg_aes_xts_256;
break;
case QCE_MODE_CCM:
+ if (key_size == AES128_KEY_SIZE)
+ encr_cfg = pce_dev->reg.encr_cfg_aes_ccm_128;
+ else
+ encr_cfg = pce_dev->reg.encr_cfg_aes_ccm_256;
encr_cfg |= (CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE) |
(CRYPTO_LAST_CCM_XFR << CRYPTO_LAST_CCM);
break;
case QCE_MODE_CTR:
default:
- encr_cfg |= (CRYPTO_ENCR_MODE_CTR << CRYPTO_ENCR_MODE);
+ if (key_size == AES128_KEY_SIZE)
+ encr_cfg = pce_dev->reg.encr_cfg_aes_ctr_128;
+ else
+ encr_cfg = pce_dev->reg.encr_cfg_aes_ctr_256;
break;
}
pce_dev->mode = creq->mode;
@@ -600,13 +610,15 @@
uint32_t xtsklen =
creq->encklen/(2 * sizeof(uint32_t));
- _byte_stream_to_net_words(xtskey32, (creq->enckey +
- creq->encklen/2), creq->encklen/2);
- /* write xts encr key */
- pce = cmdlistinfo->encr_xts_key;
- for (i = 0; i < xtsklen; i++, pce++)
- pce->data = xtskey32[i];
-
+ if ((use_hw_key == false) && (use_pipe_key == false)) {
+ _byte_stream_to_net_words(xtskey32,
+ (creq->enckey + creq->encklen/2),
+ creq->encklen/2);
+ /* write xts encr key */
+ pce = cmdlistinfo->encr_xts_key;
+ for (i = 0; i < xtsklen; i++, pce++)
+ pce->data = xtskey32[i];
+ }
/* write xts du size */
pce = cmdlistinfo->encr_xts_du_size;
if (use_pipe_key == true)
@@ -642,26 +654,13 @@
if (creq->op == QCE_REQ_ABLK_CIPHER_NO_KEY) {
encr_cfg |= (CRYPTO_ENCR_KEY_SZ_AES128 <<
CRYPTO_ENCR_KEY_SZ);
- encr_cfg |= CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG;
} else {
if (use_hw_key == false) {
/* write encr key */
pce = cmdlistinfo->encr_key;
for (i = 0; i < enck_size_in_word; i++, pce++)
pce->data = enckey32[i];
- switch (key_size) {
- case AES128_KEY_SIZE:
- encr_cfg |= (CRYPTO_ENCR_KEY_SZ_AES128
- << CRYPTO_ENCR_KEY_SZ);
- break;
- case AES256_KEY_SIZE:
- default:
- encr_cfg |= (CRYPTO_ENCR_KEY_SZ_AES256
- << CRYPTO_ENCR_KEY_SZ);
- break;
- } /* end of switch (creq->encklen) */
}
- encr_cfg |= CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG;
} /* else of if (creq->op == QCE_REQ_ABLK_CIPHER_NO_KEY) */
break;
} /* end of switch (creq->mode) */
@@ -706,10 +705,499 @@
return 0;
};
+static int _ce_setup_hash_direct(struct qce_device *pce_dev,
+ struct qce_sha_req *sreq)
+{
+ uint32_t auth32[SHA256_DIGEST_SIZE / sizeof(uint32_t)];
+ uint32_t diglen;
+ bool use_hw_key = false;
+ int i;
+ uint32_t mackey32[SHA_HMAC_KEY_SIZE/sizeof(uint32_t)] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ bool sha1 = false;
+ uint32_t auth_cfg = 0;
+
+ writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
+ CRYPTO_CONFIG_REG));
+ /*
+ * Ensure previous instructions (setting the CONFIG register)
+ * was completed before issuing starting to set other config register
+ * This is to ensure the configurations are done in correct endian-ness
+ * as set in the CONFIG registers
+ */
+ mb();
+
+ if (sreq->alg == QCE_HASH_AES_CMAC) {
+ /* write seg_cfg */
+ writel_relaxed(0, pce_dev->iobase + CRYPTO_AUTH_SEG_CFG_REG);
+ /* write seg_cfg */
+ writel_relaxed(0, pce_dev->iobase + CRYPTO_ENCR_SEG_CFG_REG);
+ /* write seg_cfg */
+ writel_relaxed(0, pce_dev->iobase + CRYPTO_ENCR_SEG_SIZE_REG);
+
+ /* Clear auth_ivn, auth_keyn registers */
+ for (i = 0; i < 16; i++) {
+ writel_relaxed(0, (pce_dev->iobase +
+ (CRYPTO_AUTH_IV0_REG + i*sizeof(uint32_t))));
+ writel_relaxed(0, (pce_dev->iobase +
+ (CRYPTO_AUTH_KEY0_REG + i*sizeof(uint32_t))));
+ }
+ /* write auth_bytecnt 0/1/2/3, start with 0 */
+ for (i = 0; i < 4; i++)
+ writel_relaxed(0, pce_dev->iobase +
+ CRYPTO_AUTH_BYTECNT0_REG +
+ i * sizeof(uint32_t));
+
+ if (sreq->authklen == AES128_KEY_SIZE)
+ auth_cfg = pce_dev->reg.auth_cfg_cmac_128;
+ else
+ auth_cfg = pce_dev->reg.auth_cfg_cmac_256;
+ }
+
+ if ((sreq->alg == QCE_HASH_SHA1_HMAC) ||
+ (sreq->alg == QCE_HASH_SHA256_HMAC) ||
+ (sreq->alg == QCE_HASH_AES_CMAC)) {
+ uint32_t authk_size_in_word = sreq->authklen/sizeof(uint32_t);
+
+ _byte_stream_to_net_words(mackey32, sreq->authkey,
+ sreq->authklen);
+
+ /* check for null key. If null, use hw key*/
+ for (i = 0; i < authk_size_in_word; i++) {
+ if (mackey32[i] != 0)
+ break;
+ }
+
+ if (i == authk_size_in_word)
+ use_hw_key = true;
+ else
+ /* Clear auth_ivn, auth_keyn registers */
+ for (i = 0; i < authk_size_in_word; i++)
+ writel_relaxed(mackey32[i], (pce_dev->iobase +
+ (CRYPTO_AUTH_KEY0_REG +
+ i*sizeof(uint32_t))));
+ }
+
+ if (sreq->alg == QCE_HASH_AES_CMAC)
+ goto go_proc;
+
+ /* if not the last, the size has to be on the block boundary */
+ if (sreq->last_blk == 0 && (sreq->size % SHA256_BLOCK_SIZE))
+ return -EIO;
+
+ switch (sreq->alg) {
+ case QCE_HASH_SHA1:
+ auth_cfg = pce_dev->reg.auth_cfg_sha1;
+ diglen = SHA1_DIGEST_SIZE;
+ sha1 = true;
+ break;
+ case QCE_HASH_SHA1_HMAC:
+ auth_cfg = pce_dev->reg.auth_cfg_hmac_sha1;
+ diglen = SHA1_DIGEST_SIZE;
+ sha1 = true;
+ break;
+ case QCE_HASH_SHA256:
+ auth_cfg = pce_dev->reg.auth_cfg_sha256;
+ diglen = SHA256_DIGEST_SIZE;
+ break;
+ case QCE_HASH_SHA256_HMAC:
+ auth_cfg = pce_dev->reg.auth_cfg_hmac_sha256;
+ diglen = SHA256_DIGEST_SIZE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* write 20/32 bytes, 5/8 words into auth_iv for SHA1/SHA256 */
+ if (sreq->first_blk) {
+ if (sha1) {
+ for (i = 0; i < 5; i++)
+ auth32[i] = _std_init_vector_sha1[i];
+ } else {
+ for (i = 0; i < 8; i++)
+ auth32[i] = _std_init_vector_sha256[i];
+ }
+ } else {
+ _byte_stream_to_net_words(auth32, sreq->digest, diglen);
+ }
+
+ /* Set auth_ivn, auth_keyn registers */
+ for (i = 0; i < 5; i++)
+ writel_relaxed(auth32[i], (pce_dev->iobase +
+ (CRYPTO_AUTH_IV0_REG + i*sizeof(uint32_t))));
+
+ if ((sreq->alg == QCE_HASH_SHA256) ||
+ (sreq->alg == QCE_HASH_SHA256_HMAC)) {
+ for (i = 5; i < 8; i++)
+ writel_relaxed(auth32[i], (pce_dev->iobase +
+ (CRYPTO_AUTH_IV0_REG + i*sizeof(uint32_t))));
+ }
+
+
+ /* write auth_bytecnt 0/1/2/3, start with 0 */
+ for (i = 0; i < 2; i++)
+ writel_relaxed(sreq->auth_data[i], pce_dev->iobase +
+ CRYPTO_AUTH_BYTECNT0_REG +
+ i * sizeof(uint32_t));
+
+ /* Set/reset last bit in CFG register */
+ if (sreq->last_blk)
+ auth_cfg |= 1 << CRYPTO_LAST;
+ else
+ auth_cfg &= ~(1 << CRYPTO_LAST);
+ if (sreq->first_blk)
+ auth_cfg |= 1 << CRYPTO_FIRST;
+ else
+ auth_cfg &= ~(1 << CRYPTO_FIRST);
+go_proc:
+ /* write seg_cfg */
+ writel_relaxed(auth_cfg, pce_dev->iobase + CRYPTO_AUTH_SEG_CFG_REG);
+ /* write auth seg_size */
+ writel_relaxed(sreq->size, pce_dev->iobase + CRYPTO_AUTH_SEG_SIZE_REG);
+
+ /* write auth_seg_start */
+ writel_relaxed(0, pce_dev->iobase + CRYPTO_AUTH_SEG_START_REG);
+
+ /* reset encr seg_cfg */
+ writel_relaxed(0, pce_dev->iobase + CRYPTO_ENCR_SEG_CFG_REG);
+
+ /* write seg_size */
+ writel_relaxed(sreq->size, pce_dev->iobase + CRYPTO_SEG_SIZE_REG);
+
+ writel_relaxed(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase +
+ CRYPTO_CONFIG_REG));
+ /* issue go to crypto */
+ if (use_hw_key == false)
+ writel_relaxed(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ pce_dev->iobase + CRYPTO_GOPROC_REG);
+ else
+ writel_relaxed(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ pce_dev->iobase + CRYPTO_GOPROC_QC_KEY_REG);
+ /*
+ * Ensure previous instructions (setting the GO register)
+ * was completed before issuing a DMA transfer request
+ */
+ mb();
+ return 0;
+}
+
+static int _ce_setup_cipher_direct(struct qce_device *pce_dev,
+ struct qce_req *creq, uint32_t totallen_in, uint32_t coffset)
+{
+ uint32_t enckey32[(MAX_CIPHER_KEY_SIZE * 2)/sizeof(uint32_t)] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ uint32_t enciv32[MAX_IV_LENGTH / sizeof(uint32_t)] = {
+ 0, 0, 0, 0};
+ uint32_t enck_size_in_word = 0;
+ uint32_t key_size;
+ bool use_hw_key = false;
+ bool use_pipe_key = false;
+ uint32_t encr_cfg = 0;
+ uint32_t ivsize = creq->ivsize;
+ int i;
+
+ writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
+ CRYPTO_CONFIG_REG));
+ /*
+ * Ensure previous instructions (setting the CONFIG register)
+ * was completed before issuing starting to set other config register
+ * This is to ensure the configurations are done in correct endian-ness
+ * as set in the CONFIG registers
+ */
+ mb();
+
+ if (creq->mode == QCE_MODE_XTS)
+ key_size = creq->encklen/2;
+ else
+ key_size = creq->encklen;
+
+ _byte_stream_to_net_words(enckey32, creq->enckey, key_size);
+
+ /* check for null key. If null, use hw key*/
+ enck_size_in_word = key_size/sizeof(uint32_t);
+ for (i = 0; i < enck_size_in_word; i++) {
+ if (enckey32[i] != 0)
+ break;
+ }
+ if (i == enck_size_in_word)
+ use_hw_key = true;
+
+ if (use_hw_key == false) {
+ for (i = 0; i < enck_size_in_word; i++) {
+ if (enckey32[i] != 0xFFFFFFFF)
+ break;
+ }
+ if (i == enck_size_in_word)
+ use_pipe_key = true;
+ }
+
+ if ((creq->op == QCE_REQ_AEAD) && (creq->mode == QCE_MODE_CCM)) {
+ uint32_t authklen32 = creq->encklen/sizeof(uint32_t);
+ uint32_t noncelen32 = MAX_NONCE/sizeof(uint32_t);
+ uint32_t nonce32[MAX_NONCE/sizeof(uint32_t)] = {0, 0, 0, 0};
+ uint32_t auth_cfg = 0;
+
+ /* Clear auth_ivn, auth_keyn registers */
+ for (i = 0; i < 16; i++) {
+ writel_relaxed(0, (pce_dev->iobase +
+ (CRYPTO_AUTH_IV0_REG + i*sizeof(uint32_t))));
+ writel_relaxed(0, (pce_dev->iobase +
+ (CRYPTO_AUTH_KEY0_REG + i*sizeof(uint32_t))));
+ }
+ /* write auth_bytecnt 0/1/2/3, start with 0 */
+ for (i = 0; i < 4; i++)
+ writel_relaxed(0, pce_dev->iobase +
+ CRYPTO_AUTH_BYTECNT0_REG +
+ i * sizeof(uint32_t));
+ /* write nonce */
+ _byte_stream_to_net_words(nonce32, creq->nonce, MAX_NONCE);
+ for (i = 0; i < noncelen32; i++)
+ writel_relaxed(nonce32[i], pce_dev->iobase +
+ CRYPTO_AUTH_INFO_NONCE0_REG +
+ (i*sizeof(uint32_t)));
+
+ if (creq->authklen == AES128_KEY_SIZE)
+ auth_cfg = pce_dev->reg.auth_cfg_aes_ccm_128;
+ else {
+ if (creq->authklen == AES256_KEY_SIZE)
+ auth_cfg = pce_dev->reg.auth_cfg_aes_ccm_256;
+ }
+ if (creq->dir == QCE_ENCRYPT)
+ auth_cfg |= (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+ else
+ auth_cfg |= (CRYPTO_AUTH_POS_AFTER << CRYPTO_AUTH_POS);
+ auth_cfg |= ((creq->authsize - 1) << CRYPTO_AUTH_SIZE);
+
+ if (use_hw_key == true) {
+ auth_cfg |= (1 << CRYPTO_USE_HW_KEY_AUTH);
+ } else {
+ auth_cfg &= ~(1 << CRYPTO_USE_HW_KEY_AUTH);
+ /* write auth key */
+ for (i = 0; i < authklen32; i++)
+ writel_relaxed(enckey32[i], pce_dev->iobase +
+ CRYPTO_AUTH_KEY0_REG + (i*sizeof(uint32_t)));
+ }
+ writel_relaxed(auth_cfg, pce_dev->iobase +
+ CRYPTO_AUTH_SEG_CFG_REG);
+ if (creq->dir == QCE_ENCRYPT)
+ writel_relaxed(totallen_in, pce_dev->iobase +
+ CRYPTO_AUTH_SEG_SIZE_REG);
+ else
+ writel_relaxed((totallen_in - creq->authsize),
+ pce_dev->iobase + CRYPTO_AUTH_SEG_SIZE_REG);
+ writel_relaxed(0, pce_dev->iobase + CRYPTO_AUTH_SEG_START_REG);
+ } else {
+ if (creq->op != QCE_REQ_AEAD)
+ writel_relaxed(0, pce_dev->iobase +
+ CRYPTO_AUTH_SEG_CFG_REG);
+ }
+ /*
+ * Ensure previous instructions (write to all AUTH registers)
+ * was completed before accessing a register that is not in
+ * in the same 1K range.
+ */
+ mb();
+ switch (creq->mode) {
+ case QCE_MODE_ECB:
+ if (key_size == AES128_KEY_SIZE)
+ encr_cfg = pce_dev->reg.encr_cfg_aes_ecb_128;
+ else
+ encr_cfg = pce_dev->reg.encr_cfg_aes_ecb_256;
+ break;
+ case QCE_MODE_CBC:
+ if (key_size == AES128_KEY_SIZE)
+ encr_cfg = pce_dev->reg.encr_cfg_aes_cbc_128;
+ else
+ encr_cfg = pce_dev->reg.encr_cfg_aes_cbc_256;
+ break;
+ case QCE_MODE_XTS:
+ if (key_size == AES128_KEY_SIZE)
+ encr_cfg = pce_dev->reg.encr_cfg_aes_xts_128;
+ else
+ encr_cfg = pce_dev->reg.encr_cfg_aes_xts_256;
+ break;
+ case QCE_MODE_CCM:
+ if (key_size == AES128_KEY_SIZE)
+ encr_cfg = pce_dev->reg.encr_cfg_aes_ccm_128;
+ else
+ encr_cfg = pce_dev->reg.encr_cfg_aes_ccm_256;
+ break;
+ case QCE_MODE_CTR:
+ default:
+ if (key_size == AES128_KEY_SIZE)
+ encr_cfg = pce_dev->reg.encr_cfg_aes_ctr_128;
+ else
+ encr_cfg = pce_dev->reg.encr_cfg_aes_ctr_256;
+ break;
+ }
+ pce_dev->mode = creq->mode;
+
+ switch (creq->alg) {
+ case CIPHER_ALG_DES:
+ if (creq->mode != QCE_MODE_ECB) {
+ encr_cfg = pce_dev->reg.encr_cfg_des_cbc;
+ _byte_stream_to_net_words(enciv32, creq->iv, ivsize);
+ writel_relaxed(enciv32[0], pce_dev->iobase +
+ CRYPTO_CNTR0_IV0_REG);
+ writel_relaxed(enciv32[1], pce_dev->iobase +
+ CRYPTO_CNTR1_IV1_REG);
+ } else {
+ encr_cfg = pce_dev->reg.encr_cfg_des_ecb;
+ }
+ if (use_hw_key == false) {
+ writel_relaxed(enckey32[0], pce_dev->iobase +
+ CRYPTO_ENCR_KEY0_REG);
+ writel_relaxed(enckey32[1], pce_dev->iobase +
+ CRYPTO_ENCR_KEY1_REG);
+ }
+ break;
+ case CIPHER_ALG_3DES:
+ if (creq->mode != QCE_MODE_ECB) {
+ _byte_stream_to_net_words(enciv32, creq->iv, ivsize);
+ writel_relaxed(enciv32[0], pce_dev->iobase +
+ CRYPTO_CNTR0_IV0_REG);
+ writel_relaxed(enciv32[1], pce_dev->iobase +
+ CRYPTO_CNTR1_IV1_REG);
+ encr_cfg = pce_dev->reg.encr_cfg_3des_cbc;
+ } else {
+ encr_cfg = pce_dev->reg.encr_cfg_3des_ecb;
+ }
+ if (use_hw_key == false) {
+ /* write encr key */
+ for (i = 0; i < 6; i++)
+ writel_relaxed(enckey32[0], (pce_dev->iobase +
+ (CRYPTO_ENCR_KEY0_REG + i * sizeof(uint32_t))));
+ }
+ break;
+ case CIPHER_ALG_AES:
+ default:
+ if (creq->mode == QCE_MODE_XTS) {
+ uint32_t xtskey32[MAX_CIPHER_KEY_SIZE/sizeof(uint32_t)]
+ = {0, 0, 0, 0, 0, 0, 0, 0};
+ uint32_t xtsklen =
+ creq->encklen/(2 * sizeof(uint32_t));
+
+ if ((use_hw_key == false) && (use_pipe_key == false)) {
+ _byte_stream_to_net_words(xtskey32,
+ (creq->enckey + creq->encklen/2),
+ creq->encklen/2);
+ /* write xts encr key */
+ for (i = 0; i < xtsklen; i++)
+ writel_relaxed(xtskey32[i],
+ pce_dev->iobase +
+ CRYPTO_ENCR_XTS_KEY0_REG +
+ (i * sizeof(uint32_t)));
+ }
+ /* write xts du size */
+ if (use_pipe_key == true)
+ writel_relaxed(min((uint32_t)QCE_SECTOR_SIZE,
+ creq->cryptlen),
+ pce_dev->iobase +
+ CRYPTO_ENCR_XTS_DU_SIZE_REG);
+ else
+ writel_relaxed(creq->cryptlen ,
+ pce_dev->iobase +
+ CRYPTO_ENCR_XTS_DU_SIZE_REG);
+ }
+ if (creq->mode != QCE_MODE_ECB) {
+ if (creq->mode == QCE_MODE_XTS)
+ _byte_stream_swap_to_net_words(enciv32,
+ creq->iv, ivsize);
+ else
+ _byte_stream_to_net_words(enciv32, creq->iv,
+ ivsize);
+
+ /* write encr cntr iv */
+ for (i = 0; i <= 3; i++)
+ writel_relaxed(enciv32[i], pce_dev->iobase +
+ CRYPTO_CNTR0_IV0_REG +
+ (i * sizeof(uint32_t)));
+
+ if (creq->mode == QCE_MODE_CCM) {
+ /* write cntr iv for ccm */
+ for (i = 0; i <= 3; i++)
+ writel_relaxed(enciv32[i],
+ pce_dev->iobase +
+ CRYPTO_ENCR_CCM_INT_CNTR0_REG +
+ (i * sizeof(uint32_t)));
+ /* update cntr_iv[3] by one */
+ writel_relaxed((enciv32[3] + 1),
+ pce_dev->iobase +
+ CRYPTO_CNTR0_IV0_REG +
+ (3 * sizeof(uint32_t)));
+ }
+ }
+
+ if (creq->op == QCE_REQ_ABLK_CIPHER_NO_KEY) {
+ encr_cfg |= (CRYPTO_ENCR_KEY_SZ_AES128 <<
+ CRYPTO_ENCR_KEY_SZ);
+ } else {
+ if ((use_hw_key == false) && (use_pipe_key == false)) {
+ for (i = 0; i < enck_size_in_word; i++)
+ writel_relaxed(enckey32[i],
+ pce_dev->iobase +
+ CRYPTO_ENCR_KEY0_REG +
+ (i * sizeof(uint32_t)));
+ }
+ } /* else of if (creq->op == QCE_REQ_ABLK_CIPHER_NO_KEY) */
+ break;
+ } /* end of switch (creq->mode) */
+
+ if (use_pipe_key)
+ encr_cfg |= (CRYPTO_USE_PIPE_KEY_ENCR_ENABLED
+ << CRYPTO_USE_PIPE_KEY_ENCR);
+
+ /* write encr seg cfg */
+ encr_cfg |= ((creq->dir == QCE_ENCRYPT) ? 1 : 0) << CRYPTO_ENCODE;
+ if (use_hw_key == true)
+ encr_cfg |= (CRYPTO_USE_HW_KEY << CRYPTO_USE_HW_KEY_ENCR);
+ else
+ encr_cfg &= ~(CRYPTO_USE_HW_KEY << CRYPTO_USE_HW_KEY_ENCR);
+ /* write encr seg cfg */
+ writel_relaxed(encr_cfg, pce_dev->iobase + CRYPTO_ENCR_SEG_CFG_REG);
+
+ /* write encr seg size */
+ if ((creq->mode == QCE_MODE_CCM) && (creq->dir == QCE_DECRYPT))
+ writel_relaxed((creq->cryptlen + creq->authsize),
+ pce_dev->iobase + CRYPTO_ENCR_SEG_SIZE_REG);
+ else
+ writel_relaxed(creq->cryptlen,
+ pce_dev->iobase + CRYPTO_ENCR_SEG_SIZE_REG);
+
+ /* write encr seg start */
+ writel_relaxed((coffset & 0xffff),
+ pce_dev->iobase + CRYPTO_ENCR_SEG_START_REG);
+ /* write encr seg start */
+ writel_relaxed(0xffffffff,
+ pce_dev->iobase + CRYPTO_CNTR_MASK_REG);
+
+ /* write seg size */
+ writel_relaxed(totallen_in, pce_dev->iobase + CRYPTO_SEG_SIZE_REG);
+
+ writel_relaxed(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase +
+ CRYPTO_CONFIG_REG));
+ /* issue go to crypto */
+ if (use_hw_key == false)
+ writel_relaxed(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ pce_dev->iobase + CRYPTO_GOPROC_REG);
+ else
+ writel_relaxed(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ pce_dev->iobase + CRYPTO_GOPROC_QC_KEY_REG);
+ /*
+ * Ensure previous instructions (setting the GO register)
+ * was completed before issuing a DMA transfer request
+ */
+ mb();
+ return 0;
+};
+
static int _qce_unlock_other_pipes(struct qce_device *pce_dev)
{
int rc = 0;
+ if (pce_dev->support_cmd_dscr == false)
+ return rc;
+
pce_dev->ce_sps.consumer.event.callback = NULL;
rc = sps_transfer_one(pce_dev->ce_sps.consumer.pipe,
GET_PHYS_ADDR(pce_dev->ce_sps.cmdlistptr.unlock_all_pipes.cmdlist),
@@ -1216,7 +1704,14 @@
bam.summing_threshold = 64;
/* SPS driver wll handle the crypto BAM IRQ */
bam.irq = (u32)pce_dev->ce_sps.bam_irq;
- bam.manage = SPS_BAM_MGR_LOCAL;
+ /*
+ * Set flag to indicate BAM global device control is managed
+ * remotely.
+ */
+ if (pce_dev->support_cmd_dscr == false)
+ bam.manage = SPS_BAM_MGR_DEVICE_REMOTE;
+ else
+ bam.manage = SPS_BAM_MGR_LOCAL;
bam.ee = 1;
pr_debug("bam physical base=0x%x\n", (u32)bam.phys_addr);
@@ -1411,20 +1906,11 @@
uint32_t key_reg = 0;
uint32_t xts_key_reg = 0;
uint32_t iv_reg = 0;
- uint32_t crypto_cfg = 0;
- uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
- uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
pdev->ce_sps.ce_burst_size);
ce_vaddr = (struct sps_command_element *)(*pvaddr);
ce_vaddr_start = (uint32_t)(*pvaddr);
- crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
- BIT(CRYPTO_MASK_DOUT_INTR) |
- BIT(CRYPTO_MASK_DIN_INTR) |
- BIT(CRYPTO_MASK_OP_DONE_INTR) |
- (0 << CRYPTO_HIGH_SPD_EN_N) |
- (pipe_pair << CRYPTO_PIPE_SET_SELECT);
/*
* Designate chunks of the allocated memory to various
* command list pointers related to AES cipher operations defined
@@ -1437,11 +1923,10 @@
cmdlistptr->cipher_aes_128_cbc_ctr.cmdlist =
(uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->cipher_aes_128_cbc_ctr);
-
- encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES128 <<
- CRYPTO_ENCR_KEY_SZ) |
- (CRYPTO_ENCR_ALG_AES <<
- CRYPTO_ENCR_ALG);
+ if (mode == QCE_MODE_CBC)
+ encr_cfg = pdev->reg.encr_cfg_aes_cbc_128;
+ else
+ encr_cfg = pdev->reg.encr_cfg_aes_ctr_128;
iv_reg = 4;
key_reg = 4;
xts_key_reg = 0;
@@ -1450,10 +1935,10 @@
(uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->cipher_aes_256_cbc_ctr);
- encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES256 <<
- CRYPTO_ENCR_KEY_SZ) |
- (CRYPTO_ENCR_ALG_AES <<
- CRYPTO_ENCR_ALG);
+ if (mode == QCE_MODE_CBC)
+ encr_cfg = pdev->reg.encr_cfg_aes_cbc_256;
+ else
+ encr_cfg = pdev->reg.encr_cfg_aes_ctr_256;
iv_reg = 4;
key_reg = 8;
xts_key_reg = 0;
@@ -1465,12 +1950,7 @@
(uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->cipher_aes_128_ecb);
- encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES128 <<
- CRYPTO_ENCR_KEY_SZ) |
- (CRYPTO_ENCR_ALG_AES <<
- CRYPTO_ENCR_ALG) |
- (CRYPTO_ENCR_MODE_ECB <<
- CRYPTO_ENCR_MODE);
+ encr_cfg = pdev->reg.encr_cfg_aes_ecb_128;
iv_reg = 0;
key_reg = 4;
xts_key_reg = 0;
@@ -1479,12 +1959,7 @@
(uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->cipher_aes_256_ecb);
- encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES256 <<
- CRYPTO_ENCR_KEY_SZ) |
- (CRYPTO_ENCR_ALG_AES <<
- CRYPTO_ENCR_ALG) |
- (CRYPTO_ENCR_MODE_ECB <<
- CRYPTO_ENCR_MODE);
+ encr_cfg = pdev->reg.encr_cfg_aes_ecb_256;
iv_reg = 0;
key_reg = 8;
xts_key_reg = 0;
@@ -1496,12 +1971,7 @@
(uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->cipher_aes_128_xts);
- encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES128 <<
- CRYPTO_ENCR_KEY_SZ) |
- (CRYPTO_ENCR_ALG_AES <<
- CRYPTO_ENCR_ALG) |
- (CRYPTO_ENCR_MODE_XTS <<
- CRYPTO_ENCR_MODE);
+ encr_cfg = pdev->reg.encr_cfg_aes_xts_128;
iv_reg = 4;
key_reg = 4;
xts_key_reg = 4;
@@ -1510,12 +1980,7 @@
(uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->cipher_aes_256_xts);
- encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES256 <<
- CRYPTO_ENCR_KEY_SZ) |
- (CRYPTO_ENCR_ALG_AES <<
- CRYPTO_ENCR_ALG) |
- (CRYPTO_ENCR_MODE_XTS <<
- CRYPTO_ENCR_MODE);
+ encr_cfg = pdev->reg.encr_cfg_aes_xts_256;
iv_reg = 4;
key_reg = 8;
xts_key_reg = 8;
@@ -1528,8 +1993,8 @@
break;
}
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG, crypto_cfg,
- &pcl_info->crypto_cfg);
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+ pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_SEG_SIZE_REG, 0,
&pcl_info->seg_size);
@@ -1583,7 +2048,7 @@
0, &pcl_info->auth_seg_size);
}
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
- (crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK), NULL);
+ pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1608,20 +2073,11 @@
uint32_t encr_cfg = 0;
uint32_t key_reg = 0;
uint32_t iv_reg = 0;
- uint32_t crypto_cfg = 0;
- uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
- uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
pdev->ce_sps.ce_burst_size);
ce_vaddr = (struct sps_command_element *)(*pvaddr);
ce_vaddr_start = (uint32_t)(*pvaddr);
- crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
- BIT(CRYPTO_MASK_DOUT_INTR) |
- BIT(CRYPTO_MASK_DIN_INTR) |
- BIT(CRYPTO_MASK_OP_DONE_INTR) |
- (0 << CRYPTO_HIGH_SPD_EN_N) |
- (pipe_pair << CRYPTO_PIPE_SET_SELECT);
/*
* Designate chunks of the allocated memory to various
@@ -1635,12 +2091,8 @@
(uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->cipher_des_cbc);
- encr_cfg = (CRYPTO_ENCR_KEY_SZ_DES <<
- CRYPTO_ENCR_KEY_SZ) |
- (CRYPTO_ENCR_ALG_DES <<
- CRYPTO_ENCR_ALG) |
- (CRYPTO_ENCR_MODE_CBC <<
- CRYPTO_ENCR_MODE);
+
+ encr_cfg = pdev->reg.encr_cfg_des_cbc;
iv_reg = 2;
key_reg = 2;
} else {
@@ -1648,12 +2100,7 @@
(uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->cipher_des_ecb);
- encr_cfg = (CRYPTO_ENCR_KEY_SZ_DES <<
- CRYPTO_ENCR_KEY_SZ) |
- (CRYPTO_ENCR_ALG_DES <<
- CRYPTO_ENCR_ALG) |
- (CRYPTO_ENCR_MODE_ECB <<
- CRYPTO_ENCR_MODE);
+ encr_cfg = pdev->reg.encr_cfg_des_ecb;
iv_reg = 0;
key_reg = 2;
}
@@ -1664,12 +2111,7 @@
(uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->cipher_3des_cbc);
- encr_cfg = (CRYPTO_ENCR_KEY_SZ_3DES <<
- CRYPTO_ENCR_KEY_SZ) |
- (CRYPTO_ENCR_ALG_DES <<
- CRYPTO_ENCR_ALG) |
- (CRYPTO_ENCR_MODE_CBC <<
- CRYPTO_ENCR_MODE);
+ encr_cfg = pdev->reg.encr_cfg_3des_cbc;
iv_reg = 2;
key_reg = 6;
} else {
@@ -1677,12 +2119,7 @@
(uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->cipher_3des_ecb);
- encr_cfg = (CRYPTO_ENCR_KEY_SZ_3DES <<
- CRYPTO_ENCR_KEY_SZ) |
- (CRYPTO_ENCR_ALG_DES <<
- CRYPTO_ENCR_ALG) |
- (CRYPTO_ENCR_MODE_ECB <<
- CRYPTO_ENCR_MODE);
+ encr_cfg = pdev->reg.encr_cfg_3des_ecb;
iv_reg = 0;
key_reg = 6;
}
@@ -1693,8 +2130,8 @@
break;
}
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG, crypto_cfg,
- &pcl_info->crypto_cfg);
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+ pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_SEG_SIZE_REG, 0,
&pcl_info->seg_size);
@@ -1727,8 +2164,7 @@
0, &pcl_info->auth_seg_size);
}
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
- (crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
- NULL);
+ pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1752,20 +2188,12 @@
uint32_t key_reg = 0;
uint32_t auth_cfg = 0;
uint32_t iv_reg = 0;
- uint32_t crypto_cfg = 0;
- uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
- uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
pdev->ce_sps.ce_burst_size);
ce_vaddr_start = (uint32_t)(*pvaddr);
ce_vaddr = (struct sps_command_element *)(*pvaddr);
- crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
- BIT(CRYPTO_MASK_DOUT_INTR) |
- BIT(CRYPTO_MASK_DIN_INTR) |
- BIT(CRYPTO_MASK_OP_DONE_INTR) |
- (0 << CRYPTO_HIGH_SPD_EN_N) |
- (pipe_pair << CRYPTO_PIPE_SET_SELECT);
+
/*
* Designate chunks of the allocated memory to various
* command list pointers related to authentication operations
@@ -1776,13 +2204,10 @@
cmdlistptr->auth_sha1.cmdlist = (uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->auth_sha1);
- auth_cfg = (CRYPTO_AUTH_MODE_HASH << CRYPTO_AUTH_MODE)|
- (CRYPTO_AUTH_SIZE_SHA1 << CRYPTO_AUTH_SIZE) |
- (CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
- (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+ auth_cfg = pdev->reg.auth_cfg_sha1;
iv_reg = 5;
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
- crypto_cfg, &pcl_info->crypto_cfg);
+ pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
0, NULL);
@@ -1791,13 +2216,10 @@
cmdlistptr->auth_sha256.cmdlist = (uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->auth_sha256);
- auth_cfg = (CRYPTO_AUTH_MODE_HASH << CRYPTO_AUTH_MODE)|
- (CRYPTO_AUTH_SIZE_SHA256 << CRYPTO_AUTH_SIZE) |
- (CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
- (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+ auth_cfg = pdev->reg.auth_cfg_sha256;
iv_reg = 8;
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
- crypto_cfg, &pcl_info->crypto_cfg);
+ pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
@@ -1808,14 +2230,11 @@
cmdlistptr->auth_sha1_hmac.cmdlist = (uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->auth_sha1_hmac);
- auth_cfg = (CRYPTO_AUTH_MODE_HMAC << CRYPTO_AUTH_MODE)|
- (CRYPTO_AUTH_SIZE_SHA1 << CRYPTO_AUTH_SIZE) |
- (CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
- (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+ auth_cfg = pdev->reg.auth_cfg_hmac_sha1;
key_reg = 16;
iv_reg = 5;
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
- crypto_cfg, &pcl_info->crypto_cfg);
+ pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
0, NULL);
break;
@@ -1823,16 +2242,11 @@
cmdlistptr->aead_sha1_hmac.cmdlist = (uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->aead_sha1_hmac);
- auth_cfg = (CRYPTO_AUTH_MODE_HMAC << CRYPTO_AUTH_MODE)|
- (CRYPTO_AUTH_SIZE_SHA1 << CRYPTO_AUTH_SIZE) |
- (CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
- (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS) |
- (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST);
-
+ auth_cfg = pdev->reg.auth_cfg_aead_sha1_hmac;
key_reg = 16;
iv_reg = 5;
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
- crypto_cfg, &pcl_info->crypto_cfg);
+ pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
@@ -1843,15 +2257,12 @@
cmdlistptr->auth_sha256_hmac.cmdlist = (uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->auth_sha256_hmac);
- auth_cfg = (CRYPTO_AUTH_MODE_HMAC << CRYPTO_AUTH_MODE)|
- (CRYPTO_AUTH_SIZE_SHA256 << CRYPTO_AUTH_SIZE) |
- (CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
- (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+ auth_cfg = pdev->reg.auth_cfg_hmac_sha256;
key_reg = 16;
iv_reg = 8;
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
- crypto_cfg, &pcl_info->crypto_cfg);
+ pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
@@ -1864,32 +2275,18 @@
(uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->auth_aes_128_cmac);
- auth_cfg = (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
- (CRYPTO_AUTH_MODE_CMAC << CRYPTO_AUTH_MODE)|
- (CRYPTO_AUTH_SIZE_ENUM_16_BYTES <<
- CRYPTO_AUTH_SIZE) |
- (CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
- (CRYPTO_AUTH_KEY_SZ_AES128 <<
- CRYPTO_AUTH_KEY_SIZE) |
- (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+ auth_cfg = pdev->reg.auth_cfg_cmac_128;
key_reg = 4;
} else {
cmdlistptr->auth_aes_256_cmac.cmdlist =
(uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->auth_aes_256_cmac);
- auth_cfg = (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST)|
- (CRYPTO_AUTH_MODE_CMAC << CRYPTO_AUTH_MODE)|
- (CRYPTO_AUTH_SIZE_ENUM_16_BYTES <<
- CRYPTO_AUTH_SIZE) |
- (CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
- (CRYPTO_AUTH_KEY_SZ_AES256 <<
- CRYPTO_AUTH_KEY_SIZE) |
- (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+ auth_cfg = pdev->reg.auth_cfg_cmac_256;
key_reg = 8;
}
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
- crypto_cfg, &pcl_info->crypto_cfg);
+ pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
@@ -1946,8 +2343,7 @@
0, NULL);
}
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
- (crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
- NULL);
+ pdev->reg.crypto_cfg_le, NULL);
if (alg != QCE_AEAD_SHA1_HMAC)
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
@@ -1971,20 +2367,12 @@
uint32_t encr_cfg = 0;
uint32_t auth_cfg = 0;
uint32_t key_reg = 0;
- uint32_t crypto_cfg = 0;
- uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
- uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
pdev->ce_sps.ce_burst_size);
ce_vaddr_start = (uint32_t)(*pvaddr);
ce_vaddr = (struct sps_command_element *)(*pvaddr);
- crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
- BIT(CRYPTO_MASK_DOUT_INTR) |
- BIT(CRYPTO_MASK_DIN_INTR) |
- BIT(CRYPTO_MASK_OP_DONE_INTR) |
- (0 << CRYPTO_HIGH_SPD_EN_N) |
- (pipe_pair << CRYPTO_PIPE_SET_SELECT);
+
/*
* Designate chunks of the allocated memory to various
* command list pointers related to aead operations
@@ -1994,36 +2382,21 @@
cmdlistptr->aead_aes_128_ccm.cmdlist = (uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->aead_aes_128_ccm);
- auth_cfg = (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
- (CRYPTO_AUTH_MODE_CCM << CRYPTO_AUTH_MODE)|
- (CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
- (CRYPTO_AUTH_KEY_SZ_AES128 << CRYPTO_AUTH_KEY_SIZE);
- auth_cfg &= ~(1 << CRYPTO_USE_HW_KEY_AUTH);
- encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES128 << CRYPTO_ENCR_KEY_SZ) |
- (CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
- ((CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE));
+ auth_cfg = pdev->reg.auth_cfg_aes_ccm_128;
+ encr_cfg = pdev->reg.encr_cfg_aes_ccm_128;
key_reg = 4;
} else {
cmdlistptr->aead_aes_256_ccm.cmdlist = (uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->aead_aes_256_ccm);
- auth_cfg = (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
- (CRYPTO_AUTH_MODE_CCM << CRYPTO_AUTH_MODE)|
- (CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
- (CRYPTO_AUTH_KEY_SZ_AES256 << CRYPTO_AUTH_KEY_SIZE) |
- ((MAX_NONCE/sizeof(uint32_t)) <<
- CRYPTO_AUTH_NONCE_NUM_WORDS);
- auth_cfg &= ~(1 << CRYPTO_USE_HW_KEY_AUTH);
- encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES256 << CRYPTO_ENCR_KEY_SZ) |
- (CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
- (CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE) |
- (CRYPTO_LAST_CCM_XFR << CRYPTO_LAST_CCM);
+ auth_cfg = pdev->reg.auth_cfg_aes_ccm_256;
+ encr_cfg = pdev->reg.encr_cfg_aes_ccm_256;
key_reg = 8;
}
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
- crypto_cfg, &pcl_info->crypto_cfg);
+ pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG, 0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_CFG_REG, 0, NULL);
@@ -2093,8 +2466,7 @@
0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
- (crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
- NULL);
+ pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -2197,7 +2569,8 @@
(uint32_t)GET_PHYS_ADDR(vaddr);
vaddr += QCE_MAX_NUM_DSCR * sizeof(struct sps_iovec);
- qce_setup_cmdlistptrs(pce_dev, &vaddr);
+ if (pce_dev->support_cmd_dscr)
+ qce_setup_cmdlistptrs(pce_dev, &vaddr);
vaddr = (unsigned char *) ALIGN(((unsigned int)vaddr),
pce_dev->ce_sps.ce_burst_size);
pce_dev->ce_sps.result_dump = (uint32_t)vaddr;
@@ -2207,6 +2580,160 @@
return 0;
}
+static int qce_init_ce_cfg_val(struct qce_device *pce_dev)
+{
+ uint32_t beats = (pce_dev->ce_sps.ce_burst_size >> 3) - 1;
+ uint32_t pipe_pair = pce_dev->ce_sps.pipe_pair_index;
+
+ pce_dev->reg.crypto_cfg_be = (beats << CRYPTO_REQ_SIZE) |
+ BIT(CRYPTO_MASK_DOUT_INTR) | BIT(CRYPTO_MASK_DIN_INTR) |
+ BIT(CRYPTO_MASK_OP_DONE_INTR) | (0 << CRYPTO_HIGH_SPD_EN_N) |
+ (pipe_pair << CRYPTO_PIPE_SET_SELECT);
+
+ pce_dev->reg.crypto_cfg_le =
+ (pce_dev->reg.crypto_cfg_be | CRYPTO_LITTLE_ENDIAN_MASK);
+
+ /* Initialize encr_cfg register for AES alg */
+ pce_dev->reg.encr_cfg_aes_cbc_128 =
+ (CRYPTO_ENCR_KEY_SZ_AES128 << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+ (CRYPTO_ENCR_MODE_CBC << CRYPTO_ENCR_MODE);
+
+ pce_dev->reg.encr_cfg_aes_cbc_256 =
+ (CRYPTO_ENCR_KEY_SZ_AES256 << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+ (CRYPTO_ENCR_MODE_CBC << CRYPTO_ENCR_MODE);
+
+ pce_dev->reg.encr_cfg_aes_ctr_128 =
+ (CRYPTO_ENCR_KEY_SZ_AES128 << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+ (CRYPTO_ENCR_MODE_CTR << CRYPTO_ENCR_MODE);
+
+ pce_dev->reg.encr_cfg_aes_ctr_256 =
+ (CRYPTO_ENCR_KEY_SZ_AES256 << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+ (CRYPTO_ENCR_MODE_CTR << CRYPTO_ENCR_MODE);
+
+ pce_dev->reg.encr_cfg_aes_xts_128 =
+ (CRYPTO_ENCR_KEY_SZ_AES128 << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+ (CRYPTO_ENCR_MODE_XTS << CRYPTO_ENCR_MODE);
+
+ pce_dev->reg.encr_cfg_aes_xts_256 =
+ (CRYPTO_ENCR_KEY_SZ_AES256 << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+ (CRYPTO_ENCR_MODE_XTS << CRYPTO_ENCR_MODE);
+
+ pce_dev->reg.encr_cfg_aes_ecb_128 =
+ (CRYPTO_ENCR_KEY_SZ_AES128 << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+ (CRYPTO_ENCR_MODE_ECB << CRYPTO_ENCR_MODE);
+
+ pce_dev->reg.encr_cfg_aes_ecb_256 =
+ (CRYPTO_ENCR_KEY_SZ_AES256 << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+ (CRYPTO_ENCR_MODE_ECB << CRYPTO_ENCR_MODE);
+
+ pce_dev->reg.encr_cfg_aes_ccm_128 =
+ (CRYPTO_ENCR_KEY_SZ_AES128 << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+ ((CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE));
+
+ pce_dev->reg.encr_cfg_aes_ccm_256 =
+ (CRYPTO_ENCR_KEY_SZ_AES256 << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+ (CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE) |
+ (CRYPTO_LAST_CCM_XFR << CRYPTO_LAST_CCM);
+
+ /* Initialize encr_cfg register for DES alg */
+ pce_dev->reg.encr_cfg_des_ecb =
+ (CRYPTO_ENCR_KEY_SZ_DES << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_DES << CRYPTO_ENCR_ALG) |
+ (CRYPTO_ENCR_MODE_ECB << CRYPTO_ENCR_MODE);
+
+ pce_dev->reg.encr_cfg_des_cbc =
+ (CRYPTO_ENCR_KEY_SZ_DES << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_DES << CRYPTO_ENCR_ALG) |
+ (CRYPTO_ENCR_MODE_CBC << CRYPTO_ENCR_MODE);
+
+ pce_dev->reg.encr_cfg_3des_ecb =
+ (CRYPTO_ENCR_KEY_SZ_3DES << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_DES << CRYPTO_ENCR_ALG) |
+ (CRYPTO_ENCR_MODE_ECB << CRYPTO_ENCR_MODE);
+
+ pce_dev->reg.encr_cfg_3des_cbc =
+ (CRYPTO_ENCR_KEY_SZ_3DES << CRYPTO_ENCR_KEY_SZ) |
+ (CRYPTO_ENCR_ALG_DES << CRYPTO_ENCR_ALG) |
+ (CRYPTO_ENCR_MODE_CBC << CRYPTO_ENCR_MODE);
+
+ /* Initialize auth_cfg register for CMAC alg */
+ pce_dev->reg.auth_cfg_cmac_128 =
+ (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
+ (CRYPTO_AUTH_MODE_CMAC << CRYPTO_AUTH_MODE)|
+ (CRYPTO_AUTH_SIZE_ENUM_16_BYTES << CRYPTO_AUTH_SIZE) |
+ (CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
+ (CRYPTO_AUTH_KEY_SZ_AES128 << CRYPTO_AUTH_KEY_SIZE);
+
+ pce_dev->reg.auth_cfg_cmac_256 =
+ (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
+ (CRYPTO_AUTH_MODE_CMAC << CRYPTO_AUTH_MODE)|
+ (CRYPTO_AUTH_SIZE_ENUM_16_BYTES << CRYPTO_AUTH_SIZE) |
+ (CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
+ (CRYPTO_AUTH_KEY_SZ_AES256 << CRYPTO_AUTH_KEY_SIZE);
+
+ /* Initialize auth_cfg register for HMAC alg */
+ pce_dev->reg.auth_cfg_hmac_sha1 =
+ (CRYPTO_AUTH_MODE_HMAC << CRYPTO_AUTH_MODE)|
+ (CRYPTO_AUTH_SIZE_SHA1 << CRYPTO_AUTH_SIZE) |
+ (CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
+ (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+
+ pce_dev->reg.auth_cfg_hmac_sha256 =
+ (CRYPTO_AUTH_MODE_HMAC << CRYPTO_AUTH_MODE)|
+ (CRYPTO_AUTH_SIZE_SHA256 << CRYPTO_AUTH_SIZE) |
+ (CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
+ (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+
+ /* Initialize auth_cfg register for SHA1/256 alg */
+ pce_dev->reg.auth_cfg_sha1 =
+ (CRYPTO_AUTH_MODE_HASH << CRYPTO_AUTH_MODE)|
+ (CRYPTO_AUTH_SIZE_SHA1 << CRYPTO_AUTH_SIZE) |
+ (CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
+ (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+
+ pce_dev->reg.auth_cfg_sha256 =
+ (CRYPTO_AUTH_MODE_HASH << CRYPTO_AUTH_MODE)|
+ (CRYPTO_AUTH_SIZE_SHA256 << CRYPTO_AUTH_SIZE) |
+ (CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
+ (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+
+ /* Initialize auth_cfg register for AEAD alg */
+ pce_dev->reg.auth_cfg_aead_sha1_hmac =
+ (CRYPTO_AUTH_MODE_HMAC << CRYPTO_AUTH_MODE)|
+ (CRYPTO_AUTH_SIZE_SHA1 << CRYPTO_AUTH_SIZE) |
+ (CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
+ (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS) |
+ (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST);
+
+ pce_dev->reg.auth_cfg_aes_ccm_128 =
+ (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
+ (CRYPTO_AUTH_MODE_CCM << CRYPTO_AUTH_MODE)|
+ (CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
+ (CRYPTO_AUTH_KEY_SZ_AES128 << CRYPTO_AUTH_KEY_SIZE) |
+ ((MAX_NONCE/sizeof(uint32_t)) << CRYPTO_AUTH_NONCE_NUM_WORDS);
+ pce_dev->reg.auth_cfg_aes_ccm_128 &= ~(1 << CRYPTO_USE_HW_KEY_AUTH);
+
+ pce_dev->reg.auth_cfg_aes_ccm_256 =
+ (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
+ (CRYPTO_AUTH_MODE_CCM << CRYPTO_AUTH_MODE)|
+ (CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
+ (CRYPTO_AUTH_KEY_SZ_AES256 << CRYPTO_AUTH_KEY_SIZE) |
+ ((MAX_NONCE/sizeof(uint32_t)) << CRYPTO_AUTH_NONCE_NUM_WORDS);
+ pce_dev->reg.auth_cfg_aes_ccm_256 &= ~(1 << CRYPTO_USE_HW_KEY_AUTH);
+
+ return 0;
+}
+
int qce_aead_sha1_hmac_setup(struct qce_req *creq, struct crypto_aead *aead,
struct qce_cmdlist_info *cmdlistinfo)
{
@@ -2301,10 +2828,16 @@
pce_dev->dst_nents = pce_dev->src_nents;
}
- _ce_get_cipher_cmdlistinfo(pce_dev, q_req, &cmdlistinfo);
- /* set up crypto device */
- rc = _ce_setup_cipher(pce_dev, q_req, totallen_in,
- areq->assoclen + ivsize, cmdlistinfo);
+ if (pce_dev->support_cmd_dscr) {
+ _ce_get_cipher_cmdlistinfo(pce_dev, q_req, &cmdlistinfo);
+ /* set up crypto device */
+ rc = _ce_setup_cipher(pce_dev, q_req, totallen_in,
+ areq->assoclen + ivsize, cmdlistinfo);
+ } else {
+ /* set up crypto device */
+ rc = _ce_setup_cipher_direct(pce_dev, q_req, totallen_in,
+ areq->assoclen + ivsize);
+ }
if (rc < 0)
goto bad;
@@ -2334,7 +2867,8 @@
}
_qce_sps_iovec_count_init(pce_dev);
- _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
+ if (pce_dev->support_cmd_dscr)
+ _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
&pce_dev->ce_sps.in_transfer);
if (pce_dev->ce_sps.minor_version == 0) {
@@ -2445,7 +2979,6 @@
pce_dev->src_nents = 0;
pce_dev->dst_nents = 0;
- _ce_get_cipher_cmdlistinfo(pce_dev, c_req, &cmdlistinfo);
/* cipher input */
pce_dev->src_nents = count_sg(areq->src, areq->nbytes);
@@ -2464,15 +2997,19 @@
pce_dev->dir = c_req->dir;
if ((pce_dev->ce_sps.minor_version == 0) && (c_req->dir == QCE_DECRYPT)
&& (c_req->mode == QCE_MODE_CBC)) {
- struct ablkcipher_request *areq =
- (struct ablkcipher_request *)pce_dev->areq;
memcpy(pce_dev->dec_iv, (unsigned char *)sg_virt(areq->src) +
areq->src->length - 16,
NUM_OF_CRYPTO_CNTR_IV_REG * CRYPTO_REG_SIZE);
}
/* set up crypto device */
- rc = _ce_setup_cipher(pce_dev, c_req, areq->nbytes, 0, cmdlistinfo);
+ if (pce_dev->support_cmd_dscr) {
+ _ce_get_cipher_cmdlistinfo(pce_dev, c_req, &cmdlistinfo);
+ rc = _ce_setup_cipher(pce_dev, c_req, areq->nbytes, 0,
+ cmdlistinfo);
+ } else {
+ rc = _ce_setup_cipher_direct(pce_dev, c_req, areq->nbytes, 0);
+ }
if (rc < 0)
goto bad;
@@ -2491,8 +3028,8 @@
goto bad;
}
_qce_sps_iovec_count_init(pce_dev);
-
- _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
+ if (pce_dev->support_cmd_dscr)
+ _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
&pce_dev->ce_sps.in_transfer);
if (_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes,
&pce_dev->ce_sps.in_transfer))
@@ -2547,10 +3084,15 @@
struct qce_cmdlist_info *cmdlistinfo = NULL;
pce_dev->src_nents = count_sg(sreq->src, sreq->size);
- _ce_get_hash_cmdlistinfo(pce_dev, sreq, &cmdlistinfo);
qce_dma_map_sg(pce_dev->pdev, sreq->src, pce_dev->src_nents,
DMA_TO_DEVICE);
- rc = _ce_setup_hash(pce_dev, sreq, cmdlistinfo);
+
+ if (pce_dev->support_cmd_dscr) {
+ _ce_get_hash_cmdlistinfo(pce_dev, sreq, &cmdlistinfo);
+ rc = _ce_setup_hash(pce_dev, sreq, cmdlistinfo);
+ } else {
+ rc = _ce_setup_hash_direct(pce_dev, sreq);
+ }
if (rc < 0)
goto bad;
@@ -2568,7 +3110,8 @@
}
_qce_sps_iovec_count_init(pce_dev);
- _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
+ if (pce_dev->support_cmd_dscr)
+ _qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
&pce_dev->ce_sps.in_transfer);
if (_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes,
&pce_dev->ce_sps.in_transfer))
@@ -2602,7 +3145,6 @@
pce_dev->is_shared = of_property_read_bool((&pdev->dev)->of_node,
"qcom,ce-hw-shared");
-
if (of_property_read_u32((&pdev->dev)->of_node,
"qcom,bam-pipe-pair",
&pce_dev->ce_sps.pipe_pair_index)) {
@@ -2637,7 +3179,7 @@
pce_dev->ce_sps.bam_mem = resource->start;
pce_dev->ce_sps.bam_iobase = ioremap_nocache(resource->start,
resource_size(resource));
- if (!pce_dev->iobase) {
+ if (!pce_dev->ce_sps.bam_iobase) {
rc = -ENOMEM;
pr_err("Can not map BAM io memory\n");
goto err_getting_bam_info;
@@ -2650,7 +3192,6 @@
pr_warn("ce_bam_phy_reg_base=0x%x ", pce_dev->ce_sps.bam_mem);
pr_warn("ce_bam_virt_reg_base=0x%x\n",
(uint32_t)pce_dev->ce_sps.bam_iobase);
-
resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (resource) {
pce_dev->ce_sps.bam_irq = resource->start;
@@ -2816,6 +3357,7 @@
void *qce_open(struct platform_device *pdev, int *rc)
{
struct qce_device *pce_dev;
+ uint32_t bam_cfg = 0 ;
pce_dev = kzalloc(sizeof(struct qce_device), GFP_KERNEL);
if (!pce_dev) {
@@ -2857,9 +3399,16 @@
goto err;
}
*rc = 0;
+
+ bam_cfg = readl_relaxed(pce_dev->ce_sps.bam_iobase +
+ CRYPTO_BAM_CNFG_BITS_REG);
+ pce_dev->support_cmd_dscr = (bam_cfg & CRYPTO_BAM_CD_ENABLE_MASK) ?
+ true : false;
+ qce_init_ce_cfg_val(pce_dev);
qce_setup_ce_sps_data(pce_dev);
qce_sps_init(pce_dev);
+
qce_disable_clk(pce_dev);
return pce_dev;
@@ -2889,6 +3438,9 @@
if (handle == NULL)
return -ENODEV;
+ qce_enable_clk(pce_dev);
+ qce_sps_exit(pce_dev);
+
if (pce_dev->iobase)
iounmap(pce_dev->iobase);
if (pce_dev->coh_vmem)
@@ -2898,7 +3450,6 @@
qce_disable_clk(pce_dev);
__qce_deinit_clk(pce_dev);
- qce_sps_exit(pce_dev);
kfree(handle);
return 0;
diff --git a/drivers/crypto/msm/qce50.h b/drivers/crypto/msm/qce50.h
index f5123df..38515fb 100644
--- a/drivers/crypto/msm/qce50.h
+++ b/drivers/crypto/msm/qce50.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -109,6 +109,45 @@
struct qce_cmdlist_info unlock_all_pipes;
};
+struct qce_ce_cfg_reg_setting {
+ uint32_t crypto_cfg_be;
+ uint32_t crypto_cfg_le;
+
+ uint32_t encr_cfg_aes_cbc_128;
+ uint32_t encr_cfg_aes_cbc_256;
+
+ uint32_t encr_cfg_aes_ecb_128;
+ uint32_t encr_cfg_aes_ecb_256;
+
+ uint32_t encr_cfg_aes_xts_128;
+ uint32_t encr_cfg_aes_xts_256;
+
+ uint32_t encr_cfg_aes_ctr_128;
+ uint32_t encr_cfg_aes_ctr_256;
+
+ uint32_t encr_cfg_aes_ccm_128;
+ uint32_t encr_cfg_aes_ccm_256;
+
+ uint32_t encr_cfg_des_cbc;
+ uint32_t encr_cfg_des_ecb;
+
+ uint32_t encr_cfg_3des_cbc;
+ uint32_t encr_cfg_3des_ecb;
+
+ uint32_t auth_cfg_cmac_128;
+ uint32_t auth_cfg_cmac_256;
+
+ uint32_t auth_cfg_sha1;
+ uint32_t auth_cfg_sha256;
+
+ uint32_t auth_cfg_hmac_sha1;
+ uint32_t auth_cfg_hmac_sha256;
+
+ uint32_t auth_cfg_aes_ccm_128;
+ uint32_t auth_cfg_aes_ccm_256;
+ uint32_t auth_cfg_aead_sha1_hmac;
+
+};
/* DM data structure with buffers, commandlists & commmand pointer lists */
struct ce_sps_data {
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index e91dcaa..a09bb42 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -323,10 +323,10 @@
u32 qcedev_sha_fail;
};
-static struct qcedev_stat _qcedev_stat[MAX_QCE_DEVICE];
+static struct qcedev_stat _qcedev_stat;
static struct dentry *_debug_dent;
static char _debug_read_buf[DEBUG_MAX_RW_BUF];
-static int _debug_qcedev[MAX_QCE_DEVICE];
+static int _debug_qcedev;
static struct qcedev_control *qcedev_minor_to_control(unsigned n)
{
@@ -693,7 +693,7 @@
if (ret)
qcedev_areq->err = -EIO;
- pstat = &_qcedev_stat[podev->pdev->id];
+ pstat = &_qcedev_stat;
if (qcedev_areq->op_type == QCEDEV_CRYPTO_OPER_CIPHER) {
switch (qcedev_areq->cipher_op_req.op) {
case QCEDEV_OPER_DEC:
@@ -1559,34 +1559,54 @@
static int qcedev_check_cipher_key(struct qcedev_cipher_op_req *req,
struct qcedev_control *podev)
{
+
+ if (req->encklen < 0) {
+ pr_err("%s: Invalid key size: %d\n", __func__, req->encklen);
+ return -EINVAL;
+ }
/* if intending to use HW key make sure key fields are set
* correctly and HW key is indeed supported in target
*/
if (req->encklen == 0) {
int i;
- for (i = 0; i < QCEDEV_MAX_KEY_SIZE; i++)
- if (req->enckey[i])
+ for (i = 0; i < QCEDEV_MAX_KEY_SIZE; i++) {
+ if (req->enckey[i]) {
+ pr_err("%s: Invalid key: non-zero key input\n",
+ __func__);
goto error;
+ }
+ }
if ((req->op != QCEDEV_OPER_ENC_NO_KEY) &&
(req->op != QCEDEV_OPER_DEC_NO_KEY))
- if (!podev->platform_support.hw_key_support)
+ if (!podev->platform_support.hw_key_support) {
+ pr_err("%s: Invalid op %d\n", __func__,
+ (uint32_t)req->op);
goto error;
+ }
} else {
if (req->encklen == QCEDEV_AES_KEY_192) {
- if (!podev->ce_support.aes_key_192)
+ if (!podev->ce_support.aes_key_192) {
+ pr_err("%s: AES-192 not supported\n", __func__);
goto error;
+ }
} else {
/* if not using HW key make sure key
* length is valid
*/
if ((req->mode == QCEDEV_AES_MODE_XTS)) {
- if (!((req->encklen == QCEDEV_AES_KEY_128*2) ||
- (req->encklen == QCEDEV_AES_KEY_256*2)))
+ if ((req->encklen != QCEDEV_AES_KEY_128*2) &&
+ (req->encklen != QCEDEV_AES_KEY_256*2)) {
+ pr_err("%s: unsupported key size: %d\n",
+ __func__, req->encklen);
goto error;
+ }
} else {
- if (!((req->encklen == QCEDEV_AES_KEY_128) ||
- (req->encklen == QCEDEV_AES_KEY_256)))
+ if ((req->encklen != QCEDEV_AES_KEY_128) &&
+ (req->encklen != QCEDEV_AES_KEY_256)) {
+ pr_err("%s: unsupported key size %d\n",
+ __func__, req->encklen);
goto error;
+ }
}
}
}
@@ -1602,32 +1622,48 @@
pr_err("%s: Use of PMEM is not supported\n", __func__);
goto error;
}
- if ((req->entries == 0) || (req->data_len == 0))
+ if ((req->entries == 0) || (req->data_len == 0) ||
+ (req->entries > QCEDEV_MAX_BUFFERS)) {
+ pr_err("%s: Invalid cipher length/entries\n", __func__);
goto error;
+ }
if ((req->alg >= QCEDEV_ALG_LAST) ||
- (req->mode >= QCEDEV_AES_DES_MODE_LAST))
+ (req->mode >= QCEDEV_AES_DES_MODE_LAST)) {
+ pr_err("%s: Invalid algorithm %d\n", __func__,
+ (uint32_t)req->alg);
goto error;
-
- if ((req->mode == QCEDEV_AES_MODE_XTS) && (!podev->ce_support.aes_xts))
- goto error;
-
- if (req->alg == QCEDEV_ALG_AES)
+ }
+ if ((req->mode == QCEDEV_AES_MODE_XTS) &&
+ (!podev->ce_support.aes_xts)) {
+ pr_err("%s: XTS algorithm is not supported\n", __func__);
+ goto error;
+ }
+ if (req->alg == QCEDEV_ALG_AES) {
if (qcedev_check_cipher_key(req, podev))
- goto error;
+ goto error;
+
+ }
/* if using a byteoffset, make sure it is CTR mode using vbuf */
if (req->byteoffset) {
- if (req->mode != QCEDEV_AES_MODE_CTR)
+ if (req->mode != QCEDEV_AES_MODE_CTR) {
+ pr_err("%s: Operation on byte offset not supported\n",
+ __func__);
goto error;
+ }
}
/* Ensure zer ivlen for ECB mode */
- if (req->ivlen != 0) {
+ if (req->ivlen > 0) {
if ((req->mode == QCEDEV_AES_MODE_ECB) ||
- (req->mode == QCEDEV_DES_MODE_ECB))
+ (req->mode == QCEDEV_DES_MODE_ECB)) {
+ pr_err("%s: Expecting a zero length IV\n", __func__);
goto error;
+ }
} else {
if ((req->mode != QCEDEV_AES_MODE_ECB) &&
- (req->mode != QCEDEV_DES_MODE_ECB))
+ (req->mode != QCEDEV_DES_MODE_ECB)) {
+ pr_err("%s: Expecting a non-zero ength IV\n", __func__);
goto error;
+ }
}
return 0;
@@ -1640,20 +1676,42 @@
struct qcedev_control *podev)
{
if ((req->alg == QCEDEV_ALG_AES_CMAC) &&
- (!podev->ce_support.cmac))
+ (!podev->ce_support.cmac)) {
+ pr_err("%s: CMAC not supported\n", __func__);
goto sha_error;
-
- if ((req->entries == 0) || (req->data_len == 0))
+ }
+ if ((req->entries == 0) || (req->data_len == 0) ||
+ (req->entries > QCEDEV_MAX_BUFFERS)) {
+ pr_err("%s: Invalid data length (%d)/ num entries (%d)\n",
+ __func__, req->data_len, req->entries);
goto sha_error;
+ }
- if (req->alg >= QCEDEV_ALG_SHA_ALG_LAST)
+ if (req->alg >= QCEDEV_ALG_SHA_ALG_LAST) {
+ pr_err("%s: Invalid algorithm (%d)\n", __func__, req->alg);
goto sha_error;
-
+ }
if ((req->alg == QCEDEV_ALG_SHA1_HMAC) ||
(req->alg == QCEDEV_ALG_SHA1_HMAC)) {
- if (req->authklen == 0)
+ if (req->authkey == NULL) {
+ pr_err("%s: Invalid authkey pointer\n", __func__);
goto sha_error;
+ }
+ if (req->authklen <= 0) {
+ pr_err("%s: Invalid authkey length (%d)\n",
+ __func__, req->authklen);
+ goto sha_error;
+ }
}
+
+ if (req->alg == QCEDEV_ALG_AES_CMAC) {
+ if ((req->authklen != QCEDEV_AES_KEY_128) &&
+ (req->authklen != QCEDEV_AES_KEY_256)) {
+ pr_err("%s: unsupported key length\n", __func__);
+ goto sha_error;
+ }
+ }
+
return 0;
sha_error:
return -EINVAL;
@@ -1681,7 +1739,7 @@
return -ENOTTY;
init_completion(&qcedev_areq.complete);
- pstat = &_qcedev_stat[podev->pdev->id];
+ pstat = &_qcedev_stat;
switch (cmd) {
case QCEDEV_IOCTL_LOCK_CE:
@@ -1968,11 +2026,7 @@
struct qcedev_stat *pstat;
int len = 0;
- if (id < 0) {
- pr_err("Crypto id is %d, cannot be negative\n", id);
- return len;
- }
- pstat = &_qcedev_stat[id];
+ pstat = &_qcedev_stat;
len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
"\nQualcomm QCE dev driver %d Statistics:\n",
id + 1);
@@ -2018,10 +2072,7 @@
static ssize_t _debug_stats_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
-
- int qcedev = *((int *) file->private_data);
-
- memset((char *)&_qcedev_stat[qcedev], 0, sizeof(struct qcedev_stat));
+ memset((char *)&_qcedev_stat, 0, sizeof(struct qcedev_stat));
return count;
};
@@ -2035,7 +2086,6 @@
{
int rc;
char name[DEBUG_MAX_FNAME];
- int i;
struct dentry *dent;
_debug_dent = debugfs_create_dir("qcedev", NULL);
@@ -2045,17 +2095,15 @@
return PTR_ERR(_debug_dent);
}
- for (i = 0; i < MAX_QCE_DEVICE; i++) {
- snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", i+1);
- _debug_qcedev[i] = i;
- dent = debugfs_create_file(name, 0644, _debug_dent,
- &_debug_qcedev[i], &_debug_stats_ops);
- if (dent == NULL) {
- pr_err("qcedev debugfs_create_file fail, error %ld\n",
- PTR_ERR(dent));
- rc = PTR_ERR(dent);
- goto err;
- }
+ snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", 1);
+ _debug_qcedev = 0;
+ dent = debugfs_create_file(name, 0644, _debug_dent,
+ &_debug_qcedev, &_debug_stats_ops);
+ if (dent == NULL) {
+ pr_err("qcedev debugfs_create_file fail, error %ld\n",
+ PTR_ERR(dent));
+ rc = PTR_ERR(dent);
+ goto err;
}
return 0;
err:
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 40fb29ac..d1cb933 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -42,7 +42,6 @@
#include "qce.h"
-#define MAX_CRYPTO_DEVICE 3
#define DEBUG_MAX_FNAME 16
#define DEBUG_MAX_RW_BUF 1024
@@ -53,6 +52,8 @@
u32 aead_sha1_des_dec;
u32 aead_sha1_3des_enc;
u32 aead_sha1_3des_dec;
+ u32 aead_ccm_aes_enc;
+ u32 aead_ccm_aes_dec;
u32 aead_op_success;
u32 aead_op_fail;
u32 ablk_cipher_aes_enc;
@@ -72,7 +73,7 @@
u32 sha_hmac_op_success;
u32 sha_hmac_op_fail;
};
-static struct crypto_stat _qcrypto_stat[MAX_CRYPTO_DEVICE];
+static struct crypto_stat _qcrypto_stat;
static struct dentry *_debug_dent;
static char _debug_read_buf[DEBUG_MAX_RW_BUF];
@@ -405,6 +406,39 @@
return i;
}
+size_t qcrypto_sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
+ void *buf, size_t buflen)
+{
+ int i;
+ size_t offset, len;
+
+ for (i = 0, offset = 0; i < nents; ++i) {
+ len = sg_copy_from_buffer(sgl, 1, buf, buflen);
+ buf += len;
+ buflen -= len;
+ offset += len;
+ sgl = scatterwalk_sg_next(sgl);
+ }
+
+ return offset;
+}
+
+size_t qcrypto_sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
+ void *buf, size_t buflen)
+{
+ int i;
+ size_t offset, len;
+
+ for (i = 0, offset = 0; i < nents; ++i) {
+ len = sg_copy_to_buffer(sgl, 1, buf, buflen);
+ buf += len;
+ buflen -= len;
+ offset += len;
+ sgl = scatterwalk_sg_next(sgl);
+ }
+
+ return offset;
+}
static struct qcrypto_alg *_qcrypto_sha_alg_alloc(struct crypto_priv *cp,
struct ahash_alg *template)
{
@@ -581,11 +615,7 @@
struct crypto_stat *pstat;
int len = 0;
- if (id < 0) {
- pr_err("Crypto id is %d, cannot be negative\n", id);
- return len;
- }
- pstat = &_qcrypto_stat[id];
+ pstat = &_qcrypto_stat;
len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
"\nQualcomm crypto accelerator %d Statistics:\n",
id + 1);
@@ -641,6 +671,13 @@
pstat->aead_sha1_3des_dec);
len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ " AEAD CCM-AES encryption : %d\n",
+ pstat->aead_ccm_aes_enc);
+ len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ " AEAD CCM-AES decryption : %d\n",
+ pstat->aead_ccm_aes_dec);
+
+ len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD operation success : %d\n",
pstat->aead_op_success);
len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
@@ -858,7 +895,7 @@
uint32_t diglen = crypto_ahash_digestsize(ahash);
uint32_t *auth32 = (uint32_t *)authdata;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
#ifdef QCRYPTO_DEBUG
dev_info(&cp->pdev->dev, "_qce_ahash_complete: %p ret %d\n",
@@ -916,7 +953,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
#ifdef QCRYPTO_DEBUG
dev_info(&cp->pdev->dev, "_qce_ablk_cipher_complete: %p ret %d\n",
@@ -943,7 +980,7 @@
areq->dst = rctx->orig_dst;
num_sg = qcrypto_count_sg(areq->dst, areq->nbytes);
- bytes = sg_copy_from_buffer(areq->dst, num_sg,
+ bytes = qcrypto_sg_copy_from_buffer(areq->dst, num_sg,
rctx->data, areq->nbytes);
if (bytes != areq->nbytes)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes,
@@ -967,7 +1004,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
@@ -988,7 +1025,7 @@
nbytes = areq->cryptlen -
crypto_aead_authsize(aead);
num_sg = qcrypto_count_sg(areq->dst, nbytes);
- bytes = sg_copy_from_buffer(areq->dst, num_sg,
+ bytes = qcrypto_sg_copy_from_buffer(areq->dst, num_sg,
((char *)rctx->data + areq->assoclen),
nbytes);
if (bytes != nbytes)
@@ -1118,7 +1155,7 @@
qreq->assoclen = ALIGN((alen + len), 16);
num_sg = qcrypto_count_sg(sg, alen);
- bytes = sg_copy_to_buffer(sg, num_sg, adata, alen);
+ bytes = qcrypto_sg_copy_to_buffer(sg, num_sg, adata, alen);
if (bytes != alen)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes, alen);
@@ -1145,7 +1182,7 @@
rctx->orig_src = req->src;
rctx->orig_dst = req->dst;
- rctx->data = kzalloc((req->nbytes + 64), GFP_KERNEL);
+ rctx->data = kzalloc((req->nbytes + 64), GFP_ATOMIC);
if (rctx->data == NULL) {
pr_err("Mem Alloc fail rctx->data, err %ld for 0x%x\n",
@@ -1153,7 +1190,7 @@
return -ENOMEM;
}
num_sg = qcrypto_count_sg(req->src, req->nbytes);
- bytes = sg_copy_to_buffer(req->src, num_sg, rctx->data,
+ bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg, rctx->data,
req->nbytes);
if (bytes != req->nbytes)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes,
@@ -1294,7 +1331,7 @@
rctx->orig_src = req->src;
rctx->orig_dst = req->dst;
rctx->data = kzalloc((req->cryptlen + qreq.assoclen +
- qreq.authsize + 64*2), GFP_KERNEL);
+ qreq.authsize + 64*2), GFP_ATOMIC);
if (rctx->data == NULL) {
pr_err("Mem Alloc fail rctx->data, err %ld\n",
PTR_ERR(rctx->data));
@@ -1305,7 +1342,7 @@
memcpy((char *)rctx->data, qreq.assoc, qreq.assoclen);
num_sg = qcrypto_count_sg(req->src, req->cryptlen);
- bytes = sg_copy_to_buffer(req->src, num_sg,
+ bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg,
rctx->data + qreq.assoclen , req->cryptlen);
if (bytes != req->cryptlen)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x",
@@ -1358,7 +1395,7 @@
int ret = 0;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
again:
spin_lock_irqsave(&cp->lock, flags);
@@ -1434,7 +1471,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1458,7 +1495,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1482,7 +1519,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1506,7 +1543,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1533,7 +1570,7 @@
(ctx->auth_key_len != AES_KEYSIZE_256))
return -EINVAL;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -1542,7 +1579,7 @@
rctx->mode = QCE_MODE_CCM;
rctx->iv = req->iv;
- pstat->aead_sha1_aes_enc++;
+ pstat->aead_ccm_aes_enc++;
return _qcrypto_queue_req(cp, &req->base);
}
@@ -1553,7 +1590,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1574,7 +1611,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1595,7 +1632,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1616,7 +1653,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1637,7 +1674,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1661,7 +1698,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1686,7 +1723,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1712,7 +1749,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1733,7 +1770,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1754,7 +1791,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1775,7 +1812,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1796,7 +1833,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1824,7 +1861,7 @@
(ctx->auth_key_len != AES_KEYSIZE_256))
return -EINVAL;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -1833,7 +1870,7 @@
rctx->mode = QCE_MODE_CCM;
rctx->iv = req->iv;
- pstat->aead_sha1_aes_dec++;
+ pstat->aead_ccm_aes_dec++;
return _qcrypto_queue_req(cp, &req->base);
}
@@ -1939,7 +1976,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
#ifdef QCRYPTO_DEBUG
dev_info(&cp->pdev->dev, "_qcrypto_aead_encrypt_aes_cbc: %p\n", req);
@@ -1963,7 +2000,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
#ifdef QCRYPTO_DEBUG
dev_info(&cp->pdev->dev, "_qcrypto_aead_decrypt_aes_cbc: %p\n", req);
@@ -1988,7 +2025,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
rctx->aead = 1;
@@ -2012,7 +2049,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2032,7 +2069,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2057,7 +2094,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
rctx->aead = 1;
@@ -2081,7 +2118,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2101,7 +2138,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2123,7 +2160,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
rctx->aead = 1;
@@ -2146,7 +2183,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2166,7 +2203,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2188,7 +2225,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
rctx->aead = 1;
@@ -2220,10 +2257,9 @@
static int _sha1_init(struct ahash_request *req)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
- struct crypto_priv *cp = sha_ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
_sha_init(sha_ctx);
sha_ctx->alg = QCE_HASH_SHA1;
@@ -2241,10 +2277,9 @@
static int _sha256_init(struct ahash_request *req)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
- struct crypto_priv *cp = sha_ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
_sha_init(sha_ctx);
sha_ctx->alg = QCE_HASH_SHA256;
@@ -2347,7 +2382,7 @@
srctx = ahash_request_ctx(req);
srctx->orig_src = req->src;
- srctx->data = kzalloc((req->nbytes + 64), GFP_KERNEL);
+ srctx->data = kzalloc((req->nbytes + 64), GFP_ATOMIC);
if (srctx->data == NULL) {
pr_err("Mem Alloc fail rctx->data, err %ld for 0x%x\n",
PTR_ERR(srctx->data), (req->nbytes + 64));
@@ -2355,7 +2390,8 @@
}
num_sg = qcrypto_count_sg(req->src, req->nbytes);
- bytes = sg_copy_to_buffer(req->src, num_sg, srctx->data, req->nbytes);
+ bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg, srctx->data,
+ req->nbytes);
if (bytes != req->nbytes)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes,
req->nbytes);
@@ -2390,7 +2426,7 @@
if (total <= sha_block_size) {
k_src = &sha_ctx->trailing_buf[sha_ctx->trailing_buf_len];
num_sg = qcrypto_count_sg(req->src, len);
- bytes = sg_copy_to_buffer(req->src, num_sg, k_src, len);
+ bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg, k_src, len);
sha_ctx->trailing_buf_len = total;
if (sha_ctx->alg == QCE_HASH_SHA1)
@@ -2431,13 +2467,13 @@
if (sha_ctx->trailing_buf_len) {
if (cp->ce_support.aligned_only) {
sha_ctx->sg = kzalloc(sizeof(struct scatterlist),
- GFP_KERNEL);
+ GFP_ATOMIC);
if (sha_ctx->sg == NULL) {
pr_err("MemAlloc fail sha_ctx->sg, error %ld\n",
PTR_ERR(sha_ctx->sg));
return -ENOMEM;
}
- rctx->data2 = kzalloc((req->nbytes + 64), GFP_KERNEL);
+ rctx->data2 = kzalloc((req->nbytes + 64), GFP_ATOMIC);
if (rctx->data2 == NULL) {
pr_err("Mem Alloc fail srctx->data2, err %ld\n",
PTR_ERR(rctx->data2));
@@ -2458,7 +2494,7 @@
} else {
sg_mark_end(sg_last);
sha_ctx->sg = kzalloc(2 * (sizeof(struct scatterlist)),
- GFP_KERNEL);
+ GFP_ATOMIC);
if (sha_ctx->sg == NULL) {
pr_err("MEMalloc fail sha_ctx->sg, error %ld\n",
PTR_ERR(sha_ctx->sg));
@@ -2688,7 +2724,7 @@
struct crypto_stat *pstat;
int ret = 0;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
pstat->sha1_hmac_digest++;
_sha_init(sha_ctx);
@@ -2715,7 +2751,7 @@
struct crypto_stat *pstat;
int ret = 0;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
pstat->sha256_hmac_digest++;
_sha_init(sha_ctx);
@@ -2853,10 +2889,9 @@
static int _sha1_hmac_digest(struct ahash_request *req)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
- struct crypto_priv *cp = sha_ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
pstat->sha1_hmac_digest++;
_sha_init(sha_ctx);
@@ -2871,10 +2906,9 @@
static int _sha256_hmac_digest(struct ahash_request *req)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
- struct crypto_priv *cp = sha_ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
pstat->sha256_hmac_digest++;
_sha_init(sha_ctx);
@@ -3327,12 +3361,6 @@
int i;
struct msm_ce_hw_support *platform_support;
- if (pdev->id >= MAX_CRYPTO_DEVICE) {
- pr_err("%s: device id %d exceeds allowed %d\n",
- __func__, pdev->id, MAX_CRYPTO_DEVICE);
- return -ENOENT;
- }
-
cp = kzalloc(sizeof(*cp), GFP_KERNEL);
if (!cp) {
pr_err("qcrypto Memory allocation of q_alg FAIL, error %ld\n",
@@ -3572,7 +3600,7 @@
},
};
-static int _debug_qcrypto[MAX_CRYPTO_DEVICE];
+static int _debug_qcrypto;
static int _debug_stats_open(struct inode *inode, struct file *file)
{
@@ -3599,9 +3627,7 @@
size_t count, loff_t *ppos)
{
- int qcrypto = *((int *) file->private_data);
-
- memset((char *)&_qcrypto_stat[qcrypto], 0, sizeof(struct crypto_stat));
+ memset((char *)&_qcrypto_stat, 0, sizeof(struct crypto_stat));
return count;
};
@@ -3615,7 +3641,6 @@
{
int rc;
char name[DEBUG_MAX_FNAME];
- int i;
struct dentry *dent;
_debug_dent = debugfs_create_dir("qcrypto", NULL);
@@ -3625,17 +3650,15 @@
return PTR_ERR(_debug_dent);
}
- for (i = 0; i < MAX_CRYPTO_DEVICE; i++) {
- snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", i+1);
- _debug_qcrypto[i] = i;
- dent = debugfs_create_file(name, 0644, _debug_dent,
- &_debug_qcrypto[i], &_debug_stats_ops);
- if (dent == NULL) {
- pr_err("qcrypto debugfs_create_file fail, error %ld\n",
- PTR_ERR(dent));
- rc = PTR_ERR(dent);
- goto err;
- }
+ snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", 1);
+ _debug_qcrypto = 0;
+ dent = debugfs_create_file(name, 0644, _debug_dent,
+ &_debug_qcrypto, &_debug_stats_ops);
+ if (dent == NULL) {
+ pr_err("qcrypto debugfs_create_file fail, error %ld\n",
+ PTR_ERR(dent));
+ rc = PTR_ERR(dent);
+ goto err;
}
return 0;
err:
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index 245d737..1be2702 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,10 @@
#define _DRIVERS_CRYPTO_MSM_QCRYPTOHW_50_H_
+#define CRYPTO_BAM_CNFG_BITS_REG 0x0007C
+#define CRYPTO_BAM_CD_ENABLE 27
+#define CRYPTO_BAM_CD_ENABLE_MASK (1 << CRYPTO_BAM_CD_ENABLE)
+
#define QCE_AUTH_REG_BYTE_COUNT 4
#define CRYPTO_VERSION_REG 0x1A000
@@ -28,7 +32,7 @@
#define CRYPTO_DATA_OUT3_REG 0x1A02C
#define CRYPTO_STATUS_REG 0x1A100
-#define CRYPTO_STATUS2_REG 0x1A100
+#define CRYPTO_STATUS2_REG 0x1A104
#define CRYPTO_ENGINES_AVAIL 0x1A108
#define CRYPTO_FIFO_SIZES_REG 0x1A10C
@@ -64,9 +68,9 @@
#define CRYPTO_ENCR_PIPE0_KEY2_REG 0x1E008
#define CRYPTO_ENCR_PIPE0_KEY3_REG 0x1E00C
#define CRYPTO_ENCR_PIPE0_KEY4_REG 0x1E010
-#define CRYPTO_ENCR_PIPE0_KEY5_REG 0x1E004
-#define CRYPTO_ENCR_PIPE0_KEY6_REG 0x1E008
-#define CRYPTO_ENCR_PIPE0_KEY7_REG 0x1E00C
+#define CRYPTO_ENCR_PIPE0_KEY5_REG 0x1E014
+#define CRYPTO_ENCR_PIPE0_KEY6_REG 0x1E018
+#define CRYPTO_ENCR_PIPE0_KEY7_REG 0x1E01C
#define CRYPTO_ENCR_PIPE1_KEY0_REG 0x1E020
#define CRYPTO_ENCR_PIPE1_KEY1_REG 0x1E024
@@ -185,56 +189,56 @@
#define CRYPTO_AUTH_PIPE0_KEY14_REG 0x1E838
#define CRYPTO_AUTH_PIPE0_KEY15_REG 0x1E83C
-#define CRYPTO_AUTH_PIPE1_KEY0_REG 0x1E800
-#define CRYPTO_AUTH_PIPE1_KEY1_REG 0x1E804
-#define CRYPTO_AUTH_PIPE1_KEY2_REG 0x1E808
-#define CRYPTO_AUTH_PIPE1_KEY3_REG 0x1E80C
-#define CRYPTO_AUTH_PIPE1_KEY4_REG 0x1E810
-#define CRYPTO_AUTH_PIPE1_KEY5_REG 0x1E814
-#define CRYPTO_AUTH_PIPE1_KEY6_REG 0x1E818
-#define CRYPTO_AUTH_PIPE1_KEY7_REG 0x1E81C
-#define CRYPTO_AUTH_PIPE1_KEY8_REG 0x1E820
-#define CRYPTO_AUTH_PIPE1_KEY9_REG 0x1E824
-#define CRYPTO_AUTH_PIPE1_KEY10_REG 0x1E828
-#define CRYPTO_AUTH_PIPE1_KEY11_REG 0x1E82C
-#define CRYPTO_AUTH_PIPE1_KEY12_REG 0x1E830
-#define CRYPTO_AUTH_PIPE1_KEY13_REG 0x1E834
-#define CRYPTO_AUTH_PIPE1_KEY14_REG 0x1E838
-#define CRYPTO_AUTH_PIPE1_KEY15_REG 0x1E83C
+#define CRYPTO_AUTH_PIPE1_KEY0_REG 0x1E880
+#define CRYPTO_AUTH_PIPE1_KEY1_REG 0x1E884
+#define CRYPTO_AUTH_PIPE1_KEY2_REG 0x1E888
+#define CRYPTO_AUTH_PIPE1_KEY3_REG 0x1E88C
+#define CRYPTO_AUTH_PIPE1_KEY4_REG 0x1E890
+#define CRYPTO_AUTH_PIPE1_KEY5_REG 0x1E894
+#define CRYPTO_AUTH_PIPE1_KEY6_REG 0x1E898
+#define CRYPTO_AUTH_PIPE1_KEY7_REG 0x1E89C
+#define CRYPTO_AUTH_PIPE1_KEY8_REG 0x1E8A0
+#define CRYPTO_AUTH_PIPE1_KEY9_REG 0x1E8A4
+#define CRYPTO_AUTH_PIPE1_KEY10_REG 0x1E8A8
+#define CRYPTO_AUTH_PIPE1_KEY11_REG 0x1E8AC
+#define CRYPTO_AUTH_PIPE1_KEY12_REG 0x1E8B0
+#define CRYPTO_AUTH_PIPE1_KEY13_REG 0x1E8B4
+#define CRYPTO_AUTH_PIPE1_KEY14_REG 0x1E8B8
+#define CRYPTO_AUTH_PIPE1_KEY15_REG 0x1E8BC
-#define CRYPTO_AUTH_PIPE2_KEY0_REG 0x1E840
-#define CRYPTO_AUTH_PIPE2_KEY1_REG 0x1E844
-#define CRYPTO_AUTH_PIPE2_KEY2_REG 0x1E848
-#define CRYPTO_AUTH_PIPE2_KEY3_REG 0x1E84C
-#define CRYPTO_AUTH_PIPE2_KEY4_REG 0x1E850
-#define CRYPTO_AUTH_PIPE2_KEY5_REG 0x1E854
-#define CRYPTO_AUTH_PIPE2_KEY6_REG 0x1E858
-#define CRYPTO_AUTH_PIPE2_KEY7_REG 0x1E85C
-#define CRYPTO_AUTH_PIPE2_KEY8_REG 0x1E860
-#define CRYPTO_AUTH_PIPE2_KEY9_REG 0x1E864
-#define CRYPTO_AUTH_PIPE2_KEY10_REG 0x1E868
-#define CRYPTO_AUTH_PIPE2_KEY11_REG 0x1E86C
-#define CRYPTO_AUTH_PIPE2_KEY12_REG 0x1E870
-#define CRYPTO_AUTH_PIPE2_KEY13_REG 0x1E874
-#define CRYPTO_AUTH_PIPE2_KEY14_REG 0x1E878
-#define CRYPTO_AUTH_PIPE2_KEY15_REG 0x1E87C
+#define CRYPTO_AUTH_PIPE2_KEY0_REG 0x1E900
+#define CRYPTO_AUTH_PIPE2_KEY1_REG 0x1E904
+#define CRYPTO_AUTH_PIPE2_KEY2_REG 0x1E908
+#define CRYPTO_AUTH_PIPE2_KEY3_REG 0x1E90C
+#define CRYPTO_AUTH_PIPE2_KEY4_REG 0x1E910
+#define CRYPTO_AUTH_PIPE2_KEY5_REG 0x1E914
+#define CRYPTO_AUTH_PIPE2_KEY6_REG 0x1E918
+#define CRYPTO_AUTH_PIPE2_KEY7_REG 0x1E91C
+#define CRYPTO_AUTH_PIPE2_KEY8_REG 0x1E920
+#define CRYPTO_AUTH_PIPE2_KEY9_REG 0x1E924
+#define CRYPTO_AUTH_PIPE2_KEY10_REG 0x1E928
+#define CRYPTO_AUTH_PIPE2_KEY11_REG 0x1E92C
+#define CRYPTO_AUTH_PIPE2_KEY12_REG 0x1E930
+#define CRYPTO_AUTH_PIPE2_KEY13_REG 0x1E934
+#define CRYPTO_AUTH_PIPE2_KEY14_REG 0x1E938
+#define CRYPTO_AUTH_PIPE2_KEY15_REG 0x1E93C
-#define CRYPTO_AUTH_PIPE3_KEY0_REG 0x1E880
-#define CRYPTO_AUTH_PIPE3_KEY1_REG 0x1E884
-#define CRYPTO_AUTH_PIPE3_KEY2_REG 0x1E888
-#define CRYPTO_AUTH_PIPE3_KEY3_REG 0x1E88C
-#define CRYPTO_AUTH_PIPE3_KEY4_REG 0x1E890
-#define CRYPTO_AUTH_PIPE3_KEY5_REG 0x1E894
-#define CRYPTO_AUTH_PIPE3_KEY6_REG 0x1E898
-#define CRYPTO_AUTH_PIPE3_KEY7_REG 0x1E89C
-#define CRYPTO_AUTH_PIPE3_KEY8_REG 0x1E8A0
-#define CRYPTO_AUTH_PIPE3_KEY9_REG 0x1E8A4
-#define CRYPTO_AUTH_PIPE3_KEY10_REG 0x1E8A8
-#define CRYPTO_AUTH_PIPE3_KEY11_REG 0x1E8AC
-#define CRYPTO_AUTH_PIPE3_KEY12_REG 0x1E8B0
-#define CRYPTO_AUTH_PIPE3_KEY13_REG 0x1E8B4
-#define CRYPTO_AUTH_PIPE3_KEY14_REG 0x1E8B8
-#define CRYPTO_AUTH_PIPE3_KEY15_REG 0x1E8BC
+#define CRYPTO_AUTH_PIPE3_KEY0_REG 0x1E980
+#define CRYPTO_AUTH_PIPE3_KEY1_REG 0x1E984
+#define CRYPTO_AUTH_PIPE3_KEY2_REG 0x1E988
+#define CRYPTO_AUTH_PIPE3_KEY3_REG 0x1E98C
+#define CRYPTO_AUTH_PIPE3_KEY4_REG 0x1E990
+#define CRYPTO_AUTH_PIPE3_KEY5_REG 0x1E994
+#define CRYPTO_AUTH_PIPE3_KEY6_REG 0x1E998
+#define CRYPTO_AUTH_PIPE3_KEY7_REG 0x1E99C
+#define CRYPTO_AUTH_PIPE3_KEY8_REG 0x1E9A0
+#define CRYPTO_AUTH_PIPE3_KEY9_REG 0x1E9A4
+#define CRYPTO_AUTH_PIPE3_KEY10_REG 0x1E9A8
+#define CRYPTO_AUTH_PIPE3_KEY11_REG 0x1E9AC
+#define CRYPTO_AUTH_PIPE3_KEY12_REG 0x1E9B0
+#define CRYPTO_AUTH_PIPE3_KEY13_REG 0x1E9B4
+#define CRYPTO_AUTH_PIPE3_KEY14_REG 0x1E9B8
+#define CRYPTO_AUTH_PIPE3_KEY15_REG 0x1E9BC
#define CRYPTO_AUTH_IV0_REG 0x1A310
@@ -375,7 +379,7 @@
#define CRYPTO_FIRST 17
#define CRYPTO_LAST 16
-#define CRYPTO_AUTH_POS 15 /* bit 15 .. 14*/
+#define CRYPTO_AUTH_POS 14 /* bit 15 .. 14*/
#define CRYPTO_AUTH_POS_MASK (0x3 << CRYPTO_AUTH_POS)
#define CRYPTO_AUTH_POS_BEFORE 0
#define CRYPTO_AUTH_POS_AFTER 1
@@ -421,6 +425,7 @@
#define CRYPTO_AUTH_ALG_AES 2
#define CRYPTO_AUTH_ALG_KASUMI 3
#define CRYPTO_AUTH_ALG_SNOW3G 4
+#define CRYPTO_AUTH_ALG_ZUC 5
/* encr_xts_du_size reg */
#define CRYPTO_ENCR_XTS_DU_SIZE 0 /* bit 19-0 */
@@ -471,33 +476,49 @@
#define CRYPTO_ENCR_KEY_SZ_3DES 1
#define CRYPTO_ENCR_KEY_SZ_AES128 0
#define CRYPTO_ENCR_KEY_SZ_AES256 2
-#define CRYPTO_ENCR_KEY_SZ_UEA1 0
-#define CRYPTO_ENCR_KEY_SZ_UEA2 1
#define CRYPTO_ENCR_ALG 0 /* bit 2-0 */
#define CRYPTO_ENCR_ALG_MASK (7 << CRYPTO_ENCR_ALG)
#define CRYPTO_ENCR_ALG_NONE 0
#define CRYPTO_ENCR_ALG_DES 1
#define CRYPTO_ENCR_ALG_AES 2
-#define CRYPTO_ENCR_ALG_KASUMI 3
+#define CRYPTO_ENCR_ALG_KASUMI 4
#define CRYPTO_ENCR_ALG_SNOW_3G 5
+#define CRYPTO_ENCR_ALG_ZUC 6
/* goproc reg */
#define CRYPTO_GO 0
#define CRYPTO_CLR_CNTXT 1
#define CRYPTO_RESULTS_DUMP 2
+/* F8 definition of CRYPTO_ENCR_CNTR1_IV1 REG */
+#define CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT 16 /* bit 31 - 16 */
+#define CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT_MASK \
+ (0xffff << CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT)
+
+#define CRYPTO_CNTR1_IV1_REG_F8_BEARER 0 /* bit 4 - 0 */
+#define CRYPTO_CNTR1_IV1_REG_F8_BEARER_MASK \
+ (0x1f << CRYPTO_CNTR1_IV1_REG_F8_BEARER)
+
+/* F9 definition of CRYPTO_AUTH_IV4 REG */
+#define CRYPTO_AUTH_IV4_REG_F9_VALID_BIS 0 /* bit 2 - 0 */
+#define CRYPTO_AUTH_IV4_REG_F9_VALID_BIS_MASK \
+ (0x7 << CRYPTO_AUTH_IV4_REG_F9_VALID_BIS)
/* engines_avail */
#define CRYPTO_ENCR_AES_SEL 0
-#define CRYPTO_DES_SEL 3
-#define CRYPTO_ENCR_SNOW3G_SEL 4
-#define CRYPTO_ENCR_KASUMI_SEL 5
-#define CRYPTO_SHA_SEL 6
-#define CRYPTO_SHA512_SEL 7
-#define CRYPTO_AUTH_AES_SEL 8
-#define CRYPTO_AUTH_SNOW3G_SEL 9
-#define CRYPTO_AUTH_KASUMI_SEL 10
-#define CRYPTO_BAM_SEL 11
-
+#define CRYPTO_DES_SEL 1
+#define CRYPTO_ENCR_SNOW3G_SEL 2
+#define CRYPTO_ENCR_KASUMI_SEL 3
+#define CRYPTO_SHA_SEL 4
+#define CRYPTO_SHA512_SEL 5
+#define CRYPTO_AUTH_AES_SEL 6
+#define CRYPTO_AUTH_SNOW3G_SEL 7
+#define CRYPTO_AUTH_KASUMI_SEL 8
+#define CRYPTO_BAM_PIPE_SETS 9 /* bit 12 - 9 */
+#define CRYPTO_AXI_WR_BEATS 13 /* bit 18 - 13 */
+#define CRYPTO_AXI_RD_BEATS 19 /* bit 24 - 19 */
+#define CRYPTO_ENCR_ZUC_SEL 26
+#define CRYPTO_AUTH_ZUC_SEL 27
+#define CRYPTO_ZUC_ENABLE 28
#endif /* _DRIVERS_CRYPTO_MSM_QCRYPTOHW_50_H_ */
diff --git a/drivers/gpu/ion/Kconfig b/drivers/gpu/ion/Kconfig
index 39133b5..5bb254b 100644
--- a/drivers/gpu/ion/Kconfig
+++ b/drivers/gpu/ion/Kconfig
@@ -16,12 +16,3 @@
depends on ARCH_MSM && ION
help
Choose this option if you wish to use ion on an MSM target.
-
-config ION_LEAK_CHECK
- bool "Check for leaked Ion buffers (debugging)"
- depends on ION
- help
- Choose this option if you wish to enable checking for leaked
- ion buffers at runtime. Choosing this option will also add a
- debugfs node under the ion directory that can be used to
- enable/disable the leak checking.
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index d7ff73a..0e460c8 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -1,6 +1,5 @@
-obj-$(CONFIG_ION) += ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o \
- ion_iommu_heap.o ion_cp_heap.o ion_removed_heap.o \
- ion_page_pool.o ion_chunk_heap.o
+obj-$(CONFIG_ION) += ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \
+ ion_carveout_heap.o ion_chunk_heap.o
obj-$(CONFIG_CMA) += ion_cma_heap.o ion_cma_secure_heap.o
obj-$(CONFIG_ION_TEGRA) += tegra/
-obj-$(CONFIG_ION_MSM) += msm/
+obj-$(CONFIG_ION_MSM) += ion_iommu_heap.o ion_cp_heap.o ion_removed_heap.o msm/
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index fbe4da0..250b387 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -16,7 +16,6 @@
*
*/
-#include <linux/module.h>
#include <linux/device.h>
#include <linux/file.h>
#include <linux/freezer.h>
@@ -27,6 +26,7 @@
#include <linux/list.h>
#include <linux/memblock.h>
#include <linux/miscdevice.h>
+#include <linux/export.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/rbtree.h>
@@ -41,7 +41,6 @@
#include <trace/events/kmem.h>
-#include <mach/iommu_domains.h>
#include "ion_priv.h"
/**
@@ -83,7 +82,6 @@
struct ion_device *dev;
struct rb_root handles;
struct mutex lock;
- unsigned int heap_type_mask;
char *name;
struct task_struct *task;
pid_t pid;
@@ -108,7 +106,6 @@
struct ion_buffer *buffer;
struct rb_node node;
unsigned int kmap_cnt;
- unsigned int iommu_map_cnt;
};
bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
@@ -545,8 +542,8 @@
mutex_lock(&client->lock);
valid_handle = ion_handle_validate(client, handle);
if (!valid_handle) {
- mutex_unlock(&client->lock);
WARN(1, "%s: invalid handle passed to free.\n", __func__);
+ mutex_unlock(&client->lock);
return;
}
ion_handle_put(handle);
@@ -678,30 +675,21 @@
struct ion_client *client = s->private;
struct rb_node *n;
- seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s : %12.12s : %s\n",
+ seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s\n",
"heap_name", "size_in_bytes", "handle refcount",
- "buffer", "physical", "[domain,partition] - virt");
+ "buffer");
mutex_lock(&client->lock);
for (n = rb_first(&client->handles); n; n = rb_next(n)) {
struct ion_handle *handle = rb_entry(n, struct ion_handle,
node);
- enum ion_heap_type type = handle->buffer->heap->type;
-
seq_printf(s, "%16.16s: %16x : %16d : %12p",
handle->buffer->heap->name,
handle->buffer->size,
atomic_read(&handle->ref.refcount),
handle->buffer);
- if (type == ION_HEAP_TYPE_SYSTEM_CONTIG ||
- type == ION_HEAP_TYPE_CARVEOUT ||
- type == (enum ion_heap_type) ION_HEAP_TYPE_CP)
- seq_printf(s, " : %12pa", &handle->buffer->priv_phys);
- else
- seq_printf(s, " : %12s", "N/A");
-
seq_printf(s, "\n");
}
mutex_unlock(&client->lock);
@@ -1287,8 +1275,8 @@
ion_free(client, data.handle);
break;
}
- case ION_IOC_MAP:
case ION_IOC_SHARE:
+ case ION_IOC_MAP:
{
struct ion_fd_data data;
if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
@@ -1391,7 +1379,7 @@
};
static size_t ion_debug_heap_total(struct ion_client *client,
- enum ion_heap_ids id)
+ unsigned int id)
{
size_t size = 0;
struct rb_node *n;
@@ -1560,7 +1548,6 @@
size_t total_size = 0;
size_t total_orphaned_size = 0;
- mutex_lock(&dev->buffer_lock);
seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size");
seq_printf(s, "----------------------------------------------------\n");
@@ -1584,25 +1571,31 @@
seq_printf(s, "----------------------------------------------------\n");
seq_printf(s, "orphaned allocations (info is from last known client):"
"\n");
+ mutex_lock(&dev->buffer_lock);
for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
struct ion_buffer *buffer = rb_entry(n, struct ion_buffer,
node);
- if (buffer->heap->type == heap->type)
- total_size += buffer->size;
+ if (buffer->heap->id != heap->id)
+ continue;
+ total_size += buffer->size;
if (!buffer->handle_count) {
- seq_printf(s, "%16.s %16u %16u\n", buffer->task_comm,
- buffer->pid, buffer->size);
+ seq_printf(s, "%16.s %16u %16u %d %d\n", buffer->task_comm,
+ buffer->pid, buffer->size, buffer->kmap_cnt,
+ atomic_read(&buffer->ref.refcount));
total_orphaned_size += buffer->size;
}
}
+ mutex_unlock(&dev->buffer_lock);
seq_printf(s, "----------------------------------------------------\n");
seq_printf(s, "%16.s %16u\n", "total orphaned",
total_orphaned_size);
seq_printf(s, "%16.s %16u\n", "total ", total_size);
seq_printf(s, "----------------------------------------------------\n");
+ if (heap->debug_show)
+ heap->debug_show(heap, s, unused);
+
ion_heap_print_debug(s, heap);
- mutex_unlock(&dev->buffer_lock);
return 0;
}
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 0dd3054..08921299 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -37,7 +37,6 @@
ion_phys_addr_t base;
unsigned long allocated_bytes;
unsigned long total_size;
- unsigned int has_outer_cache;
};
ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap,
@@ -254,7 +253,6 @@
carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
carveout_heap->allocated_bytes = 0;
carveout_heap->total_size = heap_data->size;
- carveout_heap->has_outer_cache = heap_data->has_outer_cache;
return &carveout_heap->heap;
}
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 4b724df..e3fbbda 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -247,14 +247,12 @@
unsigned long align);
void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
unsigned long size);
-
/**
* The carveout heap returns physical addresses, since 0 may be a valid
* physical address, this is used to indicate allocation failed
*/
#define ION_CARVEOUT_ALLOCATE_FAIL -1
-
/**
* functions for creating and destroying a heap pool -- allows you
* to keep a pool of pre allocated memory to use from your heap. Keeping
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 4e9f55c..fb6dc2d 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -25,17 +25,10 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
-#include <linux/seq_file.h>
#include "ion_priv.h"
-#include <mach/memory.h>
-#include <asm/cacheflush.h>
-#include <linux/msm_ion.h>
#include <linux/dma-mapping.h>
#include <trace/events/kmem.h>
-static atomic_t system_heap_allocated;
-static atomic_t system_contig_heap_allocated;
-
static unsigned int high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO |
__GFP_NOWARN | __GFP_NORETRY |
__GFP_NO_KSWAPD) & ~__GFP_WAIT;
@@ -212,7 +205,6 @@
}
buffer->priv_virt = table;
- atomic_add(size, &system_heap_allocated);
return 0;
err1:
kfree(table);
@@ -246,7 +238,6 @@
get_order(sg_dma_len(sg)));
sg_free_table(table);
kfree(table);
- atomic_sub(buffer->size, &system_heap_allocated);
}
struct sg_table *ion_system_heap_map_dma(struct ion_heap *heap,
@@ -261,15 +252,6 @@
return;
}
-static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s,
- const struct rb_root *unused)
-{
- seq_printf(s, "total bytes currently allocated: %lx\n",
- (unsigned long) atomic_read(&system_heap_allocated));
-
- return 0;
-}
-
static struct ion_heap_ops system_heap_ops = {
.allocate = ion_system_heap_allocate,
.free = ion_system_heap_free,
@@ -278,10 +260,29 @@
.map_kernel = ion_heap_map_kernel,
.unmap_kernel = ion_heap_unmap_kernel,
.map_user = ion_heap_map_user,
- .print_debug = ion_system_print_debug,
};
-struct ion_heap *ion_system_heap_create(struct ion_platform_heap *pheap)
+static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
+ void *unused)
+{
+
+ struct ion_system_heap *sys_heap = container_of(heap,
+ struct ion_system_heap,
+ heap);
+ int i;
+ for (i = 0; i < num_orders; i++) {
+ struct ion_page_pool *pool = sys_heap->pools[i];
+ seq_printf(s, "%d order %u highmem pages in pool = %lu total\n",
+ pool->high_count, pool->order,
+ (1 << pool->order) * PAGE_SIZE * pool->high_count);
+ seq_printf(s, "%d order %u lowmem pages in pool = %lu total\n",
+ pool->low_count, pool->order,
+ (1 << pool->order) * PAGE_SIZE * pool->low_count);
+ }
+ return 0;
+}
+
+struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
{
struct ion_system_heap *heap;
int i;
@@ -307,6 +308,7 @@
goto err_create_pool;
heap->pools[i] = pool;
}
+ heap->heap.debug_show = ion_system_heap_debug_show;
return &heap->heap;
err_create_pool:
for (i = 0; i < num_orders; i++)
@@ -340,14 +342,12 @@
buffer->priv_virt = kzalloc(len, GFP_KERNEL);
if (!buffer->priv_virt)
return -ENOMEM;
- atomic_add(len, &system_contig_heap_allocated);
return 0;
}
void ion_system_contig_heap_free(struct ion_buffer *buffer)
{
kfree(buffer->priv_virt);
- atomic_sub(buffer->size, &system_contig_heap_allocated);
}
static int ion_system_contig_heap_phys(struct ion_heap *heap,
@@ -385,44 +385,6 @@
kfree(buffer->sg_table);
}
-int ion_system_contig_heap_map_user(struct ion_heap *heap,
- struct ion_buffer *buffer,
- struct vm_area_struct *vma)
-{
- unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv_virt));
-
- if (ION_IS_CACHED(buffer->flags))
- return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot);
- else {
- pr_err("%s: cannot map system heap uncached\n", __func__);
- return -EINVAL;
- }
-}
-
-static int ion_system_contig_print_debug(struct ion_heap *heap,
- struct seq_file *s,
- const struct rb_root *unused)
-{
- seq_printf(s, "total bytes currently allocated: %lx\n",
- (unsigned long) atomic_read(&system_contig_heap_allocated));
-
- return 0;
-}
-
-void *ion_system_contig_heap_map_kernel(struct ion_heap *heap,
- struct ion_buffer *buffer)
-{
- return buffer->priv_virt;
-}
-
-void ion_system_contig_heap_unmap_kernel(struct ion_heap *heap,
- struct ion_buffer *buffer)
-{
- return;
-}
-
static struct ion_heap_ops kmalloc_ops = {
.allocate = ion_system_contig_heap_allocate,
.free = ion_system_contig_heap_free,
@@ -431,11 +393,10 @@
.unmap_dma = ion_system_contig_heap_unmap_dma,
.map_kernel = ion_heap_map_kernel,
.unmap_kernel = ion_heap_unmap_kernel,
- .map_user = ion_system_contig_heap_map_user,
- .print_debug = ion_system_contig_print_debug,
+ .map_user = ion_heap_map_user,
};
-struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *pheap)
+struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused)
{
struct ion_heap *heap;
diff --git a/drivers/gpu/ion/msm/ion_iommu_map.c b/drivers/gpu/ion/msm/ion_iommu_map.c
index 5ce03db..0a4fe1f 100644
--- a/drivers/gpu/ion/msm/ion_iommu_map.c
+++ b/drivers/gpu/ion/msm/ion_iommu_map.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/dma-buf.h>
#include <linux/export.h>
#include <linux/iommu.h>
#include <linux/ion.h>
@@ -69,6 +70,7 @@
struct sg_table *table;
unsigned long size;
struct mutex lock;
+ struct dma_buf *dbuf;
};
static struct rb_root iommu_root;
@@ -85,9 +87,9 @@
parent = *p;
entry = rb_entry(parent, struct ion_iommu_meta, node);
- if (meta->handle < entry->handle) {
+ if (meta->table < entry->table) {
p = &(*p)->rb_left;
- } else if (meta->handle > entry->handle) {
+ } else if (meta->table > entry->table) {
p = &(*p)->rb_right;
} else {
pr_err("%s: handle %p already exists\n", __func__,
@@ -101,7 +103,7 @@
}
-static struct ion_iommu_meta *ion_iommu_meta_lookup(struct ion_handle *handle)
+static struct ion_iommu_meta *ion_iommu_meta_lookup(struct sg_table *table)
{
struct rb_root *root = &iommu_root;
struct rb_node **p = &root->rb_node;
@@ -112,9 +114,9 @@
parent = *p;
entry = rb_entry(parent, struct ion_iommu_meta, node);
- if (handle < entry->handle)
+ if (table < entry->table)
p = &(*p)->rb_left;
- else if (handle > entry->handle)
+ else if (table > entry->table)
p = &(*p)->rb_right;
else
return entry;
@@ -319,7 +321,8 @@
return ERR_PTR(ret);
}
-static struct ion_iommu_meta *ion_iommu_meta_create(struct ion_handle *handle,
+static struct ion_iommu_meta *ion_iommu_meta_create(struct ion_client *client,
+ struct ion_handle *handle,
struct sg_table *table,
unsigned long size)
{
@@ -333,6 +336,7 @@
meta->handle = handle;
meta->table = table;
meta->size = size;
+ meta->dbuf = ion_share_dma_buf(client, handle);
kref_init(&meta->ref);
mutex_init(&meta->lock);
ion_iommu_meta_add(meta);
@@ -347,6 +351,7 @@
rb_erase(&meta->node, &iommu_root);
+ dma_buf_put(meta->dbuf);
kfree(meta);
}
@@ -427,13 +432,13 @@
}
mutex_lock(&msm_iommu_map_mutex);
- iommu_meta = ion_iommu_meta_lookup(handle);
+ iommu_meta = ion_iommu_meta_lookup(table);
if (!iommu_meta)
- iommu_meta = ion_iommu_meta_create(handle, table, size);
+ iommu_meta = ion_iommu_meta_create(client, handle, table, size);
else
kref_get(&iommu_meta->ref);
-
+ BUG_ON(iommu_meta->size != size);
mutex_unlock(&msm_iommu_map_mutex);
iommu_map = ion_iommu_lookup(iommu_meta, domain_num, partition_num);
@@ -493,6 +498,7 @@
{
struct ion_iommu_map *iommu_map;
struct ion_iommu_meta *meta;
+ struct sg_table *table;
if (IS_ERR_OR_NULL(client)) {
pr_err("%s: client pointer is invalid\n", __func__);
@@ -503,13 +509,14 @@
return;
}
+ table = ion_sg_table(client, handle);
mutex_lock(&msm_iommu_map_mutex);
- meta = ion_iommu_meta_lookup(handle);
+ meta = ion_iommu_meta_lookup(table);
if (!meta) {
WARN(1, "%s: (%d,%d) was never mapped for %p\n", __func__,
domain_num, partition_num, handle);
- mutex_lock(&msm_iommu_map_mutex);
+ mutex_unlock(&msm_iommu_map_mutex);
goto out;
}
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index f43d276..4a45313 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -89,7 +89,7 @@
},
{
.id = ION_QSECOM_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
+ .type = ION_HEAP_TYPE_DMA,
.name = ION_QSECOM_HEAP_NAME,
},
{
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 60bab32..a4f60f9 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -101,13 +101,6 @@
.iomemname = KGSL_3D0_REG_MEMORY,
.shadermemname = KGSL_3D0_SHADER_MEMORY,
.ftbl = &adreno_functable,
-#ifdef CONFIG_HAS_EARLYSUSPEND
- .display_off = {
- .level = EARLY_SUSPEND_LEVEL_STOP_DRAWING,
- .suspend = kgsl_early_suspend_driver,
- .resume = kgsl_late_resume_driver,
- },
-#endif
},
.gmem_base = 0,
.gmem_size = SZ_256K,
@@ -810,8 +803,11 @@
int num_iommu_units;
struct kgsl_context *context;
struct adreno_context *adreno_ctx = NULL;
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- if (!adreno_dev->drawctxt_active) {
+ if (!adreno_dev->drawctxt_active ||
+ KGSL_STATE_ACTIVE != device->state ||
+ !device->active_cnt) {
kgsl_mmu_device_setstate(&device->mmu, flags);
return;
}
@@ -863,12 +859,9 @@
*/
adreno_ringbuffer_issuecmds(device, adreno_ctx, KGSL_CMD_FLAGS_PMODE,
&link[0], sizedwords);
- /* timestamp based clock gating is currently unstable on iommuv1 */
- if (msm_soc_version_supports_iommu_v0()) {
- struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- kgsl_mmu_disable_clk_on_ts(&device->mmu,
- rb->timestamp[KGSL_MEMSTORE_GLOBAL], true);
- }
+
+ kgsl_mmu_disable_clk_on_ts(&device->mmu,
+ rb->timestamp[KGSL_MEMSTORE_GLOBAL], true);
kgsl_context_put(context);
}
@@ -1720,6 +1713,7 @@
{
int status = -EINVAL;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ unsigned int state = device->state;
kgsl_cffdump_open(device);
@@ -1781,8 +1775,11 @@
kgsl_mmu_stop(&device->mmu);
error_clk_off:
- if (KGSL_STATE_DUMP_AND_FT != device->state)
+ if (KGSL_STATE_DUMP_AND_FT != device->state) {
kgsl_pwrctrl_disable(device);
+ /* set the state back to original state */
+ kgsl_pwrctrl_set_state(device, state);
+ }
return status;
}
@@ -2324,7 +2321,7 @@
}
/* Check if we detected a long running IB, if false return */
- if (adreno_dev->long_ib) {
+ if ((adreno_context) && (adreno_dev->long_ib)) {
long_ib = _adreno_check_long_ib(device);
if (!long_ib) {
adreno_context->flags &= ~CTXT_FLAGS_GPU_HANG;
@@ -2774,9 +2771,6 @@
unsigned long wait;
unsigned long timeout = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
- if (!(rb->flags & KGSL_FLAGS_STARTED))
- return 0;
-
/*
* The first time into the loop, wait for 100 msecs and kick wptr again
* to ensure that the hardware has updated correctly. After that, kick
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index a76ed87..144c3d6 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -785,13 +785,13 @@
struct kgsl_memdesc *memdesc =
adreno_find_ctxtmem(device, ptbase, ibaddr,
- ibsize);
+ ibsize << 2);
/* IOMMU uses a NOP IB placed in setsate memory */
if (NULL == memdesc)
if (kgsl_gpuaddr_in_memdesc(
&device->mmu.setstate_memory,
- ibaddr, ibsize))
+ ibaddr, ibsize << 2))
memdesc = &device->mmu.setstate_memory;
/*
* The IB from CP_IB1_BASE and the IBs for legacy
@@ -822,7 +822,8 @@
int remain, void *priv)
{
struct kgsl_snapshot_replay_mem_list *header = snapshot;
- struct kgsl_process_private *private;
+ struct kgsl_process_private *private = NULL;
+ struct kgsl_process_private *tmp_private;
unsigned int ptbase;
struct rb_node *node;
struct kgsl_mem_entry *entry = NULL;
@@ -831,10 +832,12 @@
ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
mutex_lock(&kgsl_driver.process_mutex);
- list_for_each_entry(private, &kgsl_driver.process_list, list) {
- if (kgsl_mmu_pt_equal(&device->mmu, private->pagetable,
- ptbase))
+ list_for_each_entry(tmp_private, &kgsl_driver.process_list, list) {
+ if (kgsl_mmu_pt_equal(&device->mmu, tmp_private->pagetable,
+ ptbase)) {
+ private = tmp_private;
break;
+ }
}
mutex_unlock(&kgsl_driver.process_mutex);
if (!private) {
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 5275267..992f88d 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -144,10 +144,13 @@
* @ptbase - the pagetable base of the object
* @gpuaddr - the GPU address of the object
* @size - Size of the region to search
+ *
+ * Caller must kgsl_mem_entry_put() the returned entry when finished using it.
*/
-struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device,
- unsigned int ptbase, unsigned int gpuaddr, unsigned int size)
+struct kgsl_mem_entry * __must_check
+kgsl_get_mem_entry(struct kgsl_device *device, unsigned int ptbase,
+ unsigned int gpuaddr, unsigned int size)
{
struct kgsl_process_private *priv;
struct kgsl_mem_entry *entry;
@@ -157,15 +160,12 @@
list_for_each_entry(priv, &kgsl_driver.process_list, list) {
if (!kgsl_mmu_pt_equal(&device->mmu, priv->pagetable, ptbase))
continue;
- spin_lock(&priv->mem_lock);
entry = kgsl_sharedmem_find_region(priv, gpuaddr, size);
if (entry) {
- spin_unlock(&priv->mem_lock);
mutex_unlock(&kgsl_driver.process_mutex);
return entry;
}
- spin_unlock(&priv->mem_lock);
}
mutex_unlock(&kgsl_driver.process_mutex);
@@ -308,16 +308,28 @@
static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)
{
+ bool had_gpuaddr = false;
+
if (entry == NULL)
return;
+ /*
+ * Unmap the entry first so that there isn't a period of
+ * time where kgsl doesn't know about the address range
+ * but it is still present in the pagetable. Unmapping will
+ * clear the gpuaddr field, so remember if we had a mapping,
+ * and an rbtree entry for later.
+ */
+ had_gpuaddr = entry->memdesc.gpuaddr != 0;
+ kgsl_mmu_unmap(entry->memdesc.pagetable, &entry->memdesc);
+
spin_lock(&entry->priv->mem_lock);
if (entry->id != 0)
idr_remove(&entry->priv->mem_idr, entry->id);
entry->id = 0;
- if (entry->memdesc.gpuaddr != 0)
+ if (had_gpuaddr)
rb_erase(&entry->node, &entry->priv->mem_rb);
spin_unlock(&entry->priv->mem_lock);
@@ -325,7 +337,6 @@
entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
entry->priv = NULL;
- kgsl_mmu_unmap(entry->memdesc.pagetable, &entry->memdesc);
kgsl_mem_entry_put(entry);
}
@@ -614,20 +625,6 @@
};
EXPORT_SYMBOL(kgsl_pm_ops);
-void kgsl_early_suspend_driver(struct early_suspend *h)
-{
- struct kgsl_device *device = container_of(h,
- struct kgsl_device, display_off);
- KGSL_PWR_WARN(device, "early suspend start\n");
- mutex_lock(&device->mutex);
- device->pwrctrl.restore_slumber = true;
- kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
- kgsl_pwrctrl_sleep(device);
- mutex_unlock(&device->mutex);
- KGSL_PWR_WARN(device, "early suspend end\n");
-}
-EXPORT_SYMBOL(kgsl_early_suspend_driver);
-
int kgsl_suspend_driver(struct platform_device *pdev,
pm_message_t state)
{
@@ -643,101 +640,44 @@
}
EXPORT_SYMBOL(kgsl_resume_driver);
-void kgsl_late_resume_driver(struct early_suspend *h)
+/**
+ * kgsl_destroy_process_private() - Cleanup function to free process private
+ * @kref: - Pointer to object being destroyed's kref struct
+ * Free struct object and all other resources attached to it.
+ * Since the function can be used when not all resources inside process
+ * private have been allocated, there is a check to (before each resource
+ * cleanup) see if the struct member being cleaned is in fact allocated or not.
+ * If the value is not NULL, resource is freed.
+ */
+static void kgsl_destroy_process_private(struct kref *kref)
{
- struct kgsl_device *device = container_of(h,
- struct kgsl_device, display_off);
- KGSL_PWR_WARN(device, "late resume start\n");
- mutex_lock(&device->mutex);
- device->pwrctrl.restore_slumber = false;
- if (device->pwrscale.policy == NULL)
- kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
- if (kgsl_pwrctrl_wake(device) != 0)
- return;
- /*
- * We don't have a way to go directly from
- * a deeper sleep state to NAP, which is
- * the desired state here.
- */
- kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
- kgsl_pwrctrl_sleep(device);
- mutex_unlock(&device->mutex);
- KGSL_PWR_WARN(device, "late resume end\n");
-}
-EXPORT_SYMBOL(kgsl_late_resume_driver);
-/* file operations */
-static struct kgsl_process_private *
-kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv)
-{
- struct kgsl_process_private *private;
-
- mutex_lock(&kgsl_driver.process_mutex);
- list_for_each_entry(private, &kgsl_driver.process_list, list) {
- if (private->pid == task_tgid_nr(current)) {
- private->refcnt++;
- goto out;
- }
- }
-
- /* no existing process private found for this dev_priv, create one */
- private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL);
- if (private == NULL) {
- KGSL_DRV_ERR(cur_dev_priv->device, "kzalloc(%d) failed\n",
- sizeof(struct kgsl_process_private));
- goto out;
- }
-
- spin_lock_init(&private->mem_lock);
- private->refcnt = 1;
- private->pid = task_tgid_nr(current);
- private->mem_rb = RB_ROOT;
-
- idr_init(&private->mem_idr);
-
- if (kgsl_mmu_enabled())
- {
- unsigned long pt_name;
- struct kgsl_mmu *mmu = &cur_dev_priv->device->mmu;
-
- pt_name = task_tgid_nr(current);
- private->pagetable = kgsl_mmu_getpagetable(mmu, pt_name);
- if (private->pagetable == NULL) {
- kfree(private);
- private = NULL;
- goto out;
- }
- }
-
- list_add(&private->list, &kgsl_driver.process_list);
-
- kgsl_process_init_sysfs(private);
- kgsl_process_init_debugfs(private);
-
-out:
- mutex_unlock(&kgsl_driver.process_mutex);
- return private;
-}
-
-static void
-kgsl_put_process_private(struct kgsl_device *device,
- struct kgsl_process_private *private)
-{
struct kgsl_mem_entry *entry = NULL;
int next = 0;
- if (!private)
+
+ struct kgsl_process_private *private = container_of(kref,
+ struct kgsl_process_private, refcount);
+
+ /*
+ * Remove this process from global process list
+ * We do not acquire a lock first as it is expected that
+ * kgsl_destroy_process_private() is only going to be called
+ * through kref_put() which is only called after acquiring
+ * the lock.
+ */
+ if (!private) {
+ KGSL_CORE_ERR("Cannot destroy null process private\n");
+ mutex_unlock(&kgsl_driver.process_mutex);
return;
-
- mutex_lock(&kgsl_driver.process_mutex);
-
- if (--private->refcnt)
- goto unlock;
-
- kgsl_process_uninit_sysfs(private);
- debugfs_remove_recursive(private->debug_root);
-
+ }
list_del(&private->list);
+ mutex_unlock(&kgsl_driver.process_mutex);
+
+ if (private->kobj.parent)
+ kgsl_process_uninit_sysfs(private);
+ if (private->debug_root)
+ debugfs_remove_recursive(private->debug_root);
while (1) {
rcu_read_lock();
@@ -755,9 +695,110 @@
}
kgsl_mmu_putpagetable(private->pagetable);
idr_destroy(&private->mem_idr);
+
kfree(private);
-unlock:
+ return;
+}
+
+static void
+kgsl_put_process_private(struct kgsl_device *device,
+ struct kgsl_process_private *private)
+{
+ mutex_lock(&kgsl_driver.process_mutex);
+
+ /*
+ * kref_put() returns 1 when the refcnt has reached 0 and the destroy
+ * function is called. Mutex is released in the destroy function if
+ * its called, so only release mutex if kref_put() return 0
+ */
+ if (!kref_put(&private->refcount, kgsl_destroy_process_private))
+ mutex_unlock(&kgsl_driver.process_mutex);
+ return;
+}
+
+/**
+ * find_process_private() - Helper function to search for process private
+ * @cur_dev_priv: Pointer to device private structure which contains pointers
+ * to device and process_private structs.
+ * Returns: Pointer to the found/newly created private struct
+ */
+static struct kgsl_process_private *
+kgsl_find_process_private(struct kgsl_device_private *cur_dev_priv)
+{
+ struct kgsl_process_private *private;
+
+ /* Search in the process list */
+ mutex_lock(&kgsl_driver.process_mutex);
+ list_for_each_entry(private, &kgsl_driver.process_list, list) {
+ if (private->pid == task_tgid_nr(current)) {
+ kref_get(&private->refcount);
+ goto done;
+ }
+ }
+
+ /* no existing process private found for this dev_priv, create one */
+ private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL);
+ if (private == NULL) {
+ KGSL_DRV_ERR(cur_dev_priv->device, "kzalloc(%d) failed\n",
+ sizeof(struct kgsl_process_private));
+ goto done;
+ }
+
+ kref_init(&private->refcount);
+
+ private->pid = task_tgid_nr(current);
+ spin_lock_init(&private->mem_lock);
+ mutex_init(&private->process_private_mutex);
+ /* Add the newly created process struct obj to the process list */
+ list_add(&private->list, &kgsl_driver.process_list);
+done:
mutex_unlock(&kgsl_driver.process_mutex);
+ return private;
+}
+
+/**
+ * kgsl_get_process_private() - Used to find the process private structure
+ * @cur_dev_priv: Current device pointer
+ * Finds or creates a new porcess private structire and initializes its members
+ * Returns: Pointer to the private process struct obj found/created or
+ * NULL if pagetable creation for this process private obj failed.
+ */
+static struct kgsl_process_private *
+kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv)
+{
+ struct kgsl_process_private *private;
+
+ private = kgsl_find_process_private(cur_dev_priv);
+
+ mutex_lock(&private->process_private_mutex);
+
+ if (!private->mem_rb.rb_node) {
+ private->mem_rb = RB_ROOT;
+ idr_init(&private->mem_idr);
+ }
+
+ if ((!private->pagetable) && kgsl_mmu_enabled()) {
+ unsigned long pt_name;
+ struct kgsl_mmu *mmu = &cur_dev_priv->device->mmu;
+
+ pt_name = task_tgid_nr(current);
+ private->pagetable = kgsl_mmu_getpagetable(mmu, pt_name);
+ if (private->pagetable == NULL) {
+ mutex_unlock(&private->process_private_mutex);
+ kgsl_put_process_private(cur_dev_priv->device,
+ private);
+ return NULL;
+ }
+ }
+
+ if (!private->kobj.parent)
+ kgsl_process_init_sysfs(private);
+ if (!private->debug_root)
+ kgsl_process_init_debugfs(private);
+
+ mutex_unlock(&private->process_private_mutex);
+
+ return private;
}
static int kgsl_release(struct inode *inodep, struct file *filep)
@@ -868,7 +909,12 @@
result = device->ftbl->start(device);
if (result)
goto err_freedevpriv;
-
+ /*
+ * Make sure the gates are open, so they don't block until
+ * we start suspend or FT.
+ */
+ complete_all(&device->ft_gate);
+ complete_all(&device->hwaccess_gate);
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
kgsl_active_count_put(device);
}
@@ -913,8 +959,17 @@
return result;
}
-/*call with private->mem_lock locked */
-struct kgsl_mem_entry *
+/**
+ * kgsl_sharedmem_find_region() - Find a gpu memory allocation
+ *
+ * @private: private data for the process to check.
+ * @gpuaddr: start address of the region
+ * @size: size of the region
+ *
+ * Find a gpu allocation. Caller must kgsl_mem_entry_put()
+ * the returned entry when finished using it.
+ */
+struct kgsl_mem_entry * __must_check
kgsl_sharedmem_find_region(struct kgsl_process_private *private,
unsigned int gpuaddr, size_t size)
{
@@ -923,46 +978,57 @@
if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, gpuaddr))
return NULL;
+ spin_lock(&private->mem_lock);
while (node != NULL) {
struct kgsl_mem_entry *entry;
entry = rb_entry(node, struct kgsl_mem_entry, node);
-
- if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size))
+ if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) {
+ kgsl_mem_entry_get(entry);
+ spin_unlock(&private->mem_lock);
return entry;
-
+ }
if (gpuaddr < entry->memdesc.gpuaddr)
node = node->rb_left;
else if (gpuaddr >=
(entry->memdesc.gpuaddr + entry->memdesc.size))
node = node->rb_right;
else {
+ spin_unlock(&private->mem_lock);
return NULL;
}
}
+ spin_unlock(&private->mem_lock);
return NULL;
}
EXPORT_SYMBOL(kgsl_sharedmem_find_region);
-/*call with private->mem_lock locked */
-static inline struct kgsl_mem_entry *
+/**
+ * kgsl_sharedmem_find() - Find a gpu memory allocation
+ *
+ * @private: private data for the process to check.
+ * @gpuaddr: start address of the region
+ *
+ * Find a gpu allocation. Caller must kgsl_mem_entry_put()
+ * the returned entry when finished using it.
+ */
+static inline struct kgsl_mem_entry * __must_check
kgsl_sharedmem_find(struct kgsl_process_private *private, unsigned int gpuaddr)
{
return kgsl_sharedmem_find_region(private, gpuaddr, 1);
}
/**
- * kgsl_sharedmem_region_empty - Check if an addression region is empty
+ * kgsl_sharedmem_region_empty() - Check if an addression region is empty
*
* @private: private data for the process to check.
* @gpuaddr: start address of the region
* @size: length of the region.
*
* Checks that there are no existing allocations within an address
- * region. Note that unlike other kgsl_sharedmem* search functions,
- * this one manages locking on its own.
+ * region.
*/
int
kgsl_sharedmem_region_empty(struct kgsl_process_private *private,
@@ -1006,19 +1072,24 @@
}
/**
- * kgsl_sharedmem_find_id - find a memory entry by id
+ * kgsl_sharedmem_find_id() - find a memory entry by id
* @process: the owning process
* @id: id to find
*
* @returns - the mem_entry or NULL
+ *
+ * Caller must kgsl_mem_entry_put() the returned entry, when finished using
+ * it.
*/
-static inline struct kgsl_mem_entry *
+static inline struct kgsl_mem_entry * __must_check
kgsl_sharedmem_find_id(struct kgsl_process_private *process, unsigned int id)
{
struct kgsl_mem_entry *entry;
rcu_read_lock();
entry = idr_find(&process->mem_idr, id);
+ if (entry)
+ kgsl_mem_entry_get(entry);
rcu_read_unlock();
return entry;
@@ -1314,23 +1385,26 @@
struct kgsl_device *device = dev_priv->device;
unsigned int context_id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
- spin_lock(&dev_priv->process_priv->mem_lock);
entry = kgsl_sharedmem_find(dev_priv->process_priv, gpuaddr);
- spin_unlock(&dev_priv->process_priv->mem_lock);
if (!entry) {
KGSL_DRV_ERR(dev_priv->device,
"invalid gpuaddr %08x\n", gpuaddr);
- result = -EINVAL;
- goto done;
+ return -EINVAL;
}
+ if (entry->memdesc.priv & KGSL_MEMDESC_FREE_PENDING) {
+ kgsl_mem_entry_put(entry);
+ return -EBUSY;
+ }
+ entry->memdesc.priv |= KGSL_MEMDESC_FREE_PENDING;
+
trace_kgsl_mem_timestamp_queue(device, entry, context_id,
kgsl_readtimestamp(device, context,
KGSL_TIMESTAMP_RETIRED),
timestamp);
result = kgsl_add_event(dev_priv->device, context_id, timestamp,
kgsl_freemem_event_cb, entry, dev_priv);
-done:
+ kgsl_mem_entry_put(entry);
return result;
}
@@ -1416,15 +1490,18 @@
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- spin_unlock(&private->mem_lock);
-
if (!entry) {
KGSL_MEM_INFO(dev_priv->device, "invalid gpuaddr %08x\n",
param->gpuaddr);
return -EINVAL;
}
+
+ if (entry->memdesc.priv & KGSL_MEMDESC_FREE_PENDING) {
+ kgsl_mem_entry_put(entry);
+ return -EBUSY;
+ }
+
trace_kgsl_mem_free(entry);
kgsl_memfree_hist_set_event(entry->priv->pid,
@@ -1433,6 +1510,7 @@
entry->memdesc.flags);
kgsl_mem_entry_detach_process(entry);
+ kgsl_mem_entry_put(entry);
return 0;
}
@@ -1449,6 +1527,12 @@
KGSL_MEM_INFO(dev_priv->device, "invalid id %d\n", param->id);
return -EINVAL;
}
+
+ if (entry->memdesc.priv & KGSL_MEMDESC_FREE_PENDING) {
+ kgsl_mem_entry_put(entry);
+ return -EBUSY;
+ }
+
trace_kgsl_mem_free(entry);
kgsl_memfree_hist_set_event(entry->priv->pid,
@@ -1457,6 +1541,7 @@
entry->memdesc.flags);
kgsl_mem_entry_detach_process(entry);
+ kgsl_mem_entry_put(entry);
return 0;
}
@@ -1842,6 +1927,9 @@
if (!kgsl_mmu_use_cpu_map(private->pagetable->mmu))
entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
+ if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU)
+ entry->memdesc.priv |= KGSL_MEMDESC_GUARD_PAGE;
+
switch (memtype) {
case KGSL_USER_MEM_TYPE_PMEM:
if (param->fd == 0 || param->len == 0)
@@ -1990,6 +2078,7 @@
struct kgsl_gpumem_sync_cache *param = data;
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
+ long ret;
if (param->id != 0) {
entry = kgsl_sharedmem_find_id(private, param->id);
@@ -1999,9 +2088,7 @@
return -EINVAL;
}
} else if (param->gpuaddr != 0) {
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- spin_unlock(&private->mem_lock);
if (entry == NULL) {
KGSL_MEM_INFO(dev_priv->device,
"can't find gpuaddr %x\n",
@@ -2012,7 +2099,9 @@
return -EINVAL;
}
- return _kgsl_gpumem_sync_cache(entry, param->op);
+ ret = _kgsl_gpumem_sync_cache(entry, param->op);
+ kgsl_mem_entry_put(entry);
+ return ret;
}
/* Legacy cache function, does a flush (clean + invalidate) */
@@ -2024,10 +2113,9 @@
struct kgsl_sharedmem_free *param = data;
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
+ long ret;
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- spin_unlock(&private->mem_lock);
if (entry == NULL) {
KGSL_MEM_INFO(dev_priv->device,
"can't find gpuaddr %x\n",
@@ -2035,7 +2123,9 @@
return -EINVAL;
}
- return _kgsl_gpumem_sync_cache(entry, KGSL_GPUMEM_CACHE_FLUSH);
+ ret = _kgsl_gpumem_sync_cache(entry, KGSL_GPUMEM_CACHE_FLUSH);
+ kgsl_mem_entry_put(entry);
+ return ret;
}
/*
@@ -2064,6 +2154,9 @@
if (entry == NULL)
return -ENOMEM;
+ if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU)
+ entry->memdesc.priv |= KGSL_MEMDESC_GUARD_PAGE;
+
result = kgsl_allocate_user(&entry->memdesc, private->pagetable, size,
flags);
if (result != 0)
@@ -2173,9 +2266,7 @@
return -EINVAL;
}
} else if (param->gpuaddr != 0) {
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- spin_unlock(&private->mem_lock);
if (entry == NULL) {
KGSL_MEM_INFO(dev_priv->device,
"can't find gpuaddr %lx\n",
@@ -2191,6 +2282,8 @@
param->size = entry->memdesc.size;
param->mmapsize = kgsl_memdesc_mmapsize(&entry->memdesc);
param->useraddr = entry->memdesc.useraddr;
+
+ kgsl_mem_entry_put(entry);
return result;
}
@@ -2202,14 +2295,14 @@
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find_region(private, param->gpuaddr, param->len);
- if (entry)
- kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr,
- param->len, true);
- else
- result = -EINVAL;
- spin_unlock(&private->mem_lock);
+ if (!entry)
+ return -EINVAL;
+
+ kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr,
+ param->len, true);
+
+ kgsl_mem_entry_put(entry);
return result;
}
@@ -2601,21 +2694,17 @@
struct kgsl_mem_entry **out_entry, unsigned long pgoff,
unsigned long len)
{
- int ret = -EINVAL;
+ int ret = 0;
struct kgsl_mem_entry *entry;
entry = kgsl_sharedmem_find_id(private, pgoff);
if (entry == NULL) {
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, pgoff << PAGE_SHIFT);
- spin_unlock(&private->mem_lock);
}
if (!entry)
return -EINVAL;
- kgsl_mem_entry_get(entry);
-
if (!entry->memdesc.ops ||
!entry->memdesc.ops->vmflags ||
!entry->memdesc.ops->vmfault) {
@@ -2768,6 +2857,10 @@
if (vma_offset == device->memstore.gpuaddr)
return kgsl_mmap_memstore(device, vma);
+ /*
+ * The reference count on the entry that we get from
+ * get_mmap_entry() will be held until kgsl_gpumem_vm_close().
+ */
ret = get_mmap_entry(private, &entry, vma->vm_pgoff,
vma->vm_end - vma->vm_start);
if (ret)
@@ -2817,10 +2910,6 @@
int sglen = entry->memdesc.sglen;
unsigned long addr = vma->vm_start;
- /* don't map in the guard page, it should always fault */
- if (kgsl_memdesc_has_guard_page(&entry->memdesc))
- sglen--;
-
for_each_sg(entry->memdesc.sg, s, sglen, i) {
int j;
for (j = 0; j < (sg_dma_len(s) >> PAGE_SHIFT); j++) {
@@ -2837,7 +2926,6 @@
entry->memdesc.useraddr = vma->vm_start;
trace_kgsl_mem_mmap(entry);
-
return 0;
}
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index abe9100..c7cbaf8 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -46,7 +46,11 @@
#define KGSL_PAGETABLE_ENTRY_SIZE 4
/* Pagetable Virtual Address base */
+#ifndef CONFIG_MSM_KGSL_CFF_DUMP
#define KGSL_PAGETABLE_BASE 0x10000000
+#else
+#define KGSL_PAGETABLE_BASE 0xE0000000
+#endif
/* Extra accounting entries needed in the pagetable */
#define KGSL_PT_EXTRA_ENTRIES 16
@@ -151,6 +155,8 @@
#define KGSL_MEMDESC_GLOBAL BIT(1)
/* The memdesc is frozen during a snapshot */
#define KGSL_MEMDESC_FROZEN BIT(2)
+/* The memdesc is scheduled to be freed on a timestamp */
+#define KGSL_MEMDESC_FREE_PENDING BIT(3)
/* shared memory allocation */
struct kgsl_memdesc {
@@ -220,11 +226,8 @@
extern const struct dev_pm_ops kgsl_pm_ops;
-struct early_suspend;
int kgsl_suspend_driver(struct platform_device *pdev, pm_message_t state);
int kgsl_resume_driver(struct platform_device *pdev);
-void kgsl_early_suspend_driver(struct early_suspend *h);
-void kgsl_late_resume_driver(struct early_suspend *h);
void kgsl_trace_regwrite(struct kgsl_device *device, unsigned int offset,
unsigned int value);
@@ -251,6 +254,10 @@
static inline int kgsl_gpuaddr_in_memdesc(const struct kgsl_memdesc *memdesc,
unsigned int gpuaddr, unsigned int size)
{
+ /* set a minimum size to search for */
+ if (!size)
+ size = 1;
+
/* don't overflow */
if ((gpuaddr + size) < gpuaddr)
return 0;
diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c
index 6dc2ccc..c3bdf80 100644
--- a/drivers/gpu/msm/kgsl_cffdump.c
+++ b/drivers/gpu/msm/kgsl_cffdump.c
@@ -360,12 +360,16 @@
void kgsl_cffdump_open(struct kgsl_device *device)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ if (!kgsl_cff_dump_enable)
+ return;
if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
kgsl_cffdump_memory_base(device->id,
- kgsl_mmu_get_base_addr(&device->mmu),
- kgsl_mmu_get_ptsize(&device->mmu) +
- KGSL_IOMMU_GLOBAL_MEM_SIZE, adreno_dev->gmem_size);
+ KGSL_PAGETABLE_BASE,
+ KGSL_IOMMU_GLOBAL_MEM_BASE +
+ KGSL_IOMMU_GLOBAL_MEM_SIZE -
+ KGSL_PAGETABLE_BASE,
+ adreno_dev->gmem_size);
} else {
kgsl_cffdump_memory_base(device->id,
kgsl_mmu_get_base_addr(&device->mmu),
@@ -377,24 +381,33 @@
void kgsl_cffdump_memory_base(enum kgsl_deviceid device_id, unsigned int base,
unsigned int range, unsigned gmemsize)
{
+ if (!kgsl_cff_dump_enable)
+ return;
cffdump_printline(device_id, CFF_OP_MEMORY_BASE, base,
range, gmemsize, 0, 0);
}
void kgsl_cffdump_hang(enum kgsl_deviceid device_id)
{
+ if (!kgsl_cff_dump_enable)
+ return;
cffdump_printline(device_id, CFF_OP_HANG, 0, 0, 0, 0, 0);
}
void kgsl_cffdump_close(enum kgsl_deviceid device_id)
{
+ if (!kgsl_cff_dump_enable)
+ return;
cffdump_printline(device_id, CFF_OP_EOF, 0, 0, 0, 0, 0);
}
+
void kgsl_cffdump_user_event(unsigned int cff_opcode, unsigned int op1,
unsigned int op2, unsigned int op3,
unsigned int op4, unsigned int op5)
{
+ if (!kgsl_cff_dump_enable)
+ return;
cffdump_printline(-1, cff_opcode, op1, op2, op3, op4, op5);
}
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index ac82820..e80721a 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -15,7 +15,6 @@
#include <linux/idr.h>
#include <linux/pm_qos.h>
-#include <linux/earlysuspend.h>
#include "kgsl.h"
#include "kgsl_mmu.h"
@@ -190,7 +189,6 @@
struct completion ft_gate;
struct dentry *d_debugfs;
struct idr context_idr;
- struct early_suspend display_off;
void *snapshot; /* Pointer to the snapshot memory region */
int snapshot_maxsize; /* Max size of the snapshot region */
@@ -280,6 +278,12 @@
unsigned int refcnt;
pid_t pid;
spinlock_t mem_lock;
+
+ /* General refcount for process private struct obj */
+ struct kref refcount;
+ /* Mutex to synchronize access to each process_private struct obj */
+ struct mutex process_private_mutex;
+
struct rb_root mem_rb;
struct idr mem_idr;
struct kgsl_pagetable *pagetable;
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index d872783..3b01e54 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -143,6 +143,15 @@
cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
id = context->id;
+ /*
+ * Increment the refcount to avoid freeing the context while
+ * cancelling its events
+ */
+ kgsl_context_get(context);
+
+ /* Remove ourselves from the master pending list */
+ list_del_init(&context->events_list);
+
list_for_each_entry_safe(event, event_tmp, &context->events, list) {
/*
* "cancel" the events by calling their callback.
@@ -165,9 +174,7 @@
kgsl_active_count_put(device);
}
-
- /* Remove ourselves from the master pending list */
- list_del_init(&context->events_list);
+ kgsl_context_put(context);
}
/**
@@ -313,12 +320,18 @@
events_list) {
/*
+ * Increment the refcount to make sure that the list_del_init
+ * is called with a valid context's list
+ */
+ kgsl_context_get(context);
+ /*
* If kgsl_timestamp_expired_context returns 0 then it no longer
* has any pending events and can be removed from the list
*/
if (kgsl_process_context_events(device, context) == 0)
list_del_init(&context->events_list);
+ kgsl_context_put(context);
}
mutex_unlock(&device->mutex);
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 8d071d1..6f139b9 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -615,7 +615,7 @@
{
unsigned int numpages;
unsigned int pte, ptefirst, ptelast, superpte;
- unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+ unsigned int range = memdesc->size;
struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
/* All GPU addresses as assigned are page aligned, but some
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 15f35c9..513fb90 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -46,7 +46,7 @@
{ 0x03C, 1 }, /* TLBLKCR */
{ 0x818, 1 }, /* V2PUR */
{ 0x2C, 1 }, /* FSYNR0 */
- { 0x2C, 1 }, /* FSYNR0 */
+ { 0x30, 1 }, /* FSYNR1 */
{ 0, 0 }, /* TLBSYNC, not in v0 */
{ 0, 0 }, /* TLBSTATUS, not in v0 */
{ 0, 0 } /* IMPLDEF_MICRO_MMU_CRTL, not in v0 */
@@ -84,6 +84,13 @@
struct remote_iommu_petersons_spinlock kgsl_iommu_sync_lock_vars;
+/*
+ * One page allocation for a guard region to protect against over-zealous
+ * GPU pre-fetch
+ */
+
+static struct page *kgsl_guard_page;
+
static int get_iommu_unit(struct device *dev, struct kgsl_mmu **mmu_out,
struct kgsl_iommu_unit **iommu_unit_out)
{
@@ -268,6 +275,8 @@
void *base = kgsl_driver.memfree_hist.base_hist_rb;
struct kgsl_memfree_hist_elem *wptr;
struct kgsl_memfree_hist_elem *p;
+ char name[32];
+ memset(name, 0, sizeof(name));
mutex_lock(&kgsl_driver.memfree_hist_mutex);
wptr = kgsl_driver.memfree_hist.wptr;
@@ -277,12 +286,15 @@
if (addr >= p->gpuaddr &&
addr < (p->gpuaddr + p->size)) {
+ kgsl_get_memory_usage(name, sizeof(name) - 1,
+ p->flags),
KGSL_LOG_DUMP(iommu_dev->kgsldev,
"---- premature free ----\n");
KGSL_LOG_DUMP(iommu_dev->kgsldev,
- "[%8.8X-%8.8X] was already freed by pid %d\n",
+ "[%8.8X-%8.8X] (%s) was already freed by pid %d\n",
p->gpuaddr,
p->gpuaddr + p->size,
+ name,
p->pid);
}
p++;
@@ -347,22 +359,17 @@
KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT)) ? 1 : 0);
pid = kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase);
- KGSL_MEM_CRIT(iommu_dev->kgsldev,
- "GPU PAGE FAULT: addr = %lX pid = %d\n", addr, pid);
- KGSL_MEM_CRIT(iommu_dev->kgsldev,
- "context = %d FSR = %X FSYNR0 = %X FSYNR1 = %X(%s fault)\n",
- iommu_dev->ctx_id, fsr, fsynr0, fsynr1,
- write ? "write" : "read");
if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE)
no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, addr);
if (!no_page_fault_log) {
KGSL_MEM_CRIT(iommu_dev->kgsldev,
- "GPU PAGE FAULT: addr = %lX pid = %d\n",
- addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
- KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
- iommu_dev->ctx_id, fsr);
+ "GPU PAGE FAULT: addr = %lX pid = %d\n", addr, pid);
+ KGSL_MEM_CRIT(iommu_dev->kgsldev,
+ "context = %d FSR = %X FSYNR0 = %X FSYNR1 = %X(%s fault)\n",
+ iommu_dev->ctx_id, fsr, fsynr0, fsynr1,
+ write ? "write" : "read");
_check_if_freed(iommu_dev, addr, pid);
@@ -390,18 +397,20 @@
kgsl_sharedmem_readl(&device->memstore, &curr_context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context));
context = idr_find(&device->context_idr, curr_context_id);
- if (context != NULL)
+ if (context != NULL) {
curr_context = context->devctxt;
- kgsl_sharedmem_readl(&device->memstore, &curr_global_ts,
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, eoptimestamp));
+ kgsl_sharedmem_readl(&device->memstore, &curr_global_ts,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp));
- /*
- * Store pagefault's timestamp in adreno context,
- * this information will be used in GFT
- */
- curr_context->pagefault = 1;
- curr_context->pagefault_ts = curr_global_ts;
+ /*
+ * Store pagefault's timestamp in adreno context,
+ * this information will be used in GFT
+ */
+ curr_context->pagefault = 1;
+ curr_context->pagefault_ts = curr_global_ts;
+ }
trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase),
@@ -624,8 +633,10 @@
{
struct kgsl_iommu_pt *iommu_pt = pt->priv;
if (iommu_pt->domain)
- iommu_domain_free(iommu_pt->domain);
+ msm_unregister_domain(iommu_pt->domain);
+
kfree(iommu_pt);
+ iommu_pt = NULL;
}
/*
@@ -1334,13 +1345,27 @@
* we're better off with extra room.
*/
if (mmu->pt_per_process) {
+#ifndef CONFIG_MSM_KGSL_CFF_DUMP
mmu->pt_base = PAGE_OFFSET;
mmu->pt_size = KGSL_IOMMU_GLOBAL_MEM_BASE
- kgsl_mmu_get_base_addr(mmu) - SZ_1M;
mmu->use_cpu_map = true;
+#else
+ mmu->pt_base = KGSL_PAGETABLE_BASE;
+ mmu->pt_size = KGSL_IOMMU_GLOBAL_MEM_BASE +
+ KGSL_IOMMU_GLOBAL_MEM_SIZE -
+ KGSL_PAGETABLE_BASE;
+ mmu->use_cpu_map = false;
+#endif
} else {
mmu->pt_base = KGSL_PAGETABLE_BASE;
+#ifndef CONFIG_MSM_KGSL_CFF_DUMP
mmu->pt_size = SZ_2G;
+#else
+ mmu->pt_size = KGSL_IOMMU_GLOBAL_MEM_BASE +
+ KGSL_IOMMU_GLOBAL_MEM_SIZE -
+ KGSL_PAGETABLE_BASE;
+#endif
mmu->use_cpu_map = false;
}
@@ -1374,6 +1399,15 @@
iommu_ops.mmu_cleanup_pt = kgsl_iommu_cleanup_regs;
}
+ if (kgsl_guard_page == NULL) {
+ kgsl_guard_page = alloc_page(GFP_KERNEL | __GFP_ZERO |
+ __GFP_HIGHMEM);
+ if (kgsl_guard_page == NULL) {
+ status = -ENOMEM;
+ goto done;
+ }
+ }
+
dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
__func__);
done:
@@ -1624,7 +1658,7 @@
unsigned int *tlb_flags)
{
int ret;
- unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+ unsigned int range = memdesc->size;
struct kgsl_iommu_pt *iommu_pt = pt->priv;
/* All GPU addresses as assigned are page aligned, but some
@@ -1636,6 +1670,9 @@
if (range == 0 || gpuaddr == 0)
return 0;
+ if (kgsl_memdesc_has_guard_page(memdesc))
+ range += PAGE_SIZE;
+
ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
if (ret)
KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
@@ -1660,14 +1697,10 @@
int ret;
unsigned int iommu_virt_addr;
struct kgsl_iommu_pt *iommu_pt = pt->priv;
- int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+ int size = memdesc->size;
BUG_ON(NULL == iommu_pt);
- /* if there's a guard page, we'll map it read only below */
- if ((protflags & IOMMU_WRITE) && kgsl_memdesc_has_guard_page(memdesc))
- size -= PAGE_SIZE;
-
iommu_virt_addr = memdesc->gpuaddr;
ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
@@ -1678,16 +1711,14 @@
protflags, ret);
return ret;
}
- if ((protflags & IOMMU_WRITE) && kgsl_memdesc_has_guard_page(memdesc)) {
- struct scatterlist *sg = &memdesc->sg[memdesc->sglen - 1];
-
+ if (kgsl_memdesc_has_guard_page(memdesc)) {
ret = iommu_map(iommu_pt->domain, iommu_virt_addr + size,
- kgsl_get_sg_pa(sg), PAGE_SIZE,
+ page_to_phys(kgsl_guard_page), PAGE_SIZE,
protflags & ~IOMMU_WRITE);
if (ret) {
- KGSL_CORE_ERR("iommu_map(%p, %x, %x, %x) err: %d\n",
+ KGSL_CORE_ERR("iommu_map(%p, %x, guard, %x) err: %d\n",
iommu_pt->domain, iommu_virt_addr + size,
- kgsl_get_sg_pa(sg), protflags & ~IOMMU_WRITE,
+ protflags & ~IOMMU_WRITE,
ret);
/* cleanup the partial mapping */
iommu_unmap_range(iommu_pt->domain, iommu_virt_addr,
@@ -1767,6 +1798,11 @@
kfree(iommu);
+ if (kgsl_guard_page != NULL) {
+ __free_page(kgsl_guard_page);
+ kgsl_guard_page = NULL;
+ }
+
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 6e41707..3ebfdcd 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -640,7 +640,10 @@
}
}
- size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+ /* Add space for the guard page when allocating the mmu VA. */
+ size = memdesc->size;
+ if (kgsl_memdesc_has_guard_page(memdesc))
+ size += PAGE_SIZE;
pool = pagetable->pool;
@@ -738,7 +741,10 @@
return 0;
}
- size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+ /* Add space for the guard page when freeing the mmu VA. */
+ size = memdesc->size;
+ if (kgsl_memdesc_has_guard_page(memdesc))
+ size += PAGE_SIZE;
start_addr = memdesc->gpuaddr;
end_addr = (memdesc->gpuaddr + size);
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index ef5b0f4..02cde94 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -410,7 +410,7 @@
*/
static inline int kgsl_mmu_use_cpu_map(struct kgsl_mmu *mmu)
{
- return mmu->pt_per_process;
+ return mmu->use_cpu_map;
}
/*
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index b124257..e071650 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1021,7 +1021,6 @@
pwr->pm_qos_latency = 501;
pm_runtime_enable(device->parentdev);
- register_early_suspend(&device->display_off);
return result;
clk_err:
@@ -1041,7 +1040,6 @@
KGSL_PWR_INFO(device, "close device %d\n", device->id);
pm_runtime_disable(device->parentdev);
- unregister_early_suspend(&device->display_off);
clk_put(pwr->ebi1_clk);
@@ -1151,8 +1149,7 @@
KGSL_PWR_INFO(device, "idle timer expired device %d\n", device->id);
if (device->requested_state != KGSL_STATE_SUSPEND) {
- if (device->pwrctrl.restore_slumber ||
- device->pwrctrl.strtstp_sleepwake)
+ if (device->pwrctrl.strtstp_sleepwake)
kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
else
kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
@@ -1448,16 +1445,11 @@
BUG_ON(!mutex_is_locked(&device->mutex));
if (device->active_cnt == 0) {
- if (device->requested_state == KGSL_STATE_SUSPEND ||
- device->state == KGSL_STATE_SUSPEND) {
- mutex_unlock(&device->mutex);
- wait_for_completion(&device->hwaccess_gate);
- mutex_lock(&device->mutex);
- } else if (device->state == KGSL_STATE_DUMP_AND_FT) {
- mutex_unlock(&device->mutex);
- wait_for_completion(&device->ft_gate);
- mutex_lock(&device->mutex);
- }
+ mutex_unlock(&device->mutex);
+ wait_for_completion(&device->hwaccess_gate);
+ wait_for_completion(&device->ft_gate);
+ mutex_lock(&device->mutex);
+
ret = kgsl_pwrctrl_wake(device);
}
if (ret == 0)
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index b3e8702..2b986c8 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -58,7 +58,6 @@
* @nap_allowed - true if the device supports naps
* @idle_needed - true if the device needs a idle before clock change
* @irq_name - resource name for the IRQ
- * @restore_slumber - Flag to indicate that we are in a suspend/restore sequence
* @clk_stats - structure of clock statistics
* @pm_qos_req_dma - the power management quality of service structure
* @pm_qos_latency - allowed CPU latency in microseconds
@@ -86,7 +85,6 @@
unsigned int idle_needed;
const char *irq_name;
s64 time;
- unsigned int restore_slumber;
struct kgsl_clk_stats clk_stats;
struct pm_qos_request pm_qos_req_dma;
unsigned int pm_qos_latency;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 62db513..b9bc432 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -65,14 +65,6 @@
mem_entry_max_show), \
}
-
-/*
- * One page allocation for a guard region to protect against over-zealous
- * GPU pre-fetch
- */
-
-static struct page *kgsl_guard_page;
-
/**
* Given a kobj, find the process structure attached to it
*/
@@ -364,10 +356,6 @@
struct scatterlist *sg;
int sglen = memdesc->sglen;
- /* Don't free the guard page if it was used */
- if (memdesc->priv & KGSL_MEMDESC_GUARD_PAGE)
- sglen--;
-
kgsl_driver.stats.page_alloc -= memdesc->size;
if (memdesc->hostptr) {
@@ -402,10 +390,6 @@
int sglen = memdesc->sglen;
int i, count = 0;
- /* Don't map the guard page if it exists */
- if (memdesc->priv & KGSL_MEMDESC_GUARD_PAGE)
- sglen--;
-
/* create a list of pages to call vmap */
pages = vmalloc(npages * sizeof(struct page *));
if (!pages) {
@@ -564,14 +548,6 @@
sglen_alloc = PAGE_ALIGN(size) >> PAGE_SHIFT;
- /*
- * Add guard page to the end of the allocation when the
- * IOMMU is in use.
- */
-
- if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU)
- sglen_alloc++;
-
memdesc->size = size;
memdesc->pagetable = pagetable;
memdesc->ops = &kgsl_page_alloc_ops;
@@ -647,26 +623,6 @@
len -= page_size;
}
- /* Add the guard page to the end of the sglist */
-
- if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU) {
- /*
- * It doesn't matter if we use GFP_ZERO here, this never
- * gets mapped, and we only allocate it once in the life
- * of the system
- */
-
- if (kgsl_guard_page == NULL)
- kgsl_guard_page = alloc_page(GFP_KERNEL | __GFP_ZERO |
- __GFP_HIGHMEM);
-
- if (kgsl_guard_page != NULL) {
- sg_set_page(&memdesc->sg[sglen++], kgsl_guard_page,
- PAGE_SIZE, 0);
- memdesc->priv |= KGSL_MEMDESC_GUARD_PAGE;
- }
- }
-
memdesc->sglen = sglen;
/*
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 279490f..14ae0dc 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -295,15 +295,4 @@
return ret;
}
-static inline int kgsl_sg_size(struct scatterlist *sg, int sglen)
-{
- int i, size = 0;
- struct scatterlist *s;
-
- for_each_sg(sg, s, sglen, i) {
- size += s->length;
- }
-
- return size;
-}
#endif /* __KGSL_SHAREDMEM_H */
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index abcebfb..f09c623 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -345,6 +345,10 @@
struct kgsl_mem_entry *entry;
struct kgsl_snapshot_object *obj;
int offset;
+ int ret = -EINVAL;
+
+ if (!gpuaddr)
+ return 0;
entry = kgsl_get_mem_entry(device, ptbase, gpuaddr, size);
@@ -358,7 +362,7 @@
if (entry->memtype != KGSL_MEM_ENTRY_KERNEL) {
KGSL_DRV_ERR(device,
"Only internal GPU buffers can be frozen\n");
- return -EINVAL;
+ goto err_put;
}
/*
@@ -381,7 +385,7 @@
if (size + offset > entry->memdesc.size) {
KGSL_DRV_ERR(device, "Invalid size for GPU buffer %8.8X\n",
gpuaddr);
- return -EINVAL;
+ goto err_put;
}
/* If the buffer is already on the list, skip it */
@@ -390,27 +394,24 @@
/* If the size is different, use the bigger size */
if (obj->size < size)
obj->size = size;
-
- return 0;
+ ret = 0;
+ goto err_put;
}
}
if (kgsl_memdesc_map(&entry->memdesc) == NULL) {
KGSL_DRV_ERR(device, "Unable to map GPU buffer %X\n",
gpuaddr);
- return -EINVAL;
+ goto err_put;
}
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
if (obj == NULL) {
KGSL_DRV_ERR(device, "Unable to allocate memory\n");
- return -EINVAL;
+ goto err_put;
}
- /* Ref count the mem entry */
- kgsl_mem_entry_get(entry);
-
obj->type = type;
obj->entry = entry;
obj->gpuaddr = gpuaddr;
@@ -428,12 +429,15 @@
* 0 so it doesn't get counted twice
*/
- if (entry->memdesc.priv & KGSL_MEMDESC_FROZEN)
- return 0;
+ ret = (entry->memdesc.priv & KGSL_MEMDESC_FROZEN) ? 0
+ : entry->memdesc.size;
entry->memdesc.priv |= KGSL_MEMDESC_FROZEN;
- return entry->memdesc.size;
+ return ret;
+err_put:
+ kgsl_mem_entry_put(entry);
+ return ret;
}
EXPORT_SYMBOL(kgsl_snapshot_get_object);
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index 813305a..aad8ef1 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -168,7 +168,6 @@
fail_event:
fail_copy_fd:
/* clean up sync_fence_install */
- sync_fence_put(fence);
put_unused_fd(priv.fence_fd);
fail_fd:
/* clean up sync_fence_create */
diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c
index c1e5f07..55b8faa 100644
--- a/drivers/gpu/msm/z180_postmortem.c
+++ b/drivers/gpu/msm/z180_postmortem.c
@@ -168,6 +168,7 @@
KGSL_LOG_DUMP(device,
"Could not map IB to kernel memory, Ringbuffer Slot: %d\n",
rb_slot_num);
+ kgsl_mem_entry_put(entry);
continue;
}
@@ -190,6 +191,7 @@
linebuf);
}
KGSL_LOG_DUMP(device, "IB Dump Finished\n");
+ kgsl_mem_entry_put(entry);
}
}
}
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index b3b5643..8e350f0 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -130,6 +130,60 @@
{790, 203}
};
+static const struct qpnp_vadc_map_pt adcmap_qrd_btm_threshold[] = {
+ {-200, 1672},
+ {-180, 1656},
+ {-160, 1639},
+ {-140, 1620},
+ {-120, 1599},
+ {-100, 1577},
+ {-80, 1553},
+ {-60, 1527},
+ {-40, 1550},
+ {-20, 1471},
+ {0, 1440},
+ {20, 1408},
+ {40, 1374},
+ {60, 1339},
+ {80, 1303},
+ {100, 1266},
+ {120, 1228},
+ {140, 1190},
+ {160, 1150},
+ {180, 1111},
+ {200, 1071},
+ {220, 1032},
+ {240, 992},
+ {260, 953},
+ {280, 915},
+ {300, 877},
+ {320, 841},
+ {340, 805},
+ {360, 770},
+ {380, 736},
+ {400, 704},
+ {420, 673},
+ {440, 643},
+ {460, 614},
+ {480, 587},
+ {500, 561},
+ {520, 536},
+ {540, 513},
+ {560, 491},
+ {580, 470},
+ {600, 450},
+ {620, 431},
+ {640, 414},
+ {660, 397},
+ {680, 382},
+ {700, 367},
+ {720, 353},
+ {740, 340},
+ {760, 328},
+ {780, 317},
+ {800, 306},
+};
+
/* Voltage to temperature */
static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb[] = {
{1758, -40},
@@ -373,7 +427,7 @@
{
struct qpnp_vadc_linear_graph btm_param;
int64_t low_output = 0, high_output = 0;
- int rc = 0;
+ int rc = 0, sign = 0;
rc = qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_ABSOLUTE);
if (rc < 0) {
@@ -384,19 +438,36 @@
/* Convert to Kelvin and account for voltage to be written as 2mV/K */
low_output = (param->low_temp + KELVINMIL_DEGMIL) * 2;
/* Convert to voltage threshold */
- low_output *= btm_param.dy;
- do_div(low_output, btm_param.adc_vref);
+ low_output = (low_output - QPNP_ADC_625_UV) * btm_param.dy;
+ if (low_output < 0) {
+ sign = 1;
+ low_output = -low_output;
+ }
+ do_div(low_output, QPNP_ADC_625_UV);
+ if (sign)
+ low_output = -low_output;
low_output += btm_param.adc_gnd;
+ sign = 0;
/* Convert to Kelvin and account for voltage to be written as 2mV/K */
high_output = (param->high_temp + KELVINMIL_DEGMIL) * 2;
/* Convert to voltage threshold */
- high_output *= btm_param.dy;
- do_div(high_output, btm_param.adc_vref);
+ high_output = (high_output - QPNP_ADC_625_UV) * btm_param.dy;
+ if (high_output < 0) {
+ sign = 1;
+ high_output = -high_output;
+ }
+ do_div(high_output, QPNP_ADC_625_UV);
+ if (sign)
+ high_output = -high_output;
high_output += btm_param.adc_gnd;
- *low_threshold = low_output;
- *high_threshold = high_output;
+ *low_threshold = (uint32_t) low_output;
+ *high_threshold = (uint32_t) high_output;
+ pr_debug("high_temp:%d, low_temp:%d\n", param->high_temp,
+ param->low_temp);
+ pr_debug("adc_code_high:%x, adc_code_low:%x\n", *high_threshold,
+ *low_threshold);
return 0;
}
@@ -446,6 +517,24 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_batt_therm);
+int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int64_t bat_voltage = 0;
+
+ bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+ adc_properties, chan_properties);
+
+ return qpnp_adc_map_temp_voltage(
+ adcmap_qrd_btm_threshold,
+ ARRAY_SIZE(adcmap_qrd_btm_threshold),
+ bat_voltage,
+ &adc_chan_result->physical);
+}
+EXPORT_SYMBOL(qpnp_adc_scale_qrd_batt_therm);
+
int32_t qpnp_adc_scale_therm_pu1(int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
const struct qpnp_vadc_chan_properties *chan_properties,
@@ -637,7 +726,7 @@
uint32_t *low_threshold, uint32_t *high_threshold)
{
struct qpnp_vadc_linear_graph vbatt_param;
- int rc = 0;
+ int rc = 0, sign = 0;
int64_t low_thr = 0, high_thr = 0;
rc = qpnp_get_vadc_gain_and_offset(&vbatt_param, CALIB_ABSOLUTE);
@@ -646,12 +735,25 @@
low_thr = (((param->low_thr/3) - QPNP_ADC_625_UV) *
vbatt_param.dy);
+ if (low_thr < 0) {
+ sign = 1;
+ low_thr = -low_thr;
+ }
do_div(low_thr, QPNP_ADC_625_UV);
+ if (sign)
+ low_thr = -low_thr;
*low_threshold = low_thr + vbatt_param.adc_gnd;
+ sign = 0;
high_thr = (((param->high_thr/3) - QPNP_ADC_625_UV) *
vbatt_param.dy);
+ if (high_thr < 0) {
+ sign = 1;
+ high_thr = -high_thr;
+ }
do_div(high_thr, QPNP_ADC_625_UV);
+ if (sign)
+ high_thr = -high_thr;
*high_threshold = high_thr + vbatt_param.adc_gnd;
pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
@@ -877,8 +979,6 @@
init_completion(&adc_qpnp->adc_rslt_completion);
- mutex_init(&adc_qpnp->adc_lock);
-
return 0;
}
EXPORT_SYMBOL(qpnp_adc_get_devicetree_data);
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 66811bf..09fcd0e 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -95,6 +95,7 @@
#define QPNP_IADC_LSB_OFFSET 0xF3
#define QPNP_IADC_NOMINAL_RSENSE 0xF4
#define QPNP_IADC_ATE_GAIN_CALIB_OFFSET 0xF5
+#define QPNP_INT_TEST_VAL 0xE1
#define QPNP_IADC_ADC_CH_SEL_CTL 0x48
#define QPNP_IADC_ADC_CHX_SEL_SHIFT 3
@@ -126,16 +127,24 @@
#define QPNP_RSENSE_MSB_SIGN_CHECK 0x80
#define QPNP_ADC_COMPLETION_TIMEOUT HZ
+struct qpnp_iadc_comp {
+ bool ext_rsense;
+ u8 id;
+ u8 sys_gain;
+ u8 revision;
+};
+
struct qpnp_iadc_drv {
struct qpnp_adc_drv *adc;
int32_t rsense;
bool external_rsense;
struct device *iadc_hwmon;
bool iadc_initialized;
- int64_t die_temp_calib_offset;
+ int64_t die_temp;
struct delayed_work iadc_work;
struct mutex iadc_vadc_lock;
bool iadc_mode_sel;
+ struct qpnp_iadc_comp iadc_comp;
struct sensor_device_attribute sens_attr[0];
};
@@ -293,6 +302,99 @@
return 0;
}
+static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_comp comp,
+ int64_t die_temp)
+{
+ int64_t temp_var = 0, sign_coeff = 0, sys_gain_coeff = 0;
+
+ *result = *result * 1000000;
+
+ if (comp.revision == QPNP_IADC_VER_3_1) {
+ /* revision 3.1 */
+ if (comp.sys_gain > 127)
+ sys_gain_coeff = -QPNP_COEFF_6 * (comp.sys_gain - 128);
+ else
+ sys_gain_coeff = QPNP_COEFF_6 * comp.sys_gain;
+ }
+
+ comp.id = 0;
+ if (!comp.ext_rsense) {
+ /* internal rsense */
+ switch (comp.id) {
+ case COMP_ID_TSMC:
+ temp_var = ((QPNP_COEFF_2 * die_temp) -
+ QPNP_COEFF_3_TYPEB);
+ break;
+ case COMP_ID_GF:
+ default:
+ temp_var = ((QPNP_COEFF_2 * die_temp) -
+ QPNP_COEFF_3_TYPEA);
+ break;
+ }
+ temp_var = div64_s64(temp_var, QPNP_COEFF_4);
+ if (comp.revision == QPNP_IADC_VER_3_0)
+ temp_var = QPNP_COEFF_1 * (1000000 - temp_var);
+ else if (comp.revision == QPNP_IADC_VER_3_1)
+ temp_var = (1000000 - temp_var);
+ *result = div64_s64(*result, temp_var);
+ }
+
+ sign_coeff = *result < 0 ? QPNP_COEFF_7 : QPNP_COEFF_5;
+ if (comp.ext_rsense) {
+ /* external rsense and current charging */
+ temp_var = div64_s64((-sign_coeff * die_temp) + QPNP_COEFF_8,
+ QPNP_COEFF_4);
+ temp_var = 1000000000 - temp_var;
+ if (comp.revision == QPNP_IADC_VER_3_1) {
+ sys_gain_coeff = (1000000 +
+ div64_s64(sys_gain_coeff, QPNP_COEFF_4));
+ temp_var = div64_s64(temp_var * sys_gain_coeff,
+ 1000000000);
+ }
+ *result = div64_s64(*result, temp_var);
+ }
+
+ return 0;
+}
+
+int32_t qpnp_iadc_comp_result(int64_t *result)
+{
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
+
+ return qpnp_iadc_comp(result, iadc->iadc_comp, iadc->die_temp);
+}
+EXPORT_SYMBOL(qpnp_iadc_comp_result);
+
+static int32_t qpnp_iadc_comp_info(void)
+{
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
+ int rc = 0;
+
+ rc = qpnp_iadc_read_reg(QPNP_INT_TEST_VAL, &iadc->iadc_comp.id);
+ if (rc < 0) {
+ pr_err("qpnp adc comp id failed with %d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &iadc->iadc_comp.revision);
+ if (rc < 0) {
+ pr_err("qpnp adc revision read failed with %d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_iadc_read_reg(QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
+ &iadc->iadc_comp.sys_gain);
+ if (rc < 0)
+ pr_err("full scale read failed with %d\n", rc);
+
+ pr_debug("fab id = %u, revision = %u, sys gain = %u, external_rsense = %d\n",
+ iadc->iadc_comp.id,
+ iadc->iadc_comp.revision,
+ iadc->iadc_comp.sys_gain,
+ iadc->iadc_comp.ext_rsense);
+ return rc;
+}
+
static int32_t qpnp_iadc_configure(enum qpnp_iadc_channels channel,
uint16_t *raw_code, uint32_t mode_sel)
{
@@ -583,12 +685,12 @@
return rc;
die_temp_offset = result_pmic_therm.physical -
- iadc->die_temp_calib_offset;
+ iadc->die_temp;
if (die_temp_offset < 0)
die_temp_offset = -die_temp_offset;
if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
- iadc->die_temp_calib_offset =
+ iadc->die_temp =
result_pmic_therm.physical;
rc = qpnp_iadc_calibrate_for_trim();
if (rc)
@@ -640,12 +742,17 @@
(iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
result_current = result->result_uv;
result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
+ /* Intentional fall through. Process the result w/o comp */
do_div(result_current, rsense_u_ohms);
if (sign) {
result->result_uv = -result->result_uv;
result_current = -result_current;
}
+ rc = qpnp_iadc_comp_result(&result_current);
+ if (rc < 0)
+ pr_err("Error during compensating the IADC\n");
+ rc = 0;
result->result_ua = (int32_t) result_current;
fail:
@@ -830,6 +937,8 @@
goto fail;
}
+ mutex_init(&iadc->adc->adc_lock);
+
rc = of_property_read_u32(node, "qcom,rsense",
&iadc->rsense);
if (rc)
@@ -866,6 +975,11 @@
mutex_init(&iadc->iadc_vadc_lock);
INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
+ rc = qpnp_iadc_comp_info();
+ if (rc) {
+ dev_err(&spmi->dev, "abstracting IADC comp info failed!\n");
+ goto fail;
+ }
iadc->iadc_initialized = true;
rc = qpnp_iadc_calibrate_for_trim();
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index d296a47..cc7073e 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -83,6 +83,7 @@
#define QPNP_VADC_M1_LOW_THR_MSB 0x6a
#define QPNP_VADC_M1_HIGH_THR_LSB 0x6b
#define QPNP_VADC_M1_HIGH_THR_MSB 0x6c
+#define QPNP_INT_TEST_VAL 0xE1
#define QPNP_VADC_DATA0 0x60
#define QPNP_VADC_DATA1 0x61
@@ -100,7 +101,8 @@
bool vadc_initialized;
int max_channels_available;
bool vadc_iadc_sync_lock;
- struct sensor_device_attribute sens_attr[0];
+ u8 id;
+ struct sensor_device_attribute sens_attr[0];
};
struct qpnp_vadc_drv *qpnp_vadc;
@@ -112,6 +114,7 @@
[SCALE_XOTHERM] = {qpnp_adc_tdkntcg_therm},
[SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
[SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
+ [SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
};
static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
@@ -431,12 +434,86 @@
return 0;
}
-static uint32_t qpnp_vadc_calib_device(void)
+static int32_t qpnp_vbat_sns_comp(int64_t *result, u8 id, int64_t die_temp)
+{
+ int64_t temp_var = 0;
+
+ if (die_temp < 25000)
+ return 0;
+
+ switch (id) {
+ case COMP_ID_TSMC:
+ temp_var = (((die_temp *
+ (-QPNP_VBAT_SNS_COEFF_1_TYPEB))
+ + QPNP_VBAT_SNS_COEFF_2_TYPEB));
+ break;
+ default:
+ case COMP_ID_GF:
+ temp_var = (((die_temp *
+ (-QPNP_VBAT_SNS_COEFF_1_TYPEA))
+ + QPNP_VBAT_SNS_COEFF_2_TYPEA));
+ break;
+ }
+
+ temp_var = div64_s64(temp_var, QPNP_VBAT_SNS_COEFF_3);
+
+ temp_var = 1000000 + temp_var;
+
+ *result = *result * temp_var;
+
+ *result = div64_s64(*result, 1000000);
+
+ return 0;
+}
+
+int32_t qpnp_vbat_sns_comp_result(int64_t *result)
+{
+ struct qpnp_vadc_drv *vadc = qpnp_vadc;
+ struct qpnp_vadc_result die_temp_result;
+ int rc = 0;
+
+ rc = qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+ DIE_TEMP, &die_temp_result);
+ if (rc < 0) {
+ pr_err("Error reading die_temp\n");
+ return rc;
+ }
+
+ rc = qpnp_vbat_sns_comp(result, vadc->id,
+ die_temp_result.physical);
+ if (rc < 0)
+ pr_err("Error with vbat compensation\n");
+
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_vbat_sns_comp_result);
+
+static void qpnp_vadc_625mv_channel_sel(uint32_t *ref_channel_sel)
+{
+ struct qpnp_vadc_drv *vadc = qpnp_vadc;
+ uint32_t dt_index = 0;
+
+ /* Check if the buffered 625mV channel exists */
+ while ((vadc->adc->adc_channels[dt_index].channel_num
+ != SPARE1) && (dt_index < vadc->max_channels_available))
+ dt_index++;
+
+ if (dt_index >= vadc->max_channels_available) {
+ pr_debug("Use default 625mV ref channel\n");
+ *ref_channel_sel = REF_625MV;
+ } else {
+ pr_debug("Use buffered 625mV ref channel\n");
+ *ref_channel_sel = SPARE1;
+ }
+}
+
+static int32_t qpnp_vadc_calib_device(void)
{
struct qpnp_vadc_drv *vadc = qpnp_vadc;
struct qpnp_adc_amux_properties conv;
int rc, calib_read_1, calib_read_2, count = 0;
u8 status1 = 0;
+ uint32_t ref_channel_sel = 0;
conv.amux_channel = REF_125V;
conv.decimation = DECIMATION_TYPE2;
@@ -470,7 +547,8 @@
goto calib_fail;
}
- conv.amux_channel = REF_625MV;
+ qpnp_vadc_625mv_channel_sel(&ref_channel_sel);
+ conv.amux_channel = ref_channel_sel;
conv.decimation = DECIMATION_TYPE2;
conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
@@ -647,6 +725,7 @@
{
struct qpnp_vadc_drv *vadc = qpnp_vadc;
int rc = 0, scale_type, amux_prescaling, dt_index = 0;
+ uint32_t ref_channel;
if (!vadc || !vadc->vadc_initialized)
return -EPROBE_DEFER;
@@ -666,6 +745,11 @@
vadc->vadc_init_calib = true;
}
+ if (channel == REF_625MV) {
+ qpnp_vadc_625mv_channel_sel(&ref_channel);
+ channel = ref_channel;
+ }
+
vadc->adc->amux_prop->amux_channel = channel;
while ((vadc->adc->adc_channels[dt_index].channel_num
@@ -762,7 +846,34 @@
int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
struct qpnp_vadc_result *result)
{
- return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+ struct qpnp_vadc_drv *vadc = qpnp_vadc;
+ enum qpnp_vadc_channels;
+ struct qpnp_vadc_result die_temp_result;
+ int rc = 0;
+
+ if (channel == VBAT_SNS) {
+ rc = qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+ channel, result);
+ if (rc < 0) {
+ pr_err("Error reading vbatt\n");
+ return rc;
+ }
+
+ rc = qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+ DIE_TEMP, &die_temp_result);
+ if (rc < 0) {
+ pr_err("Error reading die_temp\n");
+ return rc;
+ }
+
+ rc = qpnp_vbat_sns_comp(&result->physical, vadc->id,
+ die_temp_result.physical);
+ if (rc < 0)
+ pr_err("Error with vbat compensation\n");
+
+ return 0;
+ } else
+ return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
channel, result);
}
EXPORT_SYMBOL(qpnp_vadc_read);
@@ -942,6 +1053,7 @@
struct device_node *node = spmi->dev.of_node;
struct device_node *child;
int rc, count_adc_channel_list = 0;
+ u8 fab_id = 0;
if (!node)
return -EINVAL;
@@ -982,6 +1094,7 @@
dev_err(&spmi->dev, "failed to read device tree\n");
goto fail;
}
+ mutex_init(&vadc->adc->adc_lock);
rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
qpnp_vadc_isr, IRQF_TRIGGER_RISING,
@@ -1004,6 +1117,13 @@
vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
vadc->vadc_init_calib = false;
vadc->max_channels_available = count_adc_channel_list;
+ rc = qpnp_vadc_read_reg(QPNP_INT_TEST_VAL, &fab_id);
+ if (rc < 0) {
+ pr_err("qpnp adc comp id failed with %d\n", rc);
+ return rc;
+ }
+ vadc->id = fab_id;
+
vadc->vadc_initialized = true;
vadc->vadc_iadc_sync_lock = false;
diff --git a/drivers/input/touchscreen/gen_vkeys.c b/drivers/input/touchscreen/gen_vkeys.c
index fcda6c9..efddf61 100644
--- a/drivers/input/touchscreen/gen_vkeys.c
+++ b/drivers/input/touchscreen/gen_vkeys.c
@@ -24,6 +24,8 @@
#define HEIGHT_SCALE_NUM 8
#define HEIGHT_SCALE_DENOM 10
+#define VKEY_Y_OFFSET_DEFAULT 0
+
/* numerator and denomenator for border equations */
#define BORDER_ADJUST_NUM 3
#define BORDER_ADJUST_DENOM 4
@@ -59,7 +61,7 @@
{
struct device_node *np = dev->of_node;
struct property *prop;
- int rc;
+ int rc, val;
rc = of_property_read_string(np, "label", &pdata->name);
if (rc) {
@@ -105,6 +107,15 @@
return -EINVAL;
}
}
+
+ pdata->y_offset = VKEY_Y_OFFSET_DEFAULT;
+ rc = of_property_read_u32(np, "qcom,y-offset", &val);
+ if (!rc)
+ pdata->y_offset = val;
+ else if (rc != -EINVAL) {
+ dev_err(dev, "Failed to read y position offset\n");
+ return rc;
+ }
return 0;
}
@@ -147,7 +158,7 @@
width = ((pdata->disp_maxx - (border * (pdata->num_keys - 1)))
/ pdata->num_keys);
height = (pdata->panel_maxy - pdata->disp_maxy);
- center_y = pdata->disp_maxy + (height / 2);
+ center_y = pdata->disp_maxy + (height / 2) + pdata->y_offset;
height = height * HEIGHT_SCALE_NUM / HEIGHT_SCALE_DENOM;
x2 -= border * BORDER_ADJUST_NUM / BORDER_ADJUST_DENOM;
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 986c062..d51481f 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -25,6 +25,7 @@
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/firmware.h>
+#include <linux/string.h>
#include <linux/input/synaptics_dsx.h>
#include "synaptics_i2c_rmi4.h"
@@ -34,14 +35,7 @@
#define FORCE_UPDATE false
#define INSIDE_FIRMWARE_UPDATE
-#define CHECKSUM_OFFSET 0x00
-#define BOOTLOADER_VERSION_OFFSET 0x07
-#define IMAGE_SIZE_OFFSET 0x08
-#define CONFIG_SIZE_OFFSET 0x0C
-#define PRODUCT_ID_OFFSET 0x10
-#define PRODUCT_INFO_OFFSET 0x1E
#define FW_IMAGE_OFFSET 0x100
-#define PRODUCT_ID_SIZE 10
#define BOOTLOADER_ID_OFFSET 0
#define FLASH_PROPERTIES_OFFSET 2
@@ -59,10 +53,14 @@
#define BLOCK_NUMBER_OFFSET 0
#define BLOCK_DATA_OFFSET 2
-#define UI_CONFIG_AREA 0x00
-#define PERM_CONFIG_AREA 0x01
-#define BL_CONFIG_AREA 0x02
-#define DISP_CONFIG_AREA 0x03
+#define NAME_BUFFER_SIZE 128
+
+enum falsh_config_area {
+ UI_CONFIG_AREA = 0x00,
+ PERM_CONFIG_AREA = 0x01,
+ BL_CONFIG_AREA = 0x02,
+ DISP_CONFIG_AREA = 0x03
+};
enum flash_command {
CMD_WRITE_FW_BLOCK = 0x2,
@@ -70,9 +68,10 @@
CMD_READ_CONFIG_BLOCK = 0x5,
CMD_WRITE_CONFIG_BLOCK = 0x6,
CMD_ERASE_CONFIG = 0x7,
+ CMD_READ_SENSOR_ID = 0x8,
CMD_ERASE_BL_CONFIG = 0x9,
CMD_ERASE_DISP_CONFIG = 0xA,
- CMD_ENABLE_FLASH_PROG = 0xF,
+ CMD_ENABLE_FLASH_PROG = 0xF
};
enum flash_area {
@@ -81,6 +80,11 @@
CONFIG_AREA
};
+enum image_file_option {
+ OPTION_BUILD_INFO = 0,
+ OPTION_CONTAIN_BOOTLOADER = 1,
+};
+
#define SLEEP_MODE_NORMAL (0x00)
#define SLEEP_MODE_SENSOR_SLEEP (0x01)
#define SLEEP_MODE_RESERVED0 (0x02)
@@ -91,6 +95,8 @@
#define ERASE_WAIT_MS (5 * 1000)
#define RESET_WAIT_MS (500)
+#define POLLING_MODE 0
+
#define SLEEP_TIME_US 50
static ssize_t fwu_sysfs_show_image(struct file *data_file,
@@ -101,6 +107,9 @@
struct kobject *kobj, struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count);
+static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
@@ -139,6 +148,40 @@
static int fwu_wait_for_idle(int timeout_ms);
+struct image_header_data {
+ union {
+ struct {
+ /* 0x00-0x0F */
+ unsigned char file_checksum[4];
+ unsigned char reserved_04;
+ unsigned char reserved_05;
+ unsigned char options_firmware_id:1;
+ unsigned char options_contain_bootloader:1;
+ unsigned char options_reserved:6;
+ unsigned char bootloader_version;
+ unsigned char firmware_size[4];
+ unsigned char config_size[4];
+ /* 0x10-0x1F */
+ unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE];
+ unsigned char reserved_1a;
+ unsigned char reserved_1b;
+ unsigned char reserved_1c;
+ unsigned char reserved_1d;
+ unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
+ /* 0x20-0x2F */
+ unsigned char reserved_20_2f[0x10];
+ /* 0x30-0x3F */
+ unsigned char ds_firmware_id[0x10];
+ /* 0x40-0x4F */
+ unsigned char ds_customize_info[10];
+ unsigned char reserved_4a_4f[6];
+ /* 0x50-0x53*/
+ unsigned char firmware_id[4];
+ } __packed;
+ unsigned char data[54];
+ };
+};
+
struct image_header {
unsigned int checksum;
unsigned int image_size;
@@ -147,6 +190,8 @@
unsigned char bootloader_version;
unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
+ unsigned int firmware_id;
+ bool is_contain_build_info;
};
struct pdt_properties {
@@ -245,6 +290,7 @@
struct f34_flash_properties flash_properties;
struct workqueue_struct *fwu_workqueue;
struct delayed_work fwu_work;
+ char *firmware_name;
};
static struct bin_attribute dev_attr_data = {
@@ -258,6 +304,9 @@
};
static struct device_attribute attrs[] = {
+ __ATTR(forceflash, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_force_reflash_store),
__ATTR(doreflash, S_IWUGO,
synaptics_rmi4_show_error,
fwu_sysfs_do_reflash_store),
@@ -308,18 +357,36 @@
(unsigned int)ptr[3] * 0x1000000;
}
+static unsigned int extract_uint_be(const unsigned char *ptr)
+{
+ return (unsigned int)ptr[3] +
+ (unsigned int)ptr[2] * 0x100 +
+ (unsigned int)ptr[1] * 0x10000 +
+ (unsigned int)ptr[0] * 0x1000000;
+}
+
static void parse_header(struct image_header *header,
const unsigned char *fw_image)
{
- header->checksum = extract_uint(&fw_image[CHECKSUM_OFFSET]);
- header->bootloader_version = fw_image[BOOTLOADER_VERSION_OFFSET];
- header->image_size = extract_uint(&fw_image[IMAGE_SIZE_OFFSET]);
- header->config_size = extract_uint(&fw_image[CONFIG_SIZE_OFFSET]);
- memcpy(header->product_id, &fw_image[PRODUCT_ID_OFFSET],
- SYNAPTICS_RMI4_PRODUCT_ID_SIZE);
- header->product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE] = 0;
- memcpy(header->product_info, &fw_image[PRODUCT_INFO_OFFSET],
- SYNAPTICS_RMI4_PRODUCT_INFO_SIZE);
+ struct image_header_data *data = (struct image_header_data *)fw_image;
+ header->checksum = extract_uint(data->file_checksum);
+ header->bootloader_version = data->bootloader_version;
+ header->image_size = extract_uint(data->firmware_size);
+ header->config_size = extract_uint(data->config_size);
+ memcpy(header->product_id, data->product_id,
+ sizeof(data->product_id));
+ header->product_id[sizeof(data->product_info)] = 0;
+ memcpy(header->product_info, data->product_info,
+ sizeof(data->product_info));
+
+ header->is_contain_build_info =
+ (data->options_firmware_id == (1 << OPTION_BUILD_INFO));
+ if (header->is_contain_build_info) {
+ header->firmware_id = extract_uint(data->firmware_id);
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s Firwmare build id %d\n", __func__,
+ header->firmware_id);
+ }
#ifdef DEBUG_FW_UPDATE
dev_info(&fwu->rmi4_data->i2c_client->dev,
@@ -516,6 +583,9 @@
int count = 0;
int timeout_count = ((timeout_ms * 1000) / SLEEP_TIME_US) + 1;
do {
+ #if POLLING_MODE
+ fwu_read_f34_flash_status();
+ #endif
if (fwu->flash_control.command == 0x00)
return 0;
@@ -533,7 +603,7 @@
return -ETIMEDOUT;
}
-static enum flash_area fwu_go_nogo(void)
+static enum flash_area fwu_go_nogo(struct image_header *header)
{
int retval = 0;
int index = 0;
@@ -569,7 +639,6 @@
goto exit;
}
-
/* device firmware id */
retval = fwu->fn_ptr->read(fwu->rmi4_data,
fwu->f01_fd.query_base_addr + 18,
@@ -577,37 +646,45 @@
sizeof(firmware_id));
if (retval < 0) {
dev_err(&i2c_client->dev,
- "Failed to read firmware ID (code %d).\n", retval);
+ "%s: Failed to read firmware ID (code %d).\n",
+ __func__, retval);
goto exit;
}
firmware_id[3] = 0;
deviceFirmwareID = extract_uint(firmware_id);
/* .img firmware id */
- strptr = strnstr(fwu->rmi4_data->fw_image_name, "PR",
- sizeof(fwu->rmi4_data->fw_image_name));
- if (!strptr) {
+ if (header->is_contain_build_info) {
dev_err(&i2c_client->dev,
- "No valid PR number (PRxxxxxxx)" \
- "found in image file name...\n");
- goto exit;
+ "%s: Image option contains build info.\n",
+ __func__);
+ imageFirmwareID = header->firmware_id;
+ } else {
+ strptr = strnstr(fwu->firmware_name, "PR",
+ sizeof(fwu->firmware_name));
+ if (!strptr) {
+ dev_err(&i2c_client->dev,
+ "No valid PR number (PRxxxxxxx)" \
+ "found in image file name...\n");
+ goto exit;
+ }
+
+ strptr += 2;
+ while (strptr[index] >= '0' && strptr[index] <= '9') {
+ imagePR[index] = strptr[index];
+ index++;
+ }
+ imagePR[index] = 0;
+
+ retval = kstrtoul(imagePR, 10, &imageFirmwareID);
+ if (retval == -EINVAL) {
+ dev_err(&i2c_client->dev,
+ "invalid image firmware id...\n");
+ goto exit;
+ }
}
- strptr += 2;
- while (strptr[index] >= '0' && strptr[index] <= '9') {
- imagePR[index] = strptr[index];
- index++;
- }
- imagePR[index] = 0;
-
- retval = kstrtoul(imagePR, 10, &imageFirmwareID);
- if (retval == -EINVAL) {
- dev_err(&i2c_client->dev,
- "invalid image firmware id...\n");
- goto exit;
- }
-
- dev_info(&i2c_client->dev,
+ dev_dbg(&i2c_client->dev,
"Device firmware id %d, .img firmware id %d\n",
deviceFirmwareID,
(unsigned int)imageFirmwareID);
@@ -617,7 +694,8 @@
} else if (imageFirmwareID < deviceFirmwareID) {
flash_area = NONE;
dev_info(&i2c_client->dev,
- "Img fw is older than device fw. Skip fw update.\n");
+ "%s: Img fw is older than device fw. Skip fw update.\n",
+ __func__);
goto exit;
}
@@ -628,24 +706,29 @@
sizeof(config_id));
if (retval < 0) {
dev_err(&i2c_client->dev,
- "Failed to read config ID (code %d).\n", retval);
+ "%s: Failed to read config ID (code %d).\n",
+ __func__, retval);
flash_area = NONE;
goto exit;
}
- deviceConfigID = extract_uint(config_id);
+ deviceConfigID = extract_uint_be(config_id);
- dev_info(&i2c_client->dev,
+ dev_dbg(&i2c_client->dev,
"Device config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n",
config_id[0], config_id[1], config_id[2], config_id[3]);
/* .img config id */
- dev_info(&i2c_client->dev,
+ dev_dbg(&i2c_client->dev,
".img config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n",
fwu->config_data[0],
fwu->config_data[1],
fwu->config_data[2],
fwu->config_data[3]);
- imageConfigID = extract_uint(fwu->config_data);
+ imageConfigID = extract_uint_be(fwu->config_data);
+
+ dev_dbg(&i2c_client->dev,
+ "%s: Device config ID %d, .img config ID %d\n",
+ __func__, deviceConfigID, imageConfigID);
if (imageConfigID > deviceConfigID) {
flash_area = CONFIG_AREA;
@@ -656,10 +739,10 @@
kfree(imagePR);
if (flash_area == NONE)
dev_info(&i2c_client->dev,
- "Nothing needs to be updated\n");
+ "%s: Nothing needs to be updated\n", __func__);
else
dev_info(&i2c_client->dev,
- "Update %s block\n",
+ "%s: Update %s block\n", __func__,
flash_area == UI_FIRMWARE ? "UI FW" : "CONFIG");
return flash_area;
}
@@ -1210,7 +1293,7 @@
static int fwu_start_reflash(void)
{
- int retval;
+ int retval = 0;
struct image_header header;
const unsigned char *fw_image;
const struct firmware *fw_entry = NULL;
@@ -1229,18 +1312,30 @@
if (fwu->ext_data_source)
fw_image = fwu->ext_data_source;
else {
- dev_dbg(&fwu->rmi4_data->i2c_client->dev,
- "%s: Requesting firmware image %s\n",
- __func__, fwu->rmi4_data->fw_image_name);
+ fwu->firmware_name = kcalloc(NAME_BUFFER_SIZE,
+ sizeof(char), GFP_KERNEL);
+ if (!fwu->firmware_name) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s Failed to allocate firmware name (%d).\n",
+ __func__, NAME_BUFFER_SIZE);
+ retval = -ENOMEM;
+ goto memory_exit;
+ }
+
+ snprintf(fwu->firmware_name, NAME_BUFFER_SIZE, "%s",
+ fwu->rmi4_data->fw_image_name);
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Requesting firmware image %s\n",
+ __func__, fwu->firmware_name);
retval = request_firmware(&fw_entry,
- fwu->rmi4_data->fw_image_name,
+ fwu->firmware_name,
&fwu->rmi4_data->i2c_client->dev);
if (retval != 0) {
dev_err(&fwu->rmi4_data->i2c_client->dev,
"%s: Firmware image %s not available\n",
__func__,
- fwu->rmi4_data->fw_image_name);
+ fwu->firmware_name);
retval = -EINVAL;
goto exit;
}
@@ -1264,7 +1359,7 @@
if (fwu->ext_data_source)
flash_area = UI_FIRMWARE;
else
- flash_area = fwu_go_nogo();
+ flash_area = fwu_go_nogo(&header);
switch (flash_area) {
case NONE:
@@ -1318,6 +1413,8 @@
pr_notice("%s: End of reflash process\n", __func__);
exit:
+ kfree(fwu->firmware_name);
+memory_exit:
return retval;
}
@@ -1371,6 +1468,40 @@
return count;
}
+static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned int input;
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+
+ if (sscanf(buf, "%u", &input) != 1) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (input != 1) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ fwu->force_update = true;
+ retval = synaptics_fw_updater(fwu->ext_data_source);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to do reflash\n",
+ __func__);
+ goto exit;
+ }
+
+ retval = count;
+
+exit:
+ kfree(fwu->ext_data_source);
+ fwu->ext_data_source = NULL;
+ return retval;
+}
+
static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 4e2b1a4..ed53c41 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -103,20 +103,25 @@
static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data);
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#ifdef CONFIG_PM
+static int synaptics_rmi4_suspend(struct device *dev);
+
+static int synaptics_rmi4_resume(struct device *dev);
+
static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t synaptics_rmi4_full_pm_cycle_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
static void synaptics_rmi4_early_suspend(struct early_suspend *h);
static void synaptics_rmi4_late_resume(struct early_suspend *h);
-
-static int synaptics_rmi4_suspend(struct device *dev);
-
-static int synaptics_rmi4_resume(struct device *dev);
+#endif
#endif
static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
@@ -228,7 +233,7 @@
};
static struct device_attribute attrs[] = {
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#ifdef CONFIG_PM
__ATTR(full_pm_cycle, (S_IRUGO | S_IWUGO),
synaptics_rmi4_full_pm_cycle_show,
synaptics_rmi4_full_pm_cycle_store),
@@ -259,8 +264,7 @@
static bool exp_fn_inited;
static struct mutex exp_fn_list_mutex;
static struct list_head exp_fn_list;
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#ifdef CONFIG_PM
static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -283,6 +287,36 @@
return count;
}
+
+#ifdef CONFIG_FB
+static void configure_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval = 0;
+
+ rmi4_data->fb_notif.notifier_call = fb_notifier_callback;
+
+ retval = fb_register_client(&rmi4_data->fb_notif);
+ if (retval)
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Unable to register fb_notifier: %d\n", retval);
+ return;
+}
+#elif defined CONFIG_HAS_EARLYSUSPEND
+static void configure_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+ rmi4_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ rmi4_data->early_suspend.suspend = synaptics_rmi4_early_suspend;
+ rmi4_data->early_suspend.resume = synaptics_rmi4_late_resume;
+ register_early_suspend(&rmi4_data->early_suspend);
+
+ return;
+}
+#else
+static void configure_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+ return;
+}
+#endif
#endif
static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
@@ -1081,17 +1115,25 @@
bool enable)
{
int retval = 0;
- unsigned char intr_status;
+ unsigned char *intr_status;
if (enable) {
if (rmi4_data->irq_enabled)
return retval;
+ intr_status = kzalloc(rmi4_data->num_of_intr_regs, GFP_KERNEL);
+ if (!intr_status) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc memory\n",
+ __func__);
+ return -ENOMEM;
+ }
/* Clear interrupts first */
retval = synaptics_rmi4_i2c_read(rmi4_data,
rmi4_data->f01_data_base_addr + 1,
- &intr_status,
+ intr_status,
rmi4_data->num_of_intr_regs);
+ kfree(intr_status);
if (retval < 0)
return retval;
@@ -1838,7 +1880,7 @@
RMI4_VTG_MIN_UV, RMI4_VTG_MAX_UV);
if (retval) {
dev_err(&rmi4_data->i2c_client->dev,
- "regulator set_vtg failed retval=%d\n",
+ "regulator set_vtg failed retval =%d\n",
retval);
goto err_set_vtg_vdd;
}
@@ -1861,7 +1903,7 @@
RMI4_I2C_VTG_MIN_UV, RMI4_I2C_VTG_MAX_UV);
if (retval) {
dev_err(&rmi4_data->i2c_client->dev,
- "reg set i2c vtg failed retval=%d\n",
+ "reg set i2c vtg failed retval =%d\n",
retval);
goto err_set_vtg_i2c;
}
@@ -2194,12 +2236,7 @@
goto err_register_input;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
- rmi4_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
- rmi4_data->early_suspend.suspend = synaptics_rmi4_early_suspend;
- rmi4_data->early_suspend.resume = synaptics_rmi4_late_resume;
- register_early_suspend(&rmi4_data->early_suspend);
-#endif
+ configure_sleep(rmi4_data);
if (!exp_fn_inited) {
mutex_init(&exp_fn_list_mutex);
@@ -2437,7 +2474,27 @@
return;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct fb_event *evdata = data;
+ int *blank;
+ struct synaptics_rmi4_data *rmi4_data =
+ container_of(self, struct synaptics_rmi4_data, fb_notif);
+
+ if (evdata && evdata->data && event == FB_EVENT_BLANK &&
+ rmi4_data && rmi4_data->i2c_client) {
+ blank = evdata->data;
+ if (*blank == FB_BLANK_UNBLANK)
+ synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
+ else if (*blank == FB_BLANK_POWERDOWN)
+ synaptics_rmi4_suspend(&(rmi4_data->input_dev->dev));
+ }
+
+ return 0;
+}
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
/**
* synaptics_rmi4_early_suspend()
*
@@ -2492,6 +2549,75 @@
}
#endif
+static int synaptics_rmi4_regulator_lpm(struct synaptics_rmi4_data *rmi4_data,
+ bool on)
+{
+ int retval;
+
+ if (on == false)
+ goto regulator_hpm;
+
+ retval = reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_LPM_LOAD_UA);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vcc_ana set_opt failed rc=%d\n",
+ retval);
+ goto fail_regulator_lpm;
+ }
+
+ if (rmi4_data->board->i2c_pull_up) {
+ retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
+ RMI4_I2C_LOAD_UA);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vcc_i2c set_opt failed rc=%d\n",
+ retval);
+ goto fail_regulator_lpm;
+ }
+ }
+
+ return 0;
+
+regulator_hpm:
+
+ retval = reg_set_optimum_mode_check(rmi4_data->vdd,
+ RMI4_ACTIVE_LOAD_UA);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vcc_ana set_opt failed rc=%d\n",
+ retval);
+ goto fail_regulator_hpm;
+ }
+
+ if (rmi4_data->board->i2c_pull_up) {
+ retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
+ RMI4_I2C_LOAD_UA);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vcc_i2c set_opt failed rc=%d\n",
+ retval);
+ goto fail_regulator_hpm;
+ }
+ }
+
+ return 0;
+
+fail_regulator_lpm:
+ reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_ACTIVE_LOAD_UA);
+ if (rmi4_data->board->i2c_pull_up)
+ reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
+ RMI4_I2C_LOAD_UA);
+
+ return retval;
+
+fail_regulator_hpm:
+ reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_LPM_LOAD_UA);
+ if (rmi4_data->board->i2c_pull_up)
+ reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
+ RMI4_I2C_LPM_LOAD_UA);
+ return retval;
+}
+
/**
* synaptics_rmi4_suspend()
*
@@ -2505,6 +2631,7 @@
static int synaptics_rmi4_suspend(struct device *dev)
{
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ int retval;
if (!rmi4_data->sensor_sleep) {
rmi4_data->touch_stopped = true;
@@ -2513,6 +2640,12 @@
synaptics_rmi4_sensor_sleep(rmi4_data);
}
+ retval = synaptics_rmi4_regulator_lpm(rmi4_data, true);
+ if (retval < 0) {
+ dev_err(dev, "failed to enter low power mode\n");
+ return retval;
+ }
+
return 0;
}
@@ -2529,6 +2662,13 @@
static int synaptics_rmi4_resume(struct device *dev)
{
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ int retval;
+
+ retval = synaptics_rmi4_regulator_lpm(rmi4_data, false);
+ if (retval < 0) {
+ dev_err(dev, "failed to enter active power mode\n");
+ return retval;
+ }
synaptics_rmi4_sensor_wake(rmi4_data);
rmi4_data->touch_stopped = false;
@@ -2537,10 +2677,15 @@
return 0;
}
+#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND))
static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
.suspend = synaptics_rmi4_suspend,
.resume = synaptics_rmi4_resume,
};
+#else
+static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
+};
+#endif
#endif
static const struct i2c_device_id synaptics_rmi4_id_table[] = {
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index 16b1f8f..681b95c 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -24,10 +24,14 @@
#define SYNAPTICS_DS4 (1 << 0)
#define SYNAPTICS_DS5 (1 << 1)
#define SYNAPTICS_DSX_DRIVER_PRODUCT SYNAPTICS_DS4
-#define SYNAPTICS_DSX_DRIVER_VERSION 0x1004
+#define SYNAPTICS_DSX_DRIVER_VERSION 0x1005
#include <linux/version.h>
-#ifdef CONFIG_HAS_EARLYSUSPEND
+
+#ifdef CONFIG_FB
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#elif defined CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
@@ -227,6 +231,13 @@
unsigned char *data, unsigned short length);
int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable);
int (*reset_device)(struct synaptics_rmi4_data *rmi4_data);
+#ifdef CONFIG_FB
+ struct notifier_block fb_notif;
+#else
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+#endif
};
enum exp_fn {
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index b1960c6..b92ec7f 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -148,12 +148,26 @@
if (ret)
clk_disable_unprepare(drvdata->pclk);
}
+
+ if (ret)
+ goto fail;
+
+ if (drvdata->aclk) {
+ ret = clk_prepare_enable(drvdata->aclk);
+ if (ret) {
+ clk_disable_unprepare(drvdata->clk);
+ clk_disable_unprepare(drvdata->pclk);
+ }
+ }
+
fail:
return ret;
}
static void __disable_clocks(struct msm_iommu_drvdata *drvdata)
{
+ if (drvdata->aclk)
+ clk_disable_unprepare(drvdata->aclk);
if (drvdata->clk)
clk_disable_unprepare(drvdata->clk);
clk_disable_unprepare(drvdata->pclk);
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index 8a26003..8e68beb 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -804,6 +804,19 @@
ctx_drvdata = dev_get_drvdata(&pdev->dev);
BUG_ON(!ctx_drvdata);
+ if (!drvdata->ctx_attach_count) {
+ pr_err("Unexpected IOMMU page fault!\n");
+ pr_err("name = %s\n", drvdata->name);
+ pr_err("Power is OFF. Unable to read page fault information\n");
+ /*
+ * We cannot determine which context bank caused the issue so
+ * we just return handled here to ensure IRQ handler code is
+ * happy
+ */
+ ret = IRQ_HANDLED;
+ goto fail;
+ }
+
ret = __enable_clocks(drvdata);
if (ret) {
ret = IRQ_NONE;
diff --git a/drivers/iommu/msm_iommu_dev-v0.c b/drivers/iommu/msm_iommu_dev-v0.c
index 7ae0b21..059216e 100644
--- a/drivers/iommu/msm_iommu_dev-v0.c
+++ b/drivers/iommu/msm_iommu_dev-v0.c
@@ -129,7 +129,8 @@
}
static int msm_iommu_parse_dt(struct platform_device *pdev,
- struct msm_iommu_drvdata *drvdata)
+ struct msm_iommu_drvdata *drvdata,
+ int *needs_alt_core_clk)
{
#ifdef CONFIG_OF_DEVICE
struct device_node *child;
@@ -169,6 +170,10 @@
pr_err("%s: Missing property label\n", __func__);
return -EINVAL;
}
+
+ *needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node,
+ "qcom,needs-alt-core-clk");
+
drvdata->sec_id = -1;
drvdata->ttbr_split = 0;
#endif
@@ -176,7 +181,8 @@
}
static int __get_clocks(struct platform_device *pdev,
- struct msm_iommu_drvdata *drvdata)
+ struct msm_iommu_drvdata *drvdata,
+ int needs_alt_core_clk)
{
int ret = 0;
@@ -199,6 +205,18 @@
} else {
drvdata->clk = NULL;
}
+
+ if (needs_alt_core_clk) {
+ drvdata->aclk = devm_clk_get(&pdev->dev, "alt_core_clk");
+ if (IS_ERR(drvdata->aclk))
+ return PTR_ERR(drvdata->aclk);
+ }
+
+ if (drvdata->aclk && clk_get_rate(drvdata->aclk) == 0) {
+ ret = clk_round_rate(drvdata->aclk, 1000);
+ clk_set_rate(drvdata->aclk, ret);
+ }
+
return 0;
fail:
return ret;
@@ -206,35 +224,13 @@
static void __put_clocks(struct msm_iommu_drvdata *drvdata)
{
+ if (drvdata->aclk)
+ clk_put(drvdata->aclk);
if (drvdata->clk)
clk_put(drvdata->clk);
clk_put(drvdata->pclk);
}
-static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
-{
- int ret;
-
- ret = clk_prepare_enable(drvdata->pclk);
- if (ret)
- goto fail;
-
- if (drvdata->clk) {
- ret = clk_prepare_enable(drvdata->clk);
- if (ret)
- clk_disable_unprepare(drvdata->pclk);
- }
-fail:
- return ret;
-}
-
-static void __disable_clocks(struct msm_iommu_drvdata *drvdata)
-{
- if (drvdata->clk)
- clk_disable_unprepare(drvdata->clk);
- clk_disable_unprepare(drvdata->pclk);
-}
-
/*
* Do a basic check of the IOMMU by performing an ATS operation
* on context bank 0.
@@ -326,6 +322,7 @@
struct msm_iommu_drvdata *drvdata;
struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
int ret;
+ int needs_alt_core_clk = 0;
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
@@ -335,7 +332,7 @@
}
if (pdev->dev.of_node) {
- ret = msm_iommu_parse_dt(pdev, drvdata);
+ ret = msm_iommu_parse_dt(pdev, drvdata, &needs_alt_core_clk);
if (ret)
goto fail;
} else if (pdev->dev.platform_data) {
@@ -382,12 +379,12 @@
drvdata->dev = &pdev->dev;
- ret = __get_clocks(pdev, drvdata);
+ ret = __get_clocks(pdev, drvdata, needs_alt_core_clk);
if (ret)
goto fail;
- __enable_clocks(drvdata);
+ iommu_access_ops_v0.iommu_clk_on(drvdata);
msm_iommu_reset(drvdata->base, drvdata->glb_base, drvdata->ncb);
@@ -401,7 +398,7 @@
msm_iommu_add_drv(drvdata);
platform_set_drvdata(pdev, drvdata);
- __disable_clocks(drvdata);
+ iommu_access_ops_v0.iommu_clk_off(drvdata);
pmon_info = msm_iommu_pm_alloc(&pdev->dev);
if (pmon_info != NULL) {
@@ -430,7 +427,7 @@
return 0;
fail_clk:
- __disable_clocks(drvdata);
+ iommu_access_ops_v0.iommu_clk_off(drvdata);
__put_clocks(drvdata);
fail:
return ret;
@@ -618,9 +615,9 @@
goto fail;
}
- __enable_clocks(drvdata);
+ iommu_access_ops_v0.iommu_clk_on(drvdata);
__program_m2v_tables(drvdata, ctx_drvdata);
- __disable_clocks(drvdata);
+ iommu_access_ops_v0.iommu_clk_off(drvdata);
dev_info(&pdev->dev, "context %s using bank %d\n", ctx_drvdata->name,
ctx_drvdata->num);
diff --git a/drivers/iommu/msm_iommu_pagetable.c b/drivers/iommu/msm_iommu_pagetable.c
index 9614692..b871a5a 100644
--- a/drivers/iommu/msm_iommu_pagetable.c
+++ b/drivers/iommu/msm_iommu_pagetable.c
@@ -21,6 +21,7 @@
#include <mach/iommu.h>
#include <mach/msm_iommu_priv.h>
+#include <trace/events/kmem.h>
#include "msm_iommu_pagetable.h"
/* Sharability attributes of MSM IOMMU mappings */
@@ -471,6 +472,8 @@
chunk_size = SZ_1M;
/* 64k or 4k determined later */
+ trace_iommu_map_range(va, pa, sg->length, chunk_size);
+
/* for 1M and 16M, only first level entries are required */
if (chunk_size >= SZ_1M) {
if (chunk_size == SZ_16M) {
@@ -529,6 +532,9 @@
else
chunk_size = SZ_4K;
+ trace_iommu_map_range(va, pa, sg->length,
+ chunk_size);
+
if (chunk_size == SZ_4K) {
sl_4k(&sl_table[sl_offset], pa, pgprot4k);
sl_offset++;
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 3667296..0233e18 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -93,6 +93,7 @@
#define FLASH_LED_STROBE_CTRL(base) (base + 0x47)
#define FLASH_LED_UNLOCK_SECURE(base) (base + 0xD0)
#define FLASH_LED_TORCH(base) (base + 0xE4)
+#define FLASH_FAULT_DETECT(base) (base + 0x51)
#define FLASH_MAX_LEVEL 0x4F
#define FLASH_NO_MASK 0x00
@@ -106,10 +107,9 @@
#define FLASH_TMR_MASK 0x03
#define FLASH_TMR_WATCHDOG 0x03
#define FLASH_TMR_SAFETY 0x00
-
+#define FLASH_FAULT_DETECT_MASK 0X80
#define FLASH_HW_VREG_OK 0x80
#define FLASH_VREG_MASK 0xC0
-
#define FLASH_STARTUP_DLY_MASK 0x02
#define FLASH_ENABLE_ALL 0xE0
@@ -120,6 +120,7 @@
#define FLASH_ENABLE_LED_0 0x40
#define FLASH_ENABLE_LED_1 0x20
#define FLASH_INIT_MASK 0xE0
+#define FLASH_SELFCHECK_ENABLE 0x80
#define FLASH_STROBE_SW 0xC0
#define FLASH_STROBE_HW 0xC4
@@ -130,7 +131,7 @@
#define FLASH_CURRENT_PRGM_MIN 1
#define FLASH_CURRENT_PRGM_SHIFT 1
#define FLASH_CURRENT_MAX 0x4F
-#define FLASH_CURRENT_TORCH 0x0F
+#define FLASH_CURRENT_TORCH 0x07
#define FLASH_DURATION_200ms 0x13
#define FLASH_CLAMP_200mA 0x0F
@@ -171,6 +172,8 @@
#define LED_MPP_SINK_MASK 0x07
#define LED_MPP_MODE_MASK 0x7F
#define LED_MPP_EN_MASK 0x80
+#define LED_MPP_SRC_MASK 0x0F
+#define LED_MPP_MODE_CTRL_MASK 0x70
#define LED_MPP_MODE_SINK (0x06 << 4)
#define LED_MPP_MODE_ENABLE 0x01
@@ -180,6 +183,20 @@
#define LED_MPP_EN_DISABLE 0x00
#define MPP_SOURCE_DTEST1 0x08
+
+#define KPDBL_MAX_LEVEL LED_FULL
+#define KPDBL_ROW_SRC_SEL(base) (base + 0x40)
+#define KPDBL_ENABLE(base) (base + 0x46)
+#define KPDBL_ROW_SRC(base) (base + 0xE5)
+
+#define KPDBL_ROW_SRC_SEL_VAL_MASK 0x0F
+#define KPDBL_ROW_SCAN_EN_MASK 0x80
+#define KPDBL_ROW_SCAN_VAL_MASK 0x0F
+#define KPDBL_ROW_SCAN_EN_SHIFT 7
+#define KPDBL_MODULE_EN 0x80
+#define KPDBL_MODULE_DIS 0x00
+#define KPDBL_MODULE_EN_MASK 0x80
+
/**
* enum qpnp_leds - QPNP supported led ids
* @QPNP_ID_WLED - White led backlight
@@ -192,6 +209,7 @@
QPNP_ID_RGB_GREEN,
QPNP_ID_RGB_BLUE,
QPNP_ID_LED_MPP,
+ QPNP_ID_KPDBL,
QPNP_ID_MAX,
};
@@ -237,9 +255,9 @@
DELAY_128us,
};
-enum rgb_mode {
- RGB_MODE_PWM = 0,
- RGB_MODE_LPG,
+enum led_mode {
+ PWM_MODE = 0,
+ LPG_MODE,
};
static u8 wled_debug_regs[] = {
@@ -267,6 +285,10 @@
0x40, 0x41, 0x42, 0x45, 0x46, 0x4c,
};
+static u8 kpdbl_debug_regs[] = {
+ 0x40, 0x46, 0xb1, 0xb3, 0xb4, 0xe5,
+};
+
/**
* wled_config_data - wled configuration data
* @num_strings - number of wled strings supported
@@ -331,6 +353,25 @@
};
/**
+ * kpdbl_config_data - kpdbl configuration data
+ * @pwm_device - pwm device
+ * @pwm_channel - pwm channel to be configured for led
+ * @pwm_period_us - period for pwm, in us
+ * @row_src_sel_val - select source, 0 for vph_pwr and 1 for vbst
+ * @row_scan_en - enable row scan
+ * @row_scan_val - map to enable needed rows
+ */
+struct kpdbl_config_data {
+ struct pwm_device *pwm_dev;
+ int pwm_channel;
+ u32 pwm_period_us;
+ u32 row_src_sel_val;
+ u32 row_scan_en;
+ u32 row_scan_val;
+ u8 mode;
+};
+
+/**
* rgb_config_data - rgb configuration data
* @lut_params - lut parameters to be used by pwm driver
* @pwm_device - pwm device
@@ -372,6 +413,7 @@
spinlock_t lock;
struct wled_config_data *wled_cfg;
struct flash_config_data *flash_cfg;
+ struct kpdbl_config_data *kpdbl_cfg;
struct rgb_config_data *rgb_cfg;
struct mpp_config_data *mpp_cfg;
int max_current;
@@ -414,7 +456,8 @@
led->spmi_dev->sid,
led->base + regs[i],
&val, sizeof(val));
- pr_debug("0x%x = 0x%x\n", led->base + regs[i], val);
+ pr_debug("%s: 0x%x = 0x%x\n", led->cdev.name,
+ led->base + regs[i], val);
}
pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
}
@@ -511,7 +554,8 @@
return rc;
}
- val = led->mpp_cfg->source_sel | led->mpp_cfg->mode_ctrl;
+ val = (led->mpp_cfg->source_sel & LED_MPP_SRC_MASK) |
+ (led->mpp_cfg->mode_ctrl & LED_MPP_MODE_CTRL_MASK);
rc = qpnp_led_masked_write(led,
LED_MPP_MODE_CTRL(led->base), LED_MPP_MODE_MASK,
@@ -592,18 +636,10 @@
return rc;
}
- qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
- FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Max current reg write failed(%d)\n",
- rc);
- return rc;
- }
-
rc = qpnp_led_masked_write(led,
led->flash_cfg->current_addr,
- FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+ FLASH_CURRENT_MASK,
+ led->flash_cfg->current_prgm);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Current reg write failed(%d)\n", rc);
@@ -612,7 +648,8 @@
rc = qpnp_led_masked_write(led,
led->flash_cfg->second_addr,
- FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+ FLASH_CURRENT_MASK,
+ led->flash_cfg->current_prgm);
if (rc) {
dev_err(&led->spmi_dev->dev,
"2nd Current reg write failed(%d)\n",
@@ -620,6 +657,16 @@
return rc;
}
+ qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
+ FLASH_CURRENT_MASK,
+ led->max_current);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Max current reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
+
rc = qpnp_led_masked_write(led,
FLASH_ENABLE_CONTROL(led->base),
FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
@@ -629,9 +676,22 @@
return rc;
}
} else {
+ /* Set flash safety timer */
rc = qpnp_led_masked_write(led,
- FLASH_MAX_CURR(led->base),
- FLASH_CURRENT_MASK, FLASH_CURRENT_MAX);
+ FLASH_SAFETY_TIMER(led->base),
+ FLASH_SAFETY_TIMER_MASK,
+ led->flash_cfg->duration);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Safety timer reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
+
+ /* Set max current */
+ rc = qpnp_led_masked_write(led,
+ FLASH_MAX_CURR(led->base), FLASH_CURRENT_MASK,
+ FLASH_MAX_LEVEL);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Max current reg write failed(%d)\n",
@@ -639,6 +699,18 @@
return rc;
}
+ /* Set clamp current */
+ rc = qpnp_led_masked_write(led,
+ FLASH_CLAMP_CURR(led->base),
+ FLASH_CURRENT_MASK,
+ led->flash_cfg->clamp_curr);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Clamp current reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
+
/* Write 0x80 to MODULE_ENABLE before writing 0xE0
* in order to avoid reg value goes from 0x00 to
* 0xE0. This causes a hardware bug.
@@ -674,16 +746,6 @@
}
rc = qpnp_led_masked_write(led,
- FLASH_CLAMP_CURR(led->base),
- FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Clamp Current reg write failed(%d)\n",
- rc);
- return rc;
- }
-
- rc = qpnp_led_masked_write(led,
FLASH_ENABLE_CONTROL(led->base),
FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
if (rc) {
@@ -722,25 +784,16 @@
if (rc) {
dev_err(&led->spmi_dev->dev,
"Secure reg write failed(%d)\n", rc);
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_LED_TORCH(led->base),
- FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Torch reg write failed(%d)\n", rc);
return rc;
}
rc = qpnp_led_masked_write(led,
- FLASH_SAFETY_TIMER(led->base),
- FLASH_SAFETY_TIMER_MASK,
- led->flash_cfg->duration);
+ FLASH_LED_TORCH(led->base),
+ FLASH_TORCH_MASK,
+ FLASH_LED_TORCH_DISABLE);
if (rc) {
dev_err(&led->spmi_dev->dev,
- "Safety timer reg write failed(%d)\n",
- rc);
+ "Torch reg write failed(%d)\n", rc);
return rc;
}
}
@@ -770,20 +823,57 @@
return 0;
}
+static int qpnp_kpdbl_set(struct qpnp_led_data *led)
+{
+ int duty_us;
+ int rc;
+
+ if (led->cdev.brightness) {
+ rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
+ KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
+ duty_us = (led->kpdbl_cfg->pwm_period_us *
+ led->cdev.brightness) / KPDBL_MAX_LEVEL;
+ rc = pwm_config(led->kpdbl_cfg->pwm_dev, duty_us,
+ led->kpdbl_cfg->pwm_period_us);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev, "pwm config failed\n");
+ return rc;
+ }
+ rc = pwm_enable(led->kpdbl_cfg->pwm_dev);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
+ return rc;
+ }
+ } else {
+ pwm_disable(led->kpdbl_cfg->pwm_dev);
+ rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
+ KPDBL_MODULE_EN_MASK, KPDBL_MODULE_DIS);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Failed to write led enable reg\n");
+ return rc;
+ }
+ }
+
+ qpnp_dump_regs(led, kpdbl_debug_regs, ARRAY_SIZE(kpdbl_debug_regs));
+
+ return 0;
+}
+
static int qpnp_rgb_set(struct qpnp_led_data *led)
{
int duty_us;
int rc;
if (led->cdev.brightness) {
- if (led->rgb_cfg->mode == RGB_MODE_PWM) {
+ if (led->rgb_cfg->mode == PWM_MODE) {
duty_us = (led->rgb_cfg->pwm_period_us *
led->cdev.brightness) / LED_FULL;
rc = pwm_config(led->rgb_cfg->pwm_dev, duty_us,
led->rgb_cfg->pwm_period_us);
if (rc < 0) {
- dev_err(&led->spmi_dev->dev, "Failed to " \
- "configure pwm for new values\n");
+ dev_err(&led->spmi_dev->dev,
+ "pwm config failed\n");
return rc;
}
}
@@ -796,6 +886,10 @@
return rc;
}
rc = pwm_enable(led->rgb_cfg->pwm_dev);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
+ return rc;
+ }
} else {
pwm_disable(led->rgb_cfg->pwm_dev);
rc = qpnp_led_masked_write(led,
@@ -856,6 +950,12 @@
dev_err(&led->spmi_dev->dev,
"MPP set brightness failed (%d)\n", rc);
break;
+ case QPNP_ID_KPDBL:
+ rc = qpnp_kpdbl_set(led);
+ if (rc < 0)
+ dev_err(&led->spmi_dev->dev,
+ "KPDBL set brightness failed (%d)\n", rc);
+ break;
default:
dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
break;
@@ -881,6 +981,9 @@
case QPNP_ID_LED_MPP:
led->cdev.max_brightness = MPP_MAX_LEVEL;
break;
+ case QPNP_ID_KPDBL:
+ led->cdev.max_brightness = KPDBL_MAX_LEVEL;
+ break;
default:
dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
return -EINVAL;
@@ -1119,52 +1222,7 @@
"LED %d flash write failed(%d)\n", led->id, rc);
return rc;
}
- rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
- FLASH_INIT_MASK, FLASH_ENABLE_MODULE);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Enable reg write failed(%d)\n", rc);
- return rc;
- }
- /* Set flash safety timer */
- rc = qpnp_led_masked_write(led, FLASH_SAFETY_TIMER(led->base),
- FLASH_SAFETY_TIMER_MASK, led->flash_cfg->duration);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Safety timer reg write failed(%d)\n", rc);
- return rc;
- }
-
- /* Set max current */
- rc = qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
- FLASH_CURRENT_MASK, FLASH_MAX_LEVEL);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Max current reg write failed(%d)\n", rc);
- return rc;
- }
- /* Set clamp current */
- rc = qpnp_led_masked_write(led, FLASH_CLAMP_CURR(led->base),
- FLASH_CURRENT_MASK, led->flash_cfg->clamp_curr);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Clamp current reg write failed(%d)\n", rc);
- return rc;
- }
-
- /* Set timer control - safety or watchdog */
- if (led->flash_cfg->safety_timer)
- rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
- FLASH_TMR_MASK, FLASH_TMR_SAFETY);
- else
- rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
- FLASH_TMR_MASK, FLASH_TMR_WATCHDOG);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "LED timer ctrl reg write failed(%d)\n", rc);
- return rc;
- }
/* Set headroom */
rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
@@ -1174,6 +1232,47 @@
return rc;
}
+ /* Set startup delay */
+ rc = qpnp_led_masked_write(led,
+ FLASH_STARTUP_DELAY(led->base), FLASH_STARTUP_DLY_MASK,
+ led->flash_cfg->startup_dly);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Startup delay reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ /* Set timer control - safety or watchdog */
+ if (led->flash_cfg->safety_timer) {
+ rc = qpnp_led_masked_write(led,
+ FLASH_LED_TMR_CTRL(led->base),
+ FLASH_TMR_MASK, FLASH_TMR_SAFETY);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "LED timer ctrl reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
+ }
+
+ /* Set Vreg force */
+ rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
+ FLASH_VREG_MASK, FLASH_HW_VREG_OK);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Vreg OK reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ /* Set self fault check */
+ rc = qpnp_led_masked_write(led, FLASH_FAULT_DETECT(led->base),
+ FLASH_FAULT_DETECT_MASK, FLASH_SELFCHECK_ENABLE);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Fault detect reg write failed(%d)\n", rc);
+ return rc;
+ }
+
/* Set mask enable */
rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
FLASH_MASK_REG_MASK, FLASH_MASK_1);
@@ -1183,32 +1282,7 @@
return rc;
}
- /* Set startup delay */
- rc = qpnp_led_masked_write(led, FLASH_STARTUP_DELAY(led->base),
- FLASH_STARTUP_DLY_MASK, led->flash_cfg->startup_dly);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Startup delay reg write failed(%d)\n", rc);
- return rc;
- }
-
- rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
- FLASH_VREG_MASK, FLASH_HW_VREG_OK);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Vreg OK reg write failed(%d)\n", rc);
- return rc;
- }
-
- /* Set led current and disable module */
- rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
- FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Current reg write failed(%d)\n", rc);
- return rc;
- }
-
+ /* Disable flash LED module */
rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
if (rc) {
@@ -1217,7 +1291,6 @@
return rc;
}
- led->flash_cfg->torch_enable = false;
led->flash_cfg->strobe_type = 0;
/* dump flash registers */
@@ -1226,6 +1299,81 @@
return 0;
}
+static int __devinit qpnp_kpdbl_init(struct qpnp_led_data *led)
+{
+ int rc;
+ u8 val;
+
+ /* enable row source selct */
+ rc = qpnp_led_masked_write(led, KPDBL_ROW_SRC_SEL(led->base),
+ KPDBL_ROW_SRC_SEL_VAL_MASK, led->kpdbl_cfg->row_src_sel_val);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable row src sel write failed(%d)\n", rc);
+ return rc;
+ }
+
+ /* row source */
+ rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
+ KPDBL_ROW_SRC(led->base), &val, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to read from addr=%x, rc(%d)\n",
+ KPDBL_ROW_SRC(led->base), rc);
+ return rc;
+ }
+
+ val &= ~KPDBL_ROW_SCAN_VAL_MASK;
+ val |= led->kpdbl_cfg->row_scan_val;
+
+ led->kpdbl_cfg->row_scan_en <<= KPDBL_ROW_SCAN_EN_SHIFT;
+ val &= ~KPDBL_ROW_SCAN_EN_MASK;
+ val |= led->kpdbl_cfg->row_scan_en;
+
+ rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+ KPDBL_ROW_SRC(led->base), &val, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to write to addr=%x, rc(%d)\n",
+ KPDBL_ROW_SRC(led->base), rc);
+ return rc;
+ }
+
+ /* enable module */
+ rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
+ KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable module write failed(%d)\n", rc);
+ return rc;
+ }
+
+ if (led->kpdbl_cfg->pwm_channel != -1) {
+ led->kpdbl_cfg->pwm_dev =
+ pwm_request(led->kpdbl_cfg->pwm_channel,
+ led->cdev.name);
+
+ if (IS_ERR_OR_NULL(led->kpdbl_cfg->pwm_dev)) {
+ dev_err(&led->spmi_dev->dev,
+ "could not acquire PWM Channel %d, " \
+ "error %ld\n",
+ led->kpdbl_cfg->pwm_channel,
+ PTR_ERR(led->kpdbl_cfg->pwm_dev));
+ led->kpdbl_cfg->pwm_dev = NULL;
+ return -ENODEV;
+ }
+ } else {
+ dev_err(&led->spmi_dev->dev,
+ "Invalid PWM channel\n");
+ return -EINVAL;
+ }
+
+ /* dump kpdbl registers */
+ qpnp_dump_regs(led, kpdbl_debug_regs, ARRAY_SIZE(kpdbl_debug_regs));
+
+ return 0;
+}
+
static int __devinit qpnp_rgb_init(struct qpnp_led_data *led)
{
int rc, start_idx, idx_len;
@@ -1253,7 +1401,7 @@
return -ENODEV;
}
- if (led->rgb_cfg->mode == RGB_MODE_LPG) {
+ if (led->rgb_cfg->mode == LPG_MODE) {
start_idx =
led->rgb_cfg->duty_cycles->start_idx;
idx_len =
@@ -1296,7 +1444,7 @@
static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
{
- int rc;
+ int rc = 0;
switch (led->id) {
case QPNP_ID_WLED:
@@ -1322,12 +1470,18 @@
break;
case QPNP_ID_LED_MPP:
break;
+ case QPNP_ID_KPDBL:
+ rc = qpnp_kpdbl_init(led);
+ if (rc)
+ dev_err(&led->spmi_dev->dev,
+ "KPDBL initialize failed(%d)\n", rc);
+ break;
default:
dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
return -EINVAL;
}
- return 0;
+ return rc;
}
static int __devinit qpnp_get_common_configs(struct qpnp_led_data *led,
@@ -1509,6 +1663,66 @@
led->flash_cfg->safety_timer =
of_property_read_bool(node, "qcom,safety-timer");
+ led->flash_cfg->torch_enable =
+ of_property_read_bool(node, "qcom,torch-enable");
+
+ return 0;
+}
+
+static int __devinit qpnp_get_config_kpdbl(struct qpnp_led_data *led,
+ struct device_node *node)
+{
+ int rc;
+ u32 val;
+
+ led->kpdbl_cfg = devm_kzalloc(&led->spmi_dev->dev,
+ sizeof(struct kpdbl_config_data), GFP_KERNEL);
+ if (!led->kpdbl_cfg) {
+ dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ rc = of_property_read_u32(node, "qcom,mode", &val);
+ if (!rc)
+ led->kpdbl_cfg->mode = (u8) val;
+ else
+ return rc;
+
+ if (led->kpdbl_cfg->mode == LPG_MODE) {
+ dev_err(&led->spmi_dev->dev, "LPG mode not supported\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
+ if (!rc)
+ led->kpdbl_cfg->pwm_channel = (u8) val;
+ else
+ return rc;
+
+ rc = of_property_read_u32(node, "qcom,pwm-us", &val);
+ if (!rc)
+ led->kpdbl_cfg->pwm_period_us = val;
+ else
+ return rc;
+
+ rc = of_property_read_u32(node, "qcom,row-src-sel-val", &val);
+ if (!rc)
+ led->kpdbl_cfg->row_src_sel_val = val;
+ else
+ return rc;
+
+ rc = of_property_read_u32(node, "qcom,row-scan-val", &val);
+ if (!rc)
+ led->kpdbl_cfg->row_scan_val = val;
+ else
+ return rc;
+
+ rc = of_property_read_u32(node, "qcom,row-scan-en", &val);
+ if (!rc)
+ led->kpdbl_cfg->row_scan_en = val;
+ else
+ return rc;
+
return 0;
}
@@ -1548,7 +1762,7 @@
else
return rc;
- if (led->rgb_cfg->mode == RGB_MODE_PWM) {
+ if (led->rgb_cfg->mode == PWM_MODE) {
rc = of_property_read_u32(node, "qcom,pwm-us", &val);
if (!rc)
led->rgb_cfg->pwm_period_us = val;
@@ -1556,7 +1770,7 @@
return rc;
}
- if (led->rgb_cfg->mode == RGB_MODE_LPG) {
+ if (led->rgb_cfg->mode == LPG_MODE) {
led->rgb_cfg->duty_cycles =
devm_kzalloc(&led->spmi_dev->dev,
sizeof(struct pwm_duty_cycles), GFP_KERNEL);
@@ -1791,6 +2005,12 @@
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
"Unable to read mpp config data\n");
+ }
+ } else if (strncmp(led_label, "kpdbl", sizeof("kpdbl")) == 0) {
+ rc = qpnp_get_config_kpdbl(led, temp);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to read kpdbl config data\n");
goto fail_id_check;
}
} else {
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 89500f9..fcade49 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -246,7 +246,10 @@
struct dmx_secure_mode *sec_mode);
int (*oob_command) (struct dmx_ts_feed *feed,
struct dmx_oob_command *cmd);
-
+ int (*ts_insertion_init)(struct dmx_ts_feed *feed);
+ int (*ts_insertion_terminate)(struct dmx_ts_feed *feed);
+ int (*ts_insertion_insert_buffer)(struct dmx_ts_feed *feed,
+ char *data, size_t size);
};
/*--------------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 5e7a09e..2a750a6 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -34,6 +34,8 @@
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
#include "dmxdev.h"
static int debug;
@@ -416,7 +418,33 @@
return 0;
}
-static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+static inline int dvb_dmxdev_check_data(struct dmxdev_filter *filter,
+ struct dvb_ringbuffer *src)
+{
+ int data_status_change;
+
+ if (filter)
+ if (mutex_lock_interruptible(&filter->mutex))
+ return -ERESTARTSYS;
+
+ if (!src->data ||
+ !dvb_ringbuffer_empty(src) ||
+ src->error ||
+ (filter &&
+ (filter->state != DMXDEV_STATE_GO) &&
+ (filter->state != DMXDEV_STATE_DONE)))
+ data_status_change = 1;
+ else
+ data_status_change = 0;
+
+ if (filter)
+ mutex_unlock(&filter->mutex);
+
+ return data_status_change;
+}
+
+static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_filter *filter,
+ struct dvb_ringbuffer *src,
int non_blocking, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -439,9 +467,26 @@
break;
}
- ret = wait_event_interruptible(src->queue, (!src->data) ||
- !dvb_ringbuffer_empty(src) ||
- (src->error != 0));
+ if (filter) {
+ if ((filter->state == DMXDEV_STATE_DONE) &&
+ dvb_ringbuffer_empty(src))
+ break;
+
+ mutex_unlock(&filter->mutex);
+ }
+
+ ret = wait_event_interruptible(src->queue,
+ dvb_dmxdev_check_data(filter, src));
+
+ if (filter) {
+ if (mutex_lock_interruptible(&filter->mutex))
+ return -ERESTARTSYS;
+
+ if ((filter->state != DMXDEV_STATE_GO) &&
+ (filter->state != DMXDEV_STATE_DONE))
+ return -ENODEV;
+ }
+
if (ret < 0)
break;
@@ -1108,9 +1153,9 @@
if (dmxdev->exit)
return -ENODEV;
- res = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
- file->f_flags & O_NONBLOCK,
- buf, count, ppos);
+ res = dvb_dmxdev_buffer_read(NULL, &dmxdev->dvr_buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
if (res > 0) {
dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, res);
@@ -1751,6 +1796,194 @@
return 0;
}
+static void dvb_dmxdev_ts_insertion_work(struct work_struct *worker)
+{
+ struct ts_insertion_buffer *ts_buffer =
+ container_of(worker, struct ts_insertion_buffer, dwork.work);
+ struct dmxdev_feed *feed;
+ size_t free_bytes;
+ struct dmx_ts_feed *ts;
+
+ mutex_lock(&ts_buffer->dmxdevfilter->mutex);
+
+ if (ts_buffer->abort ||
+ (ts_buffer->dmxdevfilter->state != DMXDEV_STATE_GO)) {
+ mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+ return;
+ }
+
+ feed = list_first_entry(&ts_buffer->dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
+ ts = feed->ts;
+ free_bytes = dvb_ringbuffer_free(&ts_buffer->dmxdevfilter->buffer);
+
+ mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+
+ if (ts_buffer->size < free_bytes)
+ ts->ts_insertion_insert_buffer(ts,
+ ts_buffer->buffer, ts_buffer->size);
+
+ if (ts_buffer->repetition_time && !ts_buffer->abort)
+ schedule_delayed_work(&ts_buffer->dwork,
+ msecs_to_jiffies(ts_buffer->repetition_time));
+}
+
+static void dvb_dmxdev_queue_ts_insertion(
+ struct ts_insertion_buffer *ts_buffer)
+{
+ size_t tsp_size;
+
+ if (ts_buffer->dmxdevfilter->dmx_tsp_format == DMX_TSP_FORMAT_188)
+ tsp_size = 188;
+ else
+ tsp_size = 192;
+
+ if (ts_buffer->size % tsp_size) {
+ printk(KERN_ERR "%s: Wrong buffer alignment, size=%d, tsp_size=%d\n",
+ __func__, ts_buffer->size, tsp_size);
+ return;
+ }
+
+ ts_buffer->abort = 0;
+ schedule_delayed_work(&ts_buffer->dwork, 0);
+}
+
+static void dvb_dmxdev_cancel_ts_insertion(
+ struct ts_insertion_buffer *ts_buffer)
+{
+ /*
+ * This function assumes it is called while mutex
+ * of demux filter is taken. Since work in workqueue
+ * captures the filter's mutex to protect against the DB,
+ * mutex needs to be released before waiting for the work
+ * to get finished otherwise work in workqueue will
+ * never be finished.
+ */
+ if (!mutex_is_locked(&ts_buffer->dmxdevfilter->mutex)) {
+ printk(KERN_ERR "%s: mutex is not locked!\n", __func__);
+ return;
+ }
+
+ ts_buffer->abort = 1;
+
+ mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+ cancel_delayed_work_sync(&ts_buffer->dwork);
+ mutex_lock(&ts_buffer->dmxdevfilter->mutex);
+}
+
+static int dvb_dmxdev_set_ts_insertion(struct dmxdev_filter *dmxdevfilter,
+ struct dmx_set_ts_insertion *params)
+{
+ int ret = 0;
+ int first_buffer;
+ struct dmxdev_feed *feed;
+ struct ts_insertion_buffer *ts_buffer;
+
+ if (!params ||
+ !params->size ||
+ !(dmxdevfilter->dev->capabilities & DMXDEV_CAP_TS_INSERTION) ||
+ (dmxdevfilter->state < DMXDEV_STATE_SET) ||
+ (dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+ ((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) &&
+ (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP)))
+ return -EINVAL;
+
+ ts_buffer = vmalloc(sizeof(struct ts_insertion_buffer));
+ if (!ts_buffer)
+ return -ENOMEM;
+
+ ts_buffer->buffer = vmalloc(params->size);
+ if (!ts_buffer->buffer) {
+ vfree(ts_buffer);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(ts_buffer->buffer,
+ params->ts_packets, params->size)) {
+ vfree(ts_buffer->buffer);
+ vfree(ts_buffer);
+ return -EFAULT;
+ }
+
+ if (params->repetition_time &&
+ params->repetition_time < DMX_MIN_INSERTION_REPETITION_TIME)
+ params->repetition_time = DMX_MIN_INSERTION_REPETITION_TIME;
+
+ ts_buffer->size = params->size;
+ ts_buffer->identifier = params->identifier;
+ ts_buffer->repetition_time = params->repetition_time;
+ ts_buffer->dmxdevfilter = dmxdevfilter;
+ INIT_DELAYED_WORK(&ts_buffer->dwork, dvb_dmxdev_ts_insertion_work);
+
+ first_buffer = list_empty(&dmxdevfilter->insertion_buffers);
+ list_add_tail(&ts_buffer->next, &dmxdevfilter->insertion_buffers);
+
+ if (dmxdevfilter->state != DMXDEV_STATE_GO)
+ return 0;
+
+ feed = list_first_entry(&dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
+
+ if (first_buffer && feed->ts->ts_insertion_init)
+ ret = feed->ts->ts_insertion_init(feed->ts);
+
+ if (!ret) {
+ dvb_dmxdev_queue_ts_insertion(ts_buffer);
+ } else {
+ list_del(&ts_buffer->next);
+ vfree(ts_buffer->buffer);
+ vfree(ts_buffer);
+ }
+
+ return ret;
+}
+
+static int dvb_dmxdev_abort_ts_insertion(struct dmxdev_filter *dmxdevfilter,
+ struct dmx_abort_ts_insertion *params)
+{
+ int ret = 0;
+ int found_buffer;
+ struct dmxdev_feed *feed;
+ struct ts_insertion_buffer *ts_buffer, *tmp;
+
+ if (!params ||
+ !(dmxdevfilter->dev->capabilities & DMXDEV_CAP_TS_INSERTION) ||
+ (dmxdevfilter->state < DMXDEV_STATE_SET) ||
+ (dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+ ((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) &&
+ (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP)))
+ return -EINVAL;
+
+ found_buffer = 0;
+ list_for_each_entry_safe(ts_buffer, tmp,
+ &dmxdevfilter->insertion_buffers, next) {
+ if (ts_buffer->identifier == params->identifier) {
+ list_del(&ts_buffer->next);
+ found_buffer = 1;
+ break;
+ }
+ }
+
+ if (!found_buffer)
+ return -EINVAL;
+
+ if (dmxdevfilter->state == DMXDEV_STATE_GO) {
+ dvb_dmxdev_cancel_ts_insertion(ts_buffer);
+ if (list_empty(&dmxdevfilter->insertion_buffers)) {
+ feed = list_first_entry(&dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
+ if (feed->ts->ts_insertion_terminate)
+ ret = feed->ts->ts_insertion_terminate(
+ feed->ts);
+ }
+ }
+
+ vfree(ts_buffer->buffer);
+ vfree(ts_buffer);
+
+ return ret;
+}
+
static int dvb_dmxdev_ts_fullness_callback(struct dmx_ts_feed *filter,
int required_space)
{
@@ -2006,6 +2239,9 @@
dvb_ringbuffer_flush(&dmxdevfilter->buffer);
dvb_dmxdev_notify_data_read(dmxdevfilter, flush_len);
dmxdevfilter->buffer.error = 0;
+ } else if (event->type == DMX_EVENT_SECTION_TIMEOUT) {
+ /* clear buffer error now that user was notified */
+ dmxdevfilter->buffer.error = 0;
}
/*
@@ -2036,10 +2272,13 @@
static void dvb_dmxdev_filter_timeout(unsigned long data)
{
struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
+ struct dmx_filter_event event;
dmxdevfilter->buffer.error = -ETIMEDOUT;
spin_lock_irq(&dmxdevfilter->dev->lock);
dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
+ event.type = DMX_EVENT_SECTION_TIMEOUT;
+ dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
spin_unlock_irq(&dmxdevfilter->dev->lock);
wake_up_all(&dmxdevfilter->buffer.queue);
}
@@ -2612,6 +2851,7 @@
{
struct dmxdev_feed *feed;
struct dmx_demux *demux;
+ struct ts_insertion_buffer *ts_buffer;
if (dmxdevfilter->state < DMXDEV_STATE_GO)
return 0;
@@ -2631,6 +2871,18 @@
case DMXDEV_TYPE_PES:
dvb_dmxdev_feed_stop(dmxdevfilter);
demux = dmxdevfilter->dev->demux;
+
+ if (!list_empty(&dmxdevfilter->insertion_buffers)) {
+ feed = list_first_entry(&dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
+
+ list_for_each_entry(ts_buffer,
+ &dmxdevfilter->insertion_buffers, next)
+ dvb_dmxdev_cancel_ts_insertion(ts_buffer);
+ if (feed->ts->ts_insertion_terminate)
+ feed->ts->ts_insertion_terminate(feed->ts);
+ }
+
list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
demux->release_ts_feed(demux, feed->ts);
feed->ts = NULL;
@@ -2971,6 +3223,29 @@
}
dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
+
+ if ((filter->type == DMXDEV_TYPE_PES) &&
+ !list_empty(&filter->insertion_buffers)) {
+ struct ts_insertion_buffer *ts_buffer;
+
+ feed = list_first_entry(&filter->feed.ts,
+ struct dmxdev_feed, next);
+
+ ret = 0;
+ if (feed->ts->ts_insertion_init)
+ ret = feed->ts->ts_insertion_init(feed->ts);
+ if (!ret) {
+ list_for_each_entry(ts_buffer,
+ &filter->insertion_buffers, next)
+ dvb_dmxdev_queue_ts_insertion(
+ ts_buffer);
+ } else {
+ printk(KERN_ERR
+ "%s: ts_insertion_init failed, err %d\n",
+ __func__, ret);
+ }
+ }
+
return 0;
}
@@ -3017,6 +3292,8 @@
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
init_timer(&dmxdevfilter->timer);
+ INIT_LIST_HEAD(&dmxdevfilter->insertion_buffers);
+
dmxdevfilter->dmx_tsp_format = DMX_TSP_FORMAT_188;
dvbdev->users++;
@@ -3027,6 +3304,8 @@
static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
struct dmxdev_filter *dmxdevfilter)
{
+ struct ts_insertion_buffer *ts_buffer, *tmp;
+
mutex_lock(&dmxdev->mutex);
mutex_lock(&dmxdevfilter->mutex);
@@ -3034,6 +3313,13 @@
dvb_dmxdev_filter_reset(dmxdevfilter);
+ list_for_each_entry_safe(ts_buffer, tmp,
+ &dmxdevfilter->insertion_buffers, next) {
+ list_del(&ts_buffer->next);
+ vfree(ts_buffer->buffer);
+ vfree(ts_buffer);
+ }
+
if (dmxdevfilter->buffer.data) {
void *mem = dmxdevfilter->buffer.data;
@@ -3098,12 +3384,20 @@
static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
struct dmxdev_filter *filter, u16 pid)
{
+ int feed_count;
struct dmxdev_feed *feed, *tmp;
if ((filter->type != DMXDEV_TYPE_PES) ||
(filter->state < DMXDEV_STATE_SET))
return -EINVAL;
+ feed_count = 0;
+ list_for_each_entry(tmp, &filter->feed.ts, next)
+ feed_count++;
+
+ if (feed_count <= 1)
+ return -EINVAL;
+
list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
if (feed->pid == pid) {
if (feed->ts != NULL) {
@@ -3283,7 +3577,7 @@
hcount = 3 + dfil->todo;
if (hcount > count)
hcount = count;
- result = dvb_dmxdev_buffer_read(&dfil->buffer,
+ result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer,
file->f_flags & O_NONBLOCK,
buf, hcount, ppos);
if (result < 0) {
@@ -3304,7 +3598,7 @@
}
if (count > dfil->todo)
count = dfil->todo;
- result = dvb_dmxdev_buffer_read(&dfil->buffer,
+ result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer,
file->f_flags & O_NONBLOCK,
buf, count, ppos);
if (result < 0)
@@ -3333,9 +3627,10 @@
if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
else
- ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
- file->f_flags & O_NONBLOCK,
- buf, count, ppos);
+ ret = dvb_dmxdev_buffer_read(dmxdevfilter,
+ &dmxdevfilter->buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
if (ret > 0) {
dvb_dmxdev_notify_data_read(dmxdevfilter, ret);
@@ -3625,6 +3920,24 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_SET_TS_INSERTION:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_set_ts_insertion(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_ABORT_TS_INSERTION:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_abort_ts_insertion(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
default:
ret = -EINVAL;
break;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 2ed99ae..49e5e1b 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -114,6 +114,32 @@
struct dmx_filter_event queue[DMX_EVENT_QUEUE_SIZE];
};
+#define DMX_MIN_INSERTION_REPETITION_TIME 25 /* in msec */
+struct ts_insertion_buffer {
+ /* work scheduled for insertion of this buffer */
+ struct delayed_work dwork;
+
+ struct list_head next;
+
+ /* buffer holding TS packets for insertion */
+ char *buffer;
+
+ /* buffer size */
+ size_t size;
+
+ /* buffer ID from user */
+ u32 identifier;
+
+ /* repetition time for the buffer insertion */
+ u32 repetition_time;
+
+ /* the recording filter to which this buffer belongs */
+ struct dmxdev_filter *dmxdevfilter;
+
+ /* indication whether insertion should be aborted */
+ int abort;
+};
+
struct dmxdev_filter {
union {
struct dmx_section_filter *sec;
@@ -145,6 +171,9 @@
enum dmx_tsp_format_t dmx_tsp_format;
u32 rec_chunk_size;
+ /* list of buffers used for insertion (struct ts_insertion_buffer) */
+ struct list_head insertion_buffers;
+
/* End-of-stream indication has been received */
int eos_state;
@@ -170,6 +199,8 @@
#define DMXDEV_CAP_PULL_MODE 0x02
#define DMXDEV_CAP_INDEXING 0x04
#define DMXDEV_CAP_EXTERNAL_BUFFS_ONLY 0x08
+#define DMXDEV_CAP_TS_INSERTION 0x10
+
enum dmx_playback_mode_t playback_mode;
dmx_source_t source;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 3f3d222..939d591 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -2331,6 +2331,25 @@
return ret;
}
+static int dvbdmx_ts_insertion_insert_buffer(struct dmx_ts_feed *ts_feed,
+ char *data, size_t size)
+{
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+ struct dvb_demux *demux = feed->demux;
+
+ spin_lock(&demux->lock);
+ if (!ts_feed->is_filtering) {
+ spin_unlock(&demux->lock);
+ return 0;
+ }
+
+ feed->cb.ts(data, size, NULL, 0, ts_feed, DMX_OK);
+
+ spin_unlock(&demux->lock);
+
+ return 0;
+}
+
static int dmx_ts_set_tsp_out_format(
struct dmx_ts_feed *ts_feed,
enum dmx_tsp_format_t tsp_format)
@@ -2401,6 +2420,10 @@
(*ts_feed)->notify_data_read = NULL;
(*ts_feed)->set_secure_mode = dmx_ts_set_secure_mode;
(*ts_feed)->oob_command = dvbdmx_ts_feed_oob_cmd;
+ (*ts_feed)->ts_insertion_init = NULL;
+ (*ts_feed)->ts_insertion_terminate = NULL;
+ (*ts_feed)->ts_insertion_insert_buffer =
+ dvbdmx_ts_insertion_insert_buffer;
if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
feed->state = DMX_STATE_FREE;
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 71087d9..4579cee 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -595,13 +595,18 @@
struct v4l2_event event;
struct msm_video_device *pvdev = video_drvdata(filep);
struct camera_v4l2_private *sp = fh_to_private(filep->private_data);
-
BUG_ON(!pvdev);
atomic_sub_return(1, &pvdev->opened);
if (atomic_read(&pvdev->opened) == 0) {
+ camera_pack_event(filep, MSM_CAMERA_SET_PARM,
+ MSM_CAMERA_PRIV_DEL_STREAM, -1, &event);
+
+ /* Donot wait, imaging server may have crashed */
+ msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+
camera_pack_event(filep, MSM_CAMERA_DEL_SESSION, 0, -1, &event);
/* Donot wait, imaging server may have crashed */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 04afec0..59858b5 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -256,6 +256,13 @@
buf_info->state ==
MSM_ISP_BUFFER_STATE_INITIALIZED)
continue;
+
+ if (!BUF_SRC(bufq->stream_id)) {
+ if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED ||
+ buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED)
+ buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf,
+ bufq->session_id, bufq->stream_id);
+ }
msm_isp_unprepare_v4l2_buf(buf_mgr, buf_info);
}
return 0;
@@ -287,13 +294,15 @@
bufq->buf_client_count)
list_del_init(
&temp_buf_info->share_list);
- if (temp_buf_info->buf_reuse_flag)
+ if (temp_buf_info->buf_reuse_flag) {
kfree(temp_buf_info);
- else
+ } else {
*buf_info = temp_buf_info;
+ rc = 0;
+ }
spin_unlock_irqrestore(
&bufq->bufq_lock, flags);
- return 0;
+ return rc;
}
}
}
@@ -342,6 +351,7 @@
(*buf_info)->buf_used[id] = 1;
(*buf_info)->buf_get_count = 1;
(*buf_info)->buf_put_count = 0;
+ (*buf_info)->buf_reuse_flag = 0;
list_add_tail(&(*buf_info)->share_list,
&bufq->share_head);
}
@@ -375,7 +385,6 @@
switch (buf_info->state) {
case MSM_ISP_BUFFER_STATE_PREPARED:
case MSM_ISP_BUFFER_STATE_DEQUEUED:
- case MSM_ISP_BUFFER_STATE_DISPATCHED:
case MSM_ISP_BUFFER_STATE_DIVERTED:
if (BUF_SRC(bufq->stream_id))
list_add_tail(&buf_info->list, &bufq->head);
@@ -385,6 +394,13 @@
buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
rc = 0;
break;
+ case MSM_ISP_BUFFER_STATE_DISPATCHED:
+ buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
+ rc = 0;
+ break;
+ case MSM_ISP_BUFFER_STATE_QUEUED:
+ rc = 0;
+ break;
default:
pr_err("%s: incorrect state = %d",
__func__, buf_info->state);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index a251f0a..679c5cb 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -142,14 +142,13 @@
return;
if (irq_status0 & BIT(0)) {
- ISP_DBG("%s: PIX0 frame id: %lu\n", __func__,
- vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
- msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
ISP_DBG("%s: SOF IRQ\n", __func__);
if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
&& vfe_dev->axi_data.src_info[VFE_PIX_0].
pix_stream_count == 0) {
msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+ if (vfe_dev->axi_data.stream_update)
+ msm_isp_axi_stream_update(vfe_dev);
msm_isp_update_framedrop_reg(vfe_dev);
}
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 5a17635..756cb41 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -299,6 +299,8 @@
&& vfe_dev->axi_data.src_info[VFE_PIX_0].
pix_stream_count == 0) {
msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+ if (vfe_dev->axi_data.stream_update)
+ msm_isp_axi_stream_update(vfe_dev);
msm_isp_update_framedrop_reg(vfe_dev);
}
}
@@ -518,26 +520,37 @@
comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
comp_mask &= ~(0x7F << (comp_mask_index * 8));
comp_mask |= (axi_data->composite_info[comp_mask_index].
- stream_composite_mask << (comp_mask_index * 8));
+ stream_composite_mask << (comp_mask_index * 8));
+ if (stream_info->plane_offset[0])
+ comp_mask |= (axi_data->composite_info[comp_mask_index].
+ stream_composite_mask << 24);
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
irq_mask |= 1 << (comp_mask_index + 25);
+ if (stream_info->plane_offset[0] && (comp_mask >> 24))
+ irq_mask |= BIT(28);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
}
static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
+ struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index;
uint32_t irq_mask;
comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
comp_mask &= ~(0x7F << (comp_mask_index * 8));
+ if (stream_info->plane_offset[0])
+ comp_mask &= ~(axi_data->composite_info[comp_mask_index].
+ stream_composite_mask << 24);
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
irq_mask &= ~(1 << (comp_mask_index + 25));
+ if (stream_info->plane_offset[0] && !(comp_mask >> 24))
+ irq_mask &= ~BIT(28);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
}
@@ -1217,7 +1230,7 @@
static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = {
.num_wm = 4,
- .num_comp_mask = 4,
+ .num_comp_mask = 3,
.num_rdi = 3,
.num_rdi_master = 3,
.min_wm_ub = 64,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 728e172..13160ee 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -399,7 +399,10 @@
uint32_t framedrop_period = msm_isp_get_framedrop_period(
stream_cfg_cmd->frame_skip_pattern);
- stream_info->framedrop_pattern = 0x1;
+ if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL)
+ stream_info->framedrop_pattern = 0x0;
+ else
+ stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
if (stream_cfg_cmd->init_frame_drop < framedrop_period) {
@@ -706,35 +709,60 @@
}
}
-enum msm_isp_camif_update_state
- msm_isp_update_camif_output_count(
- struct vfe_device *vfe_dev,
+static enum msm_isp_camif_update_state
+ msm_isp_get_camif_update_state(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
{
int i;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- uint8_t cur_pix_count = axi_data->src_info[VFE_PIX_0].
- pix_stream_count;
- uint8_t cur_raw_count = axi_data->src_info[VFE_PIX_0].
- raw_stream_count;
- uint8_t pix_stream_cnt = 0;
+ uint8_t pix_stream_cnt = 0, cur_pix_stream_cnt;
+ cur_pix_stream_cnt =
+ axi_data->src_info[VFE_PIX_0].pix_stream_count +
+ axi_data->src_info[VFE_PIX_0].raw_stream_count;
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
stream_info =
&axi_data->stream_info[
HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
if (stream_info->stream_src < RDI_INTF_0)
pix_stream_cnt++;
+ }
+
+ if (pix_stream_cnt) {
+ if (cur_pix_stream_cnt == 0 && pix_stream_cnt &&
+ stream_cfg_cmd->cmd == START_STREAM)
+ return ENABLE_CAMIF;
+ else if (cur_pix_stream_cnt &&
+ (cur_pix_stream_cnt - pix_stream_cnt) == 0 &&
+ stream_cfg_cmd->cmd == STOP_STREAM)
+ return DISABLE_CAMIF;
+ }
+ return NO_UPDATE;
+}
+
+static void msm_isp_update_camif_output_count(
+ struct vfe_device *vfe_dev,
+ struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
+{
+ int i;
+ struct msm_vfe_axi_stream *stream_info;
+ struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+ for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+ stream_info =
+ &axi_data->stream_info[
+ HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
+ if (stream_info->stream_src >= RDI_INTF_0)
+ return;
if (stream_info->stream_src == PIX_ENCODER ||
- stream_info->stream_src == PIX_VIEWFINDER) {
+ stream_info->stream_src == PIX_VIEWFINDER ||
+ stream_info->stream_src == IDEAL_RAW) {
if (stream_cfg_cmd->cmd == START_STREAM)
vfe_dev->axi_data.src_info[VFE_PIX_0].
pix_stream_count++;
else
vfe_dev->axi_data.src_info[VFE_PIX_0].
pix_stream_count--;
- } else if (stream_info->stream_src == CAMIF_RAW ||
- stream_info->stream_src == IDEAL_RAW) {
+ } else if (stream_info->stream_src == CAMIF_RAW) {
if (stream_cfg_cmd->cmd == START_STREAM)
vfe_dev->axi_data.src_info[VFE_PIX_0].
raw_stream_count++;
@@ -743,25 +771,6 @@
raw_stream_count--;
}
}
- if (pix_stream_cnt) {
- if ((cur_pix_count + cur_raw_count == 0) &&
- (axi_data->src_info[VFE_PIX_0].
- pix_stream_count +
- axi_data->src_info[VFE_PIX_0].
- raw_stream_count != 0)) {
- return ENABLE_CAMIF;
- }
-
- if ((cur_pix_count + cur_raw_count != 0) &&
- (axi_data->src_info[VFE_PIX_0].
- pix_stream_count +
- axi_data->src_info[VFE_PIX_0].
- raw_stream_count == 0)) {
- return DISABLE_CAMIF;
- }
- }
-
- return NO_UPDATE;
}
void msm_camera_io_dump_2(void __iomem *addr, int size)
@@ -886,6 +895,20 @@
return rc;
}
+static void msm_isp_deinit_stream_ping_pong_reg(
+ struct vfe_device *vfe_dev,
+ struct msm_vfe_axi_stream *stream_info)
+{
+ int i;
+ for (i = 0; i < 2; i++) {
+ struct msm_isp_buffer *buf;
+ buf = stream_info->buf[i];
+ if (buf)
+ vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+ buf->bufq_handle, buf->buf_idx);
+ }
+}
+
static void msm_isp_get_stream_wm_mask(
struct msm_vfe_axi_stream *stream_info,
uint32_t *wm_reload_mask)
@@ -937,6 +960,7 @@
vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, wm_reload_mask);
vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
+ msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
if (camif_update == ENABLE_CAMIF)
vfe_dev->hw_info->vfe_ops.core_ops.
update_camif_state(vfe_dev, camif_update);
@@ -969,6 +993,13 @@
if (camif_update == DISABLE_CAMIF)
vfe_dev->hw_info->vfe_ops.core_ops.
update_camif_state(vfe_dev, DISABLE_CAMIF);
+ msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
+
+ for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+ stream_info = &axi_data->stream_info[
+ HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
+ msm_isp_deinit_stream_ping_pong_reg(vfe_dev, stream_info);
+ }
return rc;
}
@@ -990,8 +1021,7 @@
/*Configure UB*/
vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev);
}
- camif_update =
- msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
+ camif_update = msm_isp_get_camif_update_state(vfe_dev, stream_cfg_cmd);
if (stream_cfg_cmd->cmd == START_STREAM)
rc = msm_isp_start_axi_stream(
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index e08dea2..ce71235 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -206,7 +206,11 @@
framedrop_period = msm_isp_get_framedrop_period(
stream_req_cmd->framedrop_pattern);
- stream_info->framedrop_pattern = 0x1;
+
+ if (stream_req_cmd->framedrop_pattern == SKIP_ALL)
+ stream_info->framedrop_pattern = 0x0;
+ else
+ stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
if (!stream_info->composite_flag)
@@ -277,6 +281,20 @@
return rc;
}
+static void msm_isp_deinit_stats_ping_pong_reg(
+ struct vfe_device *vfe_dev,
+ struct msm_vfe_stats_stream *stream_info)
+{
+ int i;
+ struct msm_isp_buffer *buf;
+ for (i = 0; i < 2; i++) {
+ buf = stream_info->buf[i];
+ if (buf)
+ vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+ buf->bufq_handle, buf->buf_idx);
+ }
+}
+
void msm_isp_stats_stream_update(struct vfe_device *vfe_dev)
{
int i;
@@ -415,6 +433,12 @@
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask(
vfe_dev, comp_stats_mask, 0);
}
+
+ for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+ idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+ stream_info = &stats_data->stream_info[idx];
+ msm_isp_deinit_stats_ping_pong_reg(vfe_dev, stream_info);
+ }
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index c981901..dd8db03 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -174,6 +174,8 @@
case EVERY_32FRAME:
return 32;
break;
+ case SKIP_ALL:
+ return 1;
default:
return 1;
}
@@ -228,12 +230,12 @@
return rc;
}
-static int msm_isp_set_clk_rate(struct vfe_device *vfe_dev, uint32_t rate)
+static int msm_isp_set_clk_rate(struct vfe_device *vfe_dev, long *rate)
{
int rc = 0;
int clk_idx = vfe_dev->hw_info->vfe_clk_idx;
long round_rate =
- clk_round_rate(vfe_dev->vfe_clk[clk_idx], rate);
+ clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate);
if (round_rate < 0) {
pr_err("%s: Invalid vfe clock rate\n", __func__);
return round_rate;
@@ -244,6 +246,7 @@
pr_err("%s: Vfe set rate error\n", __func__);
return rc;
}
+ *rate = round_rate;
return 0;
}
@@ -264,7 +267,7 @@
input_cfg->d.pix_cfg.camif_cfg.pixels_per_line;
rc = msm_isp_set_clk_rate(vfe_dev,
- vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock);
+ &vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock);
if (rc < 0) {
pr_err("%s: clock set rate failed\n", __func__);
return rc;
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 962c079..a95eda7 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -94,7 +94,8 @@
for (i = 0; i < ispif->vfe_info.num_vfe; i++) {
- msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_CTRL_0(i));
+ msm_camera_io_w(1 << PIX0_LINE_BUF_EN_BIT,
+ ispif->base + ISPIF_VFE_m_CTRL_0(i));
msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(i));
msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(i));
msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(i));
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
index 59b9746..509567c 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -70,7 +70,7 @@
}
static struct msm_cam_clk_info jpeg_8x_clk_info[] = {
- {"core_clk", 228570000},
+ {"core_clk", JPEG_CLK_RATE},
{"iface_clk", -1},
{"bus_clk0", -1},
{"camss_top_ahb_clk", -1},
@@ -135,8 +135,8 @@
{
.src = MSM_BUS_MASTER_JPEG,
.dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 1027648000,
- .ib = 1105920000,
+ .ab = JPEG_CLK_RATE * 2.5,
+ .ib = JPEG_CLK_RATE * 2.5,
},
};
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h
index cd80d2e..a14b8ee 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
#include <linux/iommu.h>
#include <mach/iommu.h>
#include "msm_jpeg_sync.h"
+#define JPEG_CLK_RATE 266670000
void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file,
struct ion_handle **ionhandle, int domain_num);
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 9f1c81a..be9f613 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -661,6 +661,7 @@
rc = -ETIMEDOUT;
}
if (rc < 0) {
+ pr_err("%s: rc = %d\n", __func__, rc);
mutex_unlock(&session->lock);
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 35210a0..b0ff832 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -35,7 +35,7 @@
new_entry->vb2_buf = buf_mngr_dev->vb2_ops.get_buf(buf_info->session_id,
buf_info->stream_id);
if (!new_entry->vb2_buf) {
- pr_err("%s:Get buf is null\n", __func__);
+ pr_debug("%s:Get buf is null\n", __func__);
kfree(new_entry);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 8cdaa4b..5a174f5 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -860,7 +860,7 @@
rc = v4l2_subdev_call(cpp_dev->buf_mgr_subdev, core, ioctl,
buff_mgr_ops, buff_mgr_info);
if (rc < 0)
- pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+ pr_debug("%s: line %d rc = %d\n", __func__, __LINE__, rc);
return rc;
}
@@ -1010,7 +1010,7 @@
&buff_mgr_info);
if (rc < 0) {
rc = -EAGAIN;
- pr_err("error getting buffer rc:%d\n", rc);
+ pr_debug("error getting buffer rc:%d\n", rc);
goto ERROR2;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 47e672d..3dd3a4e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -42,13 +42,13 @@
e_ctrl->eboard_info->eeprom_name,
sizeof(cdata->cfg.eeprom_name));
break;
- case CFG_EEPROM_GET_DATA:
- CDBG("%s E CFG_EEPROM_GET_DATA\n", __func__);
+ case CFG_EEPROM_GET_CAL_DATA:
+ CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__);
cdata->cfg.get_data.num_bytes =
e_ctrl->num_bytes;
break;
- case CFG_EEPROM_READ_DATA:
- CDBG("%s E CFG_EEPROM_READ_DATA\n", __func__);
+ case CFG_EEPROM_READ_CAL_DATA:
+ CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__);
rc = copy_to_user(cdata->cfg.read_data.dbuffer,
e_ctrl->memory_data,
cdata->cfg.read_data.num_bytes);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
index 76aa695..ac697fb 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
@@ -40,7 +40,7 @@
struct msm_flash_fn_t *func_tbl;
const char *led_trigger_name[MAX_LED_TRIGGERS];
struct led_trigger *led_trigger[MAX_LED_TRIGGERS];
- uint32_t max_current[MAX_LED_TRIGGERS];
+ uint32_t op_current[MAX_LED_TRIGGERS];
void *data;
};
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index 1a75a5a..c6f1f72 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -59,11 +59,11 @@
case MSM_CAMERA_LED_LOW:
led_trigger_event(fctrl->led_trigger[0],
- fctrl->max_current[0] / 2);
+ fctrl->op_current[0] / 2);
break;
case MSM_CAMERA_LED_HIGH:
- led_trigger_event(fctrl->led_trigger[0], fctrl->max_current[0]);
+ led_trigger_event(fctrl->led_trigger[0], fctrl->op_current[0]);
break;
case MSM_CAMERA_LED_INIT:
@@ -144,7 +144,7 @@
CDBG("default trigger %s\n", fctrl.led_trigger_name[i]);
rc = of_property_read_u32(flash_src_node,
- "qcom,max-current", &fctrl.max_current[i]);
+ "qcom,current", &fctrl.op_current[i]);
if (rc < 0) {
pr_err("failed rc %d\n", rc);
of_node_put(flash_src_node);
@@ -153,7 +153,7 @@
of_node_put(flash_src_node);
- CDBG("max_current[%d] %d\n", i, fctrl.max_current[i]);
+ CDBG("max_current[%d] %d\n", i, fctrl.op_current[i]);
led_trigger_register_simple(fctrl.led_trigger_name[i],
&fctrl.led_trigger[i]);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
index 7dbbc03..e30e798 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
@@ -122,7 +122,7 @@
rc = PTR_ERR(clk_ptr[i]);
goto cam_clk_get_err;
}
- if (clk_info[i].clk_rate >= 0) {
+ if (clk_info[i].clk_rate > 0) {
rc = clk_set_rate(clk_ptr[i],
clk_info[i].clk_rate);
if (rc < 0) {
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
index 8855e85..29369de 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
@@ -703,7 +703,8 @@
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
- DMXDEV_CAP_INDEXING;
+ DMXDEV_CAP_INDEXING |
+ DMXDEV_CAP_TS_INSERTION;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
mpq_demux->dmxdev.demux->get_stc = mpq_tsif_dmx_get_stc;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
index 43a65e9..5e14d0c 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -1759,7 +1759,8 @@
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
- DMXDEV_CAP_INDEXING;
+ DMXDEV_CAP_INDEXING |
+ DMXDEV_CAP_TS_INSERTION;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
mpq_demux->dmxdev.demux->get_stc = mpq_tspp_dmx_get_stc;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
index c306488..60e3cb4 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
@@ -143,7 +143,8 @@
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
- DMXDEV_CAP_INDEXING;
+ DMXDEV_CAP_INDEXING |
+ DMXDEV_CAP_TS_INSERTION;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
mpq_demux->dmxdev.demux->get_caps = mpq_tspp_dmx_get_caps;
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 7fc8810..82a4f3c 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -316,6 +316,9 @@
case HAL_EXTRADATA_ASPECT_RATIO:
ret = HFI_PROPERTY_PARAM_INDEX_EXTRADATA;
break;
+ case HAL_EXTRADATA_MPEG2_SEQDISP:
+ ret = HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA;
+ break;
default:
dprintk(VIDC_WARN, "Extradata index not found: %d\n", index);
break;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 43a3dad..19f5dcd 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1018,6 +1018,41 @@
callback(SESSION_END_DONE, &cmd_done);
}
+static void hfi_process_session_abort_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_sys_session_abort_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+ struct hal_session *sess_close;
+
+ dprintk(VIDC_DBG, "RECEIVED:SESSION_ABORT_DONE");
+
+ if (!pkt || pkt->size !=
+ sizeof(struct hfi_msg_sys_session_abort_done_packet)) {
+ dprintk(VIDC_ERR, "%s: bad packet/packet size: %d",
+ __func__, pkt ? pkt->size : 0);
+ return;
+ }
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ cmd_done.device_id = device_id;
+ cmd_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ cmd_done.status = hfi_map_err_status((u32)pkt->error_type);
+ cmd_done.data = NULL;
+ cmd_done.size = 0;
+
+ sess_close = (struct hal_session *)pkt->session_id;
+ if (!sess_close) {
+ dprintk(VIDC_ERR, "%s: invalid session pointer\n", __func__);
+ return;
+ }
+ dprintk(VIDC_ERR, "deleted the session: 0x%x",
+ sess_close->session_id);
+ list_del(&sess_close->list);
+ kfree(sess_close);
+ callback(SESSION_ABORT_DONE, &cmd_done);
+}
+
static void hfi_process_session_get_seq_hdr_done(
msm_vidc_callback callback, u32 device_id,
struct hfi_msg_session_get_sequence_header_done_packet *pkt)
@@ -1134,6 +1169,10 @@
hfi_msg_session_release_buffers_done_packet*)
msg_hdr);
break;
+ case HFI_MSG_SYS_SESSION_ABORT_DONE:
+ hfi_process_session_abort_done(callback, device_id, (struct
+ hfi_msg_sys_session_abort_done_packet*) msg_hdr);
+ break;
default:
dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
break;
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index f458a0a..511a478 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -66,6 +66,7 @@
"Extradata input crop",
"Extradata digital zoom",
"Extradata aspect ratio",
+ "Extradata mpeg2 seqdisp",
};
static struct msm_vidc_ctrl msm_vdec_ctrls[] = {
@@ -203,7 +204,7 @@
.name = "Extradata Type",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
- .maximum = V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
+ .maximum = V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP,
.default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
@@ -223,7 +224,8 @@
(1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
(1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_INPUT_CROP) |
(1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM) |
- (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO)
+ (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP)
),
.qmenu = mpeg_video_vidc_extradata,
.step = 0,
@@ -697,32 +699,43 @@
}
int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
{
- u32 us_per_frame = 0;
- int rc = 0;
+ u64 us_per_frame = 0;
+ int rc = 0, fps = 0, rem = 0;
if (a->parm.output.timeperframe.denominator) {
switch (a->type) {
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- us_per_frame = a->parm.output.timeperframe.numerator/
- a->parm.output.timeperframe.denominator;
- break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- us_per_frame = a->parm.capture.timeperframe.numerator/
- a->parm.capture.timeperframe.denominator;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ us_per_frame = a->parm.output.timeperframe.numerator *
+ (u64)USEC_PER_SEC;
+ do_div(us_per_frame, a->parm.output.\
+ timeperframe.denominator);
break;
default:
dprintk(VIDC_ERR,
- "Scale clocks : Unknown buffer type\n");
+ "Scale clocks : Unknown buffer type %d\n",
+ a->type);
break;
}
}
+
if (!us_per_frame) {
dprintk(VIDC_ERR,
- "Failed to scale clocks : time between frames is 0\n");
+ "Failed to scale clocks : time between frames is 0\n");
rc = -EINVAL;
goto exit;
}
- inst->prop.fps = (u8) (USEC_PER_SEC / us_per_frame);
- if (inst->prop.fps) {
+
+ fps = USEC_PER_SEC;
+ rem = do_div(fps, us_per_frame);
+ if (rem) {
+ /* Effectively fps = ceil((float)USEC_PER_SEC/us_per_frame) */
+ fps++;
+ }
+
+ if (inst->prop.fps != fps) {
+ dprintk(VIDC_PROF, "reported fps changed for %p: %d->%d\n",
+ inst, inst->prop.fps, fps);
+ inst->prop.fps = fps;
msm_comm_scale_clocks_and_bus(inst);
}
exit:
@@ -1121,11 +1134,24 @@
int rc = 0;
struct v4l2_event dqevent = {0};
struct msm_vidc_core *core = inst->core;
+
+ if (!dec || !inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s invalid params", __func__);
+ return -EINVAL;
+ }
switch (dec->cmd) {
case V4L2_DEC_QCOM_CMD_FLUSH:
rc = msm_comm_flush(inst, dec->flags);
break;
case V4L2_DEC_CMD_STOP:
+ if (core->state != VIDC_CORE_INVALID &&
+ inst->state == MSM_VIDC_CORE_INVALID) {
+ rc = msm_comm_recover_from_session_error(inst);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to recover from session_error: %d\n",
+ rc);
+ }
rc = msm_comm_release_scratch_buffers(inst);
if (rc)
dprintk(VIDC_ERR,
@@ -1143,6 +1169,11 @@
goto exit;
}
rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ /* Clients rely on this event for joining poll thread.
+ * This event should be returned even if firmware has
+ * failed to respond */
+ dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+ v4l2_event_queue_fh(&inst->event_handler, &dqevent);
break;
default:
dprintk(VIDC_ERR, "Unknown Decoder Command\n");
@@ -1186,7 +1217,6 @@
inst->capability.width.min = MIN_SUPPORTED_WIDTH;
inst->capability.width.max = DEFAULT_WIDTH;
inst->prop.fps = 30;
- inst->prop.prev_time_stamp = 0;
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 5f47ae1..b6e77dc 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -20,6 +20,7 @@
#define MSM_VENC_DVC_NAME "msm_venc_8974"
#define MIN_NUM_OUTPUT_BUFFERS 4
+#define MIN_NUM_CAPTURE_BUFFERS 4
#define MIN_BIT_RATE 64000
#define MAX_BIT_RATE 160000000
#define DEFAULT_BIT_RATE 64000
@@ -777,16 +778,21 @@
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
*num_planes = 1;
buff_req = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
- *num_buffers = buff_req->buffer_count_actual =
+ if (buff_req) {
+ *num_buffers = buff_req->buffer_count_actual =
max(*num_buffers, buff_req->buffer_count_actual);
- if (*num_buffers > VIDEO_MAX_FRAME) {
- dprintk(VIDC_ERR,
+ }
+ if (*num_buffers < MIN_NUM_CAPTURE_BUFFERS)
+ *num_buffers = MIN_NUM_CAPTURE_BUFFERS;
+
+ if (*num_buffers > VIDEO_MAX_FRAME) {
+ dprintk(VIDC_ERR,
"Failed : No of slices requested = %d"\
" Max supported slices = %d",
*num_buffers, VIDEO_MAX_FRAME);
- rc = -EINVAL;
- break;
- }
+ rc = -EINVAL;
+ break;
+ }
ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA);
if (ctrl)
@@ -1899,6 +1905,11 @@
dprintk(VIDC_ERR, "Failed to release persist buf:%d\n",
rc);
rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ /* Clients rely on this event for joining poll thread.
+ * This event should be returned even if firmware has
+ * failed to respond */
+ dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+ v4l2_event_queue_fh(&inst->event_handler, &dqevent);
break;
}
if (rc)
@@ -1959,7 +1970,7 @@
{
u32 property_id = 0, us_per_frame = 0;
void *pdata;
- int rc = 0;
+ int rc = 0, fps = 0, rem = 0;
struct hal_frame_rate frame_rate;
struct hfi_device *hdev;
@@ -1967,32 +1978,45 @@
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
return -EINVAL;
}
- hdev = inst->core->device;
+ hdev = inst->core->device;
property_id = HAL_CONFIG_FRAME_RATE;
+
if (a->parm.output.timeperframe.denominator) {
switch (a->type) {
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
us_per_frame = a->parm.output.timeperframe.numerator *
- USEC_PER_SEC / a->parm.output.\
- timeperframe.denominator;
+ (u64)USEC_PER_SEC;
+ do_div(us_per_frame, a->parm.output.\
+ timeperframe.denominator);
break;
default:
dprintk(VIDC_ERR,
- "Scale clocks : Unknown buffer type\n");
+ "Scale clocks : Unknown buffer type %d\n",
+ a->type);
break;
}
}
if (!us_per_frame) {
dprintk(VIDC_ERR,
- "Failed to scale clocks : time between frames is 0\n");
+ "Failed to scale clocks : time between frames is 0\n");
rc = -EINVAL;
goto exit;
}
- inst->prop.fps = (u8) (USEC_PER_SEC / us_per_frame);
- if (inst->prop.fps) {
+
+ fps = USEC_PER_SEC;
+ rem = do_div(fps, us_per_frame);
+ if (rem) {
+ /* Effectively fps = ceil((float)USEC_PER_SEC/us_per_frame) */
+ fps++;
+ }
+
+ if (inst->prop.fps != fps) {
+ dprintk(VIDC_PROF, "reported fps changed for %p: %d->%d\n",
+ inst, inst->prop.fps, fps);
+ inst->prop.fps = fps;
frame_rate.frame_rate = inst->prop.fps * (0x1<<16);
frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
pdata = &frame_rate;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 1ee9c67..cf051b6 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -47,8 +47,6 @@
__mbs;\
})
-#define TIME_DIFF_THRESHOLD 200
-
static int msm_comm_get_load(struct msm_vidc_core *core,
enum session_type type)
{
@@ -63,8 +61,29 @@
if (inst->session_type == type &&
inst->state >= MSM_VIDC_OPEN_DONE &&
inst->state < MSM_VIDC_STOP_DONE) {
- num_mbs_per_sec += NUM_MBS_PER_SEC(inst->prop.height,
- inst->prop.width, inst->prop.fps);
+ int stride, scanlines, rc;
+ struct hfi_device *hdev;
+
+ hdev = inst->core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR,
+ "No hdev (probably in bad state)\n");
+ return -EINVAL;
+ }
+
+ rc = call_hfi_op(hdev, get_stride_scanline,
+ COLOR_FMT_NV12,
+ inst->prop.width, inst->prop.height,
+ &stride, &scanlines);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to determine stride/scan when getting load. Perf. might be affected\n");
+ stride = inst->prop.width;
+ scanlines = inst->prop.height;
+ }
+
+ num_mbs_per_sec += NUM_MBS_PER_SEC(stride, scanlines,
+ inst->prop.fps);
}
mutex_unlock(&inst->lock);
}
@@ -315,6 +334,7 @@
msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
if (!rc) {
dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
+ msm_comm_recover_from_session_error(inst);
rc = -EIO;
} else {
rc = 0;
@@ -345,7 +365,7 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- if (response) {
+ if (response && !response->status) {
struct vidc_hal_session_init_done *session_init_done =
(struct vidc_hal_session_init_done *) response->data;
inst = (struct msm_vidc_inst *)response->session_id;
@@ -582,7 +602,6 @@
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
signal_session_msg_receipt(cmd, inst);
- queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_CLOSE_DONE);
inst->session = NULL;
show_stats(inst);
} else {
@@ -639,56 +658,6 @@
}
}
-static void msm_comm_update_clocks(struct msm_vidc_inst *inst,
- u64 cur_time_stamp)
-{
- u32 new_time_diff = 0, cur_time_diff = 0;
- u8 updated_fps = 0;
- struct v4l2_ctrl *ctrl = NULL;
- u32 output_order = 0;
-
- if (inst->session_type == MSM_VIDC_ENCODER)
- goto exit;
- if (cur_time_stamp >= LLONG_MAX) {
- dprintk(VIDC_DBG,
- "Clock scaling failed : Timestamp invalid\n");
- goto exit;
- }
- ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
- V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER);
- if (!ctrl) {
- dprintk(VIDC_WARN, "Unable to find output order control\n");
- dprintk(VIDC_WARN,
- "Performance might be impacted for higher fps clips\n");
- goto exit;
- }
- output_order = v4l2_ctrl_g_ctrl(ctrl);
- if (output_order == V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) {
- new_time_diff =
- (u32)(cur_time_stamp - inst->prop.prev_time_stamp);
- inst->prop.prev_time_stamp = cur_time_stamp;
- if (!new_time_diff)
- goto exit;
- if (inst->prop.fps)
- cur_time_diff = USEC_PER_SEC / inst->prop.fps;
- cur_time_diff = cur_time_diff > new_time_diff ?
- cur_time_diff - new_time_diff :
- new_time_diff - cur_time_diff;
- if (cur_time_diff > TIME_DIFF_THRESHOLD) {
- updated_fps = (u8) (USEC_PER_SEC / new_time_diff);
- if (updated_fps && (updated_fps != inst->prop.fps)) {
- inst->prop.fps = updated_fps;
- dprintk(VIDC_DBG,
- "Updating clocks: Decoding fps = %d\n",
- inst->prop.fps);
- msm_comm_scale_clocks_and_bus(inst);
- }
- }
- }
-exit:
- return;
-}
-
static void handle_fbd(enum command_response cmd, void *data)
{
struct msm_vidc_cb_data_done *response = data;
@@ -718,7 +687,6 @@
fill_buf_done->timestamp_lo;
vb->v4l2_buf.timestamp =
ns_to_timeval(time_usec * NSEC_PER_USEC);
- msm_comm_update_clocks(inst, time_usec);
}
vb->v4l2_buf.flags = 0;
@@ -727,11 +695,17 @@
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
vb->v4l2_buf.flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
- vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_EOSEQ;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DECODEONLY)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_DATA_CORRUPT;
switch (fill_buf_done->picture_type) {
case HAL_PICTURE_IDR:
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
+ break;
case HAL_PICTURE_I:
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
break;
@@ -860,6 +834,7 @@
handle_release_res_done(cmd, data);
break;
case SESSION_END_DONE:
+ case SESSION_ABORT_DONE:
handle_session_close(cmd, data);
break;
case VIDC_EVENT_CHANGE:
@@ -1277,7 +1252,8 @@
}
mutex_unlock(&temp->lock);
}
-
+ inst->state = MSM_VIDC_CORE_INVALID;
+ msm_comm_recover_from_session_error(inst);
return -ENOMEM;
}
@@ -1929,6 +1905,8 @@
if (!rc) {
dprintk(VIDC_ERR,
"Wait interrupted or timeout: %d\n", rc);
+ inst->state = MSM_VIDC_CORE_INVALID;
+ msm_comm_recover_from_session_error(inst);
rc = -EIO;
goto exit;
}
@@ -1989,6 +1967,13 @@
mutex_unlock(&inst->lock);
rc = wait_for_sess_signal_receipt(inst,
SESSION_RELEASE_BUFFER_DONE);
+ if (rc) {
+ mutex_lock(&inst->sync_lock);
+ inst->state = MSM_VIDC_CORE_INVALID;
+ mutex_unlock(&inst->sync_lock);
+ msm_comm_recover_from_session_error(
+ inst);
+ }
mutex_lock(&inst->lock);
}
list_del(&buf->list);
@@ -2053,6 +2038,13 @@
mutex_unlock(&inst->lock);
rc = wait_for_sess_signal_receipt(inst,
SESSION_RELEASE_BUFFER_DONE);
+ if (rc) {
+ mutex_lock(&inst->sync_lock);
+ inst->state = MSM_VIDC_CORE_INVALID;
+ mutex_unlock(&inst->sync_lock);
+ msm_comm_recover_from_session_error(
+ inst);
+ }
mutex_lock(&inst->lock);
}
list_del(&buf->list);
@@ -2261,7 +2253,10 @@
kfree(temp);
}
}
- rc = call_hfi_op(hdev, session_flush, inst->session,
+ /*Do not send flush in case of session_error */
+ if (!(inst->state == MSM_VIDC_CORE_INVALID &&
+ core->state != VIDC_CORE_INVALID))
+ rc = call_hfi_op(hdev, session_flush, inst->session,
HAL_FLUSH_ALL);
}
mutex_unlock(&inst->sync_lock);
@@ -2322,6 +2317,9 @@
case V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO:
ret = HAL_EXTRADATA_ASPECT_RATIO;
break;
+ case V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP:
+ ret = HAL_EXTRADATA_MPEG2_SEQDISP;
+ break;
default:
dprintk(VIDC_WARN, "Extradata not found: %d\n", index);
break;
@@ -2431,3 +2429,57 @@
}
return rc;
}
+
+static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core *core;
+ enum command_response cmd = SYS_ERROR;
+ struct msm_vidc_cb_cmd_done response = {0};
+ if (!inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s: invalid input parameters", __func__);
+ return;
+ }
+ core = inst->core;
+ response.device_id = (u32) core->id;
+ handle_sys_error(cmd, (void *) &response);
+
+}
+int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst)
+{
+ struct hfi_device *hdev;
+ int rc = 0;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s: invalid input parameters", __func__);
+ return -EINVAL;
+ }
+ if (inst->state < MSM_VIDC_OPEN_DONE) {
+ dprintk(VIDC_WARN,
+ "No corresponding FW session. No need to send Abort");
+ inst->state = MSM_VIDC_CORE_INVALID;
+ return rc;
+ }
+ hdev = inst->core->device;
+
+ init_completion(&inst->completions[SESSION_MSG_INDEX
+ (SESSION_ABORT_DONE)]);
+
+ /* We have received session_error. Send session_abort to firmware
+ * to clean up and release the session
+ */
+ rc = call_hfi_op(hdev, session_abort, (void *) inst->session);
+ if (rc) {
+ dprintk(VIDC_ERR, "session_abort failed rc: %d\n", rc);
+ return rc;
+ }
+ rc = wait_for_completion_timeout(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_ABORT_DONE)],
+ msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+ if (!rc) {
+ dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n",
+ __func__, rc);
+ msm_comm_generate_sys_error(inst);
+ } else
+ change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
+ return rc;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 862dfab..c018345 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -48,3 +48,4 @@
V4L2_CTRL_DRIVER_PRIV(idx))
#endif
+int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 3208df9..ae1e9b7 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -198,6 +198,7 @@
write_str(&dbg_buf, "core: 0x%p\n", inst->core);
write_str(&dbg_buf, "height: %d\n", inst->prop.height);
write_str(&dbg_buf, "width: %d\n", inst->prop.width);
+ write_str(&dbg_buf, "fps: %d\n", inst->prop.fps);
write_str(&dbg_buf, "state: %d\n", inst->state);
write_str(&dbg_buf, "-----------Formats-------------\n");
for (i = 0; i < MAX_PORT_NUM; i++) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index e5696be..d9a2332 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -130,7 +130,6 @@
u32 height;
u32 fps;
u32 bitrate;
- u64 prev_time_stamp;
};
struct buf_queue {
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index ed4f317..b96a6dc 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -219,6 +219,9 @@
}
queue->qhdr_write_idx = new_write_idx;
*rx_req_is_set = (1 == queue->qhdr_rx_req) ? 1 : 0;
+ /*Memory barrier to make sure data is written before an
+ * interupt is raised on venus.*/
+ mb();
dprintk(VIDC_DBG, "Out : ");
return 0;
}
@@ -282,6 +285,7 @@
u32 packet_size_in_words, new_read_idx;
u32 *read_ptr;
struct vidc_iface_q_info *qinfo;
+ int rc = 0;
if (!info || !packet || !pb_tx_req_is_set) {
dprintk(VIDC_ERR, "Invalid Params");
@@ -293,6 +297,9 @@
dprintk(VIDC_WARN, "Queues have already been freed\n");
return -EINVAL;
}
+ /*Memory barrier to make sure data is valid before
+ *reading it*/
+ mb();
queue = (struct hfi_queue_header *) qinfo->q_hdr;
if (!queue) {
@@ -317,17 +324,27 @@
new_read_idx = queue->qhdr_read_idx + packet_size_in_words;
dprintk(VIDC_DBG, "Read Ptr: %d", (u32) new_read_idx);
- if (new_read_idx < queue->qhdr_q_size) {
- memcpy(packet, read_ptr,
- packet_size_in_words << 2);
- } else {
- new_read_idx -= queue->qhdr_q_size;
- memcpy(packet, read_ptr,
+ if (((packet_size_in_words << 2) <= VIDC_IFACEQ_MED_PKT_SIZE)
+ && queue->qhdr_read_idx <= queue->qhdr_q_size) {
+ if (new_read_idx < queue->qhdr_q_size) {
+ memcpy(packet, read_ptr,
+ packet_size_in_words << 2);
+ } else {
+ new_read_idx -= queue->qhdr_q_size;
+ memcpy(packet, read_ptr,
(packet_size_in_words - new_read_idx) << 2);
- memcpy(packet + ((packet_size_in_words -
- new_read_idx) << 2),
- (u8 *)qinfo->q_array.align_virtual_addr,
- new_read_idx << 2);
+ memcpy(packet + ((packet_size_in_words -
+ new_read_idx) << 2),
+ (u8 *)qinfo->q_array.align_virtual_addr,
+ new_read_idx << 2);
+ }
+ } else {
+ dprintk(VIDC_WARN,
+ "BAD packet received, read_idx: 0x%x, pkt_size: %d\n",
+ queue->qhdr_read_idx, packet_size_in_words << 2);
+ dprintk(VIDC_WARN, "Dropping this packet\n");
+ new_read_idx = queue->qhdr_write_idx;
+ rc = -ENODATA;
}
queue->qhdr_read_idx = new_read_idx;
@@ -340,7 +357,7 @@
*pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0;
venus_hfi_hal_sim_modify_msg_packet(packet);
dprintk(VIDC_DBG, "Out : ");
- return 0;
+ return rc;
}
static int venus_hfi_alloc(void *mem, void *clnt, u32 size, u32 align,
@@ -1072,7 +1089,6 @@
if (!(dev->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
disable_irq_nosync(dev->hal_data->irq);
dev->intr_status = 0;
- venus_hfi_interface_queues_release(dev);
mutex_unlock(&dev->clock_lock);
}
dprintk(VIDC_INFO, "HAL exited\n");
@@ -2783,6 +2799,7 @@
flush_workqueue(device->vidc_workq);
venus_hfi_disable_clks(device);
subsystem_put(device->resources.fw.cookie);
+ venus_hfi_interface_queues_release(dev);
venus_hfi_iommu_detach(device);
device->resources.fw.cookie = NULL;
}
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 1311752..bb72da7 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -75,7 +75,8 @@
#define HFI_EXTRADATA_PANSCAN_WINDOW 0x00000008
#define HFI_EXTRADATA_RECOVERY_POINT_SEI 0x00000009
#define HFI_EXTRADATA_CLOSED_CAPTION_UD 0x0000000A
-#define HFI_EXTRADATA_AFD_UD 0x0000000B
+#define HFI_EXTRADATA_AFD_UD 0x0000000B
+#define HFI_EXTRADATA_MPEG2_SEQDISP 0x0000000D
#define HFI_EXTRADATA_MULTISLICE_INFO 0x7F100000
#define HFI_EXTRADATA_NUM_CONCEALED_MB 0x7F100001
#define HFI_EXTRADATA_INDEX 0x7F100002
@@ -191,6 +192,8 @@
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x014)
#define HFI_PROPERTY_PARAM_VDEC_AVC_SESSION_SELECT \
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x015)
+#define HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x016)
#define HFI_PROPERTY_CONFIG_VDEC_OX_START \
(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x0000)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 3fbfec4..bf1c70b 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -95,6 +95,7 @@
HAL_EXTRADATA_NUM_CONCEALED_MB,
HAL_EXTRADATA_METADATA_FILLER,
HAL_EXTRADATA_ASPECT_RATIO,
+ HAL_EXTRADATA_MPEG2_SEQDISP
};
enum hal_property {
@@ -482,7 +483,7 @@
HAL_PICTURE_I = 0x01,
HAL_PICTURE_P = 0x02,
HAL_PICTURE_B = 0x04,
- HAL_PICTURE_IDR = 0x7F001000,
+ HAL_PICTURE_IDR = 0x08,
HAL_FRAME_NOTCODED = 0x7F002000,
HAL_FRAME_YUV = 0x7F004000,
HAL_UNUSED_PICT = 0x10000000,
@@ -1020,7 +1021,7 @@
};
#define call_hfi_op(q, op, args...) \
- (((q)->op) ? ((q)->op(args)) : 0)
+ (((q) && (q)->op) ? ((q)->op(args)) : 0)
struct hfi_device {
void *hfi_device_data;
diff --git a/drivers/media/platform/msm/wfd/enc-mfc-subdev.c b/drivers/media/platform/msm/wfd/enc-mfc-subdev.c
index ceb0149..26e24da 100644
--- a/drivers/media/platform/msm/wfd/enc-mfc-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-mfc-subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,7 @@
#include <media/msm/vcd_property.h>
#include <linux/time.h>
#include <linux/ktime.h>
+#include <linux/slab.h>
#define VID_ENC_MAX_ENCODER_CLIENTS 1
#define MAX_NUM_CTRLS 20
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 4f7fb44..722aa8f 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -18,6 +18,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/wait.h>
+#include <linux/slab.h>
#include <mach/iommu_domains.h>
#include <media/msm_vidc.h>
#include <media/v4l2-subdev.h>
diff --git a/drivers/media/platform/msm/wfd/mdp-4-subdev.c b/drivers/media/platform/msm/wfd/mdp-4-subdev.c
index 465ec21..2d79622 100644
--- a/drivers/media/platform/msm/wfd/mdp-4-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-4-subdev.c
@@ -11,6 +11,7 @@
*
*/
#include <linux/msm_mdp.h>
+#include <linux/slab.h>
#include <mach/iommu_domains.h>
#include <media/videobuf2-core.h>
#include "enc-subdev.h"
diff --git a/drivers/media/platform/msm/wfd/mdp-5-subdev.c b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
index 3c546d0..6399117 100644
--- a/drivers/media/platform/msm/wfd/mdp-5-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
@@ -11,6 +11,7 @@
*
*/
#include <linux/msm_mdp.h>
+#include <linux/slab.h>
#include <mach/iommu_domains.h>
#include <media/videobuf2-core.h>
#include "enc-subdev.h"
diff --git a/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c b/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
index 2242c76..10ba3c3 100644
--- a/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
@@ -12,6 +12,7 @@
*/
#include <linux/list.h>
#include <linux/msm_mdp.h>
+#include <linux/slab.h>
#include <media/videobuf2-core.h>
#include "enc-subdev.h"
diff --git a/drivers/media/platform/msm/wfd/vsg-subdev.c b/drivers/media/platform/msm/wfd/vsg-subdev.c
index 90b1957..e0a46cc 100644
--- a/drivers/media/platform/msm/wfd/vsg-subdev.c
+++ b/drivers/media/platform/msm/wfd/vsg-subdev.c
@@ -13,6 +13,7 @@
#include <linux/hrtimer.h>
#include <linux/time.h>
#include <linux/list.h>
+#include <linux/slab.h>
#include <media/videobuf2-core.h>
#include "enc-subdev.h"
#include "vsg-subdev.h"
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index b1b1980..d44792c 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -14,14 +14,14 @@
#include <linux/types.h>
#include <linux/list.h>
#include <linux/ioctl.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/platform_device.h>
-
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/time.h>
+#include <linux/slab.h>
#include <mach/board.h>
#include <media/v4l2-dev.h>
@@ -78,7 +78,8 @@
struct wfd_inst {
struct vb2_queue vid_bufq;
- spinlock_t inst_lock;
+ struct mutex lock;
+ struct mutex vb2_lock;
u32 buf_count;
struct task_struct *mdp_task;
void *mdp_inst;
@@ -114,7 +115,6 @@
{
struct file *priv_data = (struct file *)(q->drv_priv);
struct wfd_inst *inst = file_to_inst(priv_data);
- unsigned long flags;
int i;
WFD_MSG_DBG("In %s\n", __func__);
@@ -122,12 +122,12 @@
return -EINVAL;
*num_planes = 1;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
for (i = 0; i < *num_planes; ++i) {
sizes[i] = inst->out_buf_size;
alloc_ctxs[i] = inst;
}
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return 0;
}
@@ -257,16 +257,15 @@
struct mem_region *enc_mregion, *mdp_mregion;
struct mem_region_pair *mpair;
int rc;
- unsigned long flags;
struct mdp_buf_info mdp_buf = {0};
struct mem_region_map mmap_context = {0};
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (inst->input_bufs_allocated) {
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return 0;
}
inst->input_bufs_allocated = true;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
for (i = 0; i < VENC_INPUT_BUFFERS; ++i) {
mpair = kzalloc(sizeof(*mpair), GFP_KERNEL);
@@ -409,15 +408,14 @@
{
struct list_head *ptr, *next;
struct mem_region_pair *mpair;
- unsigned long flags;
int rc = 0;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (!inst->input_bufs_allocated) {
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return;
}
inst->input_bufs_allocated = false;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
if (!list_empty(&inst->input_mem_list)) {
list_for_each_safe(ptr, next,
&inst->input_mem_list) {
@@ -470,8 +468,7 @@
{
struct mem_info_entry *temp;
struct mem_info *ret = NULL;
- unsigned long flags;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (!list_empty(&inst->minfo_list)) {
list_for_each_entry(temp, &inst->minfo_list, list) {
if (temp && temp->userptr == userptr) {
@@ -480,7 +477,7 @@
}
}
}
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return ret;
}
@@ -489,8 +486,7 @@
{
struct list_head *ptr, *next;
struct mem_info_entry *temp;
- unsigned long flags;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (!list_empty(&inst->minfo_list)) {
list_for_each_safe(ptr, next,
&inst->minfo_list) {
@@ -502,7 +498,7 @@
}
}
}
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
}
static void wfd_unregister_out_buf(struct wfd_inst *inst,
struct mem_info *minfo)
@@ -806,7 +802,6 @@
struct v4l2_format *fmt)
{
struct wfd_inst *inst = file_to_inst(filp);
- unsigned long flags;
if (!fmt) {
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
@@ -815,13 +810,13 @@
WFD_MSG_ERR("Only V4L2_BUF_TYPE_VIDEO_CAPTURE is supported\n");
return -EINVAL;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
fmt->fmt.pix.width = inst->width;
fmt->fmt.pix.height = inst->height;
fmt->fmt.pix.pixelformat = inst->pixelformat;
fmt->fmt.pix.sizeimage = inst->out_buf_size;
fmt->fmt.pix.priv = 0;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return 0;
}
@@ -832,7 +827,6 @@
struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev = video_drvdata(filp);
struct mdp_prop prop;
- unsigned long flags;
struct bufreq breq;
if (!fmt) {
WFD_MSG_ERR("Invalid argument\n");
@@ -864,13 +858,13 @@
WFD_MSG_ERR("Failed to set buffer reqs on encoder\n");
return rc;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
inst->input_buf_size = breq.size;
inst->out_buf_size = fmt->fmt.pix.sizeimage;
prop.height = inst->height = fmt->fmt.pix.height;
prop.width = inst->width = fmt->fmt.pix.width;
prop.inst = inst->mdp_inst;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_SET_PROP,
(void *)&prop);
if (rc)
@@ -882,7 +876,6 @@
{
struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev = video_drvdata(filp);
- unsigned long flags;
int rc = 0;
if (b->type != V4L2_CAP_VIDEO_CAPTURE ||
@@ -897,9 +890,9 @@
WFD_MSG_ERR("Failed to get buf reqs from encoder\n");
return rc;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
inst->buf_count = b->count;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
rc = vb2_reqbufs(&inst->vid_bufq, b);
return rc;
}
@@ -908,7 +901,6 @@
{
struct mem_info_entry *minfo_entry;
struct mem_info *minfo;
- unsigned long flags;
if (!b || !inst || !b->reserved) {
WFD_MSG_ERR("Invalid arguments\n");
return -EINVAL;
@@ -924,9 +916,9 @@
return -EINVAL;
}
minfo_entry->userptr = b->m.userptr;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
list_add_tail(&minfo_entry->list, &inst->minfo_list);
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
} else
WFD_MSG_DBG("Buffer already registered\n");
@@ -948,7 +940,10 @@
return rc;
}
+ mutex_lock(&inst->vb2_lock);
rc = vb2_qbuf(&inst->vid_bufq, b);
+ mutex_unlock(&inst->vb2_lock);
+
if (rc)
WFD_MSG_ERR("Failed to queue buffer\n");
else
@@ -962,16 +957,15 @@
{
int rc = 0;
struct wfd_inst *inst = file_to_inst(filp);
- unsigned long flags;
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
WFD_MSG_ERR("stream on for buffer type = %d is not "
"supported.\n", i);
return -EINVAL;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
inst->streamoff = false;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
rc = vb2_streamon(&inst->vid_bufq, i);
if (rc) {
@@ -988,7 +982,6 @@
enum v4l2_buf_type i)
{
struct wfd_inst *inst = file_to_inst(filp);
- unsigned long flags;
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
WFD_MSG_ERR("stream off for buffer type = %d is not "
@@ -996,14 +989,14 @@
return -EINVAL;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (inst->streamoff) {
WFD_MSG_ERR("Module is already in streamoff state\n");
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return -EINVAL;
}
inst->streamoff = true;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
WFD_MSG_DBG("Calling videobuf_streamoff\n");
vb2_streamoff(&inst->vid_bufq, i);
wake_up(&inst->event_handler.wait);
@@ -1016,7 +1009,10 @@
int rc;
WFD_MSG_DBG("Waiting to dequeue buffer\n");
- rc = vb2_dqbuf(&inst->vid_bufq, b, 0);
+
+ /* XXX: If we switch to non-blocking mode in the future,
+ * we'll need to lock this with vb2_lock */
+ rc = vb2_dqbuf(&inst->vid_bufq, b, false /* blocking */);
if (rc)
WFD_MSG_ERR("Failed to dequeue buffer\n");
@@ -1233,7 +1229,6 @@
};
static int wfd_set_default_properties(struct file *filp)
{
- unsigned long flags;
struct v4l2_format fmt;
struct v4l2_control ctrl;
struct wfd_inst *inst = file_to_inst(filp);
@@ -1241,13 +1236,13 @@
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.height = inst->height = DEFAULT_WFD_HEIGHT;
fmt.fmt.pix.width = inst->width = DEFAULT_WFD_WIDTH;
fmt.fmt.pix.pixelformat = inst->pixelformat
= V4L2_PIX_FMT_H264;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
wfdioc_s_fmt(filp, filp->private_data, &fmt);
ctrl.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE;
@@ -1258,8 +1253,13 @@
static void venc_op_buffer_done(void *cookie, u32 status,
struct vb2_buffer *buf)
{
+ struct file *filp = cookie;
+ struct wfd_inst *inst = file_to_inst(filp);
+
WFD_MSG_DBG("yay!! got callback\n");
+ mutex_lock(&inst->vb2_lock);
vb2_buffer_done(buf, VB2_BUF_STATE_DONE);
+ mutex_unlock(&inst->vb2_lock);
}
static void venc_ip_buffer_done(void *cookie, u32 status,
@@ -1430,7 +1430,8 @@
goto err_mdp_open;
}
filp->private_data = &inst->event_handler;
- spin_lock_init(&inst->inst_lock);
+ mutex_init(&inst->lock);
+ mutex_init(&inst->vb2_lock);
INIT_LIST_HEAD(&inst->input_mem_list);
INIT_LIST_HEAD(&inst->minfo_list);
@@ -1531,6 +1532,8 @@
wfd_stats_deinit(&inst->stats);
v4l2_fh_del(&inst->event_handler);
+ mutex_destroy(&inst->lock);
+ mutex_destroy(&inst->vb2_lock);
kfree(inst);
}
@@ -1546,22 +1549,21 @@
unsigned int wfd_poll(struct file *filp, struct poll_table_struct *pt)
{
struct wfd_inst *inst = file_to_inst(filp);
- unsigned int poll_flags = 0;
- unsigned long flags;
+ unsigned long flags = 0;
bool streamoff = false;
poll_wait(filp, &inst->event_handler.wait, pt);
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
streamoff = inst->streamoff;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
if (v4l2_event_pending(&inst->event_handler))
- poll_flags |= POLLPRI;
+ flags |= POLLPRI;
if (streamoff)
- poll_flags |= POLLERR;
+ flags |= POLLERR;
- return poll_flags;
+ return flags;
}
static const struct v4l2_file_operations g_wfd_fops = {
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 153552d..d673713 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -3790,6 +3790,27 @@
if (retval < 0)
FMDERR("set CF0 Threshold failed\n");
break;
+ case V4L2_CID_PRIVATE_RXREPEATCOUNT:
+ rd.mode = RDS_PS0_XFR_MODE;
+ rd.length = RDS_PS0_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("default data read failed for PS0 %x", retval);
+ return retval;
+ }
+ wrd.mode = RDS_PS0_XFR_MODE;
+ wrd.length = RDS_PS0_LEN;
+ memcpy(&wrd.data, &radio->default_data.data,
+ radio->default_data.ret_data_len);
+ wrd.data[RX_REPEATE_BYTE_OFFSET] = ctrl->value;
+
+ retval = hci_def_data_write(&wrd, radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("set RxRePeat count failed\n");
+ break;
default:
retval = -EINVAL;
}
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 046faac..130ff48 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -70,8 +70,7 @@
static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *dest, bool interface_reg)
{
- int ret;
- u8 *buf = dest;
+ int i, ret;
if (bytes <= 0) {
dev_err(wcd9xxx->dev, "Invalid byte read length %d\n", bytes);
@@ -82,9 +81,11 @@
if (ret < 0) {
dev_err(wcd9xxx->dev, "Codec read failed\n");
return ret;
- } else
- dev_dbg(wcd9xxx->dev, "Read 0x%02x from 0x%x\n",
- *buf, reg);
+ } else {
+ for (i = 0; i < bytes; i++)
+ dev_dbg(wcd9xxx->dev, "Read 0x%02x from 0x%x\n",
+ ((u8 *)dest)[i], reg + i);
+ }
return 0;
}
@@ -107,15 +108,16 @@
static int wcd9xxx_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *src, bool interface_reg)
{
- u8 *buf = src;
+ int i;
if (bytes <= 0) {
pr_err("%s: Error, invalid write length\n", __func__);
return -EINVAL;
}
- dev_dbg(wcd9xxx->dev, "Write %02x to 0x%x\n",
- *buf, reg);
+ for (i = 0; i < bytes; i++)
+ dev_dbg(wcd9xxx->dev, "Write %02x to 0x%x\n", ((u8 *)src)[i],
+ reg + i);
return wcd9xxx->write_dev(wcd9xxx, reg, bytes, src, interface_reg);
}
@@ -1147,6 +1149,10 @@
(of_property_read_bool(dev->of_node, "qcom,cdc-micbias4-ext-cap") ?
MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+ micbias->bias2_is_headset_only =
+ of_property_read_bool(dev->of_node,
+ "qcom,cdc-micbias2-headset-only");
+
dev_dbg(dev, "ldoh_v %u cfilt1_mv %u cfilt2_mv %u cfilt3_mv %u",
(u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv,
(u32)micbias->cfilt2_mv, (u32)micbias->cfilt3_mv);
@@ -1162,6 +1168,8 @@
dev_dbg(dev, "bias3_ext_cap %d bias4_ext_cap %d\n",
micbias->bias3_cap_mode, micbias->bias4_cap_mode);
+ dev_dbg(dev, "bias2_is_headset_only %d\n",
+ micbias->bias2_is_headset_only);
return 0;
}
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 111131a..5efd905 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -304,9 +304,11 @@
pr_warn("%s: status1 : %s\n", __func__, linebuf);
}
- memset(status, 0, num_irq_regs);
- wcd9xxx_bulk_write(wcd9xxx, WCD9XXX_A_INTR_STATUS0,
+ memset(status, 0xff, num_irq_regs);
+ wcd9xxx_bulk_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0,
num_irq_regs, status);
+ if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
}
wcd9xxx_unlock_sleep(wcd9xxx);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 2573a16..a7932ba 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -51,10 +51,6 @@
To compile this driver as a module, choose M here: the
module will be called ad525x_dpot-spi.
-config ANDROID_PMEM
- bool "Android pmem allocator"
- default y
-
config ATMEL_PWM
tristate "Atmel AT32/AT91 PWM support"
depends on HAVE_CLK
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 327d1ec..760f768 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -19,7 +19,6 @@
obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o
obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o
obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o
-obj-$(CONFIG_ANDROID_PMEM) += pmem.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
diff --git a/drivers/misc/pmem.c b/drivers/misc/pmem.c
deleted file mode 100644
index e91db7a..0000000
--- a/drivers/misc/pmem.c
+++ /dev/null
@@ -1,2961 +0,0 @@
-/* drivers/android/pmem.c
- *
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/export.h>
-#include <linux/miscdevice.h>
-#include <linux/platform_device.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/fmem.h>
-#include <linux/mm.h>
-#include <linux/list.h>
-#include <linux/debugfs.h>
-#include <linux/android_pmem.h>
-#include <linux/mempolicy.h>
-#include <linux/sched.h>
-#include <linux/kobject.h>
-#include <linux/pm_runtime.h>
-#include <linux/memory_alloc.h>
-#include <linux/vmalloc.h>
-#include <linux/io.h>
-#include <linux/mm_types.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/cacheflush.h>
-#include <asm/sizes.h>
-#include <asm/mach/map.h>
-#include <asm/page.h>
-
-#define PMEM_MAX_DEVICES (10)
-
-#define PMEM_MAX_ORDER (128)
-#define PMEM_MIN_ALLOC PAGE_SIZE
-
-#define PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS (64)
-
-#define PMEM_32BIT_WORD_ORDER (5)
-#define PMEM_BITS_PER_WORD_MASK (BITS_PER_LONG - 1)
-
-#ifdef CONFIG_ANDROID_PMEM_DEBUG
-#define PMEM_DEBUG 1
-#else
-#define PMEM_DEBUG 0
-#endif
-
-#define SYSTEM_ALLOC_RETRY 10
-
-/* indicates that a refernce to this file has been taken via get_pmem_file,
- * the file should not be released until put_pmem_file is called */
-#define PMEM_FLAGS_BUSY 0x1
-/* indicates that this is a suballocation of a larger master range */
-#define PMEM_FLAGS_CONNECTED 0x1 << 1
-/* indicates this is a master and not a sub allocation and that it is mmaped */
-#define PMEM_FLAGS_MASTERMAP 0x1 << 2
-/* submap and unsubmap flags indicate:
- * 00: subregion has never been mmaped
- * 10: subregion has been mmaped, reference to the mm was taken
- * 11: subretion has ben released, refernece to the mm still held
- * 01: subretion has been released, reference to the mm has been released
- */
-#define PMEM_FLAGS_SUBMAP 0x1 << 3
-#define PMEM_FLAGS_UNSUBMAP 0x1 << 4
-
-struct pmem_data {
- /* in alloc mode: an index into the bitmap
- * in no_alloc mode: the size of the allocation */
- int index;
- /* see flags above for descriptions */
- unsigned int flags;
- /* protects this data field, if the mm_mmap sem will be held at the
- * same time as this sem, the mm sem must be taken first (as this is
- * the order for vma_open and vma_close ops */
- struct rw_semaphore sem;
- /* info about the mmaping process */
- struct vm_area_struct *vma;
- /* task struct of the mapping process */
- struct task_struct *task;
- /* process id of teh mapping process */
- pid_t pid;
- /* file descriptor of the master */
- int master_fd;
- /* file struct of the master */
- struct file *master_file;
- /* a list of currently available regions if this is a suballocation */
- struct list_head region_list;
- /* a linked list of data so we can access them for debugging */
- struct list_head list;
-#if PMEM_DEBUG
- int ref;
-#endif
-};
-
-struct pmem_bits {
- unsigned allocated:1; /* 1 if allocated, 0 if free */
- unsigned order:7; /* size of the region in pmem space */
-};
-
-struct pmem_region_node {
- struct pmem_region region;
- struct list_head list;
-};
-
-#define PMEM_DEBUG_MSGS 0
-#if PMEM_DEBUG_MSGS
-#define DLOG(fmt,args...) \
- do { pr_debug("[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \
- ##args); } \
- while (0)
-#else
-#define DLOG(x...) do {} while (0)
-#endif
-
-enum pmem_align {
- PMEM_ALIGN_4K,
- PMEM_ALIGN_1M,
-};
-
-#define PMEM_NAME_SIZE 16
-
-struct alloc_list {
- void *addr; /* physical addr of allocation */
- void *aaddr; /* aligned physical addr */
- unsigned int size; /* total size of allocation */
- unsigned char __iomem *vaddr; /* Virtual addr */
- struct list_head allocs;
-};
-
-struct pmem_info {
- struct miscdevice dev;
- /* physical start address of the remaped pmem space */
- unsigned long base;
- /* vitual start address of the remaped pmem space */
- unsigned char __iomem *vbase;
- /* total size of the pmem space */
- unsigned long size;
- /* number of entries in the pmem space */
- unsigned long num_entries;
- /* pfn of the garbage page in memory */
- unsigned long garbage_pfn;
- /* which memory type (i.e. SMI, EBI1) this PMEM device is backed by */
- unsigned memory_type;
-
- char name[PMEM_NAME_SIZE];
-
- /* index of the garbage page in the pmem space */
- int garbage_index;
- /* reserved virtual address range */
- struct vm_struct *area;
-
- enum pmem_allocator_type allocator_type;
-
- int (*allocate)(const int,
- const unsigned long,
- const unsigned int);
- int (*free)(int, int);
- int (*free_space)(int, struct pmem_freespace *);
- unsigned long (*len)(int, struct pmem_data *);
- unsigned long (*start_addr)(int, struct pmem_data *);
-
- /* actual size of memory element, e.g.: (4 << 10) is 4K */
- unsigned int quantum;
-
- /* indicates maps of this region should be cached, if a mix of
- * cached and uncached is desired, set this and open the device with
- * O_SYNC to get an uncached region */
- unsigned cached;
- unsigned buffered;
- union {
- struct {
- /* in all_or_nothing allocator mode the first mapper
- * gets the whole space and sets this flag */
- unsigned allocated;
- } all_or_nothing;
-
- struct {
- /* the buddy allocator bitmap for the region
- * indicating which entries are allocated and which
- * are free.
- */
-
- struct pmem_bits *buddy_bitmap;
- } buddy_bestfit;
-
- struct {
- unsigned int bitmap_free; /* # of zero bits/quanta */
- uint32_t *bitmap;
- int32_t bitmap_allocs;
- struct {
- short bit;
- unsigned short quanta;
- } *bitm_alloc;
- } bitmap;
-
- struct {
- unsigned long used; /* Bytes currently allocated */
- struct list_head alist; /* List of allocations */
- } system_mem;
- } allocator;
-
- int id;
- struct kobject kobj;
-
- /* for debugging, creates a list of pmem file structs, the
- * data_list_mutex should be taken before pmem_data->sem if both are
- * needed */
- struct mutex data_list_mutex;
- struct list_head data_list;
- /* arena_mutex protects the global allocation arena
- *
- * IF YOU TAKE BOTH LOCKS TAKE THEM IN THIS ORDER:
- * down(pmem_data->sem) => mutex_lock(arena_mutex)
- */
- struct mutex arena_mutex;
-
- long (*ioctl)(struct file *, unsigned int, unsigned long);
- int (*release)(struct inode *, struct file *);
- /* reference count of allocations */
- atomic_t allocation_cnt;
- /*
- * request function for a region when the allocation count goes
- * from 0 -> 1
- */
- int (*mem_request)(void *);
- /*
- * release function for a region when the allocation count goes
- * from 1 -> 0
- */
- int (*mem_release)(void *);
- /*
- * private data for the request/release callback
- */
- void *region_data;
- /*
- * map and unmap as needed
- */
- int map_on_demand;
- /*
- * memory will be reused through fmem
- */
- int reusable;
-};
-#define to_pmem_info_id(a) (container_of(a, struct pmem_info, kobj)->id)
-
-static void ioremap_pmem(int id);
-static void pmem_put_region(int id);
-static int pmem_get_region(int id);
-
-static struct pmem_info pmem[PMEM_MAX_DEVICES];
-static int id_count;
-
-#define PMEM_SYSFS_DIR_NAME "pmem_regions" /* under /sys/kernel/ */
-static struct kset *pmem_kset;
-
-#define PMEM_IS_FREE_BUDDY(id, index) \
- (!(pmem[id].allocator.buddy_bestfit.buddy_bitmap[index].allocated))
-#define PMEM_BUDDY_ORDER(id, index) \
- (pmem[id].allocator.buddy_bestfit.buddy_bitmap[index].order)
-#define PMEM_BUDDY_INDEX(id, index) \
- (index ^ (1 << PMEM_BUDDY_ORDER(id, index)))
-#define PMEM_BUDDY_NEXT_INDEX(id, index) \
- (index + (1 << PMEM_BUDDY_ORDER(id, index)))
-#define PMEM_OFFSET(index) (index * pmem[id].quantum)
-#define PMEM_START_ADDR(id, index) \
- (PMEM_OFFSET(index) + pmem[id].base)
-#define PMEM_BUDDY_LEN(id, index) \
- ((1 << PMEM_BUDDY_ORDER(id, index)) * pmem[id].quantum)
-#define PMEM_END_ADDR(id, index) \
- (PMEM_START_ADDR(id, index) + PMEM_LEN(id, index))
-#define PMEM_START_VADDR(id, index) \
- (PMEM_OFFSET(id, index) + pmem[id].vbase)
-#define PMEM_END_VADDR(id, index) \
- (PMEM_START_VADDR(id, index) + PMEM_LEN(id, index))
-#define PMEM_REVOKED(data) (data->flags & PMEM_FLAGS_REVOKED)
-#define PMEM_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK)))
-#define PMEM_IS_SUBMAP(data) \
- ((data->flags & PMEM_FLAGS_SUBMAP) && \
- (!(data->flags & PMEM_FLAGS_UNSUBMAP)))
-
-static int pmem_release(struct inode *, struct file *);
-static int pmem_mmap(struct file *, struct vm_area_struct *);
-static int pmem_open(struct inode *, struct file *);
-static long pmem_ioctl(struct file *, unsigned int, unsigned long);
-
-struct file_operations pmem_fops = {
- .release = pmem_release,
- .mmap = pmem_mmap,
- .open = pmem_open,
- .unlocked_ioctl = pmem_ioctl,
-};
-
-#define PMEM_ATTR(_name, _mode, _show, _store) { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .show = _show, \
- .store = _store, \
-}
-
-struct pmem_attr {
- struct attribute attr;
- ssize_t(*show) (const int id, char * const);
- ssize_t(*store) (const int id, const char * const, const size_t count);
-};
-#define to_pmem_attr(a) container_of(a, struct pmem_attr, attr)
-
-#define RW_PMEM_ATTR(name) \
-static struct pmem_attr pmem_attr_## name = \
- PMEM_ATTR(name, S_IRUGO | S_IWUSR, show_pmem_## name, store_pmem_## name)
-
-#define RO_PMEM_ATTR(name) \
-static struct pmem_attr pmem_attr_## name = \
- PMEM_ATTR(name, S_IRUGO, show_pmem_## name, NULL)
-
-#define WO_PMEM_ATTR(name) \
-static struct pmem_attr pmem_attr_## name = \
- PMEM_ATTR(name, S_IWUSR, NULL, store_pmem_## name)
-
-static ssize_t show_pmem(struct kobject *kobj,
- struct attribute *attr,
- char *buf)
-{
- struct pmem_attr *a = to_pmem_attr(attr);
- return a->show ? a->show(to_pmem_info_id(kobj), buf) : -EIO;
-}
-
-static ssize_t store_pmem(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- struct pmem_attr *a = to_pmem_attr(attr);
- return a->store ? a->store(to_pmem_info_id(kobj), buf, count) : -EIO;
-}
-
-static struct sysfs_ops pmem_ops = {
- .show = show_pmem,
- .store = store_pmem,
-};
-
-static ssize_t show_pmem_base(int id, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%lu(%#lx)\n",
- pmem[id].base, pmem[id].base);
-}
-RO_PMEM_ATTR(base);
-
-static ssize_t show_pmem_size(int id, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%lu(%#lx)\n",
- pmem[id].size, pmem[id].size);
-}
-RO_PMEM_ATTR(size);
-
-static ssize_t show_pmem_allocator_type(int id, char *buf)
-{
- switch (pmem[id].allocator_type) {
- case PMEM_ALLOCATORTYPE_ALLORNOTHING:
- return scnprintf(buf, PAGE_SIZE, "%s\n", "All or Nothing");
- case PMEM_ALLOCATORTYPE_BUDDYBESTFIT:
- return scnprintf(buf, PAGE_SIZE, "%s\n", "Buddy Bestfit");
- case PMEM_ALLOCATORTYPE_BITMAP:
- return scnprintf(buf, PAGE_SIZE, "%s\n", "Bitmap");
- case PMEM_ALLOCATORTYPE_SYSTEM:
- return scnprintf(buf, PAGE_SIZE, "%s\n", "System heap");
- default:
- return scnprintf(buf, PAGE_SIZE,
- "??? Invalid allocator type (%d) for this region! "
- "Something isn't right.\n",
- pmem[id].allocator_type);
- }
-}
-RO_PMEM_ATTR(allocator_type);
-
-static ssize_t show_pmem_mapped_regions(int id, char *buf)
-{
- struct list_head *elt;
- int ret;
-
- ret = scnprintf(buf, PAGE_SIZE,
- "pid #: mapped regions (offset, len) (offset,len)...\n");
-
- mutex_lock(&pmem[id].data_list_mutex);
- list_for_each(elt, &pmem[id].data_list) {
- struct pmem_data *data =
- list_entry(elt, struct pmem_data, list);
- struct list_head *elt2;
-
- down_read(&data->sem);
- ret += scnprintf(buf + ret, PAGE_SIZE - ret, "pid %u:",
- data->pid);
- list_for_each(elt2, &data->region_list) {
- struct pmem_region_node *region_node = list_entry(elt2,
- struct pmem_region_node,
- list);
- ret += scnprintf(buf + ret, PAGE_SIZE - ret,
- "(%lx,%lx) ",
- region_node->region.offset,
- region_node->region.len);
- }
- up_read(&data->sem);
- ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
- }
- mutex_unlock(&pmem[id].data_list_mutex);
- return ret;
-}
-RO_PMEM_ATTR(mapped_regions);
-
-#define PMEM_COMMON_SYSFS_ATTRS \
- &pmem_attr_base.attr, \
- &pmem_attr_size.attr, \
- &pmem_attr_allocator_type.attr, \
- &pmem_attr_mapped_regions.attr
-
-
-static ssize_t show_pmem_allocated(int id, char *buf)
-{
- ssize_t ret;
-
- mutex_lock(&pmem[id].arena_mutex);
- ret = scnprintf(buf, PAGE_SIZE, "%s\n",
- pmem[id].allocator.all_or_nothing.allocated ?
- "is allocated" : "is NOT allocated");
- mutex_unlock(&pmem[id].arena_mutex);
- return ret;
-}
-RO_PMEM_ATTR(allocated);
-
-static struct attribute *pmem_allornothing_attrs[] = {
- PMEM_COMMON_SYSFS_ATTRS,
-
- &pmem_attr_allocated.attr,
-
- NULL
-};
-
-static struct kobj_type pmem_allornothing_ktype = {
- .sysfs_ops = &pmem_ops,
- .default_attrs = pmem_allornothing_attrs,
-};
-
-static ssize_t show_pmem_total_entries(int id, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%lu\n", pmem[id].num_entries);
-}
-RO_PMEM_ATTR(total_entries);
-
-static ssize_t show_pmem_quantum_size(int id, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%u (%#x)\n",
- pmem[id].quantum, pmem[id].quantum);
-}
-RO_PMEM_ATTR(quantum_size);
-
-static ssize_t show_pmem_buddy_bitmap_dump(int id, char *buf)
-{
- int ret, i;
-
- mutex_lock(&pmem[id].data_list_mutex);
- ret = scnprintf(buf, PAGE_SIZE, "index\torder\tlength\tallocated\n");
-
- for (i = 0; i < pmem[id].num_entries && (PAGE_SIZE - ret);
- i = PMEM_BUDDY_NEXT_INDEX(id, i))
- ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%d\t%d\t%d\t%d\n",
- i, PMEM_BUDDY_ORDER(id, i),
- PMEM_BUDDY_LEN(id, i),
- !PMEM_IS_FREE_BUDDY(id, i));
-
- mutex_unlock(&pmem[id].data_list_mutex);
- return ret;
-}
-RO_PMEM_ATTR(buddy_bitmap_dump);
-
-#define PMEM_BITMAP_BUDDY_BESTFIT_COMMON_SYSFS_ATTRS \
- &pmem_attr_quantum_size.attr, \
- &pmem_attr_total_entries.attr
-
-static struct attribute *pmem_buddy_bestfit_attrs[] = {
- PMEM_COMMON_SYSFS_ATTRS,
-
- PMEM_BITMAP_BUDDY_BESTFIT_COMMON_SYSFS_ATTRS,
-
- &pmem_attr_buddy_bitmap_dump.attr,
-
- NULL
-};
-
-static struct kobj_type pmem_buddy_bestfit_ktype = {
- .sysfs_ops = &pmem_ops,
- .default_attrs = pmem_buddy_bestfit_attrs,
-};
-
-static ssize_t show_pmem_free_quanta(int id, char *buf)
-{
- ssize_t ret;
-
- mutex_lock(&pmem[id].arena_mutex);
- ret = scnprintf(buf, PAGE_SIZE, "%u\n",
- pmem[id].allocator.bitmap.bitmap_free);
- mutex_unlock(&pmem[id].arena_mutex);
- return ret;
-}
-RO_PMEM_ATTR(free_quanta);
-
-static ssize_t show_pmem_bits_allocated(int id, char *buf)
-{
- ssize_t ret;
- unsigned int i;
-
- mutex_lock(&pmem[id].arena_mutex);
-
- ret = scnprintf(buf, PAGE_SIZE,
- "id: %d\nbitnum\tindex\tquanta allocated\n", id);
-
- for (i = 0; i < pmem[id].allocator.bitmap.bitmap_allocs; i++)
- if (pmem[id].allocator.bitmap.bitm_alloc[i].bit != -1)
- ret += scnprintf(buf + ret, PAGE_SIZE - ret,
- "%u\t%u\t%u\n",
- i,
- pmem[id].allocator.bitmap.bitm_alloc[i].bit,
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta
- );
-
- mutex_unlock(&pmem[id].arena_mutex);
- return ret;
-}
-RO_PMEM_ATTR(bits_allocated);
-
-static struct attribute *pmem_bitmap_attrs[] = {
- PMEM_COMMON_SYSFS_ATTRS,
-
- PMEM_BITMAP_BUDDY_BESTFIT_COMMON_SYSFS_ATTRS,
-
- &pmem_attr_free_quanta.attr,
- &pmem_attr_bits_allocated.attr,
-
- NULL
-};
-
-static struct attribute *pmem_system_attrs[] = {
- PMEM_COMMON_SYSFS_ATTRS,
-
- NULL
-};
-
-static struct kobj_type pmem_bitmap_ktype = {
- .sysfs_ops = &pmem_ops,
- .default_attrs = pmem_bitmap_attrs,
-};
-
-static struct kobj_type pmem_system_ktype = {
- .sysfs_ops = &pmem_ops,
- .default_attrs = pmem_system_attrs,
-};
-
-static int pmem_allocate_from_id(const int id, const unsigned long size,
- const unsigned int align)
-{
- int ret;
- ret = pmem_get_region(id);
-
- if (ret)
- return -1;
-
- ret = pmem[id].allocate(id, size, align);
-
- if (ret < 0)
- pmem_put_region(id);
-
- return ret;
-}
-
-static int pmem_free_from_id(const int id, const int index)
-{
- pmem_put_region(id);
- return pmem[id].free(id, index);
-}
-
-static int pmem_get_region(int id)
-{
- /* Must be called with arena mutex locked */
- atomic_inc(&pmem[id].allocation_cnt);
- if (!pmem[id].vbase) {
- DLOG("PMEMDEBUG: mapping for %s", pmem[id].name);
- if (pmem[id].mem_request) {
- int ret = pmem[id].mem_request(pmem[id].region_data);
- if (ret) {
- atomic_dec(&pmem[id].allocation_cnt);
- return 1;
- }
- }
- ioremap_pmem(id);
- }
-
- if (pmem[id].vbase) {
- return 0;
- } else {
- if (pmem[id].mem_release)
- pmem[id].mem_release(pmem[id].region_data);
- atomic_dec(&pmem[id].allocation_cnt);
- return 1;
- }
-}
-
-static void pmem_put_region(int id)
-{
- /* Must be called with arena mutex locked */
- if (atomic_dec_and_test(&pmem[id].allocation_cnt)) {
- DLOG("PMEMDEBUG: unmapping for %s", pmem[id].name);
- BUG_ON(!pmem[id].vbase);
- if (pmem[id].map_on_demand) {
- /* unmap_kernel_range() flushes the caches
- * and removes the page table entries
- */
- unmap_kernel_range((unsigned long)pmem[id].vbase,
- pmem[id].size);
- pmem[id].vbase = NULL;
- if (pmem[id].mem_release) {
- int ret = pmem[id].mem_release(
- pmem[id].region_data);
- WARN(ret, "mem_release failed");
- }
-
- }
- }
-}
-
-static int get_id(struct file *file)
-{
- return MINOR(file->f_dentry->d_inode->i_rdev);
-}
-
-static char *get_name(struct file *file)
-{
- int id = get_id(file);
- return pmem[id].name;
-}
-
-static int is_pmem_file(struct file *file)
-{
- int id;
-
- if (unlikely(!file || !file->f_dentry || !file->f_dentry->d_inode))
- return 0;
-
- id = get_id(file);
- return (unlikely(id >= PMEM_MAX_DEVICES ||
- file->f_dentry->d_inode->i_rdev !=
- MKDEV(MISC_MAJOR, pmem[id].dev.minor))) ? 0 : 1;
-}
-
-static int has_allocation(struct file *file)
-{
- /* must be called with at least read lock held on
- * ((struct pmem_data *)(file->private_data))->sem which
- * means that file is guaranteed not to be NULL upon entry!!
- * check is_pmem_file first if not accessed via pmem_file_ops */
- struct pmem_data *pdata = file->private_data;
- return pdata && pdata->index != -1;
-}
-
-static int is_master_owner(struct file *file)
-{
- struct file *master_file;
- struct pmem_data *data = file->private_data;
- int put_needed, ret = 0;
-
- if (!has_allocation(file))
- return 0;
- if (PMEM_FLAGS_MASTERMAP & data->flags)
- return 1;
- master_file = fget_light(data->master_fd, &put_needed);
- if (master_file && data->master_file == master_file)
- ret = 1;
- if (master_file)
- fput_light(master_file, put_needed);
- return ret;
-}
-
-static int pmem_free_all_or_nothing(int id, int index)
-{
- /* caller should hold the lock on arena_mutex! */
- DLOG("index %d\n", index);
-
- pmem[id].allocator.all_or_nothing.allocated = 0;
- return 0;
-}
-
-static int pmem_free_space_all_or_nothing(int id,
- struct pmem_freespace *fs)
-{
- /* caller should hold the lock on arena_mutex! */
- fs->total = (unsigned long)
- pmem[id].allocator.all_or_nothing.allocated == 0 ?
- pmem[id].size : 0;
-
- fs->largest = fs->total;
- return 0;
-}
-
-
-static int pmem_free_buddy_bestfit(int id, int index)
-{
- /* caller should hold the lock on arena_mutex! */
- int curr = index;
- DLOG("index %d\n", index);
-
-
- /* clean up the bitmap, merging any buddies */
- pmem[id].allocator.buddy_bestfit.buddy_bitmap[curr].allocated = 0;
- /* find a slots buddy Buddy# = Slot# ^ (1 << order)
- * if the buddy is also free merge them
- * repeat until the buddy is not free or end of the bitmap is reached
- */
- do {
- int buddy = PMEM_BUDDY_INDEX(id, curr);
- if (buddy < pmem[id].num_entries &&
- PMEM_IS_FREE_BUDDY(id, buddy) &&
- PMEM_BUDDY_ORDER(id, buddy) ==
- PMEM_BUDDY_ORDER(id, curr)) {
- PMEM_BUDDY_ORDER(id, buddy)++;
- PMEM_BUDDY_ORDER(id, curr)++;
- curr = min(buddy, curr);
- } else {
- break;
- }
- } while (curr < pmem[id].num_entries);
-
- return 0;
-}
-
-
-static int pmem_free_space_buddy_bestfit(int id,
- struct pmem_freespace *fs)
-{
- /* caller should hold the lock on arena_mutex! */
- int curr;
- unsigned long size;
- fs->total = 0;
- fs->largest = 0;
-
- for (curr = 0; curr < pmem[id].num_entries;
- curr = PMEM_BUDDY_NEXT_INDEX(id, curr)) {
- if (PMEM_IS_FREE_BUDDY(id, curr)) {
- size = PMEM_BUDDY_LEN(id, curr);
- if (size > fs->largest)
- fs->largest = size;
- fs->total += size;
- }
- }
- return 0;
-}
-
-
-static inline uint32_t start_mask(int bit_start)
-{
- return (uint32_t)(~0) << (bit_start & PMEM_BITS_PER_WORD_MASK);
-}
-
-static inline uint32_t end_mask(int bit_end)
-{
- return (uint32_t)(~0) >>
- ((BITS_PER_LONG - bit_end) & PMEM_BITS_PER_WORD_MASK);
-}
-
-static inline int compute_total_words(int bit_end, int word_index)
-{
- return ((bit_end + BITS_PER_LONG - 1) >>
- PMEM_32BIT_WORD_ORDER) - word_index;
-}
-
-static void bitmap_bits_clear_all(uint32_t *bitp, int bit_start, int bit_end)
-{
- int word_index = bit_start >> PMEM_32BIT_WORD_ORDER, total_words;
-
- total_words = compute_total_words(bit_end, word_index);
- if (total_words > 0) {
- if (total_words == 1) {
- bitp[word_index] &=
- ~(start_mask(bit_start) & end_mask(bit_end));
- } else {
- bitp[word_index++] &= ~start_mask(bit_start);
- if (total_words > 2) {
- int total_bytes;
-
- total_words -= 2;
- total_bytes = total_words << 2;
-
- memset(&bitp[word_index], 0, total_bytes);
- word_index += total_words;
- }
- bitp[word_index] &= ~end_mask(bit_end);
- }
- }
-}
-
-static int pmem_free_bitmap(int id, int bitnum)
-{
- /* caller should hold the lock on arena_mutex! */
- int i;
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-
- DLOG("bitnum %d\n", bitnum);
-
- for (i = 0; i < pmem[id].allocator.bitmap.bitmap_allocs; i++) {
- const int curr_bit =
- pmem[id].allocator.bitmap.bitm_alloc[i].bit;
-
- if (curr_bit == bitnum) {
- const int curr_quanta =
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta;
-
- bitmap_bits_clear_all(pmem[id].allocator.bitmap.bitmap,
- curr_bit, curr_bit + curr_quanta);
- pmem[id].allocator.bitmap.bitmap_free += curr_quanta;
- pmem[id].allocator.bitmap.bitm_alloc[i].bit = -1;
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta = 0;
- return 0;
- }
- }
- printk(KERN_ALERT "pmem: %s: Attempt to free unallocated index %d, id"
- " %d, pid %d(%s)\n", __func__, bitnum, id, current->pid,
- get_task_comm(currtask_name, current));
-
- return -1;
-}
-
-static int pmem_free_system(int id, int index)
-{
- /* caller should hold the lock on arena_mutex! */
- struct alloc_list *item;
-
- DLOG("index %d\n", index);
- if (index != 0)
- item = (struct alloc_list *)index;
- else
- return 0;
-
- if (item->vaddr != NULL) {
- iounmap(item->vaddr);
- kfree(__va(item->addr));
- list_del(&item->allocs);
- kfree(item);
- }
-
- return 0;
-}
-
-static int pmem_free_space_bitmap(int id, struct pmem_freespace *fs)
-{
- int i, j;
- int max_allocs = pmem[id].allocator.bitmap.bitmap_allocs;
- int alloc_start = 0;
- int next_alloc;
- unsigned long size = 0;
-
- fs->total = 0;
- fs->largest = 0;
-
- for (i = 0; i < max_allocs; i++) {
-
- int alloc_quanta = 0;
- int alloc_idx = 0;
- next_alloc = pmem[id].num_entries;
-
- /* Look for the lowest bit where next allocation starts */
- for (j = 0; j < max_allocs; j++) {
- const int curr_alloc = pmem[id].allocator.
- bitmap.bitm_alloc[j].bit;
- if (curr_alloc != -1) {
- if (alloc_start == curr_alloc)
- alloc_idx = j;
- if (alloc_start >= curr_alloc)
- continue;
- if (curr_alloc < next_alloc)
- next_alloc = curr_alloc;
- }
- }
- alloc_quanta = pmem[id].allocator.bitmap.
- bitm_alloc[alloc_idx].quanta;
- size = (next_alloc - (alloc_start + alloc_quanta)) *
- pmem[id].quantum;
-
- if (size > fs->largest)
- fs->largest = size;
- fs->total += size;
-
- if (next_alloc == pmem[id].num_entries)
- break;
- else
- alloc_start = next_alloc;
- }
-
- return 0;
-}
-
-static int pmem_free_space_system(int id, struct pmem_freespace *fs)
-{
- fs->total = pmem[id].size;
- fs->largest = pmem[id].size;
-
- return 0;
-}
-
-static void pmem_revoke(struct file *file, struct pmem_data *data);
-
-static int pmem_release(struct inode *inode, struct file *file)
-{
- struct pmem_data *data = file->private_data;
- struct pmem_region_node *region_node;
- struct list_head *elt, *elt2;
- int id = get_id(file), ret = 0;
-
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("releasing memory pid %u(%s) file %p(%ld) dev %s(id: %d)\n",
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file), get_name(file), id);
- mutex_lock(&pmem[id].data_list_mutex);
- /* if this file is a master, revoke all the memory in the connected
- * files */
- if (PMEM_FLAGS_MASTERMAP & data->flags) {
- list_for_each(elt, &pmem[id].data_list) {
- struct pmem_data *sub_data =
- list_entry(elt, struct pmem_data, list);
- int is_master;
-
- down_read(&sub_data->sem);
- is_master = (PMEM_IS_SUBMAP(sub_data) &&
- file == sub_data->master_file);
- up_read(&sub_data->sem);
-
- if (is_master)
- pmem_revoke(file, sub_data);
- }
- }
- list_del(&data->list);
- mutex_unlock(&pmem[id].data_list_mutex);
-
- down_write(&data->sem);
-
- /* if it is not a connected file and it has an allocation, free it */
- if (!(PMEM_FLAGS_CONNECTED & data->flags) && has_allocation(file)) {
- mutex_lock(&pmem[id].arena_mutex);
- ret = pmem_free_from_id(id, data->index);
- mutex_unlock(&pmem[id].arena_mutex);
- }
-
- /* if this file is a submap (mapped, connected file), downref the
- * task struct */
- if (PMEM_FLAGS_SUBMAP & data->flags)
- if (data->task) {
- put_task_struct(data->task);
- data->task = NULL;
- }
-
- file->private_data = NULL;
-
- list_for_each_safe(elt, elt2, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node, list);
- list_del(elt);
- kfree(region_node);
- }
- BUG_ON(!list_empty(&data->region_list));
-
- up_write(&data->sem);
- kfree(data);
- if (pmem[id].release)
- ret = pmem[id].release(inode, file);
-
- return ret;
-}
-
-static int pmem_open(struct inode *inode, struct file *file)
-{
- struct pmem_data *data;
- int id = get_id(file);
- int ret = 0;
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-
- DLOG("pid %u(%s) file %p(%ld) dev %s(id: %d)\n",
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file), get_name(file), id);
- data = kmalloc(sizeof(struct pmem_data), GFP_KERNEL);
- if (!data) {
- printk(KERN_ALERT "pmem: %s: unable to allocate memory for "
- "pmem metadata.", __func__);
- return -1;
- }
- data->flags = 0;
- data->index = -1;
- data->task = NULL;
- data->vma = NULL;
- data->pid = 0;
- data->master_file = NULL;
-#if PMEM_DEBUG
- data->ref = 0;
-#endif
- INIT_LIST_HEAD(&data->region_list);
- init_rwsem(&data->sem);
-
- file->private_data = data;
- INIT_LIST_HEAD(&data->list);
-
- mutex_lock(&pmem[id].data_list_mutex);
- list_add(&data->list, &pmem[id].data_list);
- mutex_unlock(&pmem[id].data_list_mutex);
- return ret;
-}
-
-static unsigned long pmem_order(unsigned long len, int id)
-{
- int i;
-
- len = (len + pmem[id].quantum - 1)/pmem[id].quantum;
- len--;
- for (i = 0; i < sizeof(len)*8; i++)
- if (len >> i == 0)
- break;
- return i;
-}
-
-static int pmem_allocator_all_or_nothing(const int id,
- const unsigned long len,
- const unsigned int align)
-{
- /* caller should hold the lock on arena_mutex! */
- DLOG("all or nothing\n");
- if ((len > pmem[id].size) ||
- pmem[id].allocator.all_or_nothing.allocated)
- return -1;
- pmem[id].allocator.all_or_nothing.allocated = 1;
- return len;
-}
-
-static int pmem_allocator_buddy_bestfit(const int id,
- const unsigned long len,
- unsigned int align)
-{
- /* caller should hold the lock on arena_mutex! */
- int curr;
- int best_fit = -1;
- unsigned long order;
-
- DLOG("buddy bestfit\n");
- order = pmem_order(len, id);
- if (order > PMEM_MAX_ORDER)
- goto out;
-
- DLOG("order %lx\n", order);
-
- /* Look through the bitmap.
- * If a free slot of the correct order is found, use it.
- * Otherwise, use the best fit (smallest with size > order) slot.
- */
- for (curr = 0;
- curr < pmem[id].num_entries;
- curr = PMEM_BUDDY_NEXT_INDEX(id, curr))
- if (PMEM_IS_FREE_BUDDY(id, curr)) {
- if (PMEM_BUDDY_ORDER(id, curr) ==
- (unsigned char)order) {
- /* set the not free bit and clear others */
- best_fit = curr;
- break;
- }
- if (PMEM_BUDDY_ORDER(id, curr) >
- (unsigned char)order &&
- (best_fit < 0 ||
- PMEM_BUDDY_ORDER(id, curr) <
- PMEM_BUDDY_ORDER(id, best_fit)))
- best_fit = curr;
- }
-
- /* if best_fit < 0, there are no suitable slots; return an error */
- if (best_fit < 0) {
-#if PMEM_DEBUG
- printk(KERN_ALERT "pmem: %s: no space left to allocate!\n",
- __func__);
-#endif
- goto out;
- }
-
- /* now partition the best fit:
- * split the slot into 2 buddies of order - 1
- * repeat until the slot is of the correct order
- */
- while (PMEM_BUDDY_ORDER(id, best_fit) > (unsigned char)order) {
- int buddy;
- PMEM_BUDDY_ORDER(id, best_fit) -= 1;
- buddy = PMEM_BUDDY_INDEX(id, best_fit);
- PMEM_BUDDY_ORDER(id, buddy) = PMEM_BUDDY_ORDER(id, best_fit);
- }
- pmem[id].allocator.buddy_bestfit.buddy_bitmap[best_fit].allocated = 1;
-out:
- return best_fit;
-}
-
-
-static inline unsigned long paddr_from_bit(const int id, const int bitnum)
-{
- return pmem[id].base + pmem[id].quantum * bitnum;
-}
-
-static inline unsigned long bit_from_paddr(const int id,
- const unsigned long paddr)
-{
- return (paddr - pmem[id].base) / pmem[id].quantum;
-}
-
-static void bitmap_bits_set_all(uint32_t *bitp, int bit_start, int bit_end)
-{
- int word_index = bit_start >> PMEM_32BIT_WORD_ORDER, total_words;
-
- total_words = compute_total_words(bit_end, word_index);
- if (total_words > 0) {
- if (total_words == 1) {
- bitp[word_index] |=
- (start_mask(bit_start) & end_mask(bit_end));
- } else {
- bitp[word_index++] |= start_mask(bit_start);
- if (total_words > 2) {
- int total_bytes;
-
- total_words -= 2;
- total_bytes = total_words << 2;
-
- memset(&bitp[word_index], ~0, total_bytes);
- word_index += total_words;
- }
- bitp[word_index] |= end_mask(bit_end);
- }
- }
-}
-
-static int
-bitmap_allocate_contiguous(uint32_t *bitp, int num_bits_to_alloc,
- int total_bits, int spacing, int start_bit)
-{
- int bit_start, last_bit, word_index;
-
- if (num_bits_to_alloc <= 0)
- return -1;
-
- for (bit_start = start_bit; ;
- bit_start = ((last_bit +
- (word_index << PMEM_32BIT_WORD_ORDER) + spacing - 1)
- & ~(spacing - 1)) + start_bit) {
- int bit_end = bit_start + num_bits_to_alloc, total_words;
-
- if (bit_end > total_bits)
- return -1; /* out of contiguous memory */
-
- word_index = bit_start >> PMEM_32BIT_WORD_ORDER;
- total_words = compute_total_words(bit_end, word_index);
-
- if (total_words <= 0)
- return -1;
-
- if (total_words == 1) {
- last_bit = fls(bitp[word_index] &
- (start_mask(bit_start) &
- end_mask(bit_end)));
- if (last_bit)
- continue;
- } else {
- int end_word = word_index + (total_words - 1);
- last_bit =
- fls(bitp[word_index] & start_mask(bit_start));
- if (last_bit)
- continue;
-
- for (word_index++;
- word_index < end_word;
- word_index++) {
- last_bit = fls(bitp[word_index]);
- if (last_bit)
- break;
- }
- if (last_bit)
- continue;
-
- last_bit = fls(bitp[word_index] & end_mask(bit_end));
- if (last_bit)
- continue;
- }
- bitmap_bits_set_all(bitp, bit_start, bit_end);
- return bit_start;
- }
- return -1;
-}
-
-static int reserve_quanta(const unsigned int quanta_needed,
- const int id,
- unsigned int align)
-{
- /* alignment should be a valid power of 2 */
- int ret = -1, start_bit = 0, spacing = 1;
-
- /* Sanity check */
- if (quanta_needed > pmem[id].allocator.bitmap.bitmap_free) {
-#if PMEM_DEBUG
- printk(KERN_ALERT "pmem: %s: request (%d) too big for"
- " available free (%d)\n", __func__, quanta_needed,
- pmem[id].allocator.bitmap.bitmap_free);
-#endif
- return -1;
- }
-
- start_bit = bit_from_paddr(id,
- (pmem[id].base + align - 1) & ~(align - 1));
- if (start_bit <= -1) {
-#if PMEM_DEBUG
- printk(KERN_ALERT
- "pmem: %s: bit_from_paddr fails for"
- " %u alignment.\n", __func__, align);
-#endif
- return -1;
- }
- spacing = align / pmem[id].quantum;
- spacing = spacing > 1 ? spacing : 1;
-
- ret = bitmap_allocate_contiguous(pmem[id].allocator.bitmap.bitmap,
- quanta_needed,
- (pmem[id].size + pmem[id].quantum - 1) / pmem[id].quantum,
- spacing,
- start_bit);
-
-#if PMEM_DEBUG
- if (ret < 0)
- printk(KERN_ALERT "pmem: %s: not enough contiguous bits free "
- "in bitmap! Region memory is either too fragmented or"
- " request is too large for available memory.\n",
- __func__);
-#endif
-
- return ret;
-}
-
-static int pmem_allocator_bitmap(const int id,
- const unsigned long len,
- const unsigned int align)
-{
- /* caller should hold the lock on arena_mutex! */
- int bitnum, i;
- unsigned int quanta_needed;
-
- DLOG("bitmap id %d, len %ld, align %u\n", id, len, align);
- if (!pmem[id].allocator.bitmap.bitm_alloc) {
-#if PMEM_DEBUG
- printk(KERN_ALERT "pmem: bitm_alloc not present! id: %d\n",
- id);
-#endif
- return -1;
- }
-
- quanta_needed = (len + pmem[id].quantum - 1) / pmem[id].quantum;
- DLOG("quantum size %u quanta needed %u free %u id %d\n",
- pmem[id].quantum, quanta_needed,
- pmem[id].allocator.bitmap.bitmap_free, id);
-
- if (pmem[id].allocator.bitmap.bitmap_free < quanta_needed) {
-#if PMEM_DEBUG
- printk(KERN_ALERT "pmem: memory allocation failure. "
- "PMEM memory region exhausted, id %d."
- " Unable to comply with allocation request.\n", id);
-#endif
- return -1;
- }
-
- bitnum = reserve_quanta(quanta_needed, id, align);
- if (bitnum == -1)
- goto leave;
-
- for (i = 0;
- i < pmem[id].allocator.bitmap.bitmap_allocs &&
- pmem[id].allocator.bitmap.bitm_alloc[i].bit != -1;
- i++)
- ;
-
- if (i >= pmem[id].allocator.bitmap.bitmap_allocs) {
- void *temp;
- int32_t new_bitmap_allocs =
- pmem[id].allocator.bitmap.bitmap_allocs << 1;
- int j;
-
- if (!new_bitmap_allocs) { /* failed sanity check!! */
-#if PMEM_DEBUG
- pr_alert("pmem: bitmap_allocs number"
- " wrapped around to zero! Something "
- "is VERY wrong.\n");
-#endif
- return -1;
- }
-
- if (new_bitmap_allocs > pmem[id].num_entries) {
- /* failed sanity check!! */
-#if PMEM_DEBUG
- pr_alert("pmem: required bitmap_allocs"
- " number exceeds maximum entries possible"
- " for current quanta\n");
-#endif
- return -1;
- }
-
- temp = krealloc(pmem[id].allocator.bitmap.bitm_alloc,
- new_bitmap_allocs *
- sizeof(*pmem[id].allocator.bitmap.bitm_alloc),
- GFP_KERNEL);
- if (!temp) {
-#if PMEM_DEBUG
- pr_alert("pmem: can't realloc bitmap_allocs,"
- "id %d, current num bitmap allocs %d\n",
- id, pmem[id].allocator.bitmap.bitmap_allocs);
-#endif
- return -1;
- }
- pmem[id].allocator.bitmap.bitmap_allocs = new_bitmap_allocs;
- pmem[id].allocator.bitmap.bitm_alloc = temp;
-
- for (j = i; j < new_bitmap_allocs; j++) {
- pmem[id].allocator.bitmap.bitm_alloc[j].bit = -1;
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta = 0;
- }
-
- DLOG("increased # of allocated regions to %d for id %d\n",
- pmem[id].allocator.bitmap.bitmap_allocs, id);
- }
-
- DLOG("bitnum %d, bitm_alloc index %d\n", bitnum, i);
-
- pmem[id].allocator.bitmap.bitmap_free -= quanta_needed;
- pmem[id].allocator.bitmap.bitm_alloc[i].bit = bitnum;
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta = quanta_needed;
-leave:
- return bitnum;
-}
-
-static int pmem_allocator_system(const int id,
- const unsigned long len,
- const unsigned int align)
-{
- /* caller should hold the lock on arena_mutex! */
- struct alloc_list *list;
- unsigned long aligned_len;
- int count = SYSTEM_ALLOC_RETRY;
- void *buf;
-
- DLOG("system id %d, len %ld, align %u\n", id, len, align);
-
- if ((pmem[id].allocator.system_mem.used + len) > pmem[id].size) {
- DLOG("requested size would be larger than quota\n");
- return -1;
- }
-
- /* Handle alignment */
- aligned_len = len + align;
-
- /* Attempt allocation */
- list = kmalloc(sizeof(struct alloc_list), GFP_KERNEL);
- if (list == NULL) {
- printk(KERN_ERR "pmem: failed to allocate system metadata\n");
- return -1;
- }
- list->vaddr = NULL;
-
- buf = NULL;
- while ((buf == NULL) && count--) {
- buf = kmalloc((aligned_len), GFP_KERNEL);
- if (buf == NULL) {
- DLOG("pmem: kmalloc %d temporarily failed len= %ld\n",
- count, aligned_len);
- }
- }
- if (!buf) {
- printk(KERN_CRIT "pmem: kmalloc failed for id= %d len= %ld\n",
- id, aligned_len);
- kfree(list);
- return -1;
- }
- list->size = aligned_len;
- list->addr = (void *)__pa(buf);
- list->aaddr = (void *)(((unsigned int)(list->addr) + (align - 1)) &
- ~(align - 1));
-
- if (!pmem[id].cached)
- list->vaddr = ioremap(__pa(buf), aligned_len);
- else
- list->vaddr = ioremap_cached(__pa(buf), aligned_len);
-
- INIT_LIST_HEAD(&list->allocs);
- list_add(&list->allocs, &pmem[id].allocator.system_mem.alist);
-
- return (int)list;
-}
-
-static pgprot_t pmem_phys_mem_access_prot(struct file *file, pgprot_t vma_prot)
-{
- int id = get_id(file);
-#ifdef pgprot_writecombine
- if (pmem[id].cached == 0 || file->f_flags & O_SYNC)
- /* on ARMv6 and ARMv7 this expands to Normal Noncached */
- return pgprot_writecombine(vma_prot);
-#endif
-#ifdef pgprot_ext_buffered
- else if (pmem[id].buffered)
- return pgprot_ext_buffered(vma_prot);
-#endif
- return vma_prot;
-}
-
-static unsigned long pmem_start_addr_all_or_nothing(int id,
- struct pmem_data *data)
-{
- return PMEM_START_ADDR(id, 0);
-}
-
-static unsigned long pmem_start_addr_buddy_bestfit(int id,
- struct pmem_data *data)
-{
- return PMEM_START_ADDR(id, data->index);
-}
-
-static unsigned long pmem_start_addr_bitmap(int id, struct pmem_data *data)
-{
- return data->index * pmem[id].quantum + pmem[id].base;
-}
-
-static unsigned long pmem_start_addr_system(int id, struct pmem_data *data)
-{
- return (unsigned long)(((struct alloc_list *)(data->index))->aaddr);
-}
-
-static void *pmem_start_vaddr(int id, struct pmem_data *data)
-{
- if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_SYSTEM)
- return ((struct alloc_list *)(data->index))->vaddr;
- else
- return pmem[id].start_addr(id, data) - pmem[id].base + pmem[id].vbase;
-}
-
-static unsigned long pmem_len_all_or_nothing(int id, struct pmem_data *data)
-{
- return data->index;
-}
-
-static unsigned long pmem_len_buddy_bestfit(int id, struct pmem_data *data)
-{
- return PMEM_BUDDY_LEN(id, data->index);
-}
-
-static unsigned long pmem_len_bitmap(int id, struct pmem_data *data)
-{
- int i;
- unsigned long ret = 0;
-
- mutex_lock(&pmem[id].arena_mutex);
-
- for (i = 0; i < pmem[id].allocator.bitmap.bitmap_allocs; i++)
- if (pmem[id].allocator.bitmap.bitm_alloc[i].bit ==
- data->index) {
- ret = pmem[id].allocator.bitmap.bitm_alloc[i].quanta *
- pmem[id].quantum;
- break;
- }
-
- mutex_unlock(&pmem[id].arena_mutex);
-#if PMEM_DEBUG
- if (i >= pmem[id].allocator.bitmap.bitmap_allocs)
- pr_alert("pmem: %s: can't find bitnum %d in "
- "alloc'd array!\n", __func__, data->index);
-#endif
- return ret;
-}
-
-static unsigned long pmem_len_system(int id, struct pmem_data *data)
-{
- unsigned long ret = 0;
-
- mutex_lock(&pmem[id].arena_mutex);
-
- ret = ((struct alloc_list *)data->index)->size;
- mutex_unlock(&pmem[id].arena_mutex);
-
- return ret;
-}
-
-static int pmem_map_garbage(int id, struct vm_area_struct *vma,
- struct pmem_data *data, unsigned long offset,
- unsigned long len)
-{
- int i, garbage_pages = len >> PAGE_SHIFT;
-
- vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP | VM_SHARED | VM_WRITE;
- for (i = 0; i < garbage_pages; i++) {
- if (vm_insert_pfn(vma, vma->vm_start + offset + (i * PAGE_SIZE),
- pmem[id].garbage_pfn))
- return -EAGAIN;
- }
- return 0;
-}
-
-static int pmem_unmap_pfn_range(int id, struct vm_area_struct *vma,
- struct pmem_data *data, unsigned long offset,
- unsigned long len)
-{
- int garbage_pages;
- DLOG("unmap offset %lx len %lx\n", offset, len);
-
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(len));
-
- garbage_pages = len >> PAGE_SHIFT;
- zap_page_range(vma, vma->vm_start + offset, len, NULL);
- pmem_map_garbage(id, vma, data, offset, len);
- return 0;
-}
-
-static int pmem_map_pfn_range(int id, struct vm_area_struct *vma,
- struct pmem_data *data, unsigned long offset,
- unsigned long len)
-{
- int ret;
- DLOG("map offset %lx len %lx\n", offset, len);
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_start));
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_end));
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(len));
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(offset));
-
- ret = io_remap_pfn_range(vma, vma->vm_start + offset,
- (pmem[id].start_addr(id, data) + offset) >> PAGE_SHIFT,
- len, vma->vm_page_prot);
- if (ret) {
-#if PMEM_DEBUG
- pr_alert("pmem: %s: io_remap_pfn_range fails with "
- "return value: %d!\n", __func__, ret);
-#endif
-
- ret = -EAGAIN;
- }
- return ret;
-}
-
-static int pmem_remap_pfn_range(int id, struct vm_area_struct *vma,
- struct pmem_data *data, unsigned long offset,
- unsigned long len)
-{
- /* hold the mm semp for the vma you are modifying when you call this */
- BUG_ON(!vma);
- zap_page_range(vma, vma->vm_start + offset, len, NULL);
- return pmem_map_pfn_range(id, vma, data, offset, len);
-}
-
-static void pmem_vma_open(struct vm_area_struct *vma)
-{
- struct file *file = vma->vm_file;
- struct pmem_data *data = file->private_data;
- int id = get_id(file);
-
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("Dev %s(id: %d) pid %u(%s) ppid %u file %p count %ld\n",
- get_name(file), id, current->pid,
- get_task_comm(currtask_name, current),
- current->parent->pid, file, file_count(file));
- /* this should never be called as we don't support copying pmem
- * ranges via fork */
- down_read(&data->sem);
- BUG_ON(!has_allocation(file));
- /* remap the garbage pages, forkers don't get access to the data */
- pmem_unmap_pfn_range(id, vma, data, 0, vma->vm_start - vma->vm_end);
- up_read(&data->sem);
-}
-
-static void pmem_vma_close(struct vm_area_struct *vma)
-{
- struct file *file = vma->vm_file;
- struct pmem_data *data = file->private_data;
-
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("Dev %s(id: %d) pid %u(%s) ppid %u file %p count %ld\n",
- get_name(file), get_id(file), current->pid,
- get_task_comm(currtask_name, current),
- current->parent->pid, file, file_count(file));
-
- if (unlikely(!is_pmem_file(file))) {
- pr_warning("pmem: something is very wrong, you are "
- "closing a vm backing an allocation that doesn't "
- "exist!\n");
- return;
- }
-
- down_write(&data->sem);
- if (unlikely(!has_allocation(file))) {
- up_write(&data->sem);
- pr_warning("pmem: something is very wrong, you are "
- "closing a vm backing an allocation that doesn't "
- "exist!\n");
- return;
- }
- if (data->vma == vma) {
- data->vma = NULL;
- if ((data->flags & PMEM_FLAGS_CONNECTED) &&
- (data->flags & PMEM_FLAGS_SUBMAP))
- data->flags |= PMEM_FLAGS_UNSUBMAP;
- }
- /* the kernel is going to free this vma now anyway */
- up_write(&data->sem);
-}
-
-static struct vm_operations_struct vm_ops = {
- .open = pmem_vma_open,
- .close = pmem_vma_close,
-};
-
-static int pmem_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct pmem_data *data = file->private_data;
- int index = -1;
- unsigned long vma_size = vma->vm_end - vma->vm_start;
- int ret = 0, id = get_id(file);
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-
- if (!data) {
- pr_err("pmem: Invalid file descriptor, no private data\n");
- return -EINVAL;
- }
- DLOG("pid %u(%s) mmap vma_size %lu on dev %s(id: %d)\n", current->pid,
- get_task_comm(currtask_name, current), vma_size,
- get_name(file), id);
- if (vma->vm_pgoff || !PMEM_IS_PAGE_ALIGNED(vma_size)) {
-#if PMEM_DEBUG
- pr_err("pmem: mmaps must be at offset zero, aligned"
- " and a multiple of pages_size.\n");
-#endif
- return -EINVAL;
- }
-
- down_write(&data->sem);
- /* check this file isn't already mmaped, for submaps check this file
- * has never been mmaped */
- if ((data->flags & PMEM_FLAGS_SUBMAP) ||
- (data->flags & PMEM_FLAGS_UNSUBMAP)) {
-#if PMEM_DEBUG
- pr_err("pmem: you can only mmap a pmem file once, "
- "this file is already mmaped. %x\n", data->flags);
-#endif
- ret = -EINVAL;
- goto error;
- }
- /* if file->private_data == unalloced, alloc*/
- if (data->index == -1) {
- mutex_lock(&pmem[id].arena_mutex);
- index = pmem_allocate_from_id(id,
- vma->vm_end - vma->vm_start,
- SZ_4K);
- mutex_unlock(&pmem[id].arena_mutex);
- /* either no space was available or an error occured */
- if (index == -1) {
- pr_err("pmem: mmap unable to allocate memory"
- "on %s\n", get_name(file));
- ret = -ENOMEM;
- goto error;
- }
- /* store the index of a successful allocation */
- data->index = index;
- }
-
- if (pmem[id].len(id, data) < vma_size) {
-#if PMEM_DEBUG
- pr_err("pmem: mmap size [%lu] does not match"
- " size of backing region [%lu].\n", vma_size,
- pmem[id].len(id, data));
-#endif
- ret = -EINVAL;
- goto error;
- }
-
- vma->vm_pgoff = pmem[id].start_addr(id, data) >> PAGE_SHIFT;
-
- vma->vm_page_prot = pmem_phys_mem_access_prot(file, vma->vm_page_prot);
-
- if (data->flags & PMEM_FLAGS_CONNECTED) {
- struct pmem_region_node *region_node;
- struct list_head *elt;
- if (pmem_map_garbage(id, vma, data, 0, vma_size)) {
- pr_alert("pmem: mmap failed in kernel!\n");
- ret = -EAGAIN;
- goto error;
- }
- list_for_each(elt, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node,
- list);
- DLOG("remapping file: %p %lx %lx\n", file,
- region_node->region.offset,
- region_node->region.len);
- if (pmem_remap_pfn_range(id, vma, data,
- region_node->region.offset,
- region_node->region.len)) {
- ret = -EAGAIN;
- goto error;
- }
- }
- data->flags |= PMEM_FLAGS_SUBMAP;
- get_task_struct(current->group_leader);
- data->task = current->group_leader;
- data->vma = vma;
-#if PMEM_DEBUG
- data->pid = current->pid;
-#endif
- DLOG("submmapped file %p vma %p pid %u\n", file, vma,
- current->pid);
- } else {
- if (pmem_map_pfn_range(id, vma, data, 0, vma_size)) {
- pr_err("pmem: mmap failed in kernel!\n");
- ret = -EAGAIN;
- goto error;
- }
- data->flags |= PMEM_FLAGS_MASTERMAP;
- data->pid = current->pid;
- }
- vma->vm_ops = &vm_ops;
-error:
- up_write(&data->sem);
- return ret;
-}
-
-/* the following are the api for accessing pmem regions by other drivers
- * from inside the kernel */
-int get_pmem_user_addr(struct file *file, unsigned long *start,
- unsigned long *len)
-{
- int ret = -1;
-
- if (is_pmem_file(file)) {
- struct pmem_data *data = file->private_data;
-
- down_read(&data->sem);
- if (has_allocation(file)) {
- if (data->vma) {
- *start = data->vma->vm_start;
- *len = data->vma->vm_end - data->vma->vm_start;
- } else {
- *start = *len = 0;
-#if PMEM_DEBUG
- pr_err("pmem: %s: no vma present.\n",
- __func__);
-#endif
- }
- ret = 0;
- }
- up_read(&data->sem);
- }
-
-#if PMEM_DEBUG
- if (ret)
- pr_err("pmem: %s: requested pmem data from invalid"
- "file.\n", __func__);
-#endif
- return ret;
-}
-
-int get_pmem_addr(struct file *file, unsigned long *start,
- unsigned long *vstart, unsigned long *len)
-{
- int ret = -1;
-
- if (is_pmem_file(file)) {
- struct pmem_data *data = file->private_data;
-
- down_read(&data->sem);
- if (has_allocation(file)) {
- int id = get_id(file);
-
- *start = pmem[id].start_addr(id, data);
- *len = pmem[id].len(id, data);
- *vstart = (unsigned long)
- pmem_start_vaddr(id, data);
- up_read(&data->sem);
-#if PMEM_DEBUG
- down_write(&data->sem);
- data->ref++;
- up_write(&data->sem);
-#endif
- DLOG("returning start %#lx len %lu "
- "vstart %#lx\n",
- *start, *len, *vstart);
- ret = 0;
- } else {
- up_read(&data->sem);
- }
- }
- return ret;
-}
-
-int get_pmem_file(unsigned int fd, unsigned long *start, unsigned long *vstart,
- unsigned long *len, struct file **filp)
-{
- int ret = -1;
- struct file *file = fget(fd);
-
- if (unlikely(file == NULL)) {
- pr_err("pmem: %s: requested data from file "
- "descriptor that doesn't exist.\n", __func__);
- } else {
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("filp %p rdev %d pid %u(%s) file %p(%ld)"
- " dev %s(id: %d)\n", filp,
- file->f_dentry->d_inode->i_rdev,
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file), get_name(file), get_id(file));
-
- if (!get_pmem_addr(file, start, vstart, len)) {
- if (filp)
- *filp = file;
- ret = 0;
- } else {
- fput(file);
- }
- }
- return ret;
-}
-EXPORT_SYMBOL(get_pmem_file);
-
-int get_pmem_fd(int fd, unsigned long *start, unsigned long *len)
-{
- unsigned long vstart;
- return get_pmem_file(fd, start, &vstart, len, NULL);
-}
-EXPORT_SYMBOL(get_pmem_fd);
-
-void put_pmem_file(struct file *file)
-{
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("rdev %d pid %u(%s) file %p(%ld)" " dev %s(id: %d)\n",
- file->f_dentry->d_inode->i_rdev, current->pid,
- get_task_comm(currtask_name, current), file,
- file_count(file), get_name(file), get_id(file));
- if (is_pmem_file(file)) {
-#if PMEM_DEBUG
- struct pmem_data *data = file->private_data;
-
- down_write(&data->sem);
- if (!data->ref--) {
- data->ref++;
- pr_alert("pmem: pmem_put > pmem_get %s "
- "(pid %d)\n",
- pmem[get_id(file)].dev.name, data->pid);
- BUG();
- }
- up_write(&data->sem);
-#endif
- fput(file);
- }
-}
-EXPORT_SYMBOL(put_pmem_file);
-
-void put_pmem_fd(int fd)
-{
- int put_needed;
- struct file *file = fget_light(fd, &put_needed);
-
- if (file) {
- put_pmem_file(file);
- fput_light(file, put_needed);
- }
-}
-
-void flush_pmem_fd(int fd, unsigned long offset, unsigned long len)
-{
- int fput_needed;
- struct file *file = fget_light(fd, &fput_needed);
-
- if (file) {
- flush_pmem_file(file, offset, len);
- fput_light(file, fput_needed);
- }
-}
-
-void flush_pmem_file(struct file *file, unsigned long offset, unsigned long len)
-{
- struct pmem_data *data;
- int id;
- void *vaddr;
- struct pmem_region_node *region_node;
- struct list_head *elt;
- void *flush_start, *flush_end;
-#ifdef CONFIG_OUTER_CACHE
- unsigned long phy_start, phy_end;
-#endif
- if (!is_pmem_file(file))
- return;
-
- id = get_id(file);
- if (!pmem[id].cached)
- return;
-
- /* is_pmem_file fails if !file */
- data = file->private_data;
-
- down_read(&data->sem);
- if (!has_allocation(file))
- goto end;
-
- vaddr = pmem_start_vaddr(id, data);
-
- if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_SYSTEM) {
- dmac_flush_range(vaddr,
- (void *)((unsigned long)vaddr +
- ((struct alloc_list *)(data->index))->size));
-#ifdef CONFIG_OUTER_CACHE
- phy_start = pmem_start_addr_system(id, data);
-
- phy_end = phy_start +
- ((struct alloc_list *)(data->index))->size;
-
- outer_flush_range(phy_start, phy_end);
-#endif
- goto end;
- }
- /* if this isn't a submmapped file, flush the whole thing */
- if (unlikely(!(data->flags & PMEM_FLAGS_CONNECTED))) {
- dmac_flush_range(vaddr, vaddr + pmem[id].len(id, data));
-#ifdef CONFIG_OUTER_CACHE
- phy_start = (unsigned long)vaddr -
- (unsigned long)pmem[id].vbase + pmem[id].base;
-
- phy_end = phy_start + pmem[id].len(id, data);
-
- outer_flush_range(phy_start, phy_end);
-#endif
- goto end;
- }
- /* otherwise, flush the region of the file we are drawing */
- list_for_each(elt, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node, list);
- if ((offset >= region_node->region.offset) &&
- ((offset + len) <= (region_node->region.offset +
- region_node->region.len))) {
- flush_start = vaddr + region_node->region.offset;
- flush_end = flush_start + region_node->region.len;
- dmac_flush_range(flush_start, flush_end);
-#ifdef CONFIG_OUTER_CACHE
-
- phy_start = (unsigned long)flush_start -
- (unsigned long)pmem[id].vbase + pmem[id].base;
-
- phy_end = phy_start + region_node->region.len;
-
- outer_flush_range(phy_start, phy_end);
-#endif
- break;
- }
- }
-end:
- up_read(&data->sem);
-}
-
-int pmem_cache_maint(struct file *file, unsigned int cmd,
- struct pmem_addr *pmem_addr)
-{
- struct pmem_data *data;
- int id;
- unsigned long vaddr, paddr, length, offset,
- pmem_len, pmem_start_addr;
-
- /* Called from kernel-space so file may be NULL */
- if (!file)
- return -EBADF;
-
- /*
- * check that the vaddr passed for flushing is valid
- * so that you don't crash the kernel
- */
- if (!pmem_addr->vaddr)
- return -EINVAL;
-
- data = file->private_data;
- id = get_id(file);
-
- if (!pmem[id].cached)
- return 0;
-
- offset = pmem_addr->offset;
- length = pmem_addr->length;
-
- down_read(&data->sem);
- if (!has_allocation(file)) {
- up_read(&data->sem);
- return -EINVAL;
- }
- pmem_len = pmem[id].len(id, data);
- pmem_start_addr = pmem[id].start_addr(id, data);
- up_read(&data->sem);
-
- if (offset + length > pmem_len)
- return -EINVAL;
-
- vaddr = pmem_addr->vaddr;
- paddr = pmem_start_addr + offset;
-
- DLOG("pmem cache maint on dev %s(id: %d)"
- "(vaddr %lx paddr %lx len %lu bytes)\n",
- get_name(file), id, vaddr, paddr, length);
- if (cmd == PMEM_CLEAN_INV_CACHES)
- clean_and_invalidate_caches(vaddr,
- length, paddr);
- else if (cmd == PMEM_CLEAN_CACHES)
- clean_caches(vaddr, length, paddr);
- else if (cmd == PMEM_INV_CACHES)
- invalidate_caches(vaddr, length, paddr);
-
- return 0;
-}
-EXPORT_SYMBOL(pmem_cache_maint);
-
-static int pmem_connect(unsigned long connect, struct file *file)
-{
- int ret = 0, put_needed;
- struct file *src_file;
-
- if (!file) {
- pr_err("pmem: %s: NULL file pointer passed in, "
- "bailing out!\n", __func__);
- ret = -EINVAL;
- goto leave;
- }
-
- src_file = fget_light(connect, &put_needed);
-
- if (!src_file) {
- pr_err("pmem: %s: src file not found!\n", __func__);
- ret = -EBADF;
- goto leave;
- }
-
- if (src_file == file) { /* degenerative case, operator error */
- pr_err("pmem: %s: src_file and passed in file are "
- "the same; refusing to connect to self!\n", __func__);
- ret = -EINVAL;
- goto put_src_file;
- }
-
- if (unlikely(!is_pmem_file(src_file))) {
- pr_err("pmem: %s: src file is not a pmem file!\n",
- __func__);
- ret = -EINVAL;
- goto put_src_file;
- } else {
- struct pmem_data *src_data = src_file->private_data;
-
- if (!src_data) {
- pr_err("pmem: %s: src file pointer has no"
- "private data, bailing out!\n", __func__);
- ret = -EINVAL;
- goto put_src_file;
- }
-
- down_read(&src_data->sem);
-
- if (unlikely(!has_allocation(src_file))) {
- up_read(&src_data->sem);
- pr_err("pmem: %s: src file has no allocation!\n",
- __func__);
- ret = -EINVAL;
- } else {
- struct pmem_data *data;
- int src_index = src_data->index;
-
- up_read(&src_data->sem);
-
- data = file->private_data;
- if (!data) {
- pr_err("pmem: %s: passed in file "
- "pointer has no private data, bailing"
- " out!\n", __func__);
- ret = -EINVAL;
- goto put_src_file;
- }
-
- down_write(&data->sem);
- if (has_allocation(file) &&
- (data->index != src_index)) {
- up_write(&data->sem);
-
- pr_err("pmem: %s: file is already "
- "mapped but doesn't match this "
- "src_file!\n", __func__);
- ret = -EINVAL;
- } else {
- data->index = src_index;
- data->flags |= PMEM_FLAGS_CONNECTED;
- data->master_fd = connect;
- data->master_file = src_file;
-
- up_write(&data->sem);
-
- DLOG("connect %p to %p\n", file, src_file);
- }
- }
- }
-put_src_file:
- fput_light(src_file, put_needed);
-leave:
- return ret;
-}
-
-static void pmem_unlock_data_and_mm(struct pmem_data *data,
- struct mm_struct *mm)
-{
- up_write(&data->sem);
- if (mm != NULL) {
- up_write(&mm->mmap_sem);
- mmput(mm);
- }
-}
-
-static int pmem_lock_data_and_mm(struct file *file, struct pmem_data *data,
- struct mm_struct **locked_mm)
-{
- int ret = 0;
- struct mm_struct *mm = NULL;
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("pid %u(%s) file %p(%ld)\n",
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file));
-
- *locked_mm = NULL;
-lock_mm:
- down_read(&data->sem);
- if (PMEM_IS_SUBMAP(data)) {
- mm = get_task_mm(data->task);
- if (!mm) {
- up_read(&data->sem);
-#if PMEM_DEBUG
- pr_alert("pmem: can't remap - task is gone!\n");
-#endif
- return -1;
- }
- }
- up_read(&data->sem);
-
- if (mm)
- down_write(&mm->mmap_sem);
-
- down_write(&data->sem);
- /* check that the file didn't get mmaped before we could take the
- * data sem, this should be safe b/c you can only submap each file
- * once */
- if (PMEM_IS_SUBMAP(data) && !mm) {
- pmem_unlock_data_and_mm(data, mm);
- DLOG("mapping contention, repeating mmap op\n");
- goto lock_mm;
- }
- /* now check that vma.mm is still there, it could have been
- * deleted by vma_close before we could get the data->sem */
- if ((data->flags & PMEM_FLAGS_UNSUBMAP) && (mm != NULL)) {
- /* might as well release this */
- if (data->flags & PMEM_FLAGS_SUBMAP) {
- put_task_struct(data->task);
- data->task = NULL;
- /* lower the submap flag to show the mm is gone */
- data->flags &= ~(PMEM_FLAGS_SUBMAP);
- }
- pmem_unlock_data_and_mm(data, mm);
-#if PMEM_DEBUG
- pr_alert("pmem: vma.mm went away!\n");
-#endif
- return -1;
- }
- *locked_mm = mm;
- return ret;
-}
-
-int pmem_remap(struct pmem_region *region, struct file *file,
- unsigned operation)
-{
- int ret;
- struct pmem_region_node *region_node;
- struct mm_struct *mm = NULL;
- struct list_head *elt, *elt2;
- int id = get_id(file);
- struct pmem_data *data;
-
- DLOG("operation %#x, region offset %ld, region len %ld\n",
- operation, region->offset, region->len);
-
- if (!is_pmem_file(file)) {
-#if PMEM_DEBUG
- pr_err("pmem: remap request for non-pmem file descriptor\n");
-#endif
- return -EINVAL;
- }
-
- /* is_pmem_file fails if !file */
- data = file->private_data;
-
- /* pmem region must be aligned on a page boundry */
- if (unlikely(!PMEM_IS_PAGE_ALIGNED(region->offset) ||
- !PMEM_IS_PAGE_ALIGNED(region->len))) {
-#if PMEM_DEBUG
- pr_err("pmem: request for unaligned pmem"
- "suballocation %lx %lx\n",
- region->offset, region->len);
-#endif
- return -EINVAL;
- }
-
- /* if userspace requests a region of len 0, there's nothing to do */
- if (region->len == 0)
- return 0;
-
- /* lock the mm and data */
- ret = pmem_lock_data_and_mm(file, data, &mm);
- if (ret)
- return 0;
-
- /* only the owner of the master file can remap the client fds
- * that back in it */
- if (!is_master_owner(file)) {
-#if PMEM_DEBUG
- pr_err("pmem: remap requested from non-master process\n");
-#endif
- ret = -EINVAL;
- goto err;
- }
-
- /* check that the requested range is within the src allocation */
- if (unlikely((region->offset > pmem[id].len(id, data)) ||
- (region->len > pmem[id].len(id, data)) ||
- (region->offset + region->len > pmem[id].len(id, data)))) {
-#if PMEM_DEBUG
- pr_err("pmem: suballoc doesn't fit in src_file!\n");
-#endif
- ret = -EINVAL;
- goto err;
- }
-
- if (operation == PMEM_MAP) {
- region_node = kmalloc(sizeof(struct pmem_region_node),
- GFP_KERNEL);
- if (!region_node) {
- ret = -ENOMEM;
-#if PMEM_DEBUG
- pr_alert("pmem: No space to allocate remap metadata!");
-#endif
- goto err;
- }
- region_node->region = *region;
- list_add(®ion_node->list, &data->region_list);
- } else if (operation == PMEM_UNMAP) {
- int found = 0;
- list_for_each_safe(elt, elt2, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node,
- list);
- if (region->len == 0 ||
- (region_node->region.offset == region->offset &&
- region_node->region.len == region->len)) {
- list_del(elt);
- kfree(region_node);
- found = 1;
- }
- }
- if (!found) {
-#if PMEM_DEBUG
- pr_err("pmem: Unmap region does not map any"
- " mapped region!");
-#endif
- ret = -EINVAL;
- goto err;
- }
- }
-
- if (data->vma && PMEM_IS_SUBMAP(data)) {
- if (operation == PMEM_MAP)
- ret = pmem_remap_pfn_range(id, data->vma, data,
- region->offset, region->len);
- else if (operation == PMEM_UNMAP)
- ret = pmem_unmap_pfn_range(id, data->vma, data,
- region->offset, region->len);
- }
-
-err:
- pmem_unlock_data_and_mm(data, mm);
- return ret;
-}
-
-static void pmem_revoke(struct file *file, struct pmem_data *data)
-{
- struct pmem_region_node *region_node;
- struct list_head *elt, *elt2;
- struct mm_struct *mm = NULL;
- int id = get_id(file);
- int ret = 0;
-
- data->master_file = NULL;
- ret = pmem_lock_data_and_mm(file, data, &mm);
- /* if lock_data_and_mm fails either the task that mapped the fd, or
- * the vma that mapped it have already gone away, nothing more
- * needs to be done */
- if (ret)
- return;
- /* unmap everything */
- /* delete the regions and region list nothing is mapped any more */
- if (data->vma)
- list_for_each_safe(elt, elt2, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node,
- list);
- pmem_unmap_pfn_range(id, data->vma, data,
- region_node->region.offset,
- region_node->region.len);
- list_del(elt);
- kfree(region_node);
- }
- /* delete the master file */
- pmem_unlock_data_and_mm(data, mm);
-}
-
-static void pmem_get_size(struct pmem_region *region, struct file *file)
-{
- /* called via ioctl file op, so file guaranteed to be not NULL */
- struct pmem_data *data = file->private_data;
- int id = get_id(file);
-
- down_read(&data->sem);
- if (!has_allocation(file)) {
- region->offset = 0;
- region->len = 0;
- } else {
- region->offset = pmem[id].start_addr(id, data);
- region->len = pmem[id].len(id, data);
- }
- up_read(&data->sem);
- DLOG("offset 0x%lx len 0x%lx\n", region->offset, region->len);
-}
-
-
-static long pmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- /* called from user space as file op, so file guaranteed to be not
- * NULL
- */
- struct pmem_data *data = file->private_data;
- int id = get_id(file);
-#if PMEM_DEBUG_MSGS
- char currtask_name[
- FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-
- DLOG("pid %u(%s) file %p(%ld) cmd %#x, dev %s(id: %d)\n",
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file), cmd, get_name(file), id);
-
- switch (cmd) {
- case PMEM_GET_PHYS:
- {
- struct pmem_region region;
-
- DLOG("get_phys\n");
- down_read(&data->sem);
- if (!has_allocation(file)) {
- region.offset = 0;
- region.len = 0;
- } else {
- region.offset = pmem[id].start_addr(id, data);
- region.len = pmem[id].len(id, data);
- }
- up_read(&data->sem);
-
- if (copy_to_user((void __user *)arg, ®ion,
- sizeof(struct pmem_region)))
- return -EFAULT;
-
- DLOG("pmem: successful request for "
- "physical address of pmem region id %d, "
- "offset 0x%lx, len 0x%lx\n",
- id, region.offset, region.len);
-
- break;
- }
- case PMEM_MAP:
- {
- struct pmem_region region;
- DLOG("map\n");
- if (copy_from_user(®ion, (void __user *)arg,
- sizeof(struct pmem_region)))
- return -EFAULT;
- return pmem_remap(®ion, file, PMEM_MAP);
- }
- break;
- case PMEM_UNMAP:
- {
- struct pmem_region region;
- DLOG("unmap\n");
- if (copy_from_user(®ion, (void __user *)arg,
- sizeof(struct pmem_region)))
- return -EFAULT;
- return pmem_remap(®ion, file, PMEM_UNMAP);
- break;
- }
- case PMEM_GET_SIZE:
- {
- struct pmem_region region;
- DLOG("get_size\n");
- pmem_get_size(®ion, file);
- if (copy_to_user((void __user *)arg, ®ion,
- sizeof(struct pmem_region)))
- return -EFAULT;
- break;
- }
- case PMEM_GET_TOTAL_SIZE:
- {
- struct pmem_region region;
- DLOG("get total size\n");
- region.offset = 0;
- get_id(file);
- region.len = pmem[id].size;
- if (copy_to_user((void __user *)arg, ®ion,
- sizeof(struct pmem_region)))
- return -EFAULT;
- break;
- }
- case PMEM_GET_FREE_SPACE:
- {
- struct pmem_freespace fs;
- DLOG("get freespace on %s(id: %d)\n",
- get_name(file), id);
-
- mutex_lock(&pmem[id].arena_mutex);
- pmem[id].free_space(id, &fs);
- mutex_unlock(&pmem[id].arena_mutex);
-
- DLOG("%s(id: %d) total free %lu, largest %lu\n",
- get_name(file), id, fs.total, fs.largest);
-
- if (copy_to_user((void __user *)arg, &fs,
- sizeof(struct pmem_freespace)))
- return -EFAULT;
- break;
- }
-
- case PMEM_ALLOCATE:
- {
- int ret = 0;
- DLOG("allocate, id %d\n", id);
- down_write(&data->sem);
- if (has_allocation(file)) {
- pr_err("pmem: Existing allocation found on "
- "this file descrpitor\n");
- up_write(&data->sem);
- return -EINVAL;
- }
-
- mutex_lock(&pmem[id].arena_mutex);
- data->index = pmem_allocate_from_id(id,
- arg,
- SZ_4K);
- mutex_unlock(&pmem[id].arena_mutex);
- ret = data->index == -1 ? -ENOMEM :
- data->index;
- up_write(&data->sem);
- return ret;
- }
- case PMEM_ALLOCATE_ALIGNED:
- {
- struct pmem_allocation alloc;
- int ret = 0;
-
- if (copy_from_user(&alloc, (void __user *)arg,
- sizeof(struct pmem_allocation)))
- return -EFAULT;
- DLOG("allocate id align %d %u\n", id, alloc.align);
- down_write(&data->sem);
- if (has_allocation(file)) {
- pr_err("pmem: Existing allocation found on "
- "this file descrpitor\n");
- up_write(&data->sem);
- return -EINVAL;
- }
-
- if (alloc.align & (alloc.align - 1)) {
- pr_err("pmem: Alignment is not a power of 2\n");
- return -EINVAL;
- }
-
- if (alloc.align != SZ_4K &&
- (pmem[id].allocator_type !=
- PMEM_ALLOCATORTYPE_BITMAP)) {
- pr_err("pmem: Non 4k alignment requires bitmap"
- " allocator on %s\n", pmem[id].name);
- return -EINVAL;
- }
-
- if (alloc.align > SZ_1M ||
- alloc.align < SZ_4K) {
- pr_err("pmem: Invalid Alignment (%u) "
- "specified\n", alloc.align);
- return -EINVAL;
- }
-
- mutex_lock(&pmem[id].arena_mutex);
- data->index = pmem_allocate_from_id(id,
- alloc.size,
- alloc.align);
- mutex_unlock(&pmem[id].arena_mutex);
- ret = data->index == -1 ? -ENOMEM :
- data->index;
- up_write(&data->sem);
- return ret;
- }
- case PMEM_CONNECT:
- DLOG("connect\n");
- return pmem_connect(arg, file);
- case PMEM_CLEAN_INV_CACHES:
- case PMEM_CLEAN_CACHES:
- case PMEM_INV_CACHES:
- {
- struct pmem_addr pmem_addr;
-
- if (copy_from_user(&pmem_addr, (void __user *)arg,
- sizeof(struct pmem_addr)))
- return -EFAULT;
-
- return pmem_cache_maint(file, cmd, &pmem_addr);
- }
- default:
- if (pmem[id].ioctl)
- return pmem[id].ioctl(file, cmd, arg);
-
- DLOG("ioctl invalid (%#x)\n", cmd);
- return -EINVAL;
- }
- return 0;
-}
-
-static void ioremap_pmem(int id)
-{
- unsigned long addr;
- const struct mem_type *type;
-
- DLOG("PMEMDEBUG: ioremaping for %s\n", pmem[id].name);
- if (pmem[id].map_on_demand) {
- addr = (unsigned long)pmem[id].area->addr;
- if (pmem[id].cached)
- type = get_mem_type(MT_DEVICE_CACHED);
- else
- type = get_mem_type(MT_DEVICE);
- DLOG("PMEMDEBUG: Remap phys %lx to virt %lx on %s\n",
- pmem[id].base, addr, pmem[id].name);
- if (ioremap_pages(addr, pmem[id].base, pmem[id].size, type)) {
- pr_err("pmem: Failed to map pages\n");
- BUG();
- }
- pmem[id].vbase = pmem[id].area->addr;
- /* Flush the cache after installing page table entries to avoid
- * aliasing when these pages are remapped to user space.
- */
- flush_cache_vmap(addr, addr + pmem[id].size);
- } else {
- if (pmem[id].cached)
- pmem[id].vbase = ioremap_cached(pmem[id].base,
- pmem[id].size);
- #ifdef ioremap_ext_buffered
- else if (pmem[id].buffered)
- pmem[id].vbase = ioremap_ext_buffered(pmem[id].base,
- pmem[id].size);
- #endif
- else
- pmem[id].vbase = ioremap(pmem[id].base, pmem[id].size);
- }
-}
-
-int pmem_setup(struct android_pmem_platform_data *pdata,
- long (*ioctl)(struct file *, unsigned int, unsigned long),
- int (*release)(struct inode *, struct file *))
-{
- int i, index = 0, id;
- struct vm_struct *pmem_vma = NULL;
- struct page *page;
-
- if (id_count >= PMEM_MAX_DEVICES) {
- pr_alert("pmem: %s: unable to register driver(%s) - no more "
- "devices available!\n", __func__, pdata->name);
- goto err_no_mem;
- }
-
- if (!pdata->size) {
- pr_alert("pmem: %s: unable to register pmem driver(%s) - zero "
- "size passed in!\n", __func__, pdata->name);
- goto err_no_mem;
- }
-
- id = id_count++;
-
- pmem[id].id = id;
-
- if (pmem[id].allocate) {
- pr_alert("pmem: %s: unable to register pmem driver - "
- "duplicate registration of %s!\n",
- __func__, pdata->name);
- goto err_no_mem;
- }
-
- pmem[id].allocator_type = pdata->allocator_type;
-
- /* 'quantum' is a "hidden" variable that defaults to 0 in the board
- * files */
- pmem[id].quantum = pdata->quantum ?: PMEM_MIN_ALLOC;
- if (pmem[id].quantum < PMEM_MIN_ALLOC ||
- !is_power_of_2(pmem[id].quantum)) {
- pr_alert("pmem: %s: unable to register pmem driver %s - "
- "invalid quantum value (%#x)!\n",
- __func__, pdata->name, pmem[id].quantum);
- goto err_reset_pmem_info;
- }
-
- if (pdata->size % pmem[id].quantum) {
- /* bad alignment for size! */
- pr_alert("pmem: %s: Unable to register driver %s - "
- "memory region size (%#lx) is not a multiple of "
- "quantum size(%#x)!\n", __func__, pdata->name,
- pdata->size, pmem[id].quantum);
- goto err_reset_pmem_info;
- }
-
- pmem[id].cached = pdata->cached;
- pmem[id].buffered = pdata->buffered;
- pmem[id].size = pdata->size;
- pmem[id].memory_type = pdata->memory_type;
- strlcpy(pmem[id].name, pdata->name, PMEM_NAME_SIZE);
-
- pmem[id].num_entries = pmem[id].size / pmem[id].quantum;
-
- memset(&pmem[id].kobj, 0, sizeof(pmem[0].kobj));
- pmem[id].kobj.kset = pmem_kset;
-
- switch (pmem[id].allocator_type) {
- case PMEM_ALLOCATORTYPE_ALLORNOTHING:
- pmem[id].allocate = pmem_allocator_all_or_nothing;
- pmem[id].free = pmem_free_all_or_nothing;
- pmem[id].free_space = pmem_free_space_all_or_nothing;
- pmem[id].len = pmem_len_all_or_nothing;
- pmem[id].start_addr = pmem_start_addr_all_or_nothing;
- pmem[id].num_entries = 1;
- pmem[id].quantum = pmem[id].size;
- pmem[id].allocator.all_or_nothing.allocated = 0;
-
- if (kobject_init_and_add(&pmem[id].kobj,
- &pmem_allornothing_ktype, NULL,
- "%s", pdata->name))
- goto out_put_kobj;
-
- break;
-
- case PMEM_ALLOCATORTYPE_BUDDYBESTFIT:
- pmem[id].allocator.buddy_bestfit.buddy_bitmap = kmalloc(
- pmem[id].num_entries * sizeof(struct pmem_bits),
- GFP_KERNEL);
- if (!pmem[id].allocator.buddy_bestfit.buddy_bitmap)
- goto err_reset_pmem_info;
-
- memset(pmem[id].allocator.buddy_bestfit.buddy_bitmap, 0,
- sizeof(struct pmem_bits) * pmem[id].num_entries);
-
- for (i = sizeof(pmem[id].num_entries) * 8 - 1; i >= 0; i--)
- if ((pmem[id].num_entries) & 1<<i) {
- PMEM_BUDDY_ORDER(id, index) = i;
- index = PMEM_BUDDY_NEXT_INDEX(id, index);
- }
- pmem[id].allocate = pmem_allocator_buddy_bestfit;
- pmem[id].free = pmem_free_buddy_bestfit;
- pmem[id].free_space = pmem_free_space_buddy_bestfit;
- pmem[id].len = pmem_len_buddy_bestfit;
- pmem[id].start_addr = pmem_start_addr_buddy_bestfit;
- if (kobject_init_and_add(&pmem[id].kobj,
- &pmem_buddy_bestfit_ktype, NULL,
- "%s", pdata->name))
- goto out_put_kobj;
-
- break;
-
- case PMEM_ALLOCATORTYPE_BITMAP: /* 0, default if not explicit */
- pmem[id].allocator.bitmap.bitm_alloc = kmalloc(
- PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS *
- sizeof(*pmem[id].allocator.bitmap.bitm_alloc),
- GFP_KERNEL);
- if (!pmem[id].allocator.bitmap.bitm_alloc) {
- pr_alert("pmem: %s: Unable to register pmem "
- "driver %s - can't allocate "
- "bitm_alloc!\n",
- __func__, pdata->name);
- goto err_reset_pmem_info;
- }
-
- if (kobject_init_and_add(&pmem[id].kobj,
- &pmem_bitmap_ktype, NULL,
- "%s", pdata->name))
- goto out_put_kobj;
-
- for (i = 0; i < PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS; i++) {
- pmem[id].allocator.bitmap.bitm_alloc[i].bit = -1;
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta = 0;
- }
-
- pmem[id].allocator.bitmap.bitmap_allocs =
- PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS;
-
- pmem[id].allocator.bitmap.bitmap =
- kcalloc((pmem[id].num_entries + 31) / 32,
- sizeof(unsigned int), GFP_KERNEL);
- if (!pmem[id].allocator.bitmap.bitmap) {
- pr_alert("pmem: %s: Unable to register pmem "
- "driver - can't allocate bitmap!\n",
- __func__);
- goto err_cant_register_device;
- }
- pmem[id].allocator.bitmap.bitmap_free = pmem[id].num_entries;
-
- pmem[id].allocate = pmem_allocator_bitmap;
- pmem[id].free = pmem_free_bitmap;
- pmem[id].free_space = pmem_free_space_bitmap;
- pmem[id].len = pmem_len_bitmap;
- pmem[id].start_addr = pmem_start_addr_bitmap;
-
- DLOG("bitmap allocator id %d (%s), num_entries %u, raw size "
- "%lu, quanta size %u\n",
- id, pdata->name, pmem[id].allocator.bitmap.bitmap_free,
- pmem[id].size, pmem[id].quantum);
- break;
-
- case PMEM_ALLOCATORTYPE_SYSTEM:
-
- INIT_LIST_HEAD(&pmem[id].allocator.system_mem.alist);
-
- pmem[id].allocator.system_mem.used = 0;
- pmem[id].vbase = NULL;
-
- if (kobject_init_and_add(&pmem[id].kobj,
- &pmem_system_ktype, NULL,
- "%s", pdata->name))
- goto out_put_kobj;
-
- pmem[id].allocate = pmem_allocator_system;
- pmem[id].free = pmem_free_system;
- pmem[id].free_space = pmem_free_space_system;
- pmem[id].len = pmem_len_system;
- pmem[id].start_addr = pmem_start_addr_system;
- pmem[id].num_entries = 0;
- pmem[id].quantum = PAGE_SIZE;
-
- DLOG("system allocator id %d (%s), raw size %lu\n",
- id, pdata->name, pmem[id].size);
- break;
-
- default:
- pr_alert("Invalid allocator type (%d) for pmem driver\n",
- pdata->allocator_type);
- goto err_reset_pmem_info;
- }
-
- pmem[id].ioctl = ioctl;
- pmem[id].release = release;
- mutex_init(&pmem[id].arena_mutex);
- mutex_init(&pmem[id].data_list_mutex);
- INIT_LIST_HEAD(&pmem[id].data_list);
-
- pmem[id].dev.name = pdata->name;
- pmem[id].dev.minor = id;
- pmem[id].dev.fops = &pmem_fops;
- pmem[id].reusable = pdata->reusable;
- pr_info("pmem: Initializing %s as %s\n",
- pdata->name, pdata->cached ? "cached" : "non-cached");
-
- if (misc_register(&pmem[id].dev)) {
- pr_alert("Unable to register pmem driver!\n");
- goto err_cant_register_device;
- }
-
- if (!pmem[id].reusable) {
- pmem[id].base = allocate_contiguous_memory_nomap(pmem[id].size,
- pmem[id].memory_type, PAGE_SIZE);
- if (!pmem[id].base) {
- pr_err("pmem: Cannot allocate from reserved memory for %s\n",
- pdata->name);
- goto err_misc_deregister;
- }
- }
-
- /* reusable pmem requires map on demand */
- pmem[id].map_on_demand = pdata->map_on_demand || pdata->reusable;
- if (pmem[id].map_on_demand) {
- if (pmem[id].reusable) {
- const struct fmem_data *fmem_info = fmem_get_info();
- pmem[id].area = fmem_info->area;
- pmem[id].base = fmem_info->phys;
- } else {
- pmem_vma = get_vm_area(pmem[id].size, VM_IOREMAP);
- if (!pmem_vma) {
- pr_err("pmem: Failed to allocate virtual space for "
- "%s\n", pdata->name);
- goto err_free;
- }
- pr_err("pmem: Reserving virtual address range %lx - %lx for"
- " %s\n", (unsigned long) pmem_vma->addr,
- (unsigned long) pmem_vma->addr + pmem[id].size,
- pdata->name);
- pmem[id].area = pmem_vma;
- }
- } else
- pmem[id].area = NULL;
-
- page = alloc_page(GFP_KERNEL);
- if (!page) {
- pr_err("pmem: Failed to allocate page for %s\n", pdata->name);
- goto cleanup_vm;
- }
- pmem[id].garbage_pfn = page_to_pfn(page);
- atomic_set(&pmem[id].allocation_cnt, 0);
-
- if (pdata->setup_region)
- pmem[id].region_data = pdata->setup_region();
-
- if (pdata->request_region)
- pmem[id].mem_request = pdata->request_region;
-
- if (pdata->release_region)
- pmem[id].mem_release = pdata->release_region;
-
- pr_info("allocating %lu bytes at %lx physical for %s\n",
- pmem[id].size, pmem[id].base, pmem[id].name);
-
- return 0;
-
-cleanup_vm:
- if (!pmem[id].reusable)
- remove_vm_area(pmem_vma);
-err_free:
- if (!pmem[id].reusable)
- free_contiguous_memory_by_paddr(pmem[id].base);
-err_misc_deregister:
- misc_deregister(&pmem[id].dev);
-err_cant_register_device:
-out_put_kobj:
- kobject_put(&pmem[id].kobj);
- if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BUDDYBESTFIT)
- kfree(pmem[id].allocator.buddy_bestfit.buddy_bitmap);
- else if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BITMAP) {
- kfree(pmem[id].allocator.bitmap.bitmap);
- kfree(pmem[id].allocator.bitmap.bitm_alloc);
- }
-err_reset_pmem_info:
- pmem[id].allocate = 0;
- pmem[id].dev.minor = -1;
-err_no_mem:
- return -1;
-}
-
-static int pmem_probe(struct platform_device *pdev)
-{
- struct android_pmem_platform_data *pdata;
-
- if (!pdev || !pdev->dev.platform_data) {
- pr_alert("Unable to probe pmem!\n");
- return -1;
- }
- pdata = pdev->dev.platform_data;
-
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
-
- return pmem_setup(pdata, NULL, NULL);
-}
-
-static int pmem_remove(struct platform_device *pdev)
-{
- int id = pdev->id;
- __free_page(pfn_to_page(pmem[id].garbage_pfn));
- pm_runtime_disable(&pdev->dev);
- if (pmem[id].vbase)
- iounmap(pmem[id].vbase);
- if (pmem[id].map_on_demand && !pmem[id].reusable && pmem[id].area)
- free_vm_area(pmem[id].area);
- if (pmem[id].base)
- free_contiguous_memory_by_paddr(pmem[id].base);
- kobject_put(&pmem[id].kobj);
- if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BUDDYBESTFIT)
- kfree(pmem[id].allocator.buddy_bestfit.buddy_bitmap);
- else if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BITMAP) {
- kfree(pmem[id].allocator.bitmap.bitmap);
- kfree(pmem[id].allocator.bitmap.bitm_alloc);
- }
- misc_deregister(&pmem[id].dev);
- return 0;
-}
-
-static int pmem_runtime_suspend(struct device *dev)
-{
- dev_dbg(dev, "pm_runtime: suspending...\n");
- return 0;
-}
-
-static int pmem_runtime_resume(struct device *dev)
-{
- dev_dbg(dev, "pm_runtime: resuming...\n");
- return 0;
-}
-
-static const struct dev_pm_ops pmem_dev_pm_ops = {
- .runtime_suspend = pmem_runtime_suspend,
- .runtime_resume = pmem_runtime_resume,
-};
-
-static struct platform_driver pmem_driver = {
- .probe = pmem_probe,
- .remove = pmem_remove,
- .driver = { .name = "android_pmem",
- .pm = &pmem_dev_pm_ops,
- }
-};
-
-
-static int __init pmem_init(void)
-{
- /* create /sys/kernel/<PMEM_SYSFS_DIR_NAME> directory */
- pmem_kset = kset_create_and_add(PMEM_SYSFS_DIR_NAME,
- NULL, kernel_kobj);
- if (!pmem_kset) {
- pr_err("pmem(%s):kset_create_and_add fail\n", __func__);
- return -ENOMEM;
- }
-
- return platform_driver_register(&pmem_driver);
-}
-
-static void __exit pmem_exit(void)
-{
- platform_driver_unregister(&pmem_driver);
-}
-
-module_init(pmem_init);
-module_exit(pmem_exit);
-
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index fcadc30..fa28d6a 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1918,6 +1918,10 @@
qclk = &qseecom.ce_drv;
mutex_lock(&clk_access_lock);
+
+ if (qclk->clk_access_cnt == ULONG_MAX)
+ goto err;
+
if (qclk->clk_access_cnt > 0) {
qclk->clk_access_cnt++;
mutex_unlock(&clk_access_lock);
@@ -1965,6 +1969,12 @@
qclk = &qseecom.ce_drv;
mutex_lock(&clk_access_lock);
+
+ if (qclk->clk_access_cnt == 0) {
+ mutex_unlock(&clk_access_lock);
+ return;
+ }
+
if (qclk->clk_access_cnt == 1) {
if (qclk->ce_clk != NULL)
clk_disable_unprepare(qclk->ce_clk);
@@ -2495,8 +2505,8 @@
ireq.pipe = set_key_para->pipe;
ireq.flags = set_key_para->flags;
- /* set PIPE_ENC */
- ireq.pipe_type = QSEOS_PIPE_ENC;
+ /* set both PIPE_ENC and PIPE_ENC_XTS*/
+ ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
if (set_key_para->set_clear_key_flag ==
QSEECOM_SET_CE_KEY_CMD)
@@ -2513,17 +2523,6 @@
return ret;
}
- /* set PIPE_ENC_XTS */
- ireq.pipe_type = QSEOS_PIPE_ENC_XTS;
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
- &ireq, sizeof(struct qseecom_key_select_ireq),
- &resp, sizeof(struct qseecom_command_scm_resp));
- if (ret) {
- pr_err("scm call to set QSEOS_PIPE_ENC_XTS key failed : %d\n",
- ret);
- return ret;
- }
-
switch (resp.result) {
case QSEOS_RESULT_SUCCESS:
break;
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 9f12142..21e65b9 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -228,6 +228,7 @@
md = mmc_blk_get(dev_to_disk(dev));
card = md->queue.card;
+ mmc_rpm_hold(card->host, &card->dev);
mmc_claim_host(card->host);
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
@@ -240,6 +241,7 @@
card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
if (!ret) {
pr_info("%s: Locking boot partition ro until next power on\n",
@@ -602,7 +604,7 @@
md = mmc_blk_get(bdev->bd_disk);
if (!md) {
err = -EINVAL;
- goto cmd_done;
+ goto blk_err;
}
card = md->queue.card;
@@ -707,6 +709,7 @@
cmd_done:
mmc_blk_put(md);
+blk_err:
kfree(idata->buf);
kfree(idata);
return err;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 73a1b41..9fc599b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2864,6 +2864,40 @@
return ret;
}
+static int mmc_clk_update_freq(struct mmc_host *host,
+ unsigned long freq, enum mmc_load state)
+{
+ int err = 0;
+
+ if (host->ops->notify_load) {
+ err = host->ops->notify_load(host, state);
+ if (err)
+ goto out;
+ }
+
+ if (freq != host->clk_scaling.curr_freq) {
+ if (!mmc_is_vaild_state_for_clk_scaling(host)) {
+ err = -EAGAIN;
+ goto error;
+ }
+
+ err = host->bus_ops->change_bus_speed(host, &freq);
+ if (!err)
+ host->clk_scaling.curr_freq = freq;
+ else
+ pr_err("%s: %s: failed (%d) at freq=%lu\n",
+ mmc_hostname(host), __func__, err, freq);
+ }
+error:
+ if (err) {
+ /* restore previous state */
+ if (host->ops->notify_load)
+ host->ops->notify_load(host, host->clk_scaling.state);
+ }
+out:
+ return err;
+}
+
/**
* mmc_clk_scaling() - clock scaling decision algorithm
* @host: pointer to mmc host structure
@@ -2889,6 +2923,7 @@
unsigned int up_threshold = host->clk_scaling.up_threshold;
unsigned int down_threshold = host->clk_scaling.down_threshold;
bool queue_scale_down_work = false;
+ enum mmc_load state;
if (!card || !host->bus_ops || !host->bus_ops->change_bus_speed) {
pr_err("%s: %s: invalid entry\n", mmc_hostname(host), __func__);
@@ -2916,6 +2951,7 @@
busy_time_ms = host->clk_scaling.busy_time_us / USEC_PER_MSEC;
freq = host->clk_scaling.curr_freq;
+ state = host->clk_scaling.state;
/*
* Note that the max. and min. frequency should be based
@@ -2924,28 +2960,24 @@
*/
if ((busy_time_ms * 100 > total_time_ms * up_threshold)) {
freq = mmc_get_max_frequency(host);
+ state = MMC_LOAD_HIGH;
} else if ((busy_time_ms * 100 < total_time_ms * down_threshold)) {
if (!from_wq)
queue_scale_down_work = true;
freq = mmc_get_min_frequency(host);
+ state = MMC_LOAD_LOW;
}
- if (freq != host->clk_scaling.curr_freq) {
+ if (state != host->clk_scaling.state) {
if (!queue_scale_down_work) {
if (!from_wq)
cancel_delayed_work_sync(
&host->clk_scaling.work);
-
- if (!mmc_is_vaild_state_for_clk_scaling(host))
- goto bypass_scaling;
-
- err = host->bus_ops->change_bus_speed(host, &freq);
+ err = mmc_clk_update_freq(host, freq, state);
if (!err)
- host->clk_scaling.curr_freq = freq;
- else
- pr_err("%s: %s: failed (%d) at freq=%lu\n",
- mmc_hostname(host), __func__, err,
- freq);
+ host->clk_scaling.state = state;
+ else if (err == -EAGAIN)
+ goto no_reset_stats;
} else {
/*
* We hold claim host while queueing the scale down
@@ -2954,13 +2986,12 @@
*/
queue_delayed_work(system_nrt_wq,
&host->clk_scaling.work, 1);
- host->clk_scaling.in_progress = false;
- goto out;
+ goto no_reset_stats;
}
}
mmc_reset_clk_scale_stats(host);
-bypass_scaling:
+no_reset_stats:
host->clk_scaling.in_progress = false;
out:
return;
@@ -3007,6 +3038,9 @@
INIT_DELAYED_WORK(&host->clk_scaling.work, mmc_clk_scale_work);
host->clk_scaling.curr_freq = mmc_get_max_frequency(host);
+ if (host->ops->notify_load)
+ host->ops->notify_load(host, MMC_LOAD_HIGH);
+ host->clk_scaling.state = MMC_LOAD_HIGH;
mmc_reset_clk_scale_stats(host);
host->clk_scaling.enable = true;
host->clk_scaling.initialized = true;
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 8b7e0bd..903decf 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -176,9 +176,11 @@
if (val > host->f_max)
return -EINVAL;
+ mmc_rpm_hold(host, &host->class_dev);
mmc_claim_host(host);
mmc_set_clock(host, (unsigned int) val);
mmc_release_host(host);
+ mmc_rpm_release(host, &host->class_dev);
return 0;
}
@@ -208,6 +210,7 @@
if (!host || (val < host->f_min))
goto out;
+ mmc_rpm_hold(host, &host->class_dev);
mmc_claim_host(host);
if (host->bus_ops && host->bus_ops->change_bus_speed) {
old_freq = host->f_max;
@@ -219,6 +222,7 @@
host->f_max = old_freq;
}
mmc_release_host(host);
+ mmc_rpm_release(host, &host->class_dev);
out:
return err;
}
@@ -286,6 +290,7 @@
u32 status;
int ret;
+ mmc_rpm_hold(card->host, &card->dev);
mmc_claim_host(card->host);
ret = mmc_send_status(data, &status);
@@ -293,6 +298,7 @@
*val = status;
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
return ret;
}
@@ -319,9 +325,11 @@
goto out_free;
}
+ mmc_rpm_hold(card->host, &card->dev);
mmc_claim_host(card->host);
err = mmc_send_ext_csd(card, ext_csd);
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
if (err)
goto out_free;
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index c0a4cef..6c03bfc 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -466,12 +466,8 @@
goto err;
if (value && !mmc_can_scale_clk(host)) {
- if (mmc_card_ddr_mode(host->card) ||
- mmc_card_hs200(host->card) ||
- mmc_card_uhs(host->card)) {
- host->caps2 |= MMC_CAP2_CLK_SCALE;
- mmc_init_clk_scaling(host);
- }
+ host->caps2 |= MMC_CAP2_CLK_SCALE;
+ mmc_init_clk_scaling(host);
if (!mmc_can_scale_clk(host)) {
host->caps2 &= ~MMC_CAP2_CLK_SCALE;
@@ -487,6 +483,10 @@
if (host->bus_ops->change_bus_speed(host, &freq))
goto err;
}
+ if (host->ops->notify_load &&
+ host->ops->notify_load(host, MMC_LOAD_HIGH))
+ goto err;
+ host->clk_scaling.state = MMC_LOAD_HIGH;
host->clk_scaling.initialized = false;
}
retval = count;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 8a866cf..89f8c91 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1734,9 +1734,7 @@
if (err)
goto remove_card;
- /* Initialize clock scaling only for high frequency modes */
- if (mmc_card_hs200(host->card) || mmc_card_ddr_mode(host->card))
- mmc_init_clk_scaling(host);
+ mmc_init_clk_scaling(host);
return 0;
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 60e0640..ddf9a87 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1415,9 +1415,7 @@
if (err)
goto remove_card;
- /* Initialize clock scaling only for high frequency modes */
- if (mmc_card_uhs(host->card))
- mmc_init_clk_scaling(host);
+ mmc_init_clk_scaling(host);
return 0;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 3f3687b..caf5fe4 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -958,7 +958,7 @@
struct msmsdcc_nc_dmadata *nc;
dmov_box *box;
uint32_t rows;
- unsigned int n;
+ int n;
int i, err = 0, box_cmd_cnt = 0;
struct scatterlist *sg = data->sg;
unsigned int len, offset;
@@ -4393,6 +4393,39 @@
return data_cnt;
}
+static int msmsdcc_notify_load(struct mmc_host *mmc, enum mmc_load state)
+{
+ int err = 0;
+ unsigned long rate;
+ struct msmsdcc_host *host = mmc_priv(mmc);
+
+ if (IS_ERR_OR_NULL(host->bus_clk))
+ goto out;
+
+ switch (state) {
+ case MMC_LOAD_HIGH:
+ rate = MSMSDCC_BUS_VOTE_MAX_RATE;
+ break;
+ case MMC_LOAD_LOW:
+ rate = MSMSDCC_BUS_VOTE_MIN_RATE;
+ break;
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (rate != host->bus_clk_rate) {
+ err = clk_set_rate(host->bus_clk, rate);
+ if (err)
+ pr_err("%s: %s: bus clk set rate %lu Hz err %d\n",
+ mmc_hostname(mmc), __func__, rate, err);
+ else
+ host->bus_clk_rate = rate;
+ }
+out:
+ return err;
+}
+
static const struct mmc_host_ops msmsdcc_ops = {
.enable = msmsdcc_enable,
.disable = msmsdcc_disable,
@@ -4407,6 +4440,7 @@
.hw_reset = msmsdcc_hw_reset,
.stop_request = msmsdcc_stop_request,
.get_xfer_remain = msmsdcc_get_xfer_remain,
+ .notify_load = msmsdcc_notify_load,
};
static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
@@ -5975,12 +6009,13 @@
host->bus_clk = clk_get(&pdev->dev, "bus_clk");
if (!IS_ERR_OR_NULL(host->bus_clk)) {
/* Vote for max. clk rate for max. performance */
- ret = clk_set_rate(host->bus_clk, INT_MAX);
+ ret = clk_set_rate(host->bus_clk, MSMSDCC_BUS_VOTE_MAX_RATE);
if (ret)
goto bus_clk_put;
ret = clk_prepare_enable(host->bus_clk);
if (ret)
goto bus_clk_put;
+ host->bus_clk_rate = MSMSDCC_BUS_VOTE_MAX_RATE;
}
/*
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 4ed2d96..bcfde57 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -260,6 +260,12 @@
#define MMC_MAX_DMA_CMDS (MAX_NR_SG_DMA_PIO * (MMC_MAX_REQ_SIZE / \
MMC_MAX_DMA_BOX_LENGTH))
+/*
+ * Peripheral bus clock scaling vote rates
+ */
+#define MSMSDCC_BUS_VOTE_MAX_RATE 64000000 /* Hz */
+#define MSMSDCC_BUS_VOTE_MIN_RATE 32000000 /* Hz */
+
struct clk;
struct msmsdcc_nc_dmadata {
@@ -360,6 +366,7 @@
struct clk *clk; /* main MMC bus clock */
struct clk *pclk; /* SDCC peripheral bus clock */
struct clk *bus_clk; /* SDCC bus voter clock */
+ unsigned long bus_clk_rate; /* peripheral bus clk rate */
atomic_t clks_on; /* set if clocks are enabled */
unsigned int eject; /* eject state */
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index cb036dd..89730b0 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -38,6 +38,7 @@
#include <linux/dma-mapping.h>
#include <mach/gpio.h>
#include <mach/msm_bus.h>
+#include <linux/iopoll.h>
#include "sdhci-pltfm.h"
@@ -81,6 +82,31 @@
#define CORE_CLK_PWRSAVE (1 << 1)
#define CORE_IO_PAD_PWR_SWITCH (1 << 16)
+#define CORE_MCI_DATA_CTRL 0x2C
+#define CORE_MCI_DPSM_ENABLE (1 << 0)
+
+#define CORE_TESTBUS_CONFIG 0x0CC
+#define CORE_TESTBUS_ENA (1 << 3)
+#define CORE_TESTBUS_SEL2 (1 << 4)
+
+/*
+ * Waiting until end of potential AHB access for data:
+ * 16 AHB cycles (160ns for 100MHz and 320ns for 50MHz) +
+ * delay on AHB (2us) = maximum 2.32us
+ * Taking x10 times margin
+ */
+#define CORE_AHB_DATA_DELAY_US 23
+/* Waiting until end of potential AHB access for descriptor:
+ * Single (1 AHB cycle) + delay on AHB bus = max 2us
+ * INCR4 (4 AHB cycles) + delay on AHB bus = max 2us
+ * Single (1 AHB cycle) + delay on AHB bus = max 2us
+ * Total 8 us delay with margin
+ */
+#define CORE_AHB_DESC_DELAY_US 8
+
+#define CORE_SDCC_DEBUG_REG 0x124
+#define CORE_DEBUG_REG_AHB_HTRANS (3 << 12)
+
/* 8KB descriptors */
#define SDHCI_MSM_MAX_SEGMENTS (1 << 13)
#define SDHCI_MSM_MMC_CLK_GATE_DELAY 200 /* msecs */
@@ -2044,6 +2070,51 @@
return 0;
}
+/*
+ * sdhci_msm_disable_data_xfer - disable undergoing AHB bus data transfer
+ *
+ * Write 0 to bit 0 in MCI_DATA_CTL (offset 0x2C) - clearing TxActive bit by
+ * access to legacy registers. It will stop current burst and prevent start of
+ * the next on.
+ *
+ * Polling CORE_AHB_DATA_DELAY_US timeout, by reading bit 13:12 until they are 0
+ * in CORE_SDCC_DEBUG_REG (offset 0x124) will validate that AHB burst was
+ * completed and a new one didn't start.
+ *
+ * Waiting for 4us while AHB finishes descriptors fetch.
+ */
+static void sdhci_msm_disable_data_xfer(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ u32 value;
+ int ret;
+
+ value = readl_relaxed(msm_host->core_mem + CORE_MCI_DATA_CTRL);
+ value &= ~(u32)CORE_MCI_DPSM_ENABLE;
+ writel_relaxed(value, msm_host->core_mem + CORE_MCI_DATA_CTRL);
+
+ /* Enable the test bus for device slot */
+ writel_relaxed(CORE_TESTBUS_ENA | CORE_TESTBUS_SEL2,
+ msm_host->core_mem + CORE_TESTBUS_CONFIG);
+
+ ret = readl_poll_timeout_noirq(msm_host->core_mem
+ + CORE_SDCC_DEBUG_REG, value,
+ !(value & CORE_DEBUG_REG_AHB_HTRANS),
+ CORE_AHB_DATA_DELAY_US, 1);
+ if (ret) {
+ pr_err("%s: %s: can't stop ongoing AHB bus access by ADMA\n",
+ mmc_hostname(host->mmc), __func__);
+ BUG();
+ }
+ /* Disable the test bus for device slot */
+ value = readl_relaxed(msm_host->core_mem + CORE_TESTBUS_CONFIG);
+ value &= ~CORE_TESTBUS_ENA;
+ writel_relaxed(value, msm_host->core_mem + CORE_TESTBUS_CONFIG);
+
+ udelay(CORE_AHB_DESC_DELAY_US);
+}
+
static struct sdhci_ops sdhci_msm_ops = {
.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
.check_power_status = sdhci_msm_check_power_status,
@@ -2054,6 +2125,7 @@
.platform_bus_voting = sdhci_msm_bus_voting,
.get_min_clock = sdhci_msm_get_min_clock,
.get_max_clock = sdhci_msm_get_max_clock,
+ .disable_data_xfer = sdhci_msm_disable_data_xfer,
};
static int __devinit sdhci_msm_probe(struct platform_device *pdev)
@@ -2065,6 +2137,7 @@
int ret = 0, dead = 0;
u32 vdd_max_current;
u16 host_version;
+ u32 pwr;
pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -2173,7 +2246,21 @@
}
/* Set SW_RST bit in POWER register (Offset 0x0) */
- writel_relaxed(CORE_SW_RST, msm_host->core_mem + CORE_POWER);
+ writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) |
+ CORE_SW_RST, msm_host->core_mem + CORE_POWER);
+ /*
+ * SW reset can take upto 10HCLK + 15MCLK cycles.
+ * Calculating based on min clk rates (hclk = 27MHz,
+ * mclk = 400KHz) it comes to ~40us. Let's poll for
+ * max. 1ms for reset completion.
+ */
+ ret = readl_poll_timeout(msm_host->core_mem + CORE_POWER,
+ pwr, !(pwr & CORE_SW_RST), 100, 10);
+
+ if (ret) {
+ dev_err(&pdev->dev, "reset failed (%d)\n", ret);
+ goto vreg_deinit;
+ }
/* Set HC_MODE_EN bit in HC_MODE register */
writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 0549b4a..3efea77 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2126,7 +2126,49 @@
static int sdhci_stop_request(struct mmc_host *mmc)
{
- return -ENOSYS;
+ struct sdhci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+ struct mmc_data *data;
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (!host->mrq || !host->data)
+ goto out;
+
+ data = host->data;
+
+ if (host->ops->disable_data_xfer)
+ host->ops->disable_data_xfer(host);
+
+ sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+
+ if (host->flags & SDHCI_REQ_USE_DMA) {
+ if (host->flags & SDHCI_USE_ADMA) {
+ sdhci_adma_table_post(host, data);
+ } else {
+ if (!data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len,
+ (data->flags & MMC_DATA_READ) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ }
+ }
+ del_timer(&host->timer);
+ host->mrq = NULL;
+ host->cmd = NULL;
+ host->data = NULL;
+out:
+ spin_unlock_irqrestore(&host->lock, flags);
+ return 0;
+}
+
+static unsigned int sdhci_get_xfer_remain(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ u32 present_state = 0;
+
+ present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+
+ return present_state & SDHCI_DOING_WRITE;
}
static const struct mmc_host_ops sdhci_ops = {
@@ -2143,6 +2185,7 @@
.enable = sdhci_enable,
.disable = sdhci_disable,
.stop_request = sdhci_stop_request,
+ .get_xfer_remain = sdhci_get_xfer_remain,
};
/*****************************************************************************\
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index c6bef8a..a3d8442 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -286,6 +286,7 @@
void (*toggle_cdr)(struct sdhci_host *host, bool enable);
unsigned int (*get_max_segments)(void);
void (*platform_bus_voting)(struct sdhci_host *host, u32 enable);
+ void (*disable_data_xfer)(struct sdhci_host *host);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
index 570c257..0b04bbf 100644
--- a/drivers/mtd/devices/msm_qpic_nand.c
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -691,9 +691,9 @@
/* Lookup the 'APPS' partition's first page address */
for (i = 0; i < FLASH_PTABLE_MAX_PARTS_V4; i++) {
- if (!strncmp("apps", ptable.part_entry[i].name,
- strlen(ptable.part_entry[i].name))) {
- page_address = ptable.part_entry[i].offset << 6;
+ if (!strncmp("apps", mtd_part[i].name,
+ strlen(mtd_part[i].name))) {
+ page_address = mtd_part[i].offset << 6;
break;
}
}
@@ -1458,7 +1458,7 @@
int ret;
struct mtd_oob_ops ops;
- ops.mode = MTD_OPS_PLACE_OOB;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.len = len;
ops.retlen = 0;
ops.ooblen = 0;
@@ -1643,7 +1643,7 @@
int ret;
struct mtd_oob_ops ops;
- ops.mode = MTD_OPS_PLACE_OOB;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.len = len;
ops.retlen = 0;
ops.ooblen = 0;
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index f6b8051..726e9a6 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -49,18 +49,11 @@
/**
* struct ecm_ipa_dev - main driver context parameters
* @net: network interface struct implemented by this driver
- * @folder: debugfs folder for various debuging switches
+ * @directory: debugfs directory for various debuging switches
* @tx_enable: flag that enable/disable Tx path to continue to IPA
* @rx_enable: flag that enable/disable Rx path to continue to IPA
* @rm_enable: flag that enable/disable Resource manager request prior to Tx
* @dma_enable: flag that allow on-the-fly DMA mode for IPA
- * @tx_file: saved debugfs entry to allow cleanup
- * @rx_file: saved debugfs entry to allow cleanup
- * @rm_file: saved debugfs entry to allow cleanup
- * @outstanding_file: saved debugfs entry to allow cleanup
- * @outstanding_high_file saved debugfs entry to allow cleanup
- * @outstanding_low_file saved debugfs entry to allow cleanup
- * @dma_file: saved debugfs entry to allow cleanup
* @eth_ipv4_hdr_hdl: saved handle for ipv4 header-insertion table
* @eth_ipv6_hdr_hdl: saved handle for ipv6 header-insertion table
* @usb_to_ipa_hdl: save handle for IPA pipe operations
@@ -72,18 +65,11 @@
*/
struct ecm_ipa_dev {
struct net_device *net;
- bool tx_enable;
- bool rx_enable;
- bool rm_enable;
+ u32 tx_enable;
+ u32 rx_enable;
+ u32 rm_enable;
bool dma_enable;
- struct dentry *folder;
- struct dentry *tx_file;
- struct dentry *rx_file;
- struct dentry *rm_file;
- struct dentry *outstanding_high_file;
- struct dentry *outstanding_low_file;
- struct dentry *dma_file;
- struct dentry *outstanding_file;
+ struct dentry *directory;
uint32_t eth_ipv4_hdr_hdl;
uint32_t eth_ipv6_hdr_hdl;
u32 usb_to_ipa_hdl;
@@ -94,25 +80,22 @@
};
/**
- * struct ecm_ipa_ctx - saved pointer for the std ecm network device
+ * struct ecm_ipa_ctx - saved pointer for the ecm_ipa network device
* which allow ecm_ipa to be a singleton
*/
static struct ecm_ipa_dev *ecm_ipa_ctx;
-static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl);
-static int ecm_ipa_set_device_ethernet_addr(
- u8 *dev_ethaddr, u8 device_ethaddr[]);
-static void ecm_ipa_packet_receive_notify(void *priv,
- enum ipa_dp_evt_type evt,
- unsigned long data);
-static void ecm_ipa_tx_complete_notify(void *priv,
- enum ipa_dp_evt_type evt,
- unsigned long data);
-static int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl);
static int ecm_ipa_open(struct net_device *net);
+static void ecm_ipa_packet_receive_notify(void *priv,
+ enum ipa_dp_evt_type evt, unsigned long data);
+static void ecm_ipa_tx_complete_notify(void *priv,
+ enum ipa_dp_evt_type evt, unsigned long data);
static int ecm_ipa_stop(struct net_device *net);
-static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
- struct net_device *net);
+static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
+ const void *dst_mac, const void *src_mac);
+static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *dev);
+static int ecm_ipa_register_properties(void);
+static void ecm_ipa_deregister_properties(void);
static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
unsigned long data);
static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *dev);
@@ -120,28 +103,28 @@
static bool rx_filter(struct sk_buff *skb);
static bool tx_filter(struct sk_buff *skb);
static bool rm_enabled(struct ecm_ipa_dev *dev);
-
-static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
- const void *dst_mac, const void *src_mac);
-static int ecm_ipa_register_properties(void);
-static void ecm_ipa_deregister_properties(void);
-static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev);
-static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev);
-static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file);
-static int ecm_ipa_debugfs_rx_open(struct inode *inode, struct file *file);
-static int ecm_ipa_debugfs_rm_open(struct inode *inode, struct file *file);
-static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file);
+static int resource_request(struct ecm_ipa_dev *dev);
+static void resource_release(struct ecm_ipa_dev *dev);
+static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
+ struct net_device *net);
static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file);
+static ssize_t ecm_ipa_debugfs_enable_write_dma(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos);
+static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file);
+static ssize_t ecm_ipa_debugfs_enable_write(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos);
static ssize_t ecm_ipa_debugfs_enable_read(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos);
static ssize_t ecm_ipa_debugfs_atomic_read(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos);
-static ssize_t ecm_ipa_debugfs_enable_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos);
-static ssize_t ecm_ipa_debugfs_enable_write_dma(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos);
-static void eth_get_drvinfo(struct net_device *net,
- struct ethtool_drvinfo *drv_info);
+static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev);
+static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev);
+static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl);
+static int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl);
+static int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr,
+ u8 device_ethaddr[]);
+static int ecm_ipa_init_module(void);
+static void ecm_ipa_cleanup_module(void);
static const struct net_device_ops ecm_ipa_netdev_ops = {
.ndo_open = ecm_ipa_open,
@@ -149,38 +132,353 @@
.ndo_start_xmit = ecm_ipa_start_xmit,
.ndo_set_mac_address = eth_mac_addr,
};
-static const struct ethtool_ops ops = {
- .get_drvinfo = eth_get_drvinfo,
- .get_link = ethtool_op_get_link,
-};
-const struct file_operations ecm_ipa_debugfs_tx_ops = {
- .open = ecm_ipa_debugfs_tx_open,
- .read = ecm_ipa_debugfs_enable_read,
- .write = ecm_ipa_debugfs_enable_write,
-};
-const struct file_operations ecm_ipa_debugfs_rx_ops = {
- .open = ecm_ipa_debugfs_rx_open,
- .read = ecm_ipa_debugfs_enable_read,
- .write = ecm_ipa_debugfs_enable_write,
-};
-const struct file_operations ecm_ipa_debugfs_rm_ops = {
- .open = ecm_ipa_debugfs_rm_open,
- .read = ecm_ipa_debugfs_enable_read,
- .write = ecm_ipa_debugfs_enable_write,
-};
+
const struct file_operations ecm_ipa_debugfs_dma_ops = {
- .open = ecm_ipa_debugfs_dma_open,
+ .open = ecm_ipa_debugfs_dma_open,
.read = ecm_ipa_debugfs_enable_read,
.write = ecm_ipa_debugfs_enable_write_dma,
};
const struct file_operations ecm_ipa_debugfs_atomic_ops = {
- .open = ecm_ipa_debugfs_atomic_open,
- .read = ecm_ipa_debugfs_atomic_read,
+ .open = ecm_ipa_debugfs_atomic_open,
+ .read = ecm_ipa_debugfs_atomic_read,
};
/**
- * ecm_ipa_init() - initializes internal data structures
+ * ecm_ipa_init() - create network device and initializes internal
+ * data structures
+ * @params: in/out parameters required for ecm_ipa initialization
+ *
+ * Shall be called prior to pipe connection.
+ * The out parameters (the callbacks) shall be supplied to ipa_connect.
+ * Detailed description:
+ * - allocate the network device
+ * - set default values for driver internals
+ * - create debugfs folder and files
+ * - create IPA resource manager client
+ * - add header insertion rules for IPA driver (based on host/device
+ * Ethernet addresses given in input params)
+ * - register tx/rx properties to IPA driver (will be later used
+ * by IPA configuration manager to configure reset of the IPA rules)
+ * - set the carrier state to "off" (until ecm_ipa_connect is called)
+ * - register the network device
+ * - set the out parameters
+ *
+ * Returns negative errno, or zero on success
+ */
+int ecm_ipa_init(struct ecm_ipa_params *params)
+{
+ int result = 0;
+ struct net_device *net;
+ struct ecm_ipa_dev *dev;
+
+ ECM_IPA_LOG_ENTRY();
+ pr_debug("%s initializing\n", DRIVER_NAME);
+ NULL_CHECK(params);
+
+ pr_debug("host_ethaddr=%pM, device_ethaddr=%pM\n",
+ params->host_ethaddr,
+ params->device_ethaddr);
+
+ net = alloc_etherdev(sizeof(struct ecm_ipa_dev));
+ if (!net) {
+ result = -ENOMEM;
+ ECM_IPA_ERROR("fail to allocate etherdev\n");
+ goto fail_alloc_etherdev;
+ }
+ pr_debug("network device was successfully allocated\n");
+
+ dev = netdev_priv(net);
+ memset(dev, 0, sizeof(*dev));
+ dev->net = net;
+ ecm_ipa_ctx = dev;
+ dev->tx_enable = true;
+ dev->rx_enable = true;
+ dev->rm_enable = true;
+ dev->outstanding_high = DEFAULT_OUTSTANDING_HIGH;
+ dev->outstanding_low = DEFAULT_OUTSTANDING_LOW;
+ atomic_set(&dev->outstanding_pkts, 0);
+ snprintf(net->name, sizeof(net->name), "%s%%d", "ecm");
+ net->netdev_ops = &ecm_ipa_netdev_ops;
+ pr_debug("internal data structures were intialized and defaults set\n");
+
+ result = ecm_ipa_debugfs_init(dev);
+ if (result)
+ goto fail_debugfs;
+ pr_debug("debugfs entries were created\n");
+
+ result = ecm_ipa_create_rm_resource(dev);
+ if (result) {
+ ECM_IPA_ERROR("fail on RM create\n");
+ goto fail_create_rm;
+ }
+ pr_debug("RM resource was created\n");
+
+ result = ecm_ipa_set_device_ethernet_addr(net->dev_addr,
+ params->device_ethaddr);
+ if (result) {
+ ECM_IPA_ERROR("set device MAC failed\n");
+ goto fail_set_device_ethernet;
+ }
+ pr_debug("Device Ethernet address set %pM\n", net->dev_addr);
+
+ result = ecm_ipa_rules_cfg(dev, params->host_ethaddr,
+ params->device_ethaddr);
+ if (result) {
+ ECM_IPA_ERROR("fail on ipa rules set\n");
+ goto fail_rules_cfg;
+ }
+ pr_debug("Ethernet header insertion set\n");
+
+ result = ecm_ipa_register_properties();
+ if (result) {
+ ECM_IPA_ERROR("fail on properties set\n");
+ goto fail_register_tx;
+ }
+ pr_debug("ecm_ipa 2 Tx and 2 Rx properties were registered\n");
+
+ netif_carrier_off(net);
+ pr_debug("set carrier off\n");
+
+ result = register_netdev(net);
+ if (result) {
+ ECM_IPA_ERROR("register_netdev failed: %d\n", result);
+ goto fail_register_netdev;
+ }
+ pr_debug("register_netdev succeeded\n");
+
+ params->ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
+ params->ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
+ params->private = (void *)dev;
+ ECM_IPA_LOG_EXIT();
+
+ return 0;
+
+fail_register_netdev:
+ ecm_ipa_deregister_properties();
+fail_register_tx:
+ ecm_ipa_rules_destroy(dev);
+fail_set_device_ethernet:
+fail_rules_cfg:
+ ecm_ipa_destory_rm_resource(dev);
+fail_create_rm:
+ ecm_ipa_debugfs_destroy(dev);
+fail_debugfs:
+ free_netdev(net);
+fail_alloc_etherdev:
+ return result;
+}
+EXPORT_SYMBOL(ecm_ipa_init);
+
+
+int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
+ void *priv)
+{
+ struct ecm_ipa_dev *dev = priv;
+
+ ECM_IPA_LOG_ENTRY();
+ NULL_CHECK(priv);
+ pr_debug("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d, priv=0x%p\n",
+ usb_to_ipa_hdl, ipa_to_usb_hdl, priv);
+
+ if (!usb_to_ipa_hdl || usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
+ ECM_IPA_ERROR("usb_to_ipa_hdl(%d) is not a valid ipa handle\n",
+ usb_to_ipa_hdl);
+ return -EINVAL;
+ }
+ if (!ipa_to_usb_hdl || ipa_to_usb_hdl >= IPA_CLIENT_MAX) {
+ ECM_IPA_ERROR("ipa_to_usb_hdl(%d) is not a valid ipa handle\n",
+ ipa_to_usb_hdl);
+ return -EINVAL;
+ }
+ dev->ipa_to_usb_hdl = ipa_to_usb_hdl;
+ dev->usb_to_ipa_hdl = usb_to_ipa_hdl;
+ ecm_ipa_ep_registers_cfg(usb_to_ipa_hdl, ipa_to_usb_hdl);
+ pr_debug("end-point configured\n");
+
+ netif_carrier_on(dev->net);
+ if (!netif_carrier_ok(dev->net)) {
+ ECM_IPA_ERROR("netif_carrier_ok error\n");
+ return -EBUSY;
+ }
+ pr_debug("carrier_on notified, ecm_ipa is operational\n");
+
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+EXPORT_SYMBOL(ecm_ipa_connect);
+
+static int ecm_ipa_open(struct net_device *net)
+{
+ struct ecm_ipa_dev *dev;
+ ECM_IPA_LOG_ENTRY();
+
+ dev = netdev_priv(net);
+
+ if (!netif_carrier_ok(net))
+ pr_debug("carrier is not ON yet - continuing\n");
+
+ netif_start_queue(net);
+ pr_debug("queue started\n");
+
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+
+/**
+ * ecm_ipa_start_xmit() - send data from APPs to USB core via IPA core
+ * @skb: packet received from Linux stack
+ * @net: the network device being used to send this packet
+ *
+ * Several conditions needed in order to send the packet to IPA:
+ * - we are in a valid state were the queue is not stopped
+ * - Filter Tx switch is turned off
+ * - The resources required for actual Tx are all up
+ *
+ */
+static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
+ struct net_device *net)
+{
+ int ret;
+ netdev_tx_t status = NETDEV_TX_BUSY;
+ struct ecm_ipa_dev *dev = netdev_priv(net);
+
+ if (unlikely(netif_queue_stopped(net))) {
+ ECM_IPA_ERROR("interface queue is stopped\n");
+ goto out;
+ }
+
+ if (unlikely(tx_filter(skb))) {
+ dev_kfree_skb_any(skb);
+ pr_debug("packet got filtered out on Tx path\n");
+ status = NETDEV_TX_OK;
+ goto out;
+ }
+ ret = resource_request(dev);
+ if (ret) {
+ pr_debug("Waiting to resource\n");
+ netif_stop_queue(net);
+ goto resource_busy;
+ }
+
+ if (atomic_read(&dev->outstanding_pkts) >= dev->outstanding_high) {
+ pr_debug("Outstanding high boundary reached (%d)- stopping queue\n",
+ dev->outstanding_high);
+ netif_stop_queue(net);
+ status = -NETDEV_TX_BUSY;
+ goto out;
+ }
+
+ ret = ipa_tx_dp(IPA_TO_USB_CLIENT, skb, NULL);
+ if (ret) {
+ ECM_IPA_ERROR("ipa transmit failed (%d)\n", ret);
+ goto fail_tx_packet;
+ }
+
+ atomic_inc(&dev->outstanding_pkts);
+ net->stats.tx_packets++;
+ net->stats.tx_bytes += skb->len;
+ status = NETDEV_TX_OK;
+ goto out;
+
+fail_tx_packet:
+out:
+ resource_release(dev);
+resource_busy:
+ return status;
+}
+
+/**
+ * ecm_ipa_packet_receive_notify() - Rx notify
+ *
+ * @priv: ecm driver context
+ * @evt: event type
+ * @data: data provided with event
+ *
+ * IPA will pass a packet with skb->data pointing to Ethernet packet frame
+ */
+static void ecm_ipa_packet_receive_notify(void *priv,
+ enum ipa_dp_evt_type evt,
+ unsigned long data)
+{
+ struct sk_buff *skb = (struct sk_buff *)data;
+ struct ecm_ipa_dev *dev = priv;
+ int result;
+
+ if (evt != IPA_RECEIVE) {
+ ECM_IPA_ERROR("A none IPA_RECEIVE event in ecm_ipa_receive\n");
+ return;
+ }
+
+ skb->dev = dev->net;
+ skb->protocol = eth_type_trans(skb, dev->net);
+ if (rx_filter(skb)) {
+ pr_debug("packet got filtered out on Rx path\n");
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
+ result = netif_rx(skb);
+ if (result)
+ ECM_IPA_ERROR("fail on netif_rx\n");
+ dev->net->stats.rx_packets++;
+ dev->net->stats.rx_bytes += skb->len;
+
+ return;
+}
+
+static int ecm_ipa_stop(struct net_device *net)
+{
+ ECM_IPA_LOG_ENTRY();
+ pr_debug("stopping net device\n");
+ netif_stop_queue(net);
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+
+int ecm_ipa_disconnect(void *priv)
+{
+ struct ecm_ipa_dev *dev = priv;
+ ECM_IPA_LOG_ENTRY();
+ NULL_CHECK(dev);
+ pr_debug("priv=0x%p\n", priv);
+ netif_carrier_off(dev->net);
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+EXPORT_SYMBOL(ecm_ipa_disconnect);
+
+
+/**
+ * ecm_ipa_cleanup() - destroys all
+ * ecm information
+ * @priv: main driver context parameters
+ *
+ */
+void ecm_ipa_cleanup(void *priv)
+{
+ struct ecm_ipa_dev *dev = priv;
+ ECM_IPA_LOG_ENTRY();
+ pr_debug("priv=0x%p\n", priv);
+ if (!dev) {
+ ECM_IPA_ERROR("dev NULL pointer\n");
+ return;
+ }
+
+ ecm_ipa_destory_rm_resource(dev);
+ ecm_ipa_debugfs_destroy(dev);
+
+ unregister_netdev(dev->net);
+ free_netdev(dev->net);
+
+ pr_debug("cleanup done\n");
+ ecm_ipa_ctx = NULL;
+ ECM_IPA_LOG_EXIT();
+ return ;
+}
+EXPORT_SYMBOL(ecm_ipa_cleanup);
+
+/**
* @ecm_ipa_rx_dp_notify: supplied callback to be called by the IPA
* driver upon data packets received from USB pipe into IPA core.
* @ecm_ipa_rt_dp_notify: supplied callback to be called by the IPA
@@ -197,52 +495,7 @@
*
* Returns negative errno, or zero on success
*/
-int ecm_ipa_init(ecm_ipa_callback *ecm_ipa_rx_dp_notify,
- ecm_ipa_callback *ecm_ipa_tx_dp_notify,
- void **priv)
-{
- int ret = 0;
- struct net_device *net;
- struct ecm_ipa_dev *dev;
- ECM_IPA_LOG_ENTRY();
- pr_debug("%s initializing\n", DRIVER_NAME);
- NULL_CHECK(ecm_ipa_rx_dp_notify);
- NULL_CHECK(ecm_ipa_tx_dp_notify);
- NULL_CHECK(priv);
- net = alloc_etherdev(sizeof(struct ecm_ipa_dev));
- if (!net) {
- ret = -ENOMEM;
- ECM_IPA_ERROR("fail to allocate etherdev\n");
- goto fail_alloc_etherdev;
- }
- pr_debug("etherdev was successfully allocated\n");
- dev = netdev_priv(net);
- memset(dev, 0, sizeof(*dev));
- dev->tx_enable = true;
- dev->rx_enable = true;
- atomic_set(&dev->outstanding_pkts, 0);
- dev->outstanding_high = DEFAULT_OUTSTANDING_HIGH;
- dev->outstanding_low = DEFAULT_OUTSTANDING_LOW;
- dev->net = net;
- ecm_ipa_ctx = dev;
- *priv = (void *)dev;
- snprintf(net->name, sizeof(net->name), "%s%%d", "ecm");
- net->netdev_ops = &ecm_ipa_netdev_ops;
- pr_debug("internal data structures were intialized\n");
- ret = ecm_ipa_debugfs_init(dev);
- if (ret)
- goto fail_debugfs;
- pr_debug("debugfs entries were created\n");
- *ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
- *ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
- ECM_IPA_LOG_EXIT();
- return 0;
-fail_debugfs:
- free_netdev(net);
-fail_alloc_etherdev:
- return ret;
-}
-EXPORT_SYMBOL(ecm_ipa_init);
+
/**
* ecm_ipa_rules_cfg() - set header insertion and register Tx/Rx properties
@@ -418,105 +671,6 @@
*
* Returns negative errno, or zero on success
*/
-int ecm_ipa_configure(u8 host_ethaddr[], u8 device_ethaddr[],
- void *priv)
-{
- struct ecm_ipa_dev *dev = priv;
- struct net_device *net;
- int result;
- ECM_IPA_LOG_ENTRY();
- NULL_CHECK(host_ethaddr);
- NULL_CHECK(host_ethaddr);
- NULL_CHECK(dev);
- net = dev->net;
- NULL_CHECK(net);
- pr_debug("host_ethaddr=%pM device_ethaddr=%pM\n",
- host_ethaddr, device_ethaddr);
- result = ecm_ipa_create_rm_resource(dev);
- if (result) {
- ECM_IPA_ERROR("fail on RM create\n");
- return -EINVAL;
- }
- pr_debug("RM resource was created\n");
- netif_carrier_off(dev->net);
- result = ecm_ipa_set_device_ethernet_addr(net->dev_addr,
- device_ethaddr);
- if (result) {
- ECM_IPA_ERROR("set device MAC failed\n");
- goto fail_set_device_ethernet;
- }
- result = ecm_ipa_rules_cfg(dev, host_ethaddr, device_ethaddr);
- if (result) {
- ECM_IPA_ERROR("fail on ipa rules set\n");
- goto fail_set_device_ethernet;
- }
- pr_debug("Ethernet header insertion was set\n");
- result = ecm_ipa_register_properties();
- if (result) {
- ECM_IPA_ERROR("fail on properties set\n");
- goto fail_register_tx;
- }
- pr_debug("ECM 2 Tx and 2 Rx properties were registered\n");
- result = register_netdev(net);
- if (result) {
- ECM_IPA_ERROR("register_netdev failed: %d\n", result);
- goto fail_register_netdev;
- }
- pr_debug("register_netdev succeeded\n");
- ECM_IPA_LOG_EXIT();
- return 0;
-fail_register_netdev:
- ecm_ipa_deregister_properties();
-fail_register_tx:
-fail_set_device_ethernet:
- ecm_ipa_rules_destroy(dev);
- ecm_ipa_destory_rm_resource(dev);
- free_netdev(net);
- return result;
-}
-EXPORT_SYMBOL(ecm_ipa_configure);
-
-int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
- void *priv)
-{
- struct ecm_ipa_dev *dev = priv;
- ECM_IPA_LOG_ENTRY();
- NULL_CHECK(priv);
- pr_debug("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d\n",
- usb_to_ipa_hdl, ipa_to_usb_hdl);
- if (!usb_to_ipa_hdl || usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
- ECM_IPA_ERROR("usb_to_ipa_hdl(%d) is not a valid ipa handle\n",
- usb_to_ipa_hdl);
- return -EINVAL;
- }
- if (!ipa_to_usb_hdl || ipa_to_usb_hdl >= IPA_CLIENT_MAX) {
- ECM_IPA_ERROR("ipa_to_usb_hdl(%d) is not a valid ipa handle\n",
- ipa_to_usb_hdl);
- return -EINVAL;
- }
- dev->ipa_to_usb_hdl = ipa_to_usb_hdl;
- dev->usb_to_ipa_hdl = usb_to_ipa_hdl;
- ecm_ipa_ep_registers_cfg(usb_to_ipa_hdl, ipa_to_usb_hdl);
- netif_carrier_on(dev->net);
- if (!netif_carrier_ok(dev->net)) {
- ECM_IPA_ERROR("netif_carrier_ok error\n");
- return -EBUSY;
- }
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-EXPORT_SYMBOL(ecm_ipa_connect);
-
-int ecm_ipa_disconnect(void *priv)
-{
- struct ecm_ipa_dev *dev = priv;
- ECM_IPA_LOG_ENTRY();
- NULL_CHECK(dev);
- netif_carrier_off(dev->net);
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-EXPORT_SYMBOL(ecm_ipa_disconnect);
static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
@@ -578,12 +732,18 @@
static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *dev)
{
+ int result;
+
ECM_IPA_LOG_ENTRY();
+
if (!dev->rm_enable)
return;
ipa_rm_delete_dependency(IPA_RM_RESOURCE_STD_ECM_PROD,
IPA_RM_RESOURCE_USB_CONS);
ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_STD_ECM_PROD);
+ result = ipa_rm_delete_resource(IPA_RM_RESOURCE_STD_ECM_PROD);
+ if (result)
+ ECM_IPA_ERROR("resource deletion failed\n");
ECM_IPA_LOG_EXIT();
}
@@ -605,52 +765,6 @@
return dev->rm_enable;
}
-static int ecm_ipa_open(struct net_device *net)
-{
- ECM_IPA_LOG_ENTRY();
- netif_start_queue(net);
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-
-static int ecm_ipa_stop(struct net_device *net)
-{
- ECM_IPA_LOG_ENTRY();
- pr_debug("stopping net device\n");
- netif_stop_queue(net);
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-
-/**
- * ecm_ipa_cleanup() - destroys all
- * ecm information
- * @priv: main driver context parameters
- *
- */
-void ecm_ipa_cleanup(void *priv)
-{
- struct ecm_ipa_dev *dev = priv;
- ECM_IPA_LOG_ENTRY();
- if (!dev) {
- ECM_IPA_ERROR("dev NULL pointer\n");
- return;
- }
-
- ecm_ipa_destory_rm_resource(dev);
- ecm_ipa_debugfs_destroy(dev);
-
- if (!dev->net) {
- unregister_netdev(dev->net);
- free_netdev(dev->net);
- }
- pr_debug("cleanup done\n");
- ecm_ipa_ctx = NULL;
- ECM_IPA_LOG_EXIT();
- return ;
-}
-EXPORT_SYMBOL(ecm_ipa_cleanup);
-
static int resource_request(struct ecm_ipa_dev *dev)
{
int result = 0;
@@ -673,111 +787,6 @@
}
/**
- * ecm_ipa_start_xmit() - send data from APPs to USB core via IPA core
- * @skb: packet received from Linux stack
- * @net: the network device being used to send this packet
- *
- * Several conditions needed in order to send the packet to IPA:
- * - we are in a valid state were the queue is not stopped
- * - Filter Tx switch is turned off
- * - The resources required for actual Tx are all up
- *
- */
-static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
- struct net_device *net)
-{
- int ret;
- netdev_tx_t status = NETDEV_TX_BUSY;
- struct ecm_ipa_dev *dev = netdev_priv(net);
-
- if (unlikely(netif_queue_stopped(net))) {
- ECM_IPA_ERROR("interface queue is stopped\n");
- goto out;
- }
-
- if (unlikely(tx_filter(skb))) {
- dev_kfree_skb_any(skb);
- pr_debug("packet got filtered out on Tx path\n");
- status = NETDEV_TX_OK;
- goto out;
- }
- ret = resource_request(dev);
- if (ret) {
- pr_debug("Waiting to resource\n");
- netif_stop_queue(net);
- goto resource_busy;
- }
-
- pr_debug("Before sending packet the outstanding packets counter is %d\n",
- atomic_read(&dev->outstanding_pkts));
-
- if (atomic_read(&dev->outstanding_pkts) >= dev->outstanding_high) {
- pr_debug("Outstanding high boundary reached (%d)- stopping queue\n",
- dev->outstanding_high);
- netif_stop_queue(net);
- status = -NETDEV_TX_BUSY;
- goto out;
- }
-
- ret = ipa_tx_dp(IPA_TO_USB_CLIENT, skb, NULL);
- if (ret) {
- ECM_IPA_ERROR("ipa transmit failed (%d)\n", ret);
- goto fail_tx_packet;
- }
-
- atomic_inc(&dev->outstanding_pkts);
- net->stats.tx_packets++;
- net->stats.tx_bytes += skb->len;
- status = NETDEV_TX_OK;
- goto out;
-
-fail_tx_packet:
-out:
- resource_release(dev);
-resource_busy:
- return status;
-}
-
-/**
- * ecm_ipa_packet_receive_notify() - Rx notify
- *
- * @priv: ecm driver context
- * @evt: event type
- * @data: data provided with event
- *
- * IPA will pass a packet with skb->data pointing to Ethernet packet frame
- */
-void ecm_ipa_packet_receive_notify(void *priv,
- enum ipa_dp_evt_type evt,
- unsigned long data)
-{
- struct sk_buff *skb = (struct sk_buff *)data;
- struct ecm_ipa_dev *dev = priv;
- int result;
-
- if (evt != IPA_RECEIVE) {
- ECM_IPA_ERROR("A none IPA_RECEIVE event in ecm_ipa_receive\n");
- return;
- }
-
- skb->dev = dev->net;
- skb->protocol = eth_type_trans(skb, dev->net);
- if (rx_filter(skb)) {
- pr_debug("packet got filtered out on Rx path\n");
- dev_kfree_skb_any(skb);
- return;
- }
-
- result = netif_rx(skb);
- if (result)
- ECM_IPA_ERROR("fail on netif_rx\n");
- dev->net->stats.rx_packets++;
- dev->net->stats.rx_bytes += skb->len;
-
- return;
-}
-
-/**
* ecm_ipa_tx_complete_notify() - Rx notify
*
* @priv: ecm driver context
@@ -787,7 +796,7 @@
* Check that the packet is the one we sent and release it
* This function will be called in defered context in IPA wq.
*/
-void ecm_ipa_tx_complete_notify(void *priv,
+static void ecm_ipa_tx_complete_notify(void *priv,
enum ipa_dp_evt_type evt,
unsigned long data)
{
@@ -809,40 +818,11 @@
dev->outstanding_low);
netif_wake_queue(dev->net);
}
- pr_debug("After Tx-complete the outstanding packets counter is %d\n",
- atomic_read(&dev->outstanding_pkts));
dev_kfree_skb_any(skb);
return;
}
-static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file)
-{
- struct ecm_ipa_dev *dev = inode->i_private;
- ECM_IPA_LOG_ENTRY();
- file->private_data = &(dev->tx_enable);
- ECM_IPA_LOG_ENTRY();
- return 0;
-}
-
-static int ecm_ipa_debugfs_rx_open(struct inode *inode, struct file *file)
-{
- struct ecm_ipa_dev *dev = inode->i_private;
- ECM_IPA_LOG_ENTRY();
- file->private_data = &(dev->rx_enable);
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-
-static int ecm_ipa_debugfs_rm_open(struct inode *inode, struct file *file)
-{
- struct ecm_ipa_dev *dev = inode->i_private;
- ECM_IPA_LOG_ENTRY();
- file->private_data = &(dev->rm_enable);
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-
static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file)
{
struct ecm_ipa_dev *dev = inode->i_private;
@@ -937,93 +917,76 @@
static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev)
{
- const mode_t flags = S_IRUGO | S_IWUGO;
+ const mode_t flags_read_write = S_IRUGO | S_IWUGO;
const mode_t flags_read_only = S_IRUGO;
+ struct dentry *file;
- int ret = -EINVAL;
ECM_IPA_LOG_ENTRY();
+
if (!dev)
return -EINVAL;
- dev->folder = debugfs_create_dir("ecm_ipa", NULL);
- if (!dev->folder) {
- ECM_IPA_ERROR("could not create debugfs folder entry\n");
- ret = -EFAULT;
- goto fail_folder;
- }
- dev->tx_file = debugfs_create_file("tx_enable", flags, dev->folder, dev,
- &ecm_ipa_debugfs_tx_ops);
- if (!dev->tx_file) {
- ECM_IPA_ERROR("could not create debugfs tx file\n");
- ret = -EFAULT;
- goto fail_file;
- }
- dev->rx_file = debugfs_create_file("rx_enable", flags, dev->folder, dev,
- &ecm_ipa_debugfs_rx_ops);
- if (!dev->rx_file) {
- ECM_IPA_ERROR("could not create debugfs rx file\n");
- ret = -EFAULT;
- goto fail_file;
- }
- dev->rm_file = debugfs_create_file("rm_enable", flags, dev->folder, dev,
- &ecm_ipa_debugfs_rm_ops);
- if (!dev->rm_file) {
- ECM_IPA_ERROR("could not create debugfs rm file\n");
- ret = -EFAULT;
- goto fail_file;
- }
- dev->dma_file = debugfs_create_file("dma_enable", flags, dev->folder,
- dev, &ecm_ipa_debugfs_dma_ops);
- if (!dev->dma_file) {
- ECM_IPA_ERROR("could not create debugfs dma file\n");
- ret = -EFAULT;
- goto fail_file;
- }
- dev->outstanding_high_file = debugfs_create_u8("outstanding_high",
- flags, dev->folder, &dev->outstanding_high);
- if (!dev->outstanding_high_file) {
+ dev->directory = debugfs_create_dir("ecm_ipa", NULL);
+ if (!dev->directory) {
+ ECM_IPA_ERROR("could not create debugfs directory entry\n");
+ goto fail_directory;
+ }
+ file = debugfs_create_bool("tx_enable", flags_read_write,
+ dev->directory, &dev->tx_enable);
+ if (!file) {
+ ECM_IPA_ERROR("could not create debugfs tx file\n");
+ goto fail_file;
+ }
+ file = debugfs_create_bool("rx_enable", flags_read_write,
+ dev->directory, &dev->rx_enable);
+ if (!file) {
+ ECM_IPA_ERROR("could not create debugfs rx file\n");
+ goto fail_file;
+ }
+ file = debugfs_create_bool("rm_enable", flags_read_write,
+ dev->directory, &dev->rm_enable);
+ if (!file) {
+ ECM_IPA_ERROR("could not create debugfs rm file\n");
+ goto fail_file;
+ }
+ file = debugfs_create_u8("outstanding_high", flags_read_write,
+ dev->directory, &dev->outstanding_high);
+ if (!file) {
ECM_IPA_ERROR("could not create outstanding_high file\n");
- ret = -EFAULT;
goto fail_file;
}
- dev->outstanding_low_file = debugfs_create_u8("outstanding_low",
- flags, dev->folder, &dev->outstanding_low);
- if (!dev->outstanding_low_file) {
+ file = debugfs_create_u8("outstanding_low", flags_read_write,
+ dev->directory, &dev->outstanding_low);
+ if (!file) {
ECM_IPA_ERROR("could not create outstanding_low file\n");
- ret = -EFAULT;
goto fail_file;
}
- dev->outstanding_file = debugfs_create_file("outstanding",
- flags_read_only, dev->folder, dev,
- &ecm_ipa_debugfs_atomic_ops);
- if (!dev->outstanding_file) {
+ file = debugfs_create_file("dma_enable", flags_read_write,
+ dev->directory, dev, &ecm_ipa_debugfs_dma_ops);
+ if (!file) {
+ ECM_IPA_ERROR("could not create debugfs dma file\n");
+ goto fail_file;
+ }
+ file = debugfs_create_file("outstanding", flags_read_only,
+ dev->directory, dev, &ecm_ipa_debugfs_atomic_ops);
+ if (!file) {
ECM_IPA_ERROR("could not create outstanding file\n");
- ret = -EFAULT;
goto fail_file;
}
ECM_IPA_LOG_EXIT();
return 0;
fail_file:
- debugfs_remove_recursive(dev->folder);
-fail_folder:
- return ret;
+ debugfs_remove_recursive(dev->directory);
+fail_directory:
+ return -EFAULT;
}
static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev)
{
- debugfs_remove_recursive(dev->folder);
+ debugfs_remove_recursive(dev->directory);
}
-static void eth_get_drvinfo(struct net_device *net,
- struct ethtool_drvinfo *drv_info)
-{
- ECM_IPA_LOG_ENTRY();
- strlcpy(drv_info->driver, DRIVER_NAME, sizeof(drv_info->driver));
- ECM_IPA_LOG_EXIT();
-}
-
-
/**
* ecm_ipa_ep_cfg() - configure the USB endpoints for ECM
*
@@ -1039,7 +1002,7 @@
* - No aggregation
* - Add Ethernet header
*/
-int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl)
+static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl)
{
int result = 0;
struct ipa_ep_cfg usb_to_ipa_ep_cfg;
@@ -1081,7 +1044,7 @@
* which is needed for cores that does not support blocks logic
* Note that client handles are the actual pipe index
*/
-int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl)
+static int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl)
{
int result = 0;
struct ipa_ep_cfg_mode cfg_mode;
@@ -1117,7 +1080,8 @@
*
* Returns 0 for success, negative otherwise
*/
-int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr, u8 device_ethaddr[])
+static int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr,
+ u8 device_ethaddr[])
{
if (!is_valid_ether_addr(device_ethaddr))
return -EINVAL;
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
index 7e6cd4f..59a6b68 100644
--- a/drivers/net/wireless/wcnss/wcnss_vreg.c
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -172,16 +172,13 @@
}
/* NV bit is set to indicate that platform driver is capable
- * of doing NV download. SSR should not set NV bit; during
- * SSR NV bin is downloaded by WLAN driver.
+ * of doing NV download.
*/
- if (!wcnss_cold_boot_done()) {
- pr_debug("wcnss: Indicate NV bin download\n");
- spare_reg = msm_wcnss_base + spare_offset;
- reg = readl_relaxed(spare_reg);
- reg |= NVBIN_DLND_BIT;
- writel_relaxed(reg, spare_reg);
- }
+ pr_debug("wcnss: Indicate NV bin download\n");
+ spare_reg = msm_wcnss_base + spare_offset;
+ reg = readl_relaxed(spare_reg);
+ reg |= NVBIN_DLND_BIT;
+ writel_relaxed(reg, spare_reg);
pmu_conf_reg = msm_wcnss_base + pmu_offset;
writel_relaxed(0, pmu_conf_reg);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 1a175c9..f837a06 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -28,6 +28,9 @@
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <linux/ratelimit.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
#include <mach/msm_smd.h>
#include <mach/msm_iomap.h>
@@ -48,6 +51,10 @@
module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(has_48mhz_xo, "Is an external 48 MHz XO present");
+static int has_calibrated_data = WCNSS_CONFIG_UNSPECIFIED;
+module_param(has_calibrated_data, int, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(has_calibrated_data, "whether calibrated data file available");
+
static int do_not_cancel_vote = WCNSS_CONFIG_UNSPECIFIED;
module_param(do_not_cancel_vote, int, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(do_not_cancel_vote, "Do not cancel votes for wcnss");
@@ -92,20 +99,27 @@
#define CCU_PRONTO_LAST_ADDR2_OFFSET 0x14
#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
-#define WCNSS_MAX_FRAME_SIZE 500
+#define WCNSS_MAX_FRAME_SIZE (4*1024)
#define WCNSS_VERSION_LEN 30
/* message types */
#define WCNSS_CTRL_MSG_START 0x01000000
-#define WCNSS_VERSION_REQ (WCNSS_CTRL_MSG_START + 0)
-#define WCNSS_VERSION_RSP (WCNSS_CTRL_MSG_START + 1)
-#define WCNSS_NVBIN_DNLD_REQ (WCNSS_CTRL_MSG_START + 2)
-#define WCNSS_NVBIN_DNLD_RSP (WCNSS_CTRL_MSG_START + 3)
+#define WCNSS_VERSION_REQ (WCNSS_CTRL_MSG_START + 0)
+#define WCNSS_VERSION_RSP (WCNSS_CTRL_MSG_START + 1)
+#define WCNSS_NVBIN_DNLD_REQ (WCNSS_CTRL_MSG_START + 2)
+#define WCNSS_NVBIN_DNLD_RSP (WCNSS_CTRL_MSG_START + 3)
+#define WCNSS_CALDATA_UPLD_REQ (WCNSS_CTRL_MSG_START + 4)
+#define WCNSS_CALDATA_UPLD_RSP (WCNSS_CTRL_MSG_START + 5)
+#define WCNSS_CALDATA_DNLD_REQ (WCNSS_CTRL_MSG_START + 6)
+#define WCNSS_CALDATA_DNLD_RSP (WCNSS_CTRL_MSG_START + 7)
#define VALID_VERSION(version) \
((strncmp(version, "INVALID", WCNSS_VERSION_LEN)) ? 1 : 0)
+#define FW_CALDATA_CAPABLE() \
+ ((penv->fw_major >= 1) && (penv->fw_minor >= 5) ? 1 : 0)
+
struct smd_msg_hdr {
unsigned int msg_type;
unsigned int msg_len;
@@ -126,6 +140,13 @@
* header, so NV fragment size as next multiple of 1Kb is 3Kb.
*/
#define NV_FRAGMENT_SIZE 3072
+#define MAX_CALIBRATED_DATA_SIZE (64*1024)
+#define LAST_FRAGMENT (1 << 0)
+#define MESSAGE_TO_FOLLOW (1 << 1)
+#define CAN_RECEIVE_CALDATA (1 << 15)
+#define WCNSS_RESP_SUCCESS 1
+#define WCNSS_RESP_FAIL 0
+
/* Macro to find the total number fragments of the NV bin Image */
#define TOTALFRAGMENTS(x) (((x % NV_FRAGMENT_SIZE) == 0) ? \
@@ -144,11 +165,14 @@
unsigned short frag_number;
/*
- * When set to 1 it indicates that no more fragments will
- * be sent. Receiver shall send back response message after
- * the last fragment.
+ * bit 0: When set to 1 it indicates that no more fragments will
+ * be sent.
+ * bit 1: When set, a new message will be followed by this message
+ * bit 2- bit 14: Reserved
+ * bit 15: when set, it indicates that the sender is capable of
+ * receiving Calibrated data.
*/
- unsigned short is_last_fragment;
+ unsigned short msg_flags;
/* NV Image size (number of bytes) */
unsigned int nvbin_buffer_size;
@@ -160,6 +184,7 @@
*/
};
+
struct nvbin_dnld_req_msg {
/*
* Note: The length specified in nvbin_dnld_req_msg messages
@@ -170,6 +195,39 @@
struct nvbin_dnld_req_params dnld_req_params;
};
+struct cal_data_params {
+
+ /* The total size of the calibrated data, including all the
+ * fragments.
+ */
+ unsigned int total_size;
+ unsigned short frag_number;
+ /*
+ * bit 0: When set to 1 it indicates that no more fragments will
+ * be sent.
+ * bit 1: When set, a new message will be followed by this message
+ * bit 2- bit 15: Reserved
+ */
+ unsigned short msg_flags;
+ /*
+ * fragment size
+ */
+ unsigned int frag_size;
+ /*
+ * Following the frag_size, frag_size of fragmented
+ * data will be followed.
+ */
+};
+
+struct cal_data_msg {
+ /*
+ * The length specified in cal_data_msg should be
+ * hdr.msg_len = sizeof(cal_data_msg) + frag_size
+ */
+ struct smd_msg_hdr hdr;
+ struct cal_data_params cal_params;
+};
+
static struct {
struct platform_device *pdev;
void *pil;
@@ -180,9 +238,10 @@
const struct dev_pm_ops *pm_ops;
int triggered;
int smd_channel_ready;
- int cold_boot_done;
smd_channel_t *smd_ch;
unsigned char wcnss_version[WCNSS_VERSION_LEN];
+ unsigned char fw_major;
+ unsigned char fw_minor;
unsigned int serial_number;
int thermal_mitigation;
enum wcnss_hw_type wcnss_hw_type;
@@ -198,6 +257,20 @@
void __iomem *pronto_a2xb_base;
void __iomem *pronto_ccpu_base;
void __iomem *fiq_reg;
+ int ssr_boot;
+ int nv_downloaded;
+ unsigned char *fw_cal_data;
+ unsigned char *user_cal_data;
+ int fw_cal_rcvd;
+ int fw_cal_exp_frag;
+ int fw_cal_available;
+ int user_cal_read;
+ int user_cal_available;
+ int user_cal_rcvd;
+ int user_cal_exp_size;
+ int device_opened;
+ struct mutex dev_lock;
+ wait_queue_head_t read_wait;
} *penv = NULL;
static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -459,21 +532,26 @@
switch (event) {
case SMD_EVENT_DATA:
len = smd_read_avail(penv->smd_ch);
- if (len < 0)
+ if (len < 0) {
pr_err("wcnss: failed to read from smd %d\n", len);
+ return;
+ }
schedule_work(&penv->wcnssctrl_rx_work);
break;
case SMD_EVENT_OPEN:
pr_debug("wcnss: opening WCNSS SMD channel :%s",
WCNSS_CTRL_CHANNEL);
- if (!VALID_VERSION(penv->wcnss_version))
- schedule_work(&penv->wcnssctrl_version_work);
+ schedule_work(&penv->wcnssctrl_version_work);
+
break;
case SMD_EVENT_CLOSE:
pr_debug("wcnss: closing WCNSS SMD channel :%s",
WCNSS_CTRL_CHANNEL);
+ /* This SMD is closed only during SSR */
+ penv->ssr_boot = true;
+ penv->nv_downloaded = 0;
break;
default:
@@ -658,6 +736,15 @@
}
EXPORT_SYMBOL(wcnss_get_wlan_config);
+int wcnss_device_ready(void)
+{
+ if (penv && penv->pdev && penv->nv_downloaded)
+ return 1;
+ return 0;
+}
+EXPORT_SYMBOL(wcnss_device_ready);
+
+
struct resource *wcnss_wlan_get_memory_map(struct device *dev)
{
if (penv && dev && (dev == &penv->pdev->dev) && penv->smd_channel_ready)
@@ -837,15 +924,13 @@
}
EXPORT_SYMBOL(wcnss_hardware_type);
-int wcnss_cold_boot_done(void)
+int fw_cal_data_available(void)
{
if (penv)
- return penv->cold_boot_done;
+ return penv->fw_cal_available;
else
return -ENODEV;
}
-EXPORT_SYMBOL(wcnss_cold_boot_done);
-
static int wcnss_smd_tx(void *data, int len)
{
@@ -864,14 +949,145 @@
return ret;
}
+static unsigned char wcnss_fw_status(void)
+{
+ int len = 0;
+ int rc = 0;
+
+ unsigned char fw_status = 0xFF;
+
+ len = smd_read_avail(penv->smd_ch);
+ if (len < 1) {
+ pr_err("%s: invalid firmware status", __func__);
+ return fw_status;
+ }
+
+ rc = smd_read(penv->smd_ch, &fw_status, 1);
+ if (rc < 0) {
+ pr_err("%s: incomplete data read from smd\n", __func__);
+ return fw_status;
+ }
+ return fw_status;
+}
+
+static void wcnss_send_cal_rsp(unsigned char fw_status)
+{
+ struct smd_msg_hdr *rsphdr;
+ unsigned char *msg = NULL;
+ int rc;
+
+ msg = kmalloc((sizeof(struct smd_msg_hdr) + 1), GFP_KERNEL);
+ if (NULL == msg) {
+ pr_err("wcnss: %s: failed to get memory\n", __func__);
+ return;
+ }
+
+ rsphdr = (struct smd_msg_hdr *)msg;
+ rsphdr->msg_type = WCNSS_CALDATA_UPLD_RSP;
+ rsphdr->msg_len = sizeof(struct smd_msg_hdr) + 1;
+ memcpy(msg+sizeof(struct smd_msg_hdr), &fw_status, 1);
+
+ rc = wcnss_smd_tx(msg, rsphdr->msg_len);
+ if (rc < 0)
+ pr_err("wcnss: smd tx failed\n");
+}
+
+/* Collect calibrated data from WCNSS */
+void extract_cal_data(int len)
+{
+ int rc;
+ struct cal_data_params calhdr;
+ unsigned char fw_status = WCNSS_RESP_FAIL;
+
+ if (len < sizeof(struct cal_data_params)) {
+ pr_err("wcnss: incomplete cal header length\n");
+ return;
+ }
+
+ rc = smd_read(penv->smd_ch, (unsigned char *)&calhdr,
+ sizeof(struct cal_data_params));
+ if (rc < sizeof(struct cal_data_params)) {
+ pr_err("wcnss: incomplete cal header read from smd\n");
+ return;
+ }
+
+ if (penv->fw_cal_exp_frag != calhdr.frag_number) {
+ pr_err("wcnss: Invalid frgament");
+ goto exit;
+ }
+
+ if (calhdr.frag_size > WCNSS_MAX_FRAME_SIZE) {
+ pr_err("wcnss: Invalid fragment size");
+ goto exit;
+ }
+
+ if (0 == calhdr.frag_number) {
+ if (calhdr.total_size > MAX_CALIBRATED_DATA_SIZE) {
+ pr_err("wcnss: Invalid cal data size %d",
+ calhdr.total_size);
+ goto exit;
+ }
+ kfree(penv->fw_cal_data);
+ penv->fw_cal_rcvd = 0;
+ penv->fw_cal_data = kmalloc(calhdr.total_size,
+ GFP_KERNEL);
+ if (penv->fw_cal_data == NULL) {
+ smd_read(penv->smd_ch, NULL, calhdr.frag_size);
+ goto exit;
+ }
+ }
+
+ mutex_lock(&penv->dev_lock);
+ if (penv->fw_cal_rcvd + calhdr.frag_size >
+ MAX_CALIBRATED_DATA_SIZE) {
+ pr_err("calibrated data size is more than expected %d",
+ penv->fw_cal_rcvd + calhdr.frag_size);
+ penv->fw_cal_exp_frag = 0;
+ penv->fw_cal_rcvd = 0;
+ smd_read(penv->smd_ch, NULL, calhdr.frag_size);
+ goto unlock_exit;
+ }
+
+ rc = smd_read(penv->smd_ch, penv->fw_cal_data + penv->fw_cal_rcvd,
+ calhdr.frag_size);
+ if (rc < calhdr.frag_size)
+ goto unlock_exit;
+
+ penv->fw_cal_exp_frag++;
+ penv->fw_cal_rcvd += calhdr.frag_size;
+
+ if (calhdr.msg_flags & LAST_FRAGMENT) {
+ penv->fw_cal_exp_frag = 0;
+ penv->fw_cal_available = true;
+ pr_info("wcnss: cal data collection completed\n");
+ }
+ mutex_unlock(&penv->dev_lock);
+ wake_up(&penv->read_wait);
+
+ if (penv->fw_cal_available) {
+ fw_status = WCNSS_RESP_SUCCESS;
+ wcnss_send_cal_rsp(fw_status);
+ }
+ return;
+
+unlock_exit:
+ mutex_unlock(&penv->dev_lock);
+
+exit:
+ wcnss_send_cal_rsp(fw_status);
+ return;
+}
+
+
static void wcnssctrl_rx_handler(struct work_struct *worker)
{
int len = 0;
int rc = 0;
- unsigned char buf[WCNSS_MAX_FRAME_SIZE];
+ unsigned char buf[sizeof(struct wcnss_version)];
struct smd_msg_hdr *phdr;
struct wcnss_version *pversion;
int hw_type;
+ unsigned char fw_status = 0;
len = smd_read_avail(penv->smd_ch);
if (len > WCNSS_MAX_FRAME_SIZE) {
@@ -882,23 +1098,33 @@
if (len <= 0)
return;
- rc = smd_read(penv->smd_ch, buf, len);
- if (rc < len) {
- pr_err("wcnss: incomplete data read from smd\n");
+ rc = smd_read(penv->smd_ch, buf, sizeof(struct smd_msg_hdr));
+ if (rc < sizeof(struct smd_msg_hdr)) {
+ pr_err("wcnss: incomplete header read from smd\n");
return;
}
+ len -= sizeof(struct smd_msg_hdr);
phdr = (struct smd_msg_hdr *)buf;
switch (phdr->msg_type) {
case WCNSS_VERSION_RSP:
- pversion = (struct wcnss_version *)buf;
- if (len != sizeof(struct wcnss_version)) {
+ if (len != sizeof(struct wcnss_version)
+ - sizeof(struct smd_msg_hdr)) {
pr_err("wcnss: invalid version data from wcnss %d\n",
- len);
+ len);
return;
}
+ rc = smd_read(penv->smd_ch, buf+sizeof(struct smd_msg_hdr),
+ len);
+ if (rc < len) {
+ pr_err("wcnss: incomplete data read from smd\n");
+ return;
+ }
+ pversion = (struct wcnss_version *)buf;
+ penv->fw_major = pversion->major;
+ penv->fw_minor = pversion->minor;
snprintf(penv->wcnss_version, WCNSS_VERSION_LEN,
"%02x%02x%02x%02x", pversion->major, pversion->minor,
pversion->version, pversion->revision);
@@ -930,7 +1156,22 @@
break;
case WCNSS_NVBIN_DNLD_RSP:
- pr_info("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu\n");
+ penv->nv_downloaded = true;
+ fw_status = wcnss_fw_status();
+ pr_debug("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n",
+ fw_status);
+ break;
+
+ case WCNSS_CALDATA_DNLD_RSP:
+ penv->nv_downloaded = true;
+ fw_status = wcnss_fw_status();
+ pr_debug("wcnss: received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n",
+ fw_status);
+ break;
+
+ case WCNSS_CALDATA_UPLD_REQ:
+ penv->fw_cal_available = 0;
+ extract_cal_data(len);
break;
default:
@@ -953,7 +1194,8 @@
return;
}
-static void wcnss_nvbin_dnld_req(struct work_struct *worker)
+
+static void wcnss_nvbin_dnld(void)
{
int ret = 0;
struct nvbin_dnld_req_msg *dnld_req_msg;
@@ -970,8 +1212,8 @@
ret = request_firmware(&nv, NVBIN_FILE, dev);
if (ret || !nv || !nv->data || !nv->size) {
- pr_err("wcnss: wcnss_nvbin_dnld_req: request_firmware failed for %s\n",
- NVBIN_FILE);
+ pr_err("wcnss: %s: request_firmware failed for %s\n",
+ __func__, NVBIN_FILE);
return;
}
@@ -992,13 +1234,14 @@
NV_FRAGMENT_SIZE), GFP_KERNEL);
if (NULL == outbuffer) {
- pr_err("wcnss: wcnss_nvbin_dnld_req: failed to get buffer\n");
+ pr_err("wcnss: %s: failed to get buffer\n", __func__);
goto err_free_nv;
}
dnld_req_msg = (struct nvbin_dnld_req_msg *)outbuffer;
dnld_req_msg->hdr.msg_type = WCNSS_NVBIN_DNLD_REQ;
+ dnld_req_msg->dnld_req_params.msg_flags = 0;
for (count = 0; count < total_fragments; count++) {
dnld_req_msg->dnld_req_params.frag_number = count;
@@ -1009,10 +1252,14 @@
if (!cur_frag_size)
cur_frag_size = NV_FRAGMENT_SIZE;
- dnld_req_msg->dnld_req_params.is_last_fragment = 1;
+ dnld_req_msg->dnld_req_params.msg_flags |=
+ LAST_FRAGMENT;
+ dnld_req_msg->dnld_req_params.msg_flags |=
+ CAN_RECEIVE_CALDATA;
} else {
cur_frag_size = NV_FRAGMENT_SIZE;
- dnld_req_msg->dnld_req_params.is_last_fragment = 0;
+ dnld_req_msg->dnld_req_params.msg_flags &=
+ ~LAST_FRAGMENT;
}
dnld_req_msg->dnld_req_params.nvbin_buffer_size =
@@ -1030,7 +1277,8 @@
retry_count = 0;
while ((ret == -ENOSPC) && (retry_count <= 3)) {
- pr_debug("wcnss: wcnss_nvbin_dnld_req: smd tx failed, ENOSPC\n");
+ pr_debug("wcnss: %s: smd tx failed, ENOSPC\n",
+ __func__);
pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n",
count, dnld_req_msg->hdr.msg_len,
total_fragments, retry_count);
@@ -1043,7 +1291,7 @@
}
if (ret < 0) {
- pr_err("wcnss: wcnss_nvbin_dnld_req: smd tx failed\n");
+ pr_err("wcnss: %s: smd tx failed\n", __func__);
pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n",
count, dnld_req_msg->hdr.msg_len,
total_fragments, retry_count);
@@ -1062,6 +1310,138 @@
return;
}
+
+static void wcnss_caldata_dnld(const void *cal_data,
+ unsigned int cal_data_size, bool msg_to_follow)
+{
+ int ret = 0;
+ struct cal_data_msg *cal_msg;
+ unsigned short total_fragments = 0;
+ unsigned short count = 0;
+ unsigned short retry_count = 0;
+ unsigned short cur_frag_size = 0;
+ unsigned char *outbuffer = NULL;
+
+ total_fragments = TOTALFRAGMENTS(cal_data_size);
+
+ outbuffer = kmalloc((sizeof(struct cal_data_msg) +
+ NV_FRAGMENT_SIZE), GFP_KERNEL);
+
+ if (NULL == outbuffer) {
+ pr_err("wcnss: %s: failed to get buffer\n", __func__);
+ return;
+ }
+
+ cal_msg = (struct cal_data_msg *)outbuffer;
+
+ cal_msg->hdr.msg_type = WCNSS_CALDATA_DNLD_REQ;
+ cal_msg->cal_params.msg_flags = 0;
+
+ for (count = 0; count < total_fragments; count++) {
+ cal_msg->cal_params.frag_number = count;
+
+ if (count == (total_fragments - 1)) {
+ cur_frag_size = cal_data_size % NV_FRAGMENT_SIZE;
+ if (!cur_frag_size)
+ cur_frag_size = NV_FRAGMENT_SIZE;
+
+ cal_msg->cal_params.msg_flags
+ |= LAST_FRAGMENT;
+ if (msg_to_follow)
+ cal_msg->cal_params.msg_flags |=
+ MESSAGE_TO_FOLLOW;
+ } else {
+ cur_frag_size = NV_FRAGMENT_SIZE;
+ cal_msg->cal_params.msg_flags &=
+ ~LAST_FRAGMENT;
+ }
+
+ cal_msg->cal_params.total_size = cal_data_size;
+ cal_msg->cal_params.frag_size =
+ cur_frag_size;
+
+ cal_msg->hdr.msg_len =
+ sizeof(struct cal_data_msg) + cur_frag_size;
+
+ memcpy((outbuffer + sizeof(struct cal_data_msg)),
+ (cal_data + count * NV_FRAGMENT_SIZE),
+ cur_frag_size);
+
+ ret = wcnss_smd_tx(outbuffer, cal_msg->hdr.msg_len);
+
+ retry_count = 0;
+ while ((ret == -ENOSPC) && (retry_count <= 3)) {
+ pr_debug("wcnss: %s: smd tx failed, ENOSPC\n",
+ __func__);
+ pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n",
+ count, cal_msg->hdr.msg_len,
+ total_fragments, retry_count);
+
+ /* wait and try again */
+ msleep(20);
+ retry_count++;
+ ret = wcnss_smd_tx(outbuffer,
+ cal_msg->hdr.msg_len);
+ }
+
+ if (ret < 0) {
+ pr_err("wcnss: %s: smd tx failed\n", __func__);
+ pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n",
+ count, cal_msg->hdr.msg_len,
+ total_fragments, retry_count);
+ goto err_dnld;
+ }
+ }
+
+
+err_dnld:
+ /* free buffer */
+ kfree(outbuffer);
+
+ return;
+}
+
+
+static void wcnss_nvbin_dnld_main(struct work_struct *worker)
+{
+ int retry = 0;
+
+ if (!FW_CALDATA_CAPABLE())
+ goto nv_download;
+
+ if (!penv->fw_cal_available && WCNSS_CONFIG_UNSPECIFIED
+ != has_calibrated_data && !penv->user_cal_available) {
+ while (!penv->user_cal_available && retry++ < 5)
+ msleep(500);
+ }
+
+ /* only cal data is sent during ssr (if available) */
+ if (penv->fw_cal_available && penv->ssr_boot) {
+ pr_info_ratelimited("wcnss: cal download during SSR, using fw cal");
+ wcnss_caldata_dnld(penv->fw_cal_data, penv->fw_cal_rcvd, false);
+ return;
+
+ } else if (penv->user_cal_available && penv->ssr_boot) {
+ pr_info_ratelimited("wcnss: cal download during SSR, using user cal");
+ wcnss_caldata_dnld(penv->user_cal_data,
+ penv->user_cal_rcvd, false);
+ return;
+
+ } else if (penv->user_cal_available) {
+ pr_info_ratelimited("wcnss: cal download during cold boot, using user cal");
+ wcnss_caldata_dnld(penv->user_cal_data,
+ penv->user_cal_rcvd, true);
+ }
+
+nv_download:
+ pr_info_ratelimited("wcnss: NV download");
+ wcnss_nvbin_dnld();
+
+ return;
+}
+
+
+
static int
wcnss_trigger_config(struct platform_device *pdev)
{
@@ -1146,7 +1526,7 @@
}
INIT_WORK(&penv->wcnssctrl_rx_work, wcnssctrl_rx_handler);
INIT_WORK(&penv->wcnssctrl_version_work, wcnss_send_version_req);
- INIT_WORK(&penv->wcnssctrl_nvbin_dnld_work, wcnss_nvbin_dnld_req);
+ INIT_WORK(&penv->wcnssctrl_nvbin_dnld_work, wcnss_nvbin_dnld_main);
wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss");
@@ -1201,7 +1581,6 @@
goto fail_ioremap3;
}
}
- penv->cold_boot_done = 1;
return 0;
@@ -1229,20 +1608,128 @@
return ret;
}
-#ifndef MODULE
static int wcnss_node_open(struct inode *inode, struct file *file)
{
struct platform_device *pdev;
- pr_info(DEVICE " triggered by userspace\n");
+ /* first open is only to trigger WCNSS platform driver */
+ if (!penv->triggered) {
+ pr_info(DEVICE " triggered by userspace\n");
+ pdev = penv->pdev;
+ return wcnss_trigger_config(pdev);
- pdev = penv->pdev;
- return wcnss_trigger_config(pdev);
+ } else if (penv->device_opened) {
+ pr_info(DEVICE " already opened\n");
+ return -EBUSY;
+ }
+
+ mutex_lock(&penv->dev_lock);
+ penv->user_cal_rcvd = 0;
+ penv->user_cal_read = 0;
+ penv->user_cal_available = false;
+ penv->user_cal_data = NULL;
+ penv->device_opened = 1;
+ mutex_unlock(&penv->dev_lock);
+
+ return 0;
}
+static ssize_t wcnss_wlan_read(struct file *fp, char __user
+ *buffer, size_t count, loff_t *position)
+{
+ int rc = 0;
+
+ if (!penv->device_opened)
+ return -EFAULT;
+
+ rc = wait_event_interruptible(penv->read_wait, penv->fw_cal_rcvd
+ > penv->user_cal_read || penv->fw_cal_available);
+
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&penv->dev_lock);
+
+ if (penv->fw_cal_available && penv->fw_cal_rcvd
+ == penv->user_cal_read) {
+ rc = 0;
+ goto exit;
+ }
+
+ if (count > penv->fw_cal_rcvd - penv->user_cal_read)
+ count = penv->fw_cal_rcvd - penv->user_cal_read;
+
+ rc = copy_to_user(buffer, penv->fw_cal_data +
+ penv->user_cal_read, count);
+ if (rc == 0) {
+ penv->user_cal_read += count;
+ rc = count;
+ }
+
+exit:
+ mutex_unlock(&penv->dev_lock);
+ return rc;
+}
+
+/* first (valid) write to this device should be 4 bytes cal file size */
+static ssize_t wcnss_wlan_write(struct file *fp, const char __user
+ *user_buffer, size_t count, loff_t *position)
+{
+ int rc = 0;
+ int size = 0;
+
+ if (!penv->device_opened || penv->user_cal_available)
+ return -EFAULT;
+
+ if (penv->user_cal_rcvd == 0 && count >= 4
+ && !penv->user_cal_data) {
+ rc = copy_from_user((void *)&size, user_buffer, 4);
+ if (size > MAX_CALIBRATED_DATA_SIZE) {
+ pr_err(DEVICE " invalid size to write %d\n", size);
+ return -EFAULT;
+ }
+
+ rc += count;
+ count -= 4;
+ penv->user_cal_exp_size = size;
+ penv->user_cal_data = kmalloc(size, GFP_KERNEL);
+ if (penv->user_cal_data == NULL) {
+ pr_err(DEVICE " no memory to write\n");
+ return -ENOMEM;
+ }
+ if (0 == count)
+ goto exit;
+
+ } else if (penv->user_cal_rcvd == 0 && count < 4)
+ return -EFAULT;
+
+ if (MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
+ pr_err(DEVICE " invalid size to write %d\n", count +
+ penv->user_cal_rcvd);
+ rc = -ENOMEM;
+ goto exit;
+ }
+ rc = copy_from_user((void *)penv->user_cal_data +
+ penv->user_cal_rcvd, user_buffer, count);
+ if (0 == rc) {
+ penv->user_cal_rcvd += count;
+ rc += count;
+ }
+ if (penv->user_cal_rcvd == penv->user_cal_exp_size) {
+ penv->user_cal_available = true;
+ pr_info_ratelimited("wcnss: user cal written");
+ }
+
+exit:
+ return rc;
+}
+
+
static const struct file_operations wcnss_node_fops = {
.owner = THIS_MODULE,
.open = wcnss_node_open,
+ .read = wcnss_wlan_read,
+ .write = wcnss_wlan_write,
};
static struct miscdevice wcnss_misc = {
@@ -1250,8 +1737,6 @@
.name = DEVICE,
.fops = &wcnss_node_fops,
};
-#endif /* ifndef MODULE */
-
static int __devinit
wcnss_wlan_probe(struct platform_device *pdev)
@@ -1279,18 +1764,8 @@
return -ENOENT;
}
-
-#ifdef MODULE
-
- /* Since we were built as a module, we are running because
- * the module was loaded, therefore we assume userspace
- * applications are available to service PIL, so we can
- * trigger the WCNSS configuration now
- */
- pr_info(DEVICE " probed in MODULE mode\n");
- return wcnss_trigger_config(pdev);
-
-#else
+ mutex_init(&penv->dev_lock);
+ init_waitqueue_head(&penv->read_wait);
/* Since we were built into the kernel we'll be called as part
* of kernel initialization. We don't know if userspace
@@ -1303,7 +1778,6 @@
pr_info(DEVICE " probed in built-in mode\n");
return misc_register(&wcnss_misc);
-#endif
}
static int __devexit
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 0970505..5f0ba94 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -214,7 +214,7 @@
#if defined(CONFIG_MICROBLAZE)
dev->archdata.dma_mask = 0xffffffffUL;
#endif
- dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+ dev->dev.coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index 1b33dc0..fa71efc 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -86,15 +86,19 @@
struct list_head bam_tx_pool;
spinlock_t bam_tx_pool_spinlock;
struct workqueue_struct *a2_mux_tx_workqueue;
+ struct workqueue_struct *a2_mux_rx_workqueue;
int a2_mux_initialized;
bool bam_is_connected;
+ bool bam_connect_in_progress;
int a2_mux_send_power_vote_on_init_once;
int a2_mux_sw_bridge_is_connected;
+ bool a2_mux_dl_wakeup;
u32 a2_device_handle;
struct mutex wakeup_lock;
struct completion ul_wakeup_ack_completion;
struct completion bam_connection_completion;
struct completion request_resource_completion;
+ struct completion dl_wakeup_completion;
rwlock_t ul_wakeup_lock;
int wait_for_ack;
struct wake_lock bam_wakelock;
@@ -237,7 +241,6 @@
INIT_COMPLETION(a2_mux_ctx->ul_wakeup_ack_completion);
power_vote(0);
}
- a2_mux_ctx->bam_is_connected = false;
}
static void ul_wakeup(void)
@@ -245,7 +248,8 @@
int ret;
mutex_lock(&a2_mux_ctx->wakeup_lock);
- if (a2_mux_ctx->bam_is_connected) {
+ if (a2_mux_ctx->bam_is_connected &&
+ !a2_mux_ctx->bam_connect_in_progress) {
IPADBG("%s Already awake\n", __func__);
mutex_unlock(&a2_mux_ctx->wakeup_lock);
return;
@@ -259,7 +263,6 @@
grab_wakelock();
else
a2_mux_ctx->a2_pc_disabled_wakelock_skipped = 1;
- a2_mux_ctx->bam_is_connected = true;
mutex_unlock(&a2_mux_ctx->wakeup_lock);
return;
}
@@ -298,7 +301,6 @@
goto bail;
}
}
- a2_mux_ctx->bam_is_connected = true;
IPADBG("%s complete\n", __func__);
mutex_unlock(&a2_mux_ctx->wakeup_lock);
return;
@@ -367,26 +369,94 @@
dev_kfree_skb_any(skb);
}
+static bool msm_bam_dmux_kickoff_ul_power_down(void)
+
+{
+ bool is_connected;
+
+ write_lock(&a2_mux_ctx->ul_wakeup_lock);
+ if (a2_mux_ctx->bam_connect_in_progress) {
+ a2_mux_ctx->bam_is_connected = false;
+ is_connected = true;
+ } else {
+ is_connected = a2_mux_ctx->bam_is_connected;
+ a2_mux_ctx->bam_is_connected = false;
+ if (is_connected) {
+ a2_mux_ctx->bam_connect_in_progress = true;
+ queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
+ &a2_mux_ctx->kickoff_ul_power_down);
+ }
+ }
+ write_unlock(&a2_mux_ctx->ul_wakeup_lock);
+ return is_connected;
+}
+
+static bool msm_bam_dmux_kickoff_ul_wakeup(void)
+{
+ bool is_connected;
+
+ write_lock(&a2_mux_ctx->ul_wakeup_lock);
+ if (a2_mux_ctx->bam_connect_in_progress) {
+ a2_mux_ctx->bam_is_connected = true;
+ is_connected = false;
+ } else {
+ is_connected = a2_mux_ctx->bam_is_connected;
+ a2_mux_ctx->bam_is_connected = true;
+ if (!is_connected) {
+ a2_mux_ctx->bam_connect_in_progress = true;
+ queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
+ &a2_mux_ctx->kickoff_ul_wakeup);
+ }
+ }
+ write_unlock(&a2_mux_ctx->ul_wakeup_lock);
+ return is_connected;
+}
+
static void kickoff_ul_power_down_func(struct work_struct *work)
{
- unsigned long flags;
+ bool is_connected;
- write_lock_irqsave(&a2_mux_ctx->ul_wakeup_lock, flags);
- if (a2_mux_ctx->bam_is_connected) {
- IPADBG("%s: UL active - forcing powerdown\n", __func__);
- ul_powerdown();
- }
- write_unlock_irqrestore(&a2_mux_ctx->ul_wakeup_lock, flags);
- ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
- IPA_RM_RESOURCE_A2_CONS);
+ IPADBG("%s: UL active - forcing powerdown\n", __func__);
+ ul_powerdown();
+ write_lock(&a2_mux_ctx->ul_wakeup_lock);
+ is_connected = a2_mux_ctx->bam_is_connected;
+ a2_mux_ctx->bam_is_connected = false;
+ a2_mux_ctx->bam_connect_in_progress = false;
+ write_unlock(&a2_mux_ctx->ul_wakeup_lock);
+ if (is_connected)
+ msm_bam_dmux_kickoff_ul_wakeup();
+ else
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
+ IPA_RM_RESOURCE_A2_CONS);
}
static void kickoff_ul_wakeup_func(struct work_struct *work)
{
- if (!a2_mux_ctx->bam_is_connected)
- ul_wakeup();
- ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
- IPA_RM_RESOURCE_A2_CONS);
+ bool is_connected;
+ int ret;
+
+ ul_wakeup();
+ write_lock(&a2_mux_ctx->ul_wakeup_lock);
+ is_connected = a2_mux_ctx->bam_is_connected;
+ a2_mux_ctx->bam_is_connected = true;
+ a2_mux_ctx->bam_connect_in_progress = false;
+ write_unlock(&a2_mux_ctx->ul_wakeup_lock);
+ if (is_connected)
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+ IPA_RM_RESOURCE_A2_CONS);
+ INIT_COMPLETION(a2_mux_ctx->dl_wakeup_completion);
+ if (!a2_mux_ctx->a2_mux_dl_wakeup) {
+ ret = wait_for_completion_timeout(
+ &a2_mux_ctx->dl_wakeup_completion,
+ A2_MUX_COMPLETION_TIMEOUT);
+ if (unlikely(ret == 0)) {
+ IPAERR("%s timeout A2 PROD\n", __func__);
+ BUG();
+ return;
+ }
+ }
+ if (!is_connected)
+ msm_bam_dmux_kickoff_ul_power_down();
}
static void kickoff_ul_request_resource_func(struct work_struct *work)
@@ -412,33 +482,8 @@
}
}
toggle_apps_ack();
-}
-
-static bool msm_bam_dmux_kickoff_ul_wakeup(void)
-{
- bool is_connected;
-
- read_lock(&a2_mux_ctx->ul_wakeup_lock);
- is_connected = a2_mux_ctx->bam_is_connected;
- read_unlock(&a2_mux_ctx->ul_wakeup_lock);
- if (!is_connected)
- queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
- &a2_mux_ctx->kickoff_ul_wakeup);
- return is_connected;
-}
-
-static bool msm_bam_dmux_kickoff_ul_power_down(void)
-
-{
- bool is_connected;
-
- read_lock(&a2_mux_ctx->ul_wakeup_lock);
- is_connected = a2_mux_ctx->bam_is_connected;
- read_unlock(&a2_mux_ctx->ul_wakeup_lock);
- if (is_connected)
- queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
- &a2_mux_ctx->kickoff_ul_power_down);
- return is_connected;
+ a2_mux_ctx->a2_mux_dl_wakeup = true;
+ complete_all(&a2_mux_ctx->dl_wakeup_completion);
}
static void ipa_embedded_notify(void *priv,
@@ -491,10 +536,6 @@
__func__);
return -EFAULT;
}
- ret = sps_device_reset(a2_mux_ctx->a2_device_handle);
- if (ret)
- IPAERR("%s: device reset failed ret = %d\n",
- __func__, ret);
memset(&connect_params, 0, sizeof(struct ipa_sys_connect_params));
connect_params.client = IPA_CLIENT_A2_TETHERED_CONS;
connect_params.notify = ipa_tethered_notify;
@@ -606,16 +647,11 @@
__func__, ret);
return ret;
}
- ret = sps_device_reset(a2_mux_ctx->a2_device_handle);
- if (ret) {
- IPAERR("%s: device reset failed ret = %d\n",
- __func__, ret);
- return ret;
- }
verify_tx_queue_is_empty(__func__);
(void) ipa_rm_release_resource(IPA_RM_RESOURCE_A2_PROD);
if (a2_mux_ctx->disconnect_ack)
toggle_apps_ack();
+ a2_mux_ctx->a2_mux_dl_wakeup = false;
a2_mux_ctx->a2_mux_sw_bridge_is_connected = 0;
complete_all(&a2_mux_ctx->bam_connection_completion);
return 0;
@@ -641,7 +677,7 @@
IPA_STATS_INC_CNT(ipa_ctx->stats.a2_power_on_reqs_in);
grab_wakelock();
(void) connect_to_bam();
- queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
+ queue_work(a2_mux_ctx->a2_mux_rx_workqueue,
&a2_mux_ctx->kickoff_ul_request_resource);
} else if (!(new_state & SMSM_A2_POWER_CONTROL)) {
IPADBG("%s: MODEM PWR CTRL 0\n", __func__);
@@ -936,7 +972,8 @@
}
spin_unlock_irqrestore(&a2_mux_ctx->bam_ch[id].lock, flags);
read_lock(&a2_mux_ctx->ul_wakeup_lock);
- is_connected = a2_mux_ctx->bam_is_connected;
+ is_connected = a2_mux_ctx->bam_is_connected &&
+ !a2_mux_ctx->bam_connect_in_progress;
read_unlock(&a2_mux_ctx->ul_wakeup_lock);
if (!is_connected)
return -ENODEV;
@@ -1240,7 +1277,8 @@
a2_mux_ctx->bam_ch[lcid].use_wm = 0;
spin_unlock_irqrestore(&a2_mux_ctx->bam_ch[lcid].lock, flags);
read_lock(&a2_mux_ctx->ul_wakeup_lock);
- is_connected = a2_mux_ctx->bam_is_connected;
+ is_connected = a2_mux_ctx->bam_is_connected &&
+ !a2_mux_ctx->bam_connect_in_progress;
read_unlock(&a2_mux_ctx->ul_wakeup_lock);
if (!is_connected)
return -ENODEV;
@@ -1309,7 +1347,8 @@
if (!a2_mux_ctx->a2_mux_initialized)
return -ENODEV;
read_lock(&a2_mux_ctx->ul_wakeup_lock);
- is_connected = a2_mux_ctx->bam_is_connected;
+ is_connected = a2_mux_ctx->bam_is_connected &&
+ !a2_mux_ctx->bam_connect_in_progress;
read_unlock(&a2_mux_ctx->ul_wakeup_lock);
if (!is_connected && !bam_ch_is_in_reset(lcid))
return -ENODEV;
@@ -1445,6 +1484,7 @@
init_completion(&a2_mux_ctx->ul_wakeup_ack_completion);
init_completion(&a2_mux_ctx->bam_connection_completion);
init_completion(&a2_mux_ctx->request_resource_completion);
+ init_completion(&a2_mux_ctx->dl_wakeup_completion);
wake_lock_init(&a2_mux_ctx->bam_wakelock,
WAKE_LOCK_SUSPEND, "a2_mux_wakelock");
a2_mux_ctx->a2_mux_initialized = 1;
@@ -1456,6 +1496,13 @@
__func__);
return -ENOMEM;
}
+ a2_mux_ctx->a2_mux_rx_workqueue =
+ create_singlethread_workqueue("a2_mux_rx");
+ if (!a2_mux_ctx->a2_mux_rx_workqueue) {
+ IPAERR("%s: a2_mux_rx_workqueue alloc failed\n",
+ __func__);
+ return -ENOMEM;
+ }
return 0;
}
@@ -1581,5 +1628,7 @@
NULL);
if (a2_mux_ctx->a2_mux_tx_workqueue)
destroy_workqueue(a2_mux_ctx->a2_mux_tx_workqueue);
+ if (a2_mux_ctx->a2_mux_rx_workqueue)
+ destroy_workqueue(a2_mux_ctx->a2_mux_rx_workqueue);
return 0;
}
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 466e694..35b2561 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -778,66 +778,6 @@
return ret;
}
-static int ipa_handle_tx_poll_for_pipe(struct ipa_sys_context *sys,
- bool process_all)
-{
- struct ipa_tx_pkt_wrapper *tx_pkt, *t;
- struct sps_iovec iov;
- unsigned long irq_flags;
- int ret;
- int cnt = 0;
-
- do {
- iov.addr = 0;
- ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
- if (ret) {
- pr_err("%s: sps_get_iovec failed %d\n", __func__, ret);
- break;
- }
- if (!iov.addr)
- break;
- spin_lock_irqsave(&sys->spinlock, irq_flags);
- tx_pkt = list_first_entry(&sys->head_desc_list,
- struct ipa_tx_pkt_wrapper, link);
- spin_unlock_irqrestore(&sys->spinlock, irq_flags);
-
- switch (tx_pkt->cnt) {
- case 1:
- ipa_wq_write_done(&tx_pkt->work);
- ++cnt;
- break;
- case 0xFFFF:
- /* reached end of set */
- spin_lock_irqsave(&sys->spinlock, irq_flags);
- list_for_each_entry_safe(tx_pkt, t,
- &sys->wait_desc_list, link) {
- list_del(&tx_pkt->link);
- list_add(&tx_pkt->link, &sys->head_desc_list);
- }
- tx_pkt =
- list_first_entry(&sys->head_desc_list,
- struct ipa_tx_pkt_wrapper, link);
- spin_unlock_irqrestore(&sys->spinlock, irq_flags);
- ipa_wq_write_done(&tx_pkt->work);
- ++cnt;
- break;
- default:
- /* keep looping till reach the end of the set */
- spin_lock_irqsave(&sys->spinlock,
- irq_flags);
- list_del(&tx_pkt->link);
- list_add_tail(&tx_pkt->link,
- &sys->wait_desc_list);
- spin_unlock_irqrestore(&sys->spinlock,
- irq_flags);
- ++cnt;
- break;
- }
- } while (process_all);
-
- return cnt;
-}
-
static void ipa_poll_function(struct work_struct *work)
{
int ret;
@@ -857,13 +797,15 @@
/* check all the system pipes for tx comp and rx avail */
if (ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep->valid)
- cnt |= ipa_handle_rx_core(false, true);
+ cnt |= ipa_handle_rx_core(
+ &ipa_ctx->sys[IPA_A5_LAN_WAN_IN],
+ false, true);
for (i = 0; i < num_tx_pipes; i++)
if (ipa_ctx->sys[tx_pipes[i]].ep->valid)
- cnt |= ipa_handle_tx_poll_for_pipe(
+ cnt |= ipa_handle_tx_core(
&ipa_ctx->sys[tx_pipes[i]],
- false);
+ false, true);
} while (cnt);
/* re-post the poll work */
@@ -1666,10 +1608,6 @@
IPADBG("polling_mode=%u delay_ms=%u\n", polling_mode, polling_delay_ms);
ipa_ctx->polling_mode = polling_mode;
- if (ipa_ctx->polling_mode)
- atomic_set(&ipa_ctx->curr_polling_state, 1);
- else
- atomic_set(&ipa_ctx->curr_polling_state, 0);
IPADBG("hdr_lcl=%u ip4_rt=%u ip6_rt=%u ip4_flt=%u ip6_flt=%u\n",
hdr_tbl_lcl, ip4_rt_tbl_lcl, ip6_rt_tbl_lcl, ip4_flt_tbl_lcl,
ip6_flt_tbl_lcl);
@@ -1891,7 +1829,10 @@
ipa_ctx->sys[i].ep = &ipa_ctx->ep[i];
else
ipa_ctx->sys[i].ep = &ipa_ctx->ep[WLAN_AMPDU_TX_EP];
- INIT_LIST_HEAD(&ipa_ctx->sys[i].wait_desc_list);
+ if (ipa_ctx->polling_mode)
+ atomic_set(&ipa_ctx->sys[i].curr_polling_state, 1);
+ else
+ atomic_set(&ipa_ctx->sys[i].curr_polling_state, 0);
}
ipa_ctx->rx_wq = create_singlethread_workqueue("ipa rx wq");
@@ -1901,7 +1842,8 @@
goto fail_rx_wq;
}
- ipa_ctx->tx_wq = create_singlethread_workqueue("ipa tx wq");
+ ipa_ctx->tx_wq = alloc_workqueue("ipa tx wq", WQ_MEM_RECLAIM |
+ WQ_CPU_INTENSIVE, 2);
if (!ipa_ctx->tx_wq) {
IPAERR(":fail to create tx wq\n");
result = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index a78879d..a95eafe 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -15,18 +15,14 @@
static void ipa_enable_data_path(u32 clnt_hdl)
{
- struct ipa_ep_context *ep = &ipa_ctx->ep[clnt_hdl];
-
if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_VIRTUAL) {
/* IPA_HW_MODE_VIRTUAL lacks support for TAG IC & EP suspend */
return;
}
- if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1 && ep->suspended) {
+ if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1)
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 0);
- ep->suspended = false;
- }
}
static int ipa_disable_data_path(u32 clnt_hdl)
@@ -50,7 +46,7 @@
goto fail_alloc;
}
- if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1 && !ep->suspended) {
+ if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1) {
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 1);
@@ -85,7 +81,6 @@
ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR &&
ep->cfg.aggr.aggr_time_limit)
msleep(ep->cfg.aggr.aggr_time_limit);
- ep->suspended = true;
}
return 0;
@@ -298,7 +293,9 @@
if (in->client == IPA_CLIENT_HSIC1_CONS ||
in->client == IPA_CLIENT_HSIC2_CONS ||
in->client == IPA_CLIENT_HSIC3_CONS ||
- in->client == IPA_CLIENT_HSIC4_CONS) {
+ in->client == IPA_CLIENT_HSIC4_CONS ||
+ in->client == IPA_CLIENT_A2_TETHERED_CONS ||
+ in->client == IPA_CLIENT_A2_EMBEDDED_CONS) {
IPADBG("disable holb for ep=%d tmr=%d\n", ipa_ep_idx,
ipa_ctx->hol_timer);
ipa_write_reg(ipa_ctx->mmio,
@@ -367,6 +364,11 @@
ep = &ipa_ctx->ep[clnt_hdl];
+ if (ep->suspended) {
+ ipa_inc_client_enable_clks();
+ ep->suspended = false;
+ }
+
result = ipa_disable_data_path(clnt_hdl);
if (result) {
IPAERR("disable data path failed res=%d clnt=%d.\n", result,
@@ -422,55 +424,79 @@
EXPORT_SYMBOL(ipa_disconnect);
/**
- * ipa_connection_suspend() - suspend B2B connection to/from IPA
+ * ipa_resume() - low-level IPA client resume
* @clnt_hdl: [in] opaque client handle assigned by IPA to client
*
- * Should be called by the driver of the peripheral that wants to suspend
- * its BAM-BAM connection to/from IPA in BAM-BAM mode. The pipe is not
- * disconnected and must later be resumed before data transfer can begin
+ * Should be called by the driver of the peripheral that wants to resume IPA
+ * connection. Resume IPA connection results in turning on IPA clocks in
+ * case they were off as a result of suspend.
+ * this api can be called only if a call to ipa_suspend() was
+ * made.
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
-int ipa_connection_suspend(u32 clnt_hdl)
+int ipa_resume(u32 clnt_hdl)
{
- int result;
+ struct ipa_ep_context *ep;
if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
- IPAERR("bad parm.\n");
- return -EINVAL;
- }
- result = ipa_disable_data_path(clnt_hdl);
- if (result)
- IPAERR("disable data path failed res=%d clnt=%d.\n", result,
- clnt_hdl);
-
- return result;
-}
-EXPORT_SYMBOL(ipa_connection_suspend);
-
-/**
- * ipa_connection_resume() - resume B2B connection to/from IPA
- * @clnt_hdl: [in] opaque client handle assigned by IPA to client
- *
- * Should be called by the driver of the peripheral that wants to resume
- * its previously suspended BAM-BAM connection to/from IPA in BAM-BAM mode.
- *
- * Returns: 0 on success, negative on failure
- *
- * Note: Should not be called from atomic context
- */
-int ipa_connection_resume(u32 clnt_hdl)
-{
- if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
- IPAERR("bad parm.\n");
+ IPAERR("bad parm. clnt_hdl %d\n", clnt_hdl);
return -EINVAL;
}
- ipa_enable_data_path(clnt_hdl);
+ ep = &ipa_ctx->ep[clnt_hdl];
+
+ if (!ep->suspended) {
+ IPAERR("EP not suspended. clnt_hdl %d\n", clnt_hdl);
+ return -EPERM;
+ }
+
+ ipa_inc_client_enable_clks();
+ ep->suspended = false;
return 0;
}
-EXPORT_SYMBOL(ipa_connection_resume);
+EXPORT_SYMBOL(ipa_resume);
+/**
+* ipa_suspend() - low-level IPA client suspend
+* @clnt_hdl: [in] opaque client handle assigned by IPA to client
+*
+* Should be called by the driver of the peripheral that wants to suspend IPA
+* connection. Suspend IPA connection results in turning off IPA clocks in
+* case that there is no active clients using IPA. Pipes remains connected in
+* case of suspend.
+*
+* Returns: 0 on success, negative on failure
+*
+* Note: Should not be called from atomic context
+*/
+int ipa_suspend(u32 clnt_hdl)
+{
+ struct ipa_ep_context *ep;
+
+ if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
+ IPAERR("bad parm. clnt_hdl %d\n", clnt_hdl);
+ return -EINVAL;
+ }
+
+ ep = &ipa_ctx->ep[clnt_hdl];
+
+ if (ep->suspended) {
+ IPAERR("EP already suspended. clnt_hdl %d\n", clnt_hdl);
+ return -EPERM;
+ }
+
+ if (IPA_CLIENT_IS_CONS(ep->client) &&
+ ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR &&
+ ep->cfg.aggr.aggr_time_limit)
+ msleep(ep->cfg.aggr.aggr_time_limit);
+
+ ipa_dec_client_disable_clks();
+ ep->suspended = true;
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_suspend);
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index fb69817..b11c7da 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -104,6 +104,7 @@
static struct dentry *dfile_stats;
static struct dentry *dfile_dbg_cnt;
static struct dentry *dfile_msg;
+static struct dentry *dfile_ip4_nat;
static char dbg_buff[IPA_MAX_MSG_LEN];
static s8 ep_reg_idx;
@@ -608,6 +609,7 @@
"rx=%u\n"
"rx_repl_repost=%u\n"
"x_intr_repost=%u\n"
+ "x_intr_repost_tx=%u\n"
"rx_q_len=%u\n"
"act_clnt=%u\n"
"con_clnt_bmap=0x%x\n"
@@ -622,6 +624,7 @@
ipa_ctx->stats.rx_pkts,
ipa_ctx->stats.rx_repl_repost,
ipa_ctx->stats.x_intr_repost,
+ ipa_ctx->stats.x_intr_repost_tx,
ipa_ctx->stats.rx_q_len,
ipa_ctx->ipa_active_clients,
connect,
@@ -720,6 +723,238 @@
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
+static ssize_t ipa_read_nat4(struct file *file,
+ char __user *ubuf, size_t count,
+ loff_t *ppos) {
+
+#define ENTRY_U32_FIELDS 8
+#define NAT_ENTRY_ENABLE 0x8000
+#define NAT_ENTRY_RST_FIN_BIT 0x4000
+#define BASE_TABLE 0
+#define EXPANSION_TABLE 1
+
+ u32 *base_tbl, *indx_tbl;
+ u32 tbl_size, *tmp;
+ u32 value, i, j, rule_id;
+ u16 enable, tbl_entry, flag;
+ int nbytes, cnt;
+
+ cnt = 0;
+ value = ipa_ctx->nat_mem.public_ip_addr;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Table IP Address:%d.%d.%d.%d\n",
+ ((value & 0xFF000000) >> 24),
+ ((value & 0x00FF0000) >> 16),
+ ((value & 0x0000FF00) >> 8),
+ ((value & 0x000000FF)));
+ cnt += nbytes;
+
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Table Size:%d\n",
+ ipa_ctx->nat_mem.size_base_tables);
+ cnt += nbytes;
+
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Expansion Table Size:%d\n",
+ ipa_ctx->nat_mem.size_expansion_tables);
+ cnt += nbytes;
+
+ if (!ipa_ctx->nat_mem.is_sys_mem) {
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Not supported for local(shared) memory\n");
+ cnt += nbytes;
+
+ return simple_read_from_buffer(ubuf, count,
+ ppos, dbg_buff, cnt);
+ }
+
+
+ /* Print Base tables */
+ rule_id = 0;
+ for (j = 0; j < 2; j++) {
+ if (j == BASE_TABLE) {
+ tbl_size = ipa_ctx->nat_mem.size_base_tables;
+ base_tbl = (u32 *)ipa_ctx->nat_mem.ipv4_rules_addr;
+
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+ "\nBase Table:\n");
+ cnt += nbytes;
+ } else {
+ tbl_size = ipa_ctx->nat_mem.size_expansion_tables;
+ base_tbl =
+ (u32 *)ipa_ctx->nat_mem.ipv4_expansion_rules_addr;
+
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+ "\nExpansion Base Table:\n");
+ cnt += nbytes;
+ }
+
+ if (base_tbl != NULL) {
+ for (i = 0; i <= tbl_size; i++, rule_id++) {
+ tmp = base_tbl;
+ value = tmp[4];
+ enable = ((value & 0xFFFF0000) >> 16);
+
+ if (enable & NAT_ENTRY_ENABLE) {
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Rule:%d ",
+ rule_id);
+ cnt += nbytes;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Private_IP:%d.%d.%d.%d ",
+ ((value & 0xFF000000) >> 24),
+ ((value & 0x00FF0000) >> 16),
+ ((value & 0x0000FF00) >> 8),
+ ((value & 0x000000FF)));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Target_IP:%d.%d.%d.%d ",
+ ((value & 0xFF000000) >> 24),
+ ((value & 0x00FF0000) >> 16),
+ ((value & 0x0000FF00) >> 8),
+ ((value & 0x000000FF)));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Next_Index:%d Public_Port:%d ",
+ (value & 0x0000FFFF),
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Private_Port:%d Target_Port:%d ",
+ (value & 0x0000FFFF),
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "IP-CKSM-delta:0x%x ",
+ (value & 0x0000FFFF));
+ cnt += nbytes;
+
+ flag = ((value & 0xFFFF0000) >> 16);
+ if (flag & NAT_ENTRY_RST_FIN_BIT) {
+ nbytes =
+ scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "IP_CKSM_delta:0x%x Flags:%s ",
+ (value & 0x0000FFFF),
+ "Direct_To_A5");
+ cnt += nbytes;
+ } else {
+ nbytes =
+ scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "IP_CKSM_delta:0x%x Flags:%s ",
+ (value & 0x0000FFFF),
+ "Fwd_to_route");
+ cnt += nbytes;
+ }
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Time_stamp:0x%x Proto:%d ",
+ (value & 0x00FFFFFF),
+ ((value & 0xFF000000) >> 27));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Prev_Index:%d Indx_tbl_entry:%d ",
+ (value & 0x0000FFFF),
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "TCP_UDP_cksum_delta:0x%x\n",
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ }
+
+ base_tbl += ENTRY_U32_FIELDS;
+
+ }
+ }
+ }
+
+ /* Print Index tables */
+ rule_id = 0;
+ for (j = 0; j < 2; j++) {
+ if (j == BASE_TABLE) {
+ tbl_size = ipa_ctx->nat_mem.size_base_tables;
+ indx_tbl = (u32 *)ipa_ctx->nat_mem.index_table_addr;
+
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+ "\nIndex Table:\n");
+ cnt += nbytes;
+ } else {
+ tbl_size = ipa_ctx->nat_mem.size_expansion_tables;
+ indx_tbl =
+ (u32 *)ipa_ctx->nat_mem.index_table_expansion_addr;
+
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+ "\nExpansion Index Table:\n");
+ cnt += nbytes;
+ }
+
+ if (indx_tbl != NULL) {
+ for (i = 0; i <= tbl_size; i++, rule_id++) {
+ tmp = indx_tbl;
+ value = *tmp;
+ tbl_entry = (value & 0x0000FFFF);
+
+ if (tbl_entry) {
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Rule:%d ",
+ rule_id);
+ cnt += nbytes;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Table_Entry:%d Next_Index:%d\n",
+ tbl_entry,
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ }
+
+ indx_tbl++;
+ }
+ }
+ }
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
+}
+
const struct file_operations ipa_gen_reg_ops = {
.read = ipa_read_gen_reg,
};
@@ -763,6 +998,10 @@
.write = ipa_write_dbg_cnt,
};
+const struct file_operations ipa_nat4_ops = {
+ .read = ipa_read_nat4,
+};
+
void ipa_debugfs_init(void)
{
const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
@@ -860,6 +1099,13 @@
goto fail;
}
+ dfile_ip4_nat = debugfs_create_file("ip4_nat", read_only_mode, dent,
+ 0, &ipa_nat4_ops);
+ if (!dfile_ip4_nat || IS_ERR(dfile_ip4_nat)) {
+ IPAERR("fail to create file for debug_fs ip4 nat\n");
+ goto fail;
+ }
+
return;
fail:
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 228c77fe..1b6181f 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -20,14 +20,15 @@
#define list_next_entry(pos, member) \
list_entry(pos->member.next, typeof(*pos), member)
#define IPA_LAST_DESC_CNT 0xFFFF
-#define POLLING_INACTIVITY 40
-#define POLLING_MIN_SLEEP 950
-#define POLLING_MAX_SLEEP 1050
+#define POLLING_INACTIVITY_RX 40
+#define POLLING_MIN_SLEEP_RX 950
+#define POLLING_MAX_SLEEP_RX 1050
+#define POLLING_INACTIVITY_TX 40
+#define POLLING_MIN_SLEEP_TX 400
+#define POLLING_MAX_SLEEP_TX 500
static void replenish_rx_work_func(struct work_struct *work);
static struct delayed_work replenish_rx_work;
-static void switch_to_intr_work_func(struct work_struct *work);
-static struct delayed_work switch_to_intr_work;
static void ipa_wq_handle_rx(struct work_struct *work);
static DECLARE_WORK(rx_work, ipa_wq_handle_rx);
@@ -47,57 +48,166 @@
void ipa_wq_write_done(struct work_struct *work)
{
struct ipa_tx_pkt_wrapper *tx_pkt;
- struct ipa_tx_pkt_wrapper *next_pkt;
struct ipa_tx_pkt_wrapper *tx_pkt_expected;
unsigned long irq_flags;
- struct ipa_mem_buffer mult = { 0 };
- int i;
- u32 cnt;
tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
- cnt = tx_pkt->cnt;
- IPADBG("cnt=%d\n", cnt);
- if (unlikely(cnt == 0))
+ if (unlikely(tx_pkt == NULL))
WARN_ON(1);
+ WARN_ON(tx_pkt->cnt != 1);
- if (cnt > 1 && cnt != IPA_LAST_DESC_CNT)
- mult = tx_pkt->mult;
+ spin_lock_irqsave(&tx_pkt->sys->spinlock, irq_flags);
+ tx_pkt_expected = list_first_entry(&tx_pkt->sys->head_desc_list,
+ struct ipa_tx_pkt_wrapper,
+ link);
+ if (unlikely(tx_pkt != tx_pkt_expected)) {
+ spin_unlock_irqrestore(&tx_pkt->sys->spinlock,
+ irq_flags);
+ WARN_ON(1);
+ }
+ list_del(&tx_pkt->link);
+ spin_unlock_irqrestore(&tx_pkt->sys->spinlock, irq_flags);
+ if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
+ dma_pool_free(ipa_ctx->dma_pool,
+ tx_pkt->bounce,
+ tx_pkt->mem.phys_base);
+ } else {
+ dma_unmap_single(NULL, tx_pkt->mem.phys_base,
+ tx_pkt->mem.size,
+ DMA_TO_DEVICE);
+ }
- for (i = 0; i < cnt; i++) {
- if (unlikely(tx_pkt == NULL))
- WARN_ON(1);
- spin_lock_irqsave(&tx_pkt->sys->spinlock, irq_flags);
- tx_pkt_expected = list_first_entry(&tx_pkt->sys->head_desc_list,
- struct ipa_tx_pkt_wrapper,
- link);
- if (unlikely(tx_pkt != tx_pkt_expected)) {
- spin_unlock_irqrestore(&tx_pkt->sys->spinlock,
- irq_flags);
- WARN_ON(1);
+ if (tx_pkt->callback)
+ tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
+
+ kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+}
+
+int ipa_handle_tx_core(struct ipa_sys_context *sys, bool process_all,
+ bool in_poll_state)
+{
+ struct ipa_tx_pkt_wrapper *tx_pkt;
+ struct sps_iovec iov;
+ int ret;
+ int cnt = 0;
+ unsigned long irq_flags;
+
+ while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
+ !atomic_read(&sys->curr_polling_state))) {
+ if (cnt && !process_all)
+ break;
+ ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
+ if (ret) {
+ IPAERR("sps_get_iovec failed %d\n", ret);
+ break;
}
- next_pkt = list_next_entry(tx_pkt, link);
+
+ if (iov.addr == 0)
+ break;
+
+ if (unlikely(list_empty(&sys->head_desc_list)))
+ continue;
+
+ spin_lock_irqsave(&sys->spinlock, irq_flags);
+ tx_pkt = list_first_entry(&sys->head_desc_list,
+ struct ipa_tx_pkt_wrapper, link);
+
+ sys->len--;
list_del(&tx_pkt->link);
- spin_unlock_irqrestore(&tx_pkt->sys->spinlock, irq_flags);
- if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
+ spin_unlock_irqrestore(&sys->spinlock, irq_flags);
+
+ IPADBG("--curr_cnt=%d\n", sys->len);
+
+ if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
dma_pool_free(ipa_ctx->dma_pool,
tx_pkt->bounce,
tx_pkt->mem.phys_base);
- } else {
+ else
dma_unmap_single(NULL, tx_pkt->mem.phys_base,
tx_pkt->mem.size,
DMA_TO_DEVICE);
- }
if (tx_pkt->callback)
tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
+ if (tx_pkt->cnt > 1 && tx_pkt->cnt != IPA_LAST_DESC_CNT)
+ dma_pool_free(ipa_ctx->dma_pool, tx_pkt->mult.base,
+ tx_pkt->mult.phys_base);
+
kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
- tx_pkt = next_pkt;
+ cnt++;
+ };
+
+ return cnt;
+}
+
+/**
+ * ipa_tx_switch_to_intr_mode() - Operate the Tx data path in interrupt mode
+ */
+static void ipa_tx_switch_to_intr_mode(struct ipa_sys_context *sys)
+{
+ int ret;
+
+ if (!atomic_read(&sys->curr_polling_state)) {
+ IPAERR("already in intr mode\n");
+ goto fail;
}
- if (mult.phys_base)
- dma_pool_free(ipa_ctx->dma_pool, mult.base, mult.phys_base);
+ ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_get_config() failed %d\n", ret);
+ goto fail;
+ }
+ sys->event.options = SPS_O_EOT;
+ ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
+ if (ret) {
+ IPAERR("sps_register_event() failed %d\n", ret);
+ goto fail;
+ }
+ sys->ep->connect.options =
+ SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_EOT;
+ ret = sps_set_config(sys->ep->ep_hdl, &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_set_config() failed %d\n", ret);
+ goto fail;
+ }
+ atomic_set(&sys->curr_polling_state, 0);
+ ipa_handle_tx_core(sys, true, false);
+ return;
+
+fail:
+ IPA_STATS_INC_CNT(ipa_ctx->stats.x_intr_repost_tx);
+ schedule_delayed_work(&sys->switch_to_intr_work, msecs_to_jiffies(1));
+ return;
+}
+
+static void ipa_handle_tx(struct ipa_sys_context *sys)
+{
+ int inactive_cycles = 0;
+ int cnt;
+
+ ipa_inc_client_enable_clks();
+ do {
+ cnt = ipa_handle_tx_core(sys, true, true);
+ if (cnt == 0) {
+ inactive_cycles++;
+ usleep_range(POLLING_MIN_SLEEP_TX,
+ POLLING_MAX_SLEEP_TX);
+ } else {
+ inactive_cycles = 0;
+ }
+ } while (inactive_cycles <= POLLING_INACTIVITY_TX);
+
+ ipa_tx_switch_to_intr_mode(sys);
+ ipa_dec_client_disable_clks();
+}
+
+static void ipa_wq_handle_tx(struct work_struct *work)
+{
+ struct ipa_tx_pkt_wrapper *tx_pkt;
+ tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
+ ipa_handle_tx(tx_pkt->sys);
}
/**
@@ -122,7 +232,7 @@
struct ipa_tx_pkt_wrapper *tx_pkt;
unsigned long irq_flags;
int result;
- u16 sps_flags = SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT;
+ u16 sps_flags = SPS_IOVEC_FLAG_EOT;
dma_addr_t dma_address;
u16 len;
u32 mem_flag = GFP_ATOMIC;
@@ -165,7 +275,6 @@
}
INIT_LIST_HEAD(&tx_pkt->link);
- INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
tx_pkt->type = desc->type;
tx_pkt->cnt = 1; /* only 1 desc in this "set" */
@@ -187,10 +296,15 @@
IPADBG("sending cmd=%d pyld_len=%d sps_flags=%x\n",
desc->opcode, desc->len, sps_flags);
IPA_DUMP_BUFF(desc->pyld, dma_address, desc->len);
+ INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
} else {
len = desc->len;
+ INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
}
+ if (unlikely(ipa_ctx->polling_mode))
+ INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
+
spin_lock_irqsave(&sys->spinlock, irq_flags);
list_add_tail(&tx_pkt->link, &sys->head_desc_list);
result = sps_transfer_one(sys->ep->ep_hdl, dma_address, len, tx_pkt,
@@ -286,7 +400,7 @@
tx_pkt->mult.base = transfer.iovec;
tx_pkt->mult.size = size;
tx_pkt->cnt = num_desc;
- INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
+ INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
}
iovec = &transfer.iovec[i];
@@ -355,8 +469,7 @@
}
if (i == (num_desc - 1)) {
- iovec->flags |= (SPS_IOVEC_FLAG_EOT |
- SPS_IOVEC_FLAG_INT);
+ iovec->flags |= SPS_IOVEC_FLAG_EOT;
/* "mark" the last desc */
tx_pkt->cnt = IPA_LAST_DESC_CNT;
}
@@ -475,6 +588,49 @@
/**
* ipa_sps_irq_tx_notify() - Callback function which will be called by
+ * the SPS driver to start a Tx poll operation.
+ * Called in an interrupt context.
+ * @notify: SPS driver supplied notification struct
+ *
+ * This function defer the work for this event to the tx workqueue.
+ */
+static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
+{
+ struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT];
+ struct ipa_tx_pkt_wrapper *tx_pkt;
+ int ret;
+
+ IPADBG("event %d notified\n", notify->event_id);
+
+ switch (notify->event_id) {
+ case SPS_EVENT_EOT:
+ tx_pkt = notify->data.transfer.user;
+ if (!atomic_read(&sys->curr_polling_state)) {
+ ret = sps_get_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_get_config() failed %d\n", ret);
+ break;
+ }
+ sys->ep->connect.options = SPS_O_AUTO_ENABLE |
+ SPS_O_ACK_TRANSFERS | SPS_O_POLL;
+ ret = sps_set_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_set_config() failed %d\n", ret);
+ break;
+ }
+ atomic_set(&sys->curr_polling_state, 1);
+ queue_work(ipa_ctx->tx_wq, &tx_pkt->work);
+ }
+ break;
+ default:
+ IPAERR("recieved unexpected event id %d\n", notify->event_id);
+ }
+}
+
+/**
+ * ipa_sps_irq_tx_no_aggr_notify() - Callback function which will be called by
* the SPS driver after a Tx operation is complete.
* Called in an interrupt context.
* @notify: SPS driver supplied notification struct
@@ -482,7 +638,7 @@
* This function defer the work for this event to the tx workqueue.
* This event will be later handled by ipa_write_done.
*/
-static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
+static void ipa_sps_irq_tx_no_aggr_notify(struct sps_event_notify *notify)
{
struct ipa_tx_pkt_wrapper *tx_pkt;
@@ -512,7 +668,8 @@
* - Call the endpoints notify function, passing the skb in the parameters
* - Replenish the rx cache
*/
-int ipa_handle_rx_core(bool process_all, bool in_poll_state)
+int ipa_handle_rx_core(struct ipa_sys_context *sys, bool process_all,
+ bool in_poll_state)
{
struct ipa_a5_mux_hdr *mux_hdr;
struct ipa_rx_pkt_wrapper *rx_pkt;
@@ -521,15 +678,14 @@
unsigned int pull_len;
unsigned int padding;
int ret;
- struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
struct ipa_ep_context *ep;
int cnt = 0;
struct completion *compl;
struct ipa_tree_node *node;
unsigned int src_pipe;
- while ((in_poll_state ? atomic_read(&ipa_ctx->curr_polling_state) :
- !atomic_read(&ipa_ctx->curr_polling_state))) {
+ while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
+ !atomic_read(&sys->curr_polling_state))) {
if (cnt && !process_all)
break;
@@ -654,19 +810,15 @@
/**
* ipa_rx_switch_to_intr_mode() - Operate the Rx data path in interrupt mode
*/
-static void ipa_rx_switch_to_intr_mode(void)
+static void ipa_rx_switch_to_intr_mode(struct ipa_sys_context *sys)
{
int ret;
- struct ipa_sys_context *sys;
- IPADBG("Enter");
- if (!atomic_read(&ipa_ctx->curr_polling_state)) {
+ if (!atomic_read(&sys->curr_polling_state)) {
IPAERR("already in intr mode\n");
goto fail;
}
- sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
-
ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
if (ret) {
IPAERR("sps_get_config() failed %d\n", ret);
@@ -685,15 +837,16 @@
IPAERR("sps_set_config() failed %d\n", ret);
goto fail;
}
- atomic_set(&ipa_ctx->curr_polling_state, 0);
- ipa_handle_rx_core(true, false);
+ atomic_set(&sys->curr_polling_state, 0);
+ ipa_handle_rx_core(sys, true, false);
return;
fail:
IPA_STATS_INC_CNT(ipa_ctx->stats.x_intr_repost);
- schedule_delayed_work(&switch_to_intr_work, msecs_to_jiffies(1));
+ schedule_delayed_work(&sys->switch_to_intr_work, msecs_to_jiffies(1));
}
+
/**
* ipa_rx_notify() - Callback function which is called by the SPS driver when a
* a packet is received
@@ -709,29 +862,29 @@
*/
static void ipa_sps_irq_rx_notify(struct sps_event_notify *notify)
{
- struct ipa_ep_context *ep;
+ struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
int ret;
IPADBG("event %d notified\n", notify->event_id);
switch (notify->event_id) {
case SPS_EVENT_EOT:
- if (!atomic_read(&ipa_ctx->curr_polling_state)) {
- ep = ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep;
-
- ret = sps_get_config(ep->ep_hdl, &ep->connect);
+ if (!atomic_read(&sys->curr_polling_state)) {
+ ret = sps_get_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
if (ret) {
IPAERR("sps_get_config() failed %d\n", ret);
break;
}
- ep->connect.options = SPS_O_AUTO_ENABLE |
+ sys->ep->connect.options = SPS_O_AUTO_ENABLE |
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
- ret = sps_set_config(ep->ep_hdl, &ep->connect);
+ ret = sps_set_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
if (ret) {
IPAERR("sps_set_config() failed %d\n", ret);
break;
}
- atomic_set(&ipa_ctx->curr_polling_state, 1);
+ atomic_set(&sys->curr_polling_state, 1);
queue_work(ipa_ctx->rx_wq, &rx_work);
}
break;
@@ -740,6 +893,53 @@
}
}
+static void switch_to_intr_tx_work_func(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct ipa_sys_context *sys;
+ dwork = container_of(work, struct delayed_work, work);
+ sys = container_of(dwork, struct ipa_sys_context, switch_to_intr_work);
+ ipa_handle_tx(sys);
+}
+
+/**
+ * ipa_handle_rx() - handle packet reception. This function is executed in the
+ * context of a work queue.
+ * @work: work struct needed by the work queue
+ *
+ * ipa_handle_rx_core() is run in polling mode. After all packets has been
+ * received, the driver switches back to interrupt mode.
+ */
+static void ipa_handle_rx(struct ipa_sys_context *sys)
+{
+ int inactive_cycles = 0;
+ int cnt;
+
+ ipa_inc_client_enable_clks();
+ do {
+ cnt = ipa_handle_rx_core(sys, true, true);
+ if (cnt == 0) {
+ inactive_cycles++;
+ usleep_range(POLLING_MIN_SLEEP_RX,
+ POLLING_MAX_SLEEP_RX);
+ } else {
+ inactive_cycles = 0;
+ }
+ } while (inactive_cycles <= POLLING_INACTIVITY_RX);
+
+ ipa_rx_switch_to_intr_mode(sys);
+ ipa_dec_client_disable_clks();
+}
+
+static void switch_to_intr_rx_work_func(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct ipa_sys_context *sys;
+ dwork = container_of(work, struct delayed_work, work);
+ sys = container_of(dwork, struct ipa_sys_context, switch_to_intr_work);
+ ipa_handle_rx(sys);
+}
+
/**
* ipa_setup_sys_pipe() - Setup an IPA end-point in system-BAM mode and perform
* IPA EP configuration
@@ -817,11 +1017,8 @@
ipa_ctx->ep[ipa_ep_idx].connect.dest_pipe_index =
ipa_ctx->a5_pipe_index++;
ipa_ctx->ep[ipa_ep_idx].connect.src_pipe_index = ipa_ep_idx;
- ipa_ctx->ep[ipa_ep_idx].connect.options =
- SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS |
+ ipa_ctx->ep[ipa_ep_idx].connect.options = SPS_O_ACK_TRANSFERS |
SPS_O_NO_DISABLE;
- if (ipa_ctx->polling_mode)
- ipa_ctx->ep[ipa_ep_idx].connect.options |= SPS_O_POLL;
} else {
ipa_ctx->ep[ipa_ep_idx].connect.mode = SPS_MODE_DEST;
ipa_ctx->ep[ipa_ep_idx].connect.source = SPS_DEV_HANDLE_MEM;
@@ -830,13 +1027,16 @@
ipa_ctx->ep[ipa_ep_idx].connect.src_pipe_index =
ipa_ctx->a5_pipe_index++;
ipa_ctx->ep[ipa_ep_idx].connect.dest_pipe_index = ipa_ep_idx;
- ipa_ctx->ep[ipa_ep_idx].connect.options =
- SPS_O_AUTO_ENABLE | SPS_O_EOT;
- if (ipa_ctx->polling_mode)
+ if (sys_in->client == IPA_CLIENT_A5_LAN_WAN_PROD)
ipa_ctx->ep[ipa_ep_idx].connect.options |=
- SPS_O_ACK_TRANSFERS | SPS_O_POLL;
+ SPS_O_ACK_TRANSFERS;
}
+ ipa_ctx->ep[ipa_ep_idx].connect.options |= (SPS_O_AUTO_ENABLE |
+ SPS_O_EOT);
+ if (ipa_ctx->polling_mode)
+ ipa_ctx->ep[ipa_ep_idx].connect.options |= SPS_O_POLL;
+
ipa_ctx->ep[ipa_ep_idx].connect.desc.size = sys_in->desc_fifo_sz;
ipa_ctx->ep[ipa_ep_idx].connect.desc.base =
dma_alloc_coherent(NULL, ipa_ctx->ep[ipa_ep_idx].connect.desc.size,
@@ -858,14 +1058,18 @@
switch (ipa_ep_idx) {
case 1:
- /* fall through */
+ sys_idx = ipa_ep_idx;
+ break;
case 2:
- /* fall through */
+ sys_idx = ipa_ep_idx;
+ INIT_DELAYED_WORK(&ipa_ctx->sys[sys_idx].switch_to_intr_work,
+ switch_to_intr_tx_work_func);
+ break;
case 3:
sys_idx = ipa_ep_idx;
INIT_DELAYED_WORK(&replenish_rx_work, replenish_rx_work_func);
- INIT_DELAYED_WORK(&switch_to_intr_work,
- switch_to_intr_work_func);
+ INIT_DELAYED_WORK(&ipa_ctx->sys[sys_idx].switch_to_intr_work,
+ switch_to_intr_rx_work_func);
break;
case WLAN_AMPDU_TX_EP:
sys_idx = IPA_A5_WLAN_AMPDU_OUT;
@@ -886,7 +1090,10 @@
ipa_ctx->sys[sys_idx].event.callback =
IPA_CLIENT_IS_CONS(sys_in->client) ?
ipa_sps_irq_rx_notify :
- ipa_sps_irq_tx_notify;
+ (sys_in->client ==
+ IPA_CLIENT_A5_LAN_WAN_PROD ?
+ ipa_sps_irq_tx_notify :
+ ipa_sps_irq_tx_no_aggr_notify);
result = sps_register_event(ipa_ctx->ep[ipa_ep_idx].ep_hdl,
&ipa_ctx->sys[sys_idx].event);
if (result < 0) {
@@ -1078,37 +1285,9 @@
}
EXPORT_SYMBOL(ipa_tx_dp);
-static void ipa_handle_rx(void)
-{
- int inactive_cycles = 0;
- int cnt;
-
- ipa_inc_client_enable_clks();
- do {
- cnt = ipa_handle_rx_core(true, true);
- if (cnt == 0) {
- inactive_cycles++;
- usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
- } else {
- inactive_cycles = 0;
- }
- } while (inactive_cycles <= POLLING_INACTIVITY);
-
- ipa_rx_switch_to_intr_mode();
- ipa_dec_client_disable_clks();
-}
-
-/**
- * ipa_handle_rx() - handle packet reception. This function is executed in the
- * context of a work queue.
- * @work: work struct needed by the work queue
- *
- * ipa_handle_rx_core() is run in polling mode. After all packets has been
- * received, the driver switches back to interrupt mode.
- */
static void ipa_wq_handle_rx(struct work_struct *work)
{
- ipa_handle_rx();
+ ipa_handle_rx(&ipa_ctx->sys[IPA_A5_LAN_WAN_IN]);
}
/**
@@ -1166,7 +1345,7 @@
ret = sps_transfer_one(sys->ep->ep_hdl, rx_pkt->dma_address,
IPA_RX_SKB_SIZE, rx_pkt,
- SPS_IOVEC_FLAG_INT);
+ 0);
if (ret) {
IPAERR("sps_transfer_one failed %d\n", ret);
@@ -1202,11 +1381,6 @@
ipa_replenish_rx_cache();
}
-static void switch_to_intr_work_func(struct work_struct *work)
-{
- ipa_handle_rx();
-}
-
/**
* ipa_cleanup_rx() - release RX queue resources
*
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index cc3e630..b57194e 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -372,7 +372,6 @@
* @spinlock: protects the list and its size
* @event: used to request CALLBACK mode from SPS driver
* @ep: IPA EP context
- * @wait_desc_list: used to hold completed Tx packets
*
* IPA context specific to the system-bam pipes a.k.a LAN IN/OUT and WAN
*/
@@ -382,7 +381,8 @@
spinlock_t spinlock;
struct sps_register_event event;
struct ipa_ep_context *ep;
- struct list_head wait_desc_list;
+ atomic_t curr_polling_state;
+ struct delayed_work switch_to_intr_work;
};
/**
@@ -479,6 +479,14 @@
* @is_sys_mem: flag indicating if NAT memory is sys memory
* @is_dev_init: flag indicating if NAT device is initialized
* @lock: NAT memory mutex
+ * @nat_base_address: nat table virutal address
+ * @ipv4_rules_addr: base nat table address
+ * @ipv4_expansion_rules_addr: expansion table address
+ * @index_table_addr: index table address
+ * @index_table_expansion_addr: index expansion table address
+ * @size_base_tables: base table size
+ * @size_expansion_tables: expansion table size
+ * @public_ip_addr: ip address of nat table
*/
struct ipa_nat_mem {
struct class *class;
@@ -492,6 +500,14 @@
bool is_sys_mem;
bool is_dev_init;
struct mutex lock;
+ void *nat_base_address;
+ char *ipv4_rules_addr;
+ char *ipv4_expansion_rules_addr;
+ char *index_table_addr;
+ char *index_table_expansion_addr;
+ u32 size_base_tables;
+ u32 size_expansion_tables;
+ u32 public_ip_addr;
};
/**
@@ -530,6 +546,7 @@
u32 bridged_pkts[IPA_BRIDGE_TYPE_MAX][IPA_BRIDGE_DIR_MAX];
u32 rx_repl_repost;
u32 x_intr_repost;
+ u32 x_intr_repost_tx;
u32 rx_q_len;
u32 msg_w[IPA_EVENT_MAX];
u32 msg_r[IPA_EVENT_MAX];
@@ -641,7 +658,6 @@
uint aggregation_type;
uint aggregation_byte_limit;
uint aggregation_time_limit;
- atomic_t curr_polling_state;
struct delayed_work poll_work;
bool hdr_tbl_lcl;
struct ipa_mem_buffer hdr_mem;
@@ -800,7 +816,10 @@
void ipa_cleanup_rx(void);
int ipa_cfg_filter(u32 disable);
void ipa_wq_write_done(struct work_struct *work);
-int ipa_handle_rx_core(bool process_all, bool in_poll_state);
+int ipa_handle_rx_core(struct ipa_sys_context *sys, bool process_all,
+ bool in_poll_state);
+int ipa_handle_tx_core(struct ipa_sys_context *sys, bool process_all,
+ bool in_poll_state);
int ipa_pipe_mem_init(u32 start_ofst, u32 size);
int ipa_pipe_mem_alloc(u32 *ofst, u32 size);
int ipa_pipe_mem_free(u32 ofst, u32 size);
diff --git a/drivers/platform/msm/ipa/ipa_nat.c b/drivers/platform/msm/ipa/ipa_nat.c
index befa2cf..e2c344f 100644
--- a/drivers/platform/msm/ipa/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_nat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -75,6 +75,7 @@
IPAERR("unable to map memory. Err:%d\n", result);
goto bail;
}
+ ipa_ctx->nat_mem.nat_base_address = nat_ctx->vaddr;
} else {
IPADBG("Mapping shared(local) memory\n");
IPADBG("map sz=0x%lx\n", vsize);
@@ -88,7 +89,7 @@
result = -EAGAIN;
goto bail;
}
-
+ ipa_ctx->nat_mem.nat_base_address = (void *)vma->vm_start;
}
nat_ctx->is_mapped = true;
vma->vm_ops = &ipa_nat_remap_vm_ops;
@@ -299,6 +300,35 @@
goto free_cmd;
}
+ ipa_ctx->nat_mem.public_ip_addr = init->ip_addr;
+ IPADBG("Table ip address:0x%x", ipa_ctx->nat_mem.public_ip_addr);
+
+ ipa_ctx->nat_mem.ipv4_rules_addr =
+ (char *)ipa_ctx->nat_mem.nat_base_address + init->ipv4_rules_offset;
+ IPADBG("ipv4_rules_addr: 0x%p\n",
+ ipa_ctx->nat_mem.ipv4_rules_addr);
+
+ ipa_ctx->nat_mem.ipv4_expansion_rules_addr =
+ (char *)ipa_ctx->nat_mem.nat_base_address + init->expn_rules_offset;
+ IPADBG("ipv4_expansion_rules_addr: 0x%p\n",
+ ipa_ctx->nat_mem.ipv4_expansion_rules_addr);
+
+ ipa_ctx->nat_mem.index_table_addr =
+ (char *)ipa_ctx->nat_mem.nat_base_address + init->index_offset;
+ IPADBG("index_table_addr: 0x%p\n",
+ ipa_ctx->nat_mem.index_table_addr);
+
+ ipa_ctx->nat_mem.index_table_expansion_addr =
+ (char *)ipa_ctx->nat_mem.nat_base_address + init->index_expn_offset;
+ IPADBG("index_table_expansion_addr: 0x%p\n",
+ ipa_ctx->nat_mem.index_table_expansion_addr);
+
+ IPADBG("size_base_tables: %d\n", init->table_entries);
+ ipa_ctx->nat_mem.size_base_tables = init->table_entries;
+
+ IPADBG("size_expansion_tables: %d\n", init->expn_table_entries);
+ ipa_ctx->nat_mem.size_expansion_tables = init->expn_table_entries;
+
IPADBG("return\n");
result = 0;
free_cmd:
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index 1fdd300..88a49c4 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -21,6 +21,7 @@
struct ipa_rm_context_type {
struct ipa_rm_dep_graph *dep_graph;
struct workqueue_struct *ipa_rm_wq;
+ rwlock_t lock;
};
static struct ipa_rm_context_type *ipa_rm_ctx;
@@ -41,10 +42,9 @@
struct ipa_rm_resource *resource;
int result;
- if (!create_params) {
- result = -EINVAL;
- goto bail;
- }
+ if (!create_params)
+ return -EINVAL;
+ write_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
create_params->name,
&resource) == 0) {
@@ -59,11 +59,51 @@
if (result)
ipa_rm_resource_delete(resource);
bail:
+ write_unlock(&ipa_rm_ctx->lock);
return result;
}
EXPORT_SYMBOL(ipa_rm_create_resource);
/**
+ * ipa_rm_delete_resource() - delete resource
+ * @resource_name: name of resource to be deleted
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * This function is called by IPA RM client to delete client's resources.
+ *
+ */
+int ipa_rm_delete_resource(enum ipa_rm_resource_name resource_name)
+{
+ struct ipa_rm_resource *resource;
+ int result;
+
+ IPADBG("IPA RM ::ipa_rm_delete_resource num[%d] ENTER\n",
+ resource_name);
+ write_lock(&ipa_rm_ctx->lock);
+ if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+ resource_name,
+ &resource) != 0) {
+ IPADBG("ipa_rm_delete_resource param are bad********\n");
+ result = -EINVAL;
+ goto bail;
+ }
+ result = ipa_rm_resource_delete(resource);
+ if (result) {
+ IPADBG("error in ipa_rm_resource_delete\n");
+ goto bail;
+ }
+ result = ipa_rm_dep_graph_remove(ipa_rm_ctx->dep_graph,
+ resource_name);
+ IPADBG("IPA RM ::ipa_rm_delete_resource [%d] SUCCESS\n",
+ resource_name);
+bail:
+ write_unlock(&ipa_rm_ctx->lock);
+ return result;
+}
+EXPORT_SYMBOL(ipa_rm_delete_resource);
+
+/**
* ipa_rm_add_dependency() - create dependency
* between 2 resources
* @resource_name: name of dependent resource
@@ -77,13 +117,19 @@
int ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_name depends_on_name)
{
- return ipa_rm_dep_graph_add_dependency(
- ipa_rm_ctx->dep_graph,
- resource_name,
- depends_on_name);
+ int result;
+
+ read_lock(&ipa_rm_ctx->lock);
+ result = ipa_rm_dep_graph_add_dependency(
+ ipa_rm_ctx->dep_graph,
+ resource_name,
+ depends_on_name);
+ read_unlock(&ipa_rm_ctx->lock);
+ return result;
}
EXPORT_SYMBOL(ipa_rm_add_dependency);
+
/**
* ipa_rm_delete_dependency() - create dependency
* between 2 resources
@@ -98,10 +144,14 @@
int ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_name depends_on_name)
{
- return ipa_rm_dep_graph_delete_dependency(
- ipa_rm_ctx->dep_graph,
- resource_name,
- depends_on_name);
+ int result;
+ read_lock(&ipa_rm_ctx->lock);
+ result = ipa_rm_dep_graph_delete_dependency(
+ ipa_rm_ctx->dep_graph,
+ resource_name,
+ depends_on_name);
+ read_unlock(&ipa_rm_ctx->lock);
+ return result;
}
EXPORT_SYMBOL(ipa_rm_delete_dependency);
@@ -120,10 +170,9 @@
int result;
IPADBG("IPA RM ::ipa_rm_request_resource ENTER\n");
- if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
- result = -EINVAL;
- goto bail;
- }
+ if (!IPA_RM_RESORCE_IS_PROD(resource_name))
+ return -EINVAL;
+ read_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
resource_name,
&resource) != 0) {
@@ -136,6 +185,7 @@
bail:
IPADBG("IPA RM ::ipa_rm_request_resource EXIT [%d]\n", result);
+ read_unlock(&ipa_rm_ctx->lock);
return result;
}
EXPORT_SYMBOL(ipa_rm_request_resource);
@@ -155,10 +205,9 @@
int result;
IPADBG("IPA RM ::ipa_rm_release_resource ENTER\n");
- if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
- result = -EINVAL;
- goto bail;
- }
+ if (!IPA_RM_RESORCE_IS_PROD(resource_name))
+ return -EINVAL;
+ read_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
resource_name,
&resource) != 0) {
@@ -170,6 +219,7 @@
bail:
IPADBG("IPA RM ::ipa_rm_release_resource EXIT [%d]\n", result);
+ read_unlock(&ipa_rm_ctx->lock);
return result;
}
EXPORT_SYMBOL(ipa_rm_release_resource);
@@ -189,10 +239,10 @@
{
int result;
struct ipa_rm_resource *resource;
- if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
- result = -EINVAL;
- goto bail;
- }
+
+ if (!IPA_RM_RESORCE_IS_PROD(resource_name))
+ return -EINVAL;
+ read_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
resource_name,
&resource) != 0) {
@@ -203,6 +253,7 @@
(struct ipa_rm_resource_prod *)resource,
reg_params);
bail:
+ read_unlock(&ipa_rm_ctx->lock);
return result;
}
EXPORT_SYMBOL(ipa_rm_register);
@@ -222,10 +273,10 @@
{
int result;
struct ipa_rm_resource *resource;
- if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
- result = -EINVAL;
- goto bail;
- }
+
+ if (!IPA_RM_RESORCE_IS_PROD(resource_name))
+ return -EINVAL;
+ read_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
resource_name,
&resource) != 0) {
@@ -236,6 +287,7 @@
(struct ipa_rm_resource_prod *)resource,
reg_params);
bail:
+ read_unlock(&ipa_rm_ctx->lock);
return result;
}
EXPORT_SYMBOL(ipa_rm_deregister);
@@ -278,25 +330,32 @@
case IPA_RM_WQ_NOTIFY_PROD:
if (!IPA_RM_RESORCE_IS_PROD(ipa_rm_work->resource_name))
return;
+ read_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
ipa_rm_work->resource_name,
- &resource) != 0)
+ &resource) != 0){
+ read_unlock(&ipa_rm_ctx->lock);
return;
+ }
ipa_rm_resource_producer_notify_clients(
(struct ipa_rm_resource_prod *)resource,
ipa_rm_work->event);
-
+ read_unlock(&ipa_rm_ctx->lock);
break;
case IPA_RM_WQ_NOTIFY_CONS:
break;
case IPA_RM_WQ_RESOURCE_CB:
+ read_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
ipa_rm_work->resource_name,
- &resource) != 0)
+ &resource) != 0){
+ read_unlock(&ipa_rm_ctx->lock);
return;
+ }
ipa_rm_resource_consumer_handle_cb(
(struct ipa_rm_resource_cons *)resource,
ipa_rm_work->event);
+ read_unlock(&ipa_rm_ctx->lock);
break;
default:
break;
@@ -351,6 +410,7 @@
result = ipa_rm_dep_graph_create(&(ipa_rm_ctx->dep_graph));
if (result)
goto graph_alloc_fail;
+ rwlock_init(&ipa_rm_ctx->lock);
IPADBG("IPA RM ipa_rm_initialize SUCCESS\n");
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
index 6afab42..8144a42 100644
--- a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
+++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
@@ -39,7 +39,6 @@
result = -ENOMEM;
goto bail;
}
- rwlock_init(&((*dep_graph)->lock));
bail:
return result;
}
@@ -55,12 +54,10 @@
int resource_index;
if (!graph)
return;
- write_lock(&graph->lock);
for (resource_index = 0;
resource_index < IPA_RM_RESOURCE_MAX;
resource_index++)
kfree(graph->resource_table[resource_index]);
- write_unlock(&graph->lock);
memset(graph->resource_table, 0, sizeof(graph->resource_table));
}
@@ -88,9 +85,7 @@
result = -EINVAL;
goto bail;
}
- read_lock(&graph->lock);
*resource = graph->resource_table[resource_index];
- read_unlock(&graph->lock);
if (!*resource) {
result = -EINVAL;
goto bail;
@@ -112,6 +107,7 @@
{
int result = 0;
int resource_index;
+
if (!graph || !resource) {
result = -EINVAL;
goto bail;
@@ -121,14 +117,29 @@
result = -EINVAL;
goto bail;
}
- write_lock(&graph->lock);
graph->resource_table[resource_index] = resource;
- write_unlock(&graph->lock);
bail:
return result;
}
/**
+ * ipa_rm_dep_graph_remove() - removes resource from graph
+ * @graph: [in] dependency graph
+ * @resource: [in] resource to add
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_dep_graph_remove(struct ipa_rm_dep_graph *graph,
+ enum ipa_rm_resource_name resource_name)
+{
+ if (!graph)
+ return -EINVAL;
+
+ graph->resource_table[resource_name] = NULL;
+ return 0;
+}
+
+/**
* ipa_rm_dep_graph_add_dependency() - adds dependency between
* two nodes in graph
* @graph: [in] dependency graph
diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
index 19d9461..4126819 100644
--- a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
+++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
@@ -19,7 +19,6 @@
struct ipa_rm_dep_graph {
struct ipa_rm_resource *resource_table[IPA_RM_RESOURCE_MAX];
- rwlock_t lock;
};
int ipa_rm_dep_graph_get_resource(
@@ -34,6 +33,9 @@
int ipa_rm_dep_graph_add(struct ipa_rm_dep_graph *graph,
struct ipa_rm_resource *resource);
+int ipa_rm_dep_graph_remove(struct ipa_rm_dep_graph *graph,
+ enum ipa_rm_resource_name resource_name);
+
int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph,
enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_name depends_on_name);
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 3615952..8655d89 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -80,8 +80,8 @@
int result = 0;
int driver_result;
unsigned long flags;
- IPADBG("IPA RM ::ipa_rm_resource_consumer_request %d ENTER\n",
- consumer->resource.name);
+ IPADBG("IPA RM ::%s name %d ENTER\n",
+ __func__, consumer->resource.name);
spin_lock_irqsave(&consumer->resource.state_lock, flags);
switch (consumer->resource.state) {
case IPA_RM_RELEASED:
@@ -115,8 +115,7 @@
consumer->usage_count++;
bail:
spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
- IPADBG("IPA RM ::ipa_rm_resource_consumer_request %d EXIT %d\n",
- consumer->resource.name, result);
+ IPADBG("IPA RM ::ipa_rm_resource_consumer_request EXIT [%d]\n", result);
return result;
}
@@ -127,8 +126,8 @@
int driver_result;
unsigned long flags;
enum ipa_rm_resource_state save_state;
- IPADBG("IPA RM ::ipa_rm_resource_consumer_release %d ENTER\n",
- consumer->resource.name);
+ IPADBG("IPA RM ::%s name %d ENTER\n",
+ __func__, consumer->resource.name);
spin_lock_irqsave(&consumer->resource.state_lock, flags);
switch (consumer->resource.state) {
case IPA_RM_RELEASED:
@@ -163,8 +162,7 @@
}
bail:
spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
- IPADBG("IPA RM ::ipa_rm_resource_consumer_release %d EXIT %d\n",
- consumer->resource.name, result);
+ IPADBG("IPA RM ::ipa_rm_resource_consumer_release EXIT [%d]\n", result);
return result;
}
@@ -332,19 +330,61 @@
* ipa_rm_resource_delete() - deletes resource
* @resource: [in] resource
* for resource initialization with IPA RM
+ *
+ * Returns: 0 on success, negative on failure
*/
-void ipa_rm_resource_delete(struct ipa_rm_resource *resource)
+int ipa_rm_resource_delete(struct ipa_rm_resource *resource)
{
- if (!resource)
- return;
- if (resource->peers_list)
- ipa_rm_peers_list_delete(resource->peers_list);
+ struct ipa_rm_resource *consumer, *producer;
+ int peers_index, result = 0, list_size;
+
+ IPADBG("ipa_rm_resource_delete ENTER with resource %d\n",
+ resource->name);
+ if (!resource) {
+ IPADBG("ipa_rm_resource_delete ENTER with invalid param\n");
+ return -EINVAL;
+ }
if (resource->type == IPA_RM_PRODUCER) {
+ if (resource->peers_list) {
+ list_size = ipa_rm_peers_list_get_size(
+ resource->peers_list);
+ for (peers_index = 0;
+ peers_index < list_size;
+ peers_index++) {
+ consumer = ipa_rm_peers_list_get_resource(
+ peers_index,
+ resource->peers_list);
+ if (consumer)
+ ipa_rm_resource_delete_dependency(
+ resource,
+ consumer);
+ }
+ ipa_rm_peers_list_delete(resource->peers_list);
+ }
ipa_rm_resource_producer_delete(
(struct ipa_rm_resource_prod *) resource);
kfree((struct ipa_rm_resource_prod *) resource);
- } else
+ } else if (resource->type == IPA_RM_CONSUMER) {
+ if (resource->peers_list) {
+ list_size = ipa_rm_peers_list_get_size(
+ resource->peers_list);
+ for (peers_index = 0;
+ peers_index < list_size;
+ peers_index++){
+ producer = ipa_rm_peers_list_get_resource(
+ peers_index,
+ resource->peers_list);
+ if (producer)
+ ipa_rm_resource_delete_dependency(
+ producer,
+ resource);
+ }
+ ipa_rm_peers_list_delete(resource->peers_list);
+ }
kfree((struct ipa_rm_resource_cons *) resource);
+ }
+ IPADBG("ipa_rm_resource_delete SUCCESS\n");
+ return result;
}
/**
@@ -367,6 +407,8 @@
result = -EPERM;
goto bail;
}
+ IPADBG("IPA RM: %s name %d ENTER\n",
+ __func__, producer->resource.name);
read_lock(&producer->event_listeners_lock);
list_for_each(pos, &(producer->event_listeners)) {
reg_info = list_entry(pos,
@@ -511,6 +553,10 @@
unsigned long flags;
if (!resource || !depends_on)
return -EINVAL;
+ IPADBG("IPA RM: %s from %d to %d ENTER\n",
+ __func__,
+ resource->name,
+ depends_on->name);
if (!ipa_rm_peers_list_check_dependency(resource->peers_list,
resource->name,
depends_on->peers_list,
@@ -539,8 +585,6 @@
goto bail;
}
spin_unlock_irqrestore(&resource->state_lock, flags);
- (void) ipa_rm_resource_consumer_release(
- (struct ipa_rm_resource_cons *)depends_on);
if (ipa_rm_peers_list_has_last_peer(resource->peers_list)) {
(void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
resource->name,
@@ -551,6 +595,12 @@
depends_on->name);
ipa_rm_peers_list_remove_peer(depends_on->peers_list,
resource->name);
+ (void) ipa_rm_resource_consumer_release(
+ (struct ipa_rm_resource_cons *)depends_on);
+ IPADBG("IPA RM: %s from %d to %d SUCCESS\n",
+ __func__,
+ resource->name,
+ depends_on->name);
bail:
return result;
}
@@ -568,7 +618,7 @@
unsigned long flags;
struct ipa_rm_resource *consumer;
int consumer_result;
- IPADBG("IPA RM ::ipa_rm_resource_producer_request %d ENTER\n",
+ IPADBG("IPA RM ::ipa_rm_resource_producer_request [%d] ENTER\n",
producer->resource.name);
if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
spin_lock_irqsave(&producer->resource.state_lock, flags);
@@ -628,12 +678,11 @@
if (producer->pending_request == 0)
producer->resource.state = IPA_RM_GRANTED;
spin_unlock_irqrestore(&producer->resource.state_lock, flags);
- return result;
+ goto bail;
unlock_and_bail:
spin_unlock_irqrestore(&producer->resource.state_lock, flags);
bail:
- IPADBG("IPA RM ::ipa_rm_resource_producer_request %d EXIT %d\n",
- producer->resource.name, result);
+ IPADBG("IPA RM ::ipa_rm_resource_producer_request EXIT[%d]\n", result);
return result;
}
@@ -651,8 +700,9 @@
unsigned long flags;
struct ipa_rm_resource *consumer;
int consumer_result;
- IPADBG("IPA RM ::ipa_rm_resource_producer_release %d ENTER\n",
- producer->resource.name);
+ IPADBG("IPA RM: %s name %d ENTER\n",
+ __func__,
+ producer->resource.name);
if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
spin_lock_irqsave(&producer->resource.state_lock, flags);
producer->resource.state = IPA_RM_RELEASED;
@@ -708,8 +758,7 @@
return result;
bail:
spin_unlock_irqrestore(&producer->resource.state_lock, flags);
- IPADBG("IPA RM ::ipa_rm_resource_producer_release %d EXIT %d\n",
- producer->resource.name, result);
+ IPADBG("IPA RM ::ipa_rm_resource_producer_release EXIT[%d]\n", result);
return result;
}
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.h b/drivers/platform/msm/ipa/ipa_rm_resource.h
index b9c2e91..81ccc53 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.h
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.h
@@ -99,7 +99,7 @@
struct ipa_rm_create_params *create_params,
struct ipa_rm_resource **resource);
-void ipa_rm_resource_delete(struct ipa_rm_resource *resource);
+int ipa_rm_resource_delete(struct ipa_rm_resource *resource);
int ipa_rm_resource_producer_register(struct ipa_rm_resource_prod *producer,
struct ipa_rm_register_params *reg_params);
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index 40c8fc7..add9522 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -69,6 +69,13 @@
#define TETH_TOTAL_FLT_ENTRIES_IP 2
#define TETH_IP_FAMILIES 2
+/**
+ * struct mac_addresses_type - store host PC and device MAC addresses
+ * @host_pc_mac_addr: MAC address of the host PC
+ * @host_pc_mac_addr_known: is the MAC address of the host PC known ?
+ * @device_mac_addr: MAC address of the device
+ * @device_mac_addr_known: is the MAC address of the device known ?
+ */
struct mac_addresses_type {
u8 host_pc_mac_addr[ETH_ALEN];
bool host_pc_mac_addr_known;
@@ -76,12 +83,61 @@
bool device_mac_addr_known;
};
+/**
+ * struct stats - driver statistics, viewable using debugfs
+ * @a2_to_usb_num_sw_tx_packets: number of packets bridged from A2 to USB using
+ * the SW bridge
+ * @usb_to_a2_num_sw_tx_packets: number of packets bridged from USB to A2 using
+ * the SW bridge
+ * @num_sw_tx_packets_during_resource_wakeup: number of packets bridged during a
+ * resource wakeup period, there is a special treatment for these kind of
+ * packets
+ */
struct stats {
u64 a2_to_usb_num_sw_tx_packets;
u64 usb_to_a2_num_sw_tx_packets;
u64 num_sw_tx_packets_during_resource_wakeup;
};
+/**
+ * struct teth_bridge_ctx - Tethering bridge driver context information
+ * @class: kernel class pointer
+ * @dev_num: kernel device number
+ * @dev: kernel device struct pointer
+ * @cdev: kernel character device struct
+ * @usb_ipa_pipe_hdl: USB to IPA pipe handle
+ * @ipa_usb_pipe_hdl: IPA to USB pipe handle
+ * @a2_ipa_pipe_hdl: A2 to IPA pipe handle
+ * @ipa_a2_pipe_hdl: IPA to A2 pipe handle
+ * @is_connected: is the tethered bridge connected ?
+ * @link_protocol: IP / Ethernet
+ * @mac_addresses: Struct which holds host pc and device MAC addresses, relevant
+ * in ethernet mode only
+ * @is_hw_bridge_complete: is HW bridge setup ?
+ * @aggr_params: aggregation parmeters
+ * @aggr_params_known: are the aggregation parameters known ?
+ * @tethering_mode: Rmnet / MBIM
+ * @is_bridge_prod_up: completion object signaled when the bridge producer
+ * finished its resource request procedure
+ * @is_bridge_prod_down: completion object signaled when the bridge producer
+ * finished its resource release procedure
+ * @comp_hw_bridge_work: used for setting up the HW bridge using a workqueue
+ * @comp_hw_bridge_in_progress: true when the HW bridge setup is in progress
+ * @aggr_caps: aggregation capabilities
+ * @stats: statistics, how many packets were transmitted using the SW bridge
+ * @teth_wq: dedicated workqueue, used for setting up the HW bridge and for
+ * sending packets using the SW bridge when the system is waking up from power
+ * collapse
+ * @a2_ipa_hdr_len: A2 to IPA header length, used for configuring the A2
+ * endpoint for header removal
+ * @ipa_a2_hdr_len: IPA to A2 header length, used for configuring the A2
+ * endpoint for header removal
+ * @hdr_del: array to store the headers handles in order to delete them later
+ * @routing_del: array of routing rules handles, one array for IPv4 and one for
+ * IPv6
+ * @filtering_del: array of routing rules handles, one array for IPv4 and one
+ * for IPv6
+ */
struct teth_bridge_ctx {
struct class *class;
dev_t dev_num;
@@ -106,6 +162,7 @@
struct stats stats;
struct workqueue_struct *teth_wq;
u16 a2_ipa_hdr_len;
+ u16 ipa_a2_hdr_len;
struct ipa_ioc_del_hdr *hdr_del;
struct ipa_ioc_del_rt_rule *routing_del[TETH_IP_FAMILIES];
struct ipa_ioc_del_flt_rule *filtering_del[TETH_IP_FAMILIES];
@@ -117,6 +174,12 @@
TETH_A2_TO_USB,
};
+/**
+ * struct teth_work - wrapper for an skb which is sent using a workqueue
+ * @work: used by the workqueue
+ * @skb: pointer to the skb to be sent
+ * @dir: direction of send, A2 to USB or USB to A2
+ */
struct teth_work {
struct work_struct work;
struct sk_buff *skb;
@@ -128,6 +191,15 @@
static char dbg_buff[TETH_MAX_MSG_LEN];
#endif
+/**
+ * add_eth_hdrs() - add Ethernet headers to IPA
+ * @hdr_name_ipv4: header name for IPv4
+ * @hdr_name_ipv6: header name for IPv6
+ * @src_mac_addr: source MAC address
+ * @dst_mac_addr: destination MAC address
+ *
+ * This function is called only when link protocol is Ethernet
+ */
static int add_eth_hdrs(char *hdr_name_ipv4, char *hdr_name_ipv6,
u8 *src_mac_addr, u8 *dst_mac_addr)
{
@@ -218,6 +290,7 @@
}
hdr_cfg.hdr_len = ipa_a2_hdr_len;
+ teth_ctx->ipa_a2_hdr_len = ipa_a2_hdr_len;
res = ipa_cfg_ep_hdr(teth_ctx->ipa_a2_pipe_hdl, &hdr_cfg);
if (res) {
TETH_ERR("Header insertion config for IPA->A2 pipe failed\n");
@@ -269,6 +342,12 @@
return res;
}
+/**
+ * configure_ipa_header_block() - adds headers and configures endpoint registers
+ *
+ * - For IP link protocol and MBIM aggregation, configure MBIM header
+ * - For Ethernet link protocol, configure Ethernet headers
+ */
static int configure_ipa_header_block(void)
{
int res;
@@ -412,6 +491,14 @@
return res;
}
+/**
+ * configure_ipa_routing_block() - Configure the IPA routing block
+ *
+ * This function configures IPA for:
+ * - Route all packets from USB to A2
+ * - Route all packets from A2 to USB
+ * - Use the correct headers in Ethernet or MBIM cases
+ */
static int configure_ipa_routing_block(void)
{
int res;
@@ -547,6 +634,13 @@
return res;
}
+/**
+ * configure_ipa_filtering_block() - Configures IPA filtering block
+ *
+ * This function configures IPA for:
+ * - Filter all traffic coming from USB to A2 pointing routing table
+ * - Filter all traffic coming from A2 to USB pointing routing table
+ */
static int configure_ipa_filtering_block(void)
{
int res;
@@ -663,6 +757,11 @@
}
}
+/**
+ * teth_set_aggregation() - set aggregation parameters to IPA
+ *
+ * The parameters to this function are passed in the context variable ipa_ctx.
+ */
static int teth_set_aggregation(void)
{
int res;
@@ -727,6 +826,14 @@
return res;
}
+/**
+ * teth_request_resource() - wrapper function to
+ * ipa_rm_inactivity_timer_request_resource()
+ *
+ * - initialize the is_bridge_prod_up completion object
+ * - request the resource
+ * - error handling
+ */
static int teth_request_resource(void)
{
int res;
@@ -744,6 +851,10 @@
return 0;
}
+/**
+ * complete_hw_bridge() - setup the HW bridge from USB to A2 and back through
+ * IPA
+ */
static void complete_hw_bridge(struct work_struct *work)
{
int res;
@@ -812,6 +923,20 @@
mac_addr[4], mac_addr[5]);
}
+/**
+ * check_to_complete_hw_bridge() - can HW bridge be set up ?
+ * @param skb: pointer to socket buffer
+ * @param my_mac_addr: pointer to write 'my' extracted MAC address to
+ * @param my_mac_addr_known: pointer to update whether 'my' extracted MAC
+ * address is known
+ * @param peer_mac_addr_known: pointer to update whether the 'peer' extracted
+ * MAC address is known
+ *
+ * This function is used by both A2 and USB callback functions, therefore the
+ * meaning of 'my' and 'peer' changes according to the context.
+ * Extracts MAC address from the packet in Ethernet link protocol,
+ * Sets up the HW bridge in case all conditions are met.
+ */
static void check_to_complete_hw_bridge(struct sk_buff *skb,
u8 *my_mac_addr,
bool *my_mac_addr_known,
@@ -841,6 +966,9 @@
}
}
+/**
+ * teth_send_skb_work() - workqueue function for sending a packet
+ */
static void teth_send_skb_work(struct work_struct *work)
{
struct teth_work *work_data =
@@ -887,6 +1015,15 @@
kfree(work_data);
}
+/**
+ * defer_skb_send() - defer sending an skb using the SW bridge to a workqueue
+ * @param skb: pointer to the socket buffer
+ * @param dir: direction of send
+ *
+ * In case where during a packet send, the A2 or USB needs to wake up from power
+ * collapse, defer the send and return the context to IPA driver. This is
+ * important since IPA driver has a single threaded Rx path.
+ */
static void defer_skb_send(struct sk_buff *skb, enum teth_packet_direction dir)
{
struct teth_work *work = kmalloc(sizeof(struct teth_work), GFP_KERNEL);
@@ -909,6 +1046,30 @@
queue_work(teth_ctx->teth_wq, &work->work);
}
+/**
+ * usb_notify_cb() - callback function for sending packets from USB to A2
+ * @param priv: private data
+ * @param evt: event - RECEIVE or WRITE_DONE
+ * @param data: pointer to skb to be sent
+ *
+ * This callback function is installed by the IPA driver, it is invoked in 2
+ * cases:
+ * 1. When a packet comes from the USB pipe and is routed to A5 (SW bridging)
+ * 2. After a packet has been bridged from USB to A2 and its skb should be freed
+ *
+ * Invocation: sps driver --> IPA driver --> bridge driver
+ *
+ * In the event of IPA_RECEIVE:
+ * - Checks whether the HW bridge can be set up..
+ * - Requests the BRIDGE_PROD resource so that A2 and USB are not in power
+ * collapse. In case where the resource is waking up, defer the send operation
+ * to a workqueue in order to not block the IPA driver single threaded Rx path.
+ * - Sends the packets to A2 using a2_service driver API.
+ * - Releases the BRIDGE_PROD resource.
+ *
+ * In the event of IPA_WRITE_DONE:
+ * - Frees the skb memory
+ */
static void usb_notify_cb(void *priv,
enum ipa_dp_evt_type evt,
unsigned long data)
@@ -969,6 +1130,30 @@
return;
}
+/**
+ * a2_notify_cb() - callback function for sending packets from A2 to USB
+ * @param user_data: private data
+ * @param event: event - RECEIVE or WRITE_DONE
+ * @param data: pointer to skb to be sent
+ *
+ * This callback function is installed by the IPA driver, it is invoked in 2
+ * cases:
+ * 1. When a packet comes from the A2 pipe and is routed to A5 (SW bridging)
+ * 2. After a packet has been bridged from A2 to USB and its skb should be freed
+ *
+ * Invocation: sps driver --> IPA driver --> a2_service driver --> bridge driver
+ *
+ * In the event of A2_MUX_RECEIVE:
+ * - Checks whether the HW bridge can be set up..
+ * - Requests the BRIDGE_PROD resource so that A2 and USB are not in power
+ * collapse. In case where the resource is waking up, defer the send operation
+ * to a workqueue in order to not block the IPA driver single threaded Rx path.
+ * - Sends the packets to USB using IPA drivers ipa_tx_dp() API.
+ * - Releases the BRIDGE_PROD resource.
+ *
+ * In the event of A2_MUX_WRITE_DONE:
+ * - Frees the skb memory
+ */
static void a2_notify_cb(void *user_data,
enum a2_mux_event_type event,
unsigned long data)
@@ -1031,10 +1216,41 @@
return;
}
+/**
+ * bridge_prod_notify_cb() - IPA Resource Manager callback function
+ * @param notify_cb_data: private data
+ * @param event: RESOURCE_GRANTED / RESOURCE_RELEASED
+ * @param data: not used in this case
+ *
+ * This callback function is called by IPA resource manager to notify the
+ * BRIDGE_PROD entity of events like RESOURCE_GRANTED and RESOURCE_RELEASED.
+ */
static void bridge_prod_notify_cb(void *notify_cb_data,
enum ipa_rm_event event,
unsigned long data)
{
+ switch (event) {
+ case IPA_RM_RESOURCE_GRANTED:
+ complete(&teth_ctx->is_bridge_prod_up);
+ break;
+
+ case IPA_RM_RESOURCE_RELEASED:
+ complete(&teth_ctx->is_bridge_prod_down);
+ break;
+
+ default:
+ TETH_ERR("Unsupported notification!\n");
+ WARN_ON(1);
+ break;
+ }
+
+ return;
+}
+
+static void a2_prod_notify_cb(void *notify_cb_data,
+ enum ipa_rm_event event,
+ unsigned long data)
+{
int res;
struct ipa_ep_cfg ipa_ep_cfg;
@@ -1053,15 +1269,15 @@
/* Reset the various endpoints configuration */
memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+ ipa_ep_cfg.hdr.hdr_len = teth_ctx->ipa_a2_hdr_len;
ipa_cfg_ep(teth_ctx->ipa_a2_pipe_hdl, &ipa_ep_cfg);
+ memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
ipa_ep_cfg.hdr.hdr_len = teth_ctx->a2_ipa_hdr_len;
ipa_cfg_ep(teth_ctx->a2_ipa_pipe_hdl, &ipa_ep_cfg);
- complete(&teth_ctx->is_bridge_prod_up);
break;
case IPA_RM_RESOURCE_RELEASED:
- complete(&teth_ctx->is_bridge_prod_down);
break;
default:
@@ -1075,10 +1291,17 @@
/**
* teth_bridge_init() - Initialize the Tethering bridge driver
-* @usb_notify_cb_ptr: Callback function which should be used
-* by the caller. Output parameter.
-* @private_data_ptr: Data for the callback function. Should
-* be used by the caller. Output parameter.
+* @usb_notify_cb_ptr: Callback function which should be used by the caller.
+* Output parameter.
+* @private_data_ptr: Data for the callback function. Should be used by the
+* caller. Output parameter.
+*
+* USB driver gets a pointer to a callback function (usb_notify_cb) and an
+* associated data. USB driver installs this callback function in the call to
+* ipa_connect().
+*
+* Builds IPA resource manager dependency graph.
+*
* Return codes: 0: success,
* -EINVAL - Bad parameter
* Other negative value - Failure
@@ -1086,6 +1309,7 @@
int teth_bridge_init(ipa_notify_cb *usb_notify_cb_ptr, void **private_data_ptr)
{
int res = 0;
+ struct ipa_rm_register_params a2_prod_reg_params;
TETH_DBG_FUNC_ENTRY();
if (usb_notify_cb_ptr == NULL) {
@@ -1126,10 +1350,22 @@
goto fail_add_dependency_3;
}
+ /* Register for A2_PROD resource notifications */
+ a2_prod_reg_params.user_data = NULL;
+ a2_prod_reg_params.notify_cb = a2_prod_notify_cb;
+ res = ipa_rm_register(IPA_RM_RESOURCE_A2_PROD, &a2_prod_reg_params);
+ if (res) {
+ TETH_ERR("ipa_rm_register() failed\n");
+ goto fail_add_dependency_4;
+ }
+
/* Return 0 as EINPROGRESS is a valid return value at this point */
res = 0;
goto bail;
+fail_add_dependency_4:
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
+ IPA_RM_RESOURCE_USB_CONS);
fail_add_dependency_3:
ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
IPA_RM_RESOURCE_A2_CONS);
@@ -1145,6 +1381,9 @@
}
EXPORT_SYMBOL(teth_bridge_init);
+/**
+ * initialize_context() - Initialize the ipa_ctx struct
+ */
static void initialize_context(void)
{
TETH_DBG_FUNC_ENTRY();
@@ -1168,6 +1407,7 @@
teth_ctx->comp_hw_bridge_in_progress = false;
memset(&teth_ctx->stats, 0, sizeof(teth_ctx->stats));
teth_ctx->a2_ipa_hdr_len = 0;
+ teth_ctx->ipa_a2_hdr_len = 0;
memset(teth_ctx->hdr_del,
0,
sizeof(struct ipa_ioc_del_hdr) + TETH_TOTAL_HDR_ENTRIES *
@@ -1198,14 +1438,11 @@
/**
* teth_bridge_disconnect() - Disconnect tethering bridge module
-*
-* Return codes: 0: success
-* -EPERM: Operation not permitted as the bridge is already
-* disconnected
*/
int teth_bridge_disconnect(void)
{
int res;
+ struct ipa_rm_register_params a2_prod_reg_params;
TETH_DBG_FUNC_ENTRY();
if (!teth_ctx->is_connected) {
@@ -1214,19 +1451,38 @@
goto bail;
}
- /* Request the BRIDGE_PROD resource */
+ /*
+ * Delete part of IPA resource manager dependency graph. Only the
+ * BRIDGE_PROD <-> A2 dependency remains intact
+ */
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+ IPA_RM_RESOURCE_USB_CONS);
+ if ((res != 0) && (res != -EINPROGRESS))
+ TETH_ERR(
+ "Failed deleting ipa_rm dependency BRIDGE_PROD <-> USB_CONS\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
+ IPA_RM_RESOURCE_A2_CONS);
+ if ((res != 0) && (res != -EINPROGRESS))
+ TETH_ERR(
+ "Failed deleting ipa_rm dependency USB_PROD <-> A2_CONS\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
+ IPA_RM_RESOURCE_USB_CONS);
+ if ((res != 0) && (res != -EINPROGRESS))
+ TETH_ERR(
+ "Failed deleting ipa_rm dependency A2_PROD <-> USB_CONS\n");
+
+ /* Request the BRIDGE_PROD resource, A2 and IPA should power up */
res = teth_request_resource();
if (res) {
TETH_ERR("request_resource() failed.\n");
goto bail;
}
- teth_ctx->is_connected = false;
-
/* Close the channel to A2 */
if (a2_mux_close_channel(A2_MUX_TETHERED_0))
TETH_ERR("a2_mux_close_channel() failed\n");
+ /* Teardown the IPA HW bridge */
if (teth_ctx->is_hw_bridge_complete) {
/* Delete header entries */
if (ipa_del_hdr(teth_ctx->hdr_del))
@@ -1256,27 +1512,21 @@
ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
- /* Delete IPA Resource manager dependency graph */
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
- IPA_RM_RESOURCE_USB_CONS);
- if ((res != 0) && (res != -EINPROGRESS))
- TETH_ERR(
- "Failed deleting ipa_rm dependency BRIDGE_PROD <-> USB_CONS\n");
+ /* Delete the last ipa_rm dependency - BRIDGE_PROD <-> A2 */
res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
IPA_RM_RESOURCE_A2_CONS);
if ((res != 0) && (res != -EINPROGRESS))
TETH_ERR(
"Failed deleting ipa_rm dependency BRIDGE_PROD <-> A2_CONS\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
- IPA_RM_RESOURCE_A2_CONS);
- if ((res != 0) && (res != -EINPROGRESS))
- TETH_ERR(
- "Failed deleting ipa_rm dependency USB_PROD <-> A2_CONS\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
- IPA_RM_RESOURCE_USB_CONS);
- if ((res != 0) && (res != -EINPROGRESS))
- TETH_ERR(
- "Failed deleting ipa_rm dependency A2_PROD <-> USB_CONS\n");
+
+ /* Deregister from A2_PROD notifications */
+ a2_prod_reg_params.user_data = NULL;
+ a2_prod_reg_params.notify_cb = a2_prod_notify_cb;
+ res = ipa_rm_deregister(IPA_RM_RESOURCE_A2_PROD, &a2_prod_reg_params);
+ if (res)
+ TETH_ERR("Failed deregistering from A2_prod notifications.\n");
+
+ teth_ctx->is_connected = false;
bail:
TETH_DBG_FUNC_EXIT();
@@ -1384,6 +1634,9 @@
TETH_AGGR_MAX_AGGR_PACKET_SIZE_DEFAULT;
}
+/**
+ * teth_set_bridge_mode() - set the link protocol (IP / Ethernet)
+ */
static void teth_set_bridge_mode(enum teth_link_protocol_type link_protocol)
{
teth_ctx->link_protocol = link_protocol;
@@ -1391,6 +1644,14 @@
memset(&teth_ctx->mac_addresses, 0, sizeof(teth_ctx->mac_addresses));
}
+/**
+ * teth_bridge_set_aggr_params() - kernel API to set aggregation parameters
+ * @param aggr_params: aggregation parmeters for uplink and downlink
+ *
+ * Besides setting the aggregation parameters, the function enforces max tranfer
+ * size which is less then 8K and also forbids Ethernet link protocol with MBIM
+ * aggregation which is not supported by HW.
+ */
int teth_bridge_set_aggr_params(struct teth_aggr_params *aggr_params)
{
int res;
@@ -1540,6 +1801,10 @@
return res;
}
+/**
+ * set_aggr_capabilities() - allocates and fills the aggregation capabilities
+ * struct
+ */
static int set_aggr_capabilities(void)
{
u16 NUM_PROTOCOLS = 2;
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 1907adc..a85e31c 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,47 +24,51 @@
#include <linux/log2.h>
/* PON common register addresses */
-#define QPNP_PON_RT_STS(base) (base + 0x10)
-#define QPNP_PON_PULL_CTL(base) (base + 0x70)
-#define QPNP_PON_DBC_CTL(base) (base + 0x71)
+#define QPNP_PON_RT_STS(base) (base + 0x10)
+#define QPNP_PON_PULL_CTL(base) (base + 0x70)
+#define QPNP_PON_DBC_CTL(base) (base + 0x71)
/* PON/RESET sources register addresses */
-#define QPNP_PON_KPDPWR_S1_TIMER(base) (base + 0x40)
-#define QPNP_PON_KPDPWR_S2_TIMER(base) (base + 0x41)
-#define QPNP_PON_KPDPWR_S2_CNTL(base) (base + 0x42)
-#define QPNP_PON_RESIN_S1_TIMER(base) (base + 0x44)
-#define QPNP_PON_RESIN_S2_TIMER(base) (base + 0x45)
-#define QPNP_PON_RESIN_S2_CNTL(base) (base + 0x46)
-#define QPNP_PON_PS_HOLD_RST_CTL(base) (base + 0x5A)
+#define QPNP_PON_WARM_RESET_REASON1(base) (base + 0xA)
+#define QPNP_PON_WARM_RESET_REASON2(base) (base + 0xB)
+#define QPNP_PON_KPDPWR_S1_TIMER(base) (base + 0x40)
+#define QPNP_PON_KPDPWR_S2_TIMER(base) (base + 0x41)
+#define QPNP_PON_KPDPWR_S2_CNTL(base) (base + 0x42)
+#define QPNP_PON_RESIN_S1_TIMER(base) (base + 0x44)
+#define QPNP_PON_RESIN_S2_TIMER(base) (base + 0x45)
+#define QPNP_PON_RESIN_S2_CNTL(base) (base + 0x46)
+#define QPNP_PON_PS_HOLD_RST_CTL(base) (base + 0x5A)
-#define QPNP_PON_RESIN_PULL_UP BIT(0)
-#define QPNP_PON_KPDPWR_PULL_UP BIT(1)
-#define QPNP_PON_CBLPWR_PULL_UP BIT(2)
-#define QPNP_PON_S2_CNTL_EN BIT(7)
-#define QPNP_PON_S2_RESET_ENABLE BIT(7)
-#define QPNP_PON_DELAY_BIT_SHIFT 6
+#define QPNP_PON_WARM_RESET_TFT BIT(4)
-#define QPNP_PON_S1_TIMER_MASK (0xF)
-#define QPNP_PON_S2_TIMER_MASK (0x7)
-#define QPNP_PON_S2_CNTL_TYPE_MASK (0xF)
+#define QPNP_PON_RESIN_PULL_UP BIT(0)
+#define QPNP_PON_KPDPWR_PULL_UP BIT(1)
+#define QPNP_PON_CBLPWR_PULL_UP BIT(2)
+#define QPNP_PON_S2_CNTL_EN BIT(7)
+#define QPNP_PON_S2_RESET_ENABLE BIT(7)
+#define QPNP_PON_DELAY_BIT_SHIFT 6
-#define QPNP_PON_DBC_DELAY_MASK (0x7)
-#define QPNP_PON_KPDPWR_N_SET BIT(0)
-#define QPNP_PON_RESIN_N_SET BIT(1)
-#define QPNP_PON_CBLPWR_N_SET BIT(2)
-#define QPNP_PON_RESIN_BARK_N_SET BIT(4)
+#define QPNP_PON_S1_TIMER_MASK (0xF)
+#define QPNP_PON_S2_TIMER_MASK (0x7)
+#define QPNP_PON_S2_CNTL_TYPE_MASK (0xF)
-#define QPNP_PON_RESET_EN BIT(7)
-#define QPNP_PON_WARM_RESET BIT(0)
-#define QPNP_PON_SHUTDOWN BIT(2)
+#define QPNP_PON_DBC_DELAY_MASK (0x7)
+#define QPNP_PON_KPDPWR_N_SET BIT(0)
+#define QPNP_PON_RESIN_N_SET BIT(1)
+#define QPNP_PON_CBLPWR_N_SET BIT(2)
+#define QPNP_PON_RESIN_BARK_N_SET BIT(4)
+
+#define QPNP_PON_RESET_EN BIT(7)
+#define QPNP_PON_WARM_RESET BIT(0)
+#define QPNP_PON_SHUTDOWN BIT(2)
/* Ranges */
-#define QPNP_PON_S1_TIMER_MAX 10256
-#define QPNP_PON_S2_TIMER_MAX 2000
-#define QPNP_PON_RESET_TYPE_MAX 0xF
-#define PON_S1_COUNT_MAX 0xF
+#define QPNP_PON_S1_TIMER_MAX 10256
+#define QPNP_PON_S2_TIMER_MAX 2000
+#define QPNP_PON_RESET_TYPE_MAX 0xF
+#define PON_S1_COUNT_MAX 0xF
-#define QPNP_KEY_STATUS_DELAY msecs_to_jiffies(250)
+#define QPNP_KEY_STATUS_DELAY msecs_to_jiffies(250)
enum pon_type {
PON_KPDPWR,
@@ -175,6 +179,50 @@
}
EXPORT_SYMBOL(qpnp_pon_system_pwr_off);
+/**
+ * qpnp_pon_is_warm_reset - Checks if the PMIC went through a warm reset.
+ *
+ * Returns > 0 for warm resets, 0 for not warm reset, < 0 for errors
+ *
+ * Note that this function will only return the warm vs not-warm reset status
+ * of the PMIC that is configured as the system-reset device.
+ */
+int qpnp_pon_is_warm_reset(void)
+{
+ struct qpnp_pon *pon = sys_reset_dev;
+ int rc;
+ u8 reg;
+
+ if (!pon)
+ return -EPROBE_DEFER;
+
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_WARM_RESET_REASON1(pon->base), ®, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read addr=%x, rc(%d)\n",
+ QPNP_PON_WARM_RESET_REASON1(pon->base), rc);
+ return rc;
+ }
+
+ if (reg)
+ return 1;
+
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_WARM_RESET_REASON2(pon->base), ®, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read addr=%x, rc(%d)\n",
+ QPNP_PON_WARM_RESET_REASON2(pon->base), rc);
+ return rc;
+ }
+ if (reg & QPNP_PON_WARM_RESET_TFT)
+ return 1;
+
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_pon_is_warm_reset);
+
static struct qpnp_pon_config *
qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type)
{
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 52c523e..442d18f 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -319,6 +319,7 @@
#define QPNP_ENABLE_LUT_CONTROL qpnp_set_control(0, 0, 0, 0, 1)
#define QPNP_ENABLE_PWM_CONTROL qpnp_set_control(0, 0, 0, 1, 0)
#define QPNP_ENABLE_PWM_MODE qpnp_set_control(1, 1, 1, 1, 0)
+#define QPNP_ENABLE_PWM_MODE_GPLED_CHANNEL qpnp_set_control(1, 1, 1, 1, 1)
#define QPNP_ENABLE_LPG_MODE qpnp_set_control(1, 1, 1, 0, 1)
#define QPNP_DISABLE_PWM_MODE qpnp_set_control(0, 0, 0, 1, 0)
#define QPNP_DISABLE_LPG_MODE qpnp_set_control(0, 0, 0, 0, 1)
@@ -908,6 +909,17 @@
}
+#define QPNP_GPLED_LPG_CHANNEL_RANGE_START 8
+#define QPNP_GPLED_LPG_CHANNEL_RANGE_END 11
+
+static inline int qpnp_enable_pwm_mode(struct qpnp_pwm_config *pwm_conf)
+{
+ if (pwm_conf->channel_id >= QPNP_GPLED_LPG_CHANNEL_RANGE_START ||
+ pwm_conf->channel_id <= QPNP_GPLED_LPG_CHANNEL_RANGE_END)
+ return QPNP_ENABLE_PWM_MODE_GPLED_CHANNEL;
+ return QPNP_ENABLE_PWM_MODE;
+}
+
static int qpnp_lpg_configure_pwm_state(struct pwm_device *pwm,
enum qpnp_pwm_state state)
{
@@ -917,7 +929,7 @@
int rc;
if (state == QPNP_PWM_ENABLE)
- value = QPNP_ENABLE_PWM_MODE;
+ value = qpnp_enable_pwm_mode(&pwm->pwm_config);
else
value = QPNP_DISABLE_PWM_MODE;
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 1d0fb5d..64e8d7a 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -27,9 +27,11 @@
#include <linux/workqueue.h>
#include <linux/dma-mapping.h>
#include <mach/msm_smsm.h>
+#include <linux/pm_runtime.h>
#define USB_THRESHOLD 512
#define USB_BAM_MAX_STR_LEN 50
+#define USB_BAM_TIMEOUT (10*HZ)
enum usb_bam_sm {
USB_BAM_SM_INIT = 0,
@@ -73,6 +75,11 @@
* handle/device of the sps driver.
* @pipes_enabled_per_bam: This array stores for each BAM
* ("ssusb", "hsusb" or "hsic") the number of pipes currently enabled.
+* @inactivity_timer_ms: The timeout configuration per each bam for inactivity
+* timer feature.
+* @is_bam_inactivity: Is there no activity on all pipes belongs to a
+* specific bam. (no activity = no data is pulled or pushed
+* from/into ones of the pipes).
*/
struct usb_bam_ctx_type {
struct usb_bam_sps_type usb_bam_sps;
@@ -85,19 +92,61 @@
char qdss_core_name[USB_BAM_MAX_STR_LEN];
u32 h_bam[MAX_BAMS];
u8 pipes_enabled_per_bam[MAX_BAMS];
+ u32 inactivity_timer_ms[MAX_BAMS];
+ bool is_bam_inactivity[MAX_BAMS];
};
-static char *bam_enable_strings[3] = {
+static char *bam_enable_strings[MAX_BAMS] = {
[SSUSB_BAM] = "ssusb",
[HSUSB_BAM] = "hsusb",
[HSIC_BAM] = "hsic",
};
-static spinlock_t usb_bam_lock;
+static enum usb_bam ipa_rm_bams[] = {HSUSB_BAM, HSIC_BAM};
+
+static enum ipa_client_type ipa_rm_resource_prod[MAX_BAMS] = {
+ [HSUSB_BAM] = IPA_RM_RESOURCE_USB_PROD,
+ [HSIC_BAM] = IPA_RM_RESOURCE_HSIC_PROD,
+};
+
+static enum ipa_client_type ipa_rm_resource_cons[MAX_BAMS] = {
+ [HSUSB_BAM] = IPA_RM_RESOURCE_USB_CONS,
+ [HSIC_BAM] = IPA_RM_RESOURCE_HSIC_CONS,
+};
+
+static int usb_cons_request_resource(void);
+static int usb_cons_release_resource(void);
+static int hsic_cons_request_resource(void);
+static int hsic_cons_release_resource(void);
+
+static int (*request_resource_cb[MAX_BAMS])(void) = {
+ [HSUSB_BAM] = usb_cons_request_resource,
+ [HSIC_BAM] = hsic_cons_request_resource,
+};
+
+static int (*release_resource_cb[MAX_BAMS])(void) = {
+ [HSUSB_BAM] = usb_cons_release_resource,
+ [HSIC_BAM] = hsic_cons_release_resource,
+};
+
+static enum ipa_rm_event cur_prod_state[MAX_BAMS];
+static enum ipa_rm_event cur_cons_state[MAX_BAMS];
+static int sched_lpm;
+static int lpm_wait_handshake;
+static struct completion prod_avail[MAX_BAMS];
+static struct completion cons_avail[MAX_BAMS];
+static struct completion cons_released[MAX_BAMS];
+static struct completion prod_released[MAX_BAMS];
+
+static spinlock_t usb_bam_peer_handshake_info_lock;
static struct usb_bam_peer_handshake_info peer_handshake_info;
+static spinlock_t usb_bam_lock; /* Protect ctx and usb_bam_connections */
static struct usb_bam_pipe_connect *usb_bam_connections;
static struct usb_bam_ctx_type ctx;
+static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
+ void *param, bool trigger_cb_per_pipe);
+
static int get_bam_type_from_core_name(const char *name)
{
if (strnstr(name, bam_enable_strings[SSUSB_BAM],
@@ -128,6 +177,42 @@
return false;
}
+static void usb_bam_set_inactivity_timer(enum usb_bam bam)
+{
+ struct sps_timer_ctrl timer_ctrl;
+ struct usb_bam_pipe_connect *pipe_connect;
+ struct sps_pipe *pipe = NULL;
+ int i;
+
+ /*
+ * Since we configure global incativity timer for all pipes
+ * and not per each pipe, it is enough to use some pipe
+ * handle associated with this bam, so just find the first one.
+ * This pipe handle is required due to SPS driver API we use below.
+ */
+ for (i = 0; i < ctx.max_connections; i++) {
+ pipe_connect = &usb_bam_connections[i];
+ if (pipe_connect->bam_type == bam) {
+ pipe = ctx.usb_bam_sps.sps_pipes[i];
+ break;
+ }
+ }
+
+ if (!pipe) {
+ pr_err("%s: Bam %s has no pipes\n", __func__,
+ bam_enable_strings[bam]);
+ return;
+ }
+
+ timer_ctrl.op = SPS_TIMER_OP_CONFIG;
+ timer_ctrl.mode = SPS_TIMER_MODE_ONESHOT;
+ timer_ctrl.timeout_msec = ctx.inactivity_timer_ms[bam];
+ sps_timer_ctrl(pipe, &timer_ctrl, NULL);
+
+ timer_ctrl.op = SPS_TIMER_OP_RESET;
+ sps_timer_ctrl(pipe, &timer_ctrl, NULL);
+}
+
static int connect_pipe(u8 idx, u32 *usb_pipe_idx)
{
int ret, ram1_value;
@@ -281,6 +366,7 @@
pr_err("%s: sps_connect failed %d\n", __func__, ret);
goto error;
}
+
return 0;
error:
@@ -323,6 +409,10 @@
return ret;
}
+ pipe_connect->activity_notify = ipa_params->activity_notify;
+ pipe_connect->inactivity_notify = ipa_params->inactivity_notify;
+ pipe_connect->priv = ipa_params->priv;
+
/* IPA input parameters */
ipa_in_params.client_bam_hdl = usb_handle;
ipa_in_params.desc_fifo_sz = pipe_connect->desc_fifo_size;
@@ -395,6 +485,7 @@
__func__,
pipe_connect->src_pipe_index,
pipe_connect->dst_pipe_index);
+ sps_connection->options = SPS_O_NO_DISABLE;
} else {
/* IPA src, USB dest */
sps_connection->mode = SPS_MODE_DEST;
@@ -409,12 +500,13 @@
__func__,
pipe_connect->src_pipe_index,
pipe_connect->dst_pipe_index);
+ sps_connection->options = 0;
}
sps_connection->data = sps_out_params.data;
sps_connection->desc = sps_out_params.desc;
sps_connection->event_thresh = 16;
- sps_connection->options = SPS_O_AUTO_ENABLE;
+ sps_connection->options |= SPS_O_AUTO_ENABLE;
ret = sps_connect(*pipe, sps_connection);
if (ret < 0) {
@@ -422,6 +514,16 @@
goto error;
}
+ spin_lock(&usb_bam_lock);
+
+ /* Set global inactivity timer upon first pipe connection */
+ if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0 &&
+ ctx.inactivity_timer_ms[pipe_connect->bam_type] &&
+ pipe_connect->inactivity_notify)
+ usb_bam_set_inactivity_timer(pipe_connect->bam_type);
+
+ spin_unlock(&usb_bam_lock);
+
return 0;
error:
@@ -505,6 +607,8 @@
return -EINVAL;
}
+ spin_lock(&usb_bam_lock);
+
/* Check if BAM requires RESET before connect and reset of first pipe */
if ((pdata->reset_on_connect[pipe_connect->bam_type] == true) &&
(ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0))
@@ -513,24 +617,34 @@
ret = connect_pipe(idx, bam_pipe_idx);
if (ret) {
pr_err("%s: pipe connection[%d] failure\n", __func__, idx);
+ spin_unlock(&usb_bam_lock);
return ret;
}
pipe_connect->enabled = 1;
ctx.pipes_enabled_per_bam[pipe_connect->bam_type] += 1;
+ spin_unlock(&usb_bam_lock);
return 0;
}
static void usb_prod_notify_cb(void *user_data, enum ipa_rm_event event,
unsigned long data)
{
+ enum usb_bam *cur_bam = (void *)user_data;
+
switch (event) {
case IPA_RM_RESOURCE_GRANTED:
- pr_debug("USB_PROD resource granted\n");
+ pr_debug("%s: %s_PROD resource granted\n",
+ __func__, bam_enable_strings[*cur_bam]);
+ cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_GRANTED;
+ complete_all(&prod_avail[*cur_bam]);
break;
case IPA_RM_RESOURCE_RELEASED:
- pr_debug("USB_PROD resource released\n");
+ pr_debug("%s: %s_PROD resource released\n",
+ __func__, bam_enable_strings[*cur_bam]);
+ cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_RELEASED;
+ complete_all(&prod_released[*cur_bam]);
break;
default:
break;
@@ -538,50 +652,130 @@
return;
}
+static int cons_request_resource(enum usb_bam cur_bam)
+{
+ pr_debug("%s: Request %s_CONS resource\n",
+ __func__, bam_enable_strings[cur_bam]);
+
+ cur_cons_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
+ complete_all(&cons_avail[cur_bam]);
+
+ if (ctx.pipes_enabled_per_bam[cur_bam])
+ return 0;
+
+ return -EINPROGRESS;
+}
+
static int usb_cons_request_resource(void)
{
- pr_debug(": Requesting USB_CONS resource\n");
- return 0;
+ return cons_request_resource(HSUSB_BAM);
+}
+
+static int hsic_cons_request_resource(void)
+{
+ return cons_request_resource(HSIC_BAM);
+}
+
+static int cons_release_resource(enum usb_bam cur_bam)
+{
+ pr_debug("%s: Release %s_CONS resource\n",
+ __func__, bam_enable_strings[cur_bam]);
+
+ cur_cons_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
+ complete_all(&cons_released[cur_bam]);
+
+ if (!ctx.pipes_enabled_per_bam[cur_bam])
+ return 0;
+
+ return -EINPROGRESS;
+}
+
+static int hsic_cons_release_resource(void)
+{
+ return cons_release_resource(HSIC_BAM);
}
static int usb_cons_release_resource(void)
{
- pr_debug(": Releasing USB_CONS resource\n");
- return 0;
+ return cons_release_resource(HSUSB_BAM);
}
static void usb_bam_ipa_create_resources(void)
{
struct ipa_rm_create_params usb_prod_create_params;
struct ipa_rm_create_params usb_cons_create_params;
+ enum usb_bam cur_bam;
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(ipa_rm_bams); i++) {
+ /* Create USB/HSIC_PROD entity */
+ cur_bam = ipa_rm_bams[i];
+
+ memset(&usb_prod_create_params, 0,
+ sizeof(usb_prod_create_params));
+ usb_prod_create_params.name = ipa_rm_resource_prod[cur_bam];
+ usb_prod_create_params.reg_params.notify_cb =
+ usb_prod_notify_cb;
+ usb_prod_create_params.reg_params.user_data = &ipa_rm_bams[i];
+ ret = ipa_rm_create_resource(&usb_prod_create_params);
+ if (ret) {
+ pr_err("%s: Failed to create USB_PROD resource\n",
+ __func__);
+ return;
+ }
+
+ /* Create USB_CONS entity */
+ memset(&usb_cons_create_params, 0,
+ sizeof(usb_cons_create_params));
+ usb_cons_create_params.name = ipa_rm_resource_cons[cur_bam];
+ usb_cons_create_params.request_resource =
+ request_resource_cb[cur_bam];
+ usb_cons_create_params.release_resource =
+ release_resource_cb[cur_bam];
+ ret = ipa_rm_create_resource(&usb_cons_create_params);
+ if (ret) {
+ pr_err("%s: Failed to create USB_CONS resource\n",
+ __func__);
+ return ;
+ }
+ }
+}
+
+static void wait_for_prod_granted(enum usb_bam cur_bam)
+{
int ret;
- /* Create USB_PROD entity */
- memset(&usb_prod_create_params, 0, sizeof(usb_prod_create_params));
- usb_prod_create_params.name = IPA_RM_RESOURCE_USB_PROD;
- usb_prod_create_params.reg_params.notify_cb = usb_prod_notify_cb;
- usb_prod_create_params.reg_params.user_data = NULL;
- ret = ipa_rm_create_resource(&usb_prod_create_params);
- if (ret) {
- pr_err("%s: Failed to create USB_PROD resource\n", __func__);
- return;
- }
+ pr_debug("%s Request %s_PROD_RES\n", __func__,
+ bam_enable_strings[cur_bam]);
+ if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
+ pr_debug("%s: CONS already granted for some reason\n",
+ __func__);
+ if (cur_prod_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
+ pr_debug("%s: PROD already granted for some reason\n",
+ __func__);
- /* Create USB_CONS entity */
- memset(&usb_cons_create_params, 0, sizeof(usb_cons_create_params));
- usb_cons_create_params.name = IPA_RM_RESOURCE_USB_CONS;
- usb_cons_create_params.request_resource = usb_cons_request_resource;
- usb_cons_create_params.release_resource = usb_cons_release_resource;
- ret = ipa_rm_create_resource(&usb_cons_create_params);
- if (ret) {
- pr_err("%s: Failed to create USB_CONS resource\n", __func__);
- return ;
- }
+ init_completion(&prod_avail[cur_bam]);
+ init_completion(&cons_avail[cur_bam]);
+
+ ret = ipa_rm_request_resource(ipa_rm_resource_prod[cur_bam]);
+ if (!ret) {
+ cur_prod_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
+ complete_all(&prod_avail[cur_bam]);
+ pr_debug("%s: PROD_GRANTED without wait\n", __func__);
+ } else if (ret == -EINPROGRESS) {
+ pr_debug("%s: Waiting for PROD_GRANTED\n", __func__);
+ if (!wait_for_completion_timeout(&prod_avail[cur_bam],
+ USB_BAM_TIMEOUT))
+ pr_err("%s: Timeout wainting for PROD_GRANTED\n",
+ __func__);
+ } else
+ pr_err("%s: ipa_rm_request_resource ret =%d\n", __func__, ret);
}
int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
u8 idx;
+ enum usb_bam cur_bam;
struct usb_bam_pipe_connect *pipe_connect;
int ret;
struct msm_usb_bam_platform_data *pdata =
@@ -604,6 +798,14 @@
return -EINVAL;
}
pipe_connect = &usb_bam_connections[idx];
+ cur_bam = pipe_connect->bam_type;
+
+ if (cur_bam == HSUSB_BAM) {
+ spin_lock(&usb_bam_lock);
+ sched_lpm = 0;
+ lpm_wait_handshake = 1;
+ spin_unlock(&usb_bam_lock);
+ }
if (pipe_connect->enabled) {
pr_debug("%s: connection %d was already established\n",
@@ -611,21 +813,40 @@
return 0;
}
- /* Check if BAM requires RESET before connect and reset of first pipe */
- if ((pdata->reset_on_connect[pipe_connect->bam_type] == true) &&
- (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0))
- sps_device_reset(ctx.h_bam[pipe_connect->bam_type]);
+ spin_lock(&usb_bam_lock);
+
+ /* Check if BAM requires RESET before connect and reset first pipe */
+ if ((pdata->reset_on_connect[cur_bam] == true) &&
+ (ctx.pipes_enabled_per_bam[cur_bam] == 0))
+ sps_device_reset(ctx.h_bam[cur_bam]);
+
+ spin_unlock(&usb_bam_lock);
+
+ if (ipa_params->dir == USB_TO_PEER_PERIPHERAL) {
+ pr_debug("%s: Starting connect sequence\n", __func__);
+ wait_for_prod_granted(cur_bam);
+ }
ret = connect_pipe_ipa(idx, ipa_params);
- ipa_rm_request_resource(IPA_RM_RESOURCE_USB_PROD);
-
if (ret) {
- pr_err("%s: dst pipe connection failure\n", __func__);
+ pr_err("%s: pipe connection failure\n", __func__);
return ret;
}
+ spin_lock(&usb_bam_lock);
+
pipe_connect->enabled = 1;
- ctx.pipes_enabled_per_bam[pipe_connect->bam_type] += 1;
+ ctx.pipes_enabled_per_bam[cur_bam] += 1;
+
+ if (ipa_params->dir == PEER_PERIPHERAL_TO_USB &&
+ cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED) {
+ pr_debug("%s: Notify CONS_GRANTED\n", __func__);
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+ ipa_rm_resource_cons[cur_bam]);
+ pr_debug("%s: Ended connect sequence\n", __func__);
+ }
+
+ spin_unlock(&usb_bam_lock);
return 0;
}
@@ -633,22 +854,22 @@
int usb_bam_client_ready(bool ready)
{
- spin_lock(&usb_bam_lock);
+ spin_lock(&usb_bam_peer_handshake_info_lock);
if (peer_handshake_info.client_ready == ready) {
pr_debug("%s: client state is already %d\n",
__func__, ready);
- spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_peer_handshake_info_lock);
return 0;
}
peer_handshake_info.client_ready = ready;
- spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_peer_handshake_info_lock);
if (!queue_work(ctx.usb_bam_wq,
&peer_handshake_info.reset_event.event_w)) {
- spin_lock(&usb_bam_lock);
+ spin_lock(&usb_bam_peer_handshake_info_lock);
peer_handshake_info.pending_work++;
- spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_peer_handshake_info_lock);
}
return 0;
@@ -656,18 +877,108 @@
static void usb_bam_work(struct work_struct *w)
{
+ int i;
struct usb_bam_event_info *event_info =
container_of(w, struct usb_bam_event_info, event_w);
+ struct usb_bam_pipe_connect *pipe_connect =
+ container_of(event_info, struct usb_bam_pipe_connect, event);
+ struct usb_bam_pipe_connect *pipe_connect_iter;
+ int (*callback)(void *priv);
+ void *param = NULL;
- event_info->callback(event_info->param);
+ switch (event_info->type) {
+ case USB_BAM_EVENT_WAKEUP:
+ case USB_BAM_EVENT_WAKEUP_PIPE:
+
+ pr_debug("%s recieved USB_BAM_EVENT_WAKEUP\n", __func__);
+
+ /* Notify about wakeup / activity of the bam */
+ event_info->callback(event_info->param);
+
+ /*
+ * Reset inactivity timer counter if this pipe's bam
+ * has inactivity timeout.
+ */
+ spin_lock(&usb_bam_lock);
+ if (ctx.inactivity_timer_ms[pipe_connect->bam_type])
+ usb_bam_set_inactivity_timer(pipe_connect->bam_type);
+ spin_unlock(&usb_bam_lock);
+
+ break;
+
+ case USB_BAM_EVENT_INACTIVITY:
+
+ pr_debug("%s recieved USB_BAM_EVENT_INACTIVITY\n", __func__);
+
+ /*
+ * Since event info is one structure per pipe, it might be
+ * overriden when we will register the wakeup events below,
+ * and still we want ot register the wakeup events before we
+ * notify on the inactivity in order to identify the next
+ * activity as soon as possible.
+ */
+ callback = event_info->callback;
+ param = event_info->param;
+
+ /*
+ * Upon inactivity, configure wakeup irq for all pipes
+ * that are into the usb bam.
+ */
+ spin_lock(&usb_bam_lock);
+ for (i = 0; i < ctx.max_connections; i++) {
+ pipe_connect_iter = &usb_bam_connections[i];
+ if (pipe_connect_iter->bam_type ==
+ pipe_connect->bam_type &&
+ pipe_connect_iter->dir ==
+ PEER_PERIPHERAL_TO_USB &&
+ pipe_connect_iter->enabled) {
+ __usb_bam_register_wake_cb(i,
+ pipe_connect_iter->activity_notify,
+ pipe_connect_iter->priv,
+ false);
+ }
+ }
+ spin_unlock(&usb_bam_lock);
+
+ /* Notify about the inactivity */
+ if (callback)
+ callback(param);
+
+ break;
+ default:
+ pr_err("%s: unknown usb bam event type %d\n", __func__,
+ event_info->type);
+ }
}
static void usb_bam_wake_cb(struct sps_event_notify *notify)
{
- struct usb_bam_event_info *wake_event_info =
+ struct usb_bam_event_info *event_info =
(struct usb_bam_event_info *)notify->user;
+ struct usb_bam_pipe_connect *pipe_connect =
+ container_of(event_info,
+ struct usb_bam_pipe_connect,
+ event);
- queue_work(ctx.usb_bam_wq, &wake_event_info->event_w);
+ spin_lock(&usb_bam_lock);
+
+ if (event_info->type == USB_BAM_EVENT_WAKEUP_PIPE)
+ queue_work(ctx.usb_bam_wq, &event_info->event_w);
+ else if (event_info->type == USB_BAM_EVENT_WAKEUP &&
+ ctx.is_bam_inactivity[pipe_connect->bam_type]) {
+
+ /*
+ * Sps wake event is per pipe, so usb_bam_wake_cb is
+ * called per pipe. However, we want to filter the wake
+ * event to be wake event per all the pipes.
+ * Therefore, the first pipe that awaked will be considered
+ * as global bam wake event.
+ */
+ ctx.is_bam_inactivity[pipe_connect->bam_type] = false;
+ queue_work(ctx.usb_bam_wq, &event_info->event_w);
+ }
+
+ spin_unlock(&usb_bam_lock);
}
static void usb_bam_sm_work(struct work_struct *w)
@@ -675,15 +986,15 @@
pr_debug("%s: current state: %d\n", __func__,
peer_handshake_info.state);
- spin_lock(&usb_bam_lock);
+ spin_lock(&usb_bam_peer_handshake_info_lock);
switch (peer_handshake_info.state) {
case USB_BAM_SM_INIT:
if (peer_handshake_info.client_ready) {
- spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_peer_handshake_info_lock);
smsm_change_state(SMSM_APPS_STATE, 0,
SMSM_USB_PLUG_UNPLUG);
- spin_lock(&usb_bam_lock);
+ spin_lock(&usb_bam_peer_handshake_info_lock);
peer_handshake_info.state = USB_BAM_SM_PLUG_NOTIFIED;
}
break;
@@ -695,19 +1006,19 @@
break;
case USB_BAM_SM_PLUG_ACKED:
if (!peer_handshake_info.client_ready) {
- spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_peer_handshake_info_lock);
smsm_change_state(SMSM_APPS_STATE,
SMSM_USB_PLUG_UNPLUG, 0);
- spin_lock(&usb_bam_lock);
+ spin_lock(&usb_bam_peer_handshake_info_lock);
peer_handshake_info.state = USB_BAM_SM_UNPLUG_NOTIFIED;
}
break;
case USB_BAM_SM_UNPLUG_NOTIFIED:
if (peer_handshake_info.ack_received) {
- spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_peer_handshake_info_lock);
peer_handshake_info.reset_event.
callback(peer_handshake_info.reset_event.param);
- spin_lock(&usb_bam_lock);
+ spin_lock(&usb_bam_peer_handshake_info_lock);
peer_handshake_info.state = USB_BAM_SM_INIT;
peer_handshake_info.ack_received = 0;
}
@@ -716,12 +1027,12 @@
if (peer_handshake_info.pending_work) {
peer_handshake_info.pending_work--;
- spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_peer_handshake_info_lock);
queue_work(ctx.usb_bam_wq,
&peer_handshake_info.reset_event.event_w);
- spin_lock(&usb_bam_lock);
+ spin_lock(&usb_bam_peer_handshake_info_lock);
}
- spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_peer_handshake_info_lock);
}
static void usb_bam_ack_toggle_cb(void *priv,
@@ -730,29 +1041,29 @@
static int last_processed_state;
int current_state;
- spin_lock(&usb_bam_lock);
+ spin_lock(&usb_bam_peer_handshake_info_lock);
current_state = new_state & SMSM_USB_PLUG_UNPLUG;
if (current_state == last_processed_state) {
- spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_peer_handshake_info_lock);
return;
}
last_processed_state = current_state;
peer_handshake_info.ack_received = true;
- spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_peer_handshake_info_lock);
if (!queue_work(ctx.usb_bam_wq,
&peer_handshake_info.reset_event.event_w)) {
- spin_lock(&usb_bam_lock);
+ spin_lock(&usb_bam_peer_handshake_info_lock);
peer_handshake_info.pending_work++;
- spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_peer_handshake_info_lock);
}
}
-int usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
- void *param)
+static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
+ void *param, bool trigger_cb_per_pipe)
{
struct sps_pipe *pipe = ctx.usb_bam_sps.sps_pipes[idx];
struct sps_connect *sps_connection;
@@ -767,8 +1078,11 @@
pipe = ctx.usb_bam_sps.sps_pipes[idx];
sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
pipe_connect = &usb_bam_connections[idx];
- wake_event_info = &pipe_connect->wake_event;
+ wake_event_info = &pipe_connect->event;
+ wake_event_info->type = (trigger_cb_per_pipe ?
+ USB_BAM_EVENT_WAKEUP_PIPE :
+ USB_BAM_EVENT_WAKEUP);
wake_event_info->param = param;
wake_event_info->callback = callback;
wake_event_info->event.mode = SPS_TRIGGER_CALLBACK;
@@ -794,6 +1108,12 @@
return 0;
}
+int usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
+ void *param)
+{
+ return __usb_bam_register_wake_cb(idx, callback, param, true);
+}
+
int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param)
{
u32 ret = 0;
@@ -831,44 +1151,121 @@
pipe_connect = &usb_bam_connections[idx];
if (!pipe_connect->enabled) {
- pr_debug("%s: connection %d isn't enabled\n",
+ pr_err("%s: connection %d isn't enabled\n",
__func__, idx);
return 0;
}
+ spin_lock(&usb_bam_lock);
+
ret = disconnect_pipe(idx);
if (ret) {
- pr_err("%s: src pipe connection failure\n", __func__);
+ pr_err("%s: src pipe disconnection failure\n", __func__);
+ spin_unlock(&usb_bam_lock);
return ret;
}
pipe_connect->enabled = 0;
+
if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0)
pr_err("%s: wrong pipes enabled counter for bam_type=%d\n",
__func__, pipe_connect->bam_type);
else
ctx.pipes_enabled_per_bam[pipe_connect->bam_type] -= 1;
+ spin_unlock(&usb_bam_lock);
+
return 0;
}
+static void usb_bam_start_lpm(void)
+{
+ struct usb_phy *trans = usb_get_transceiver();
+ BUG_ON(trans == NULL);
+ spin_lock(&usb_bam_lock);
+ lpm_wait_handshake = 0;
+ if (sched_lpm) {
+ pr_debug("%s: Going to LPM\n", __func__);
+ spin_unlock(&usb_bam_lock);
+ pm_runtime_resume(trans->dev);
+ pm_runtime_put_noidle(trans->dev);
+ pm_runtime_suspend(trans->dev);
+ return;
+ }
+ spin_unlock(&usb_bam_lock);
+}
+
+static void wait_for_prod_release(enum usb_bam cur_bam)
+{
+ int ret;
+
+ if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ pr_debug("%s consumer already released\n", __func__);
+ if (cur_prod_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ pr_debug("%s producer already released\n", __func__);
+
+ init_completion(&prod_released[cur_bam]);
+ init_completion(&cons_released[cur_bam]);
+ pr_debug("%s: Releasing %s_PROD\n", __func__,
+ bam_enable_strings[cur_bam]);
+ ret = ipa_rm_release_resource(ipa_rm_resource_prod[cur_bam]);
+ if (!ret) {
+ pr_debug("%s: Released without waiting\n", __func__);
+ cur_prod_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
+ complete_all(&prod_released[cur_bam]);
+ } else if (ret == -EINPROGRESS) {
+ pr_debug("%s: Waiting for PROD_RELEASED\n", __func__);
+ if (!wait_for_completion_timeout(&prod_released[cur_bam],
+ USB_BAM_TIMEOUT))
+ pr_err("%s: Timeout waiting for PROD_RELEASED\n",
+ __func__);
+ } else
+ pr_err("%s: ipa_rm_request_resource ret =%d", __func__, ret);
+}
+
+static void wait_for_cons_release(enum usb_bam cur_bam)
+{
+ pr_debug("%s: Waiting for CONS release\n", __func__);
+ if (cur_prod_state[cur_bam] != IPA_RM_RESOURCE_RELEASED) {
+ if (!wait_for_completion_timeout(&cons_released[cur_bam],
+ USB_BAM_TIMEOUT))
+ pr_err("%s: Timeout wainting for CONS_RELEASE\n",
+ __func__);
+ } else
+ pr_debug("%s Didn't need to wait for CONS release\n",
+ __func__);
+}
+
int usb_bam_disconnect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
int ret;
u8 idx;
struct usb_bam_pipe_connect *pipe_connect;
struct sps_connect *sps_connection;
+ enum usb_bam cur_bam;
+
+ if (!ipa_params->prod_clnt_hdl && !ipa_params->cons_clnt_hdl) {
+ pr_err("%s: Both of the handles is missing\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: Starting disconnect sequence\n", __func__);
+ /* Delay USB core to go into lpm before we finish our handshake */
if (ipa_params->prod_clnt_hdl) {
- /* close USB -> IPA pipe */
idx = ipa_params->dst_idx;
+ pipe_connect = &usb_bam_connections[idx];
+
+ /* Do the release handshake with the A2 via RM */
+ cur_bam = pipe_connect->bam_type;
+ wait_for_prod_release(cur_bam);
+ /* close USB -> IPA pipe */
ret = ipa_disconnect(ipa_params->prod_clnt_hdl);
if (ret) {
pr_err("%s: dst pipe disconnection failure\n",
__func__);
return ret;
}
- pipe_connect = &usb_bam_connections[idx];
sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
sps_connection->data.phys_base = 0;
sps_connection->desc.phys_base = 0;
@@ -880,16 +1277,20 @@
return ret;
}
}
+
if (ipa_params->cons_clnt_hdl) {
- /* close IPA -> USB pipe */
idx = ipa_params->src_idx;
+ pipe_connect = &usb_bam_connections[idx];
+ cur_bam = pipe_connect->bam_type;
+ wait_for_cons_release(cur_bam);
+ /* close IPA -> USB pipe */
ret = ipa_disconnect(ipa_params->cons_clnt_hdl);
if (ret) {
pr_err("%s: src pipe disconnection failure\n",
__func__);
return ret;
}
- pipe_connect = &usb_bam_connections[idx];
+
sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
sps_connection->data.phys_base = 0;
sps_connection->desc.phys_base = 0;
@@ -900,9 +1301,15 @@
__func__, idx);
return ret;
}
+ pr_debug("%s: Notify CONS release\n", __func__);
+
+ if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
+ ipa_rm_resource_cons[cur_bam]);
+ pr_debug("%s Ended disconnect sequence\n", __func__);
+ usb_bam_start_lpm();
}
- ipa_rm_release_resource(IPA_RM_RESOURCE_USB_PROD);
return 0;
}
EXPORT_SYMBOL(usb_bam_disconnect_ipa);
@@ -965,6 +1372,53 @@
return ret;
}
+static void usb_bam_sps_events(enum sps_callback_case sps_cb_case, void *user)
+{
+ int i;
+ enum usb_bam bam;
+ struct usb_bam_pipe_connect *pipe_connect;
+ struct usb_bam_event_info *event_info;
+
+ switch (sps_cb_case) {
+ case SPS_CALLBACK_BAM_TIMER_IRQ:
+
+ pr_debug("%s:recieved SPS_CALLBACK_BAM_TIMER_IRQ\n", __func__);
+
+ spin_lock(&usb_bam_lock);
+
+ bam = get_bam_type_from_core_name((char *)user);
+ ctx.is_bam_inactivity[bam] = true;
+ pr_debug("%s: Incativity happened on bam=%s,%d\n", __func__,
+ (char *)user, bam);
+
+ for (i = 0; i < ctx.max_connections; i++) {
+ pipe_connect = &usb_bam_connections[i];
+
+ /*
+ * Notify inactivity once, Since it is global
+ * for all pipes on bam.
+ */
+ if (pipe_connect->bam_type == bam) {
+ event_info = &pipe_connect->event;
+ event_info->type = USB_BAM_EVENT_INACTIVITY;
+ event_info->param = pipe_connect->priv;
+ event_info->callback =
+ pipe_connect->inactivity_notify;
+ queue_work(ctx.usb_bam_wq,
+ &event_info->event_w);
+ break;
+ }
+ }
+
+ spin_unlock(&usb_bam_lock);
+
+ break;
+ default:
+ pr_debug("%s:received sps_cb_case=%d\n", __func__,
+ (int)sps_cb_case);
+ }
+}
+
static struct msm_usb_bam_platform_data *usb_bam_dt_to_pdata(
struct platform_device *pdev)
{
@@ -1174,6 +1628,9 @@
props.summing_threshold = USB_THRESHOLD;
props.event_threshold = USB_THRESHOLD;
props.num_pipes = pdata->usb_bam_num_pipes;
+ props.callback = usb_bam_sps_events;
+ props.user = bam_enable_strings[bam_idx];
+
/*
* HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
* Hence, let BAM to ignore acknowledge from USB while resetting PIPE
@@ -1234,6 +1691,78 @@
return 0;
}
+static ssize_t
+usb_bam_show_inactivity_timer(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ char *buff = buf;
+ int i;
+
+ spin_lock(&usb_bam_lock);
+
+ for (i = 0; i < ARRAY_SIZE(bam_enable_strings); i++) {
+ buff += snprintf(buff, PAGE_SIZE, "%s: %dms\n",
+ bam_enable_strings[i],
+ ctx.inactivity_timer_ms[i]);
+ }
+
+ spin_unlock(&usb_bam_lock);
+
+ return buff - buf;
+}
+
+static ssize_t usb_bam_store_inactivity_timer(struct device *dev,
+ struct device_attribute *attr,
+ const char *buff, size_t count)
+{
+ char buf[USB_BAM_MAX_STR_LEN];
+ char *trimmed_buf, *bam_str, *bam_name, *timer;
+ int timer_d;
+ enum usb_bam bam;
+
+ if (strnstr(buff, "help", USB_BAM_MAX_STR_LEN)) {
+ pr_info("Usage: <bam_name> <ms>,<bam_name> <ms>,...\n");
+ pr_info("\tbam_name: [%s, %s, %s]\n",
+ bam_enable_strings[SSUSB_BAM],
+ bam_enable_strings[HSUSB_BAM],
+ bam_enable_strings[HSIC_BAM]);
+ pr_info("\tms: time in ms. Use 0 to disable timer\n");
+ return count;
+ }
+
+ strlcpy(buf, buff, sizeof(buf));
+ trimmed_buf = strim(buf);
+
+ while (trimmed_buf) {
+ bam_str = strsep(&trimmed_buf, ",");
+ if (bam_str) {
+ bam_name = strsep(&bam_str, " ");
+ bam = get_bam_type_from_core_name(bam_name);
+
+ timer = strsep(&bam_str, " ");
+ sscanf(timer, "%d", &timer_d);
+
+ spin_lock(&usb_bam_lock);
+
+ /* Apply new timer setting if bam has running pipes */
+ if (ctx.inactivity_timer_ms[bam] != timer_d) {
+ ctx.inactivity_timer_ms[bam] = timer_d;
+ if (ctx.pipes_enabled_per_bam[bam] > 0)
+ usb_bam_set_inactivity_timer(bam);
+ }
+
+ spin_unlock(&usb_bam_lock);
+ }
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(inactivity_timer, S_IWUSR | S_IRUSR,
+ usb_bam_show_inactivity_timer,
+ usb_bam_store_inactivity_timer);
+
+
static int usb_bam_probe(struct platform_device *pdev)
{
int ret, i;
@@ -1241,10 +1770,14 @@
dev_dbg(&pdev->dev, "usb_bam_probe\n");
+ ret = device_create_file(&pdev->dev, &dev_attr_inactivity_timer);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to create fs node\n");
+ return ret;
+ }
+
ctx.mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
if (IS_ERR(ctx.mem_clk))
-
-
dev_dbg(&pdev->dev, "failed to get mem_clock\n");
ctx.mem_iface_clk = devm_clk_get(&pdev->dev, "mem_iface_clk");
@@ -1269,14 +1802,27 @@
for (i = 0; i < ctx.max_connections; i++) {
usb_bam_connections[i].enabled = 0;
- INIT_WORK(&usb_bam_connections[i].wake_event.event_w,
+ INIT_WORK(&usb_bam_connections[i].event.event_w,
usb_bam_work);
}
- for (i = 0; i < MAX_BAMS; i++)
+ for (i = 0; i < MAX_BAMS; i++) {
ctx.pipes_enabled_per_bam[i] = 0;
+ ctx.inactivity_timer_ms[i] = 0;
+ ctx.is_bam_inactivity[i] = false;
+ init_completion(&prod_avail[i]);
+ complete(&prod_avail[i]);
+ init_completion(&cons_avail[i]);
+ complete(&cons_avail[i]);
+ init_completion(&cons_released[i]);
+ complete(&cons_released[i]);
+ init_completion(&prod_released[i]);
+ complete(&prod_released[i]);
+ cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
+ cur_cons_state[i] = IPA_RM_RESOURCE_RELEASED;
+ }
- spin_lock_init(&usb_bam_lock);
+ spin_lock_init(&usb_bam_peer_handshake_info_lock);
INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
ctx.usb_bam_wq = alloc_workqueue("usb_bam_wq",
@@ -1293,6 +1839,8 @@
}
usb_bam_ipa_create_resources();
+ spin_lock_init(&usb_bam_lock);
+
return ret;
}
@@ -1361,6 +1909,22 @@
}
EXPORT_SYMBOL(usb_bam_get_connection_idx);
+bool msm_bam_lpm_ok(void)
+{
+ spin_lock(&usb_bam_lock);
+ if (lpm_wait_handshake) {
+ sched_lpm = 1;
+ spin_unlock(&usb_bam_lock);
+ pr_err("%s: Scheduling LPM for later\n", __func__);
+ return 0;
+ } else {
+ spin_unlock(&usb_bam_lock);
+ pr_err("%s: Going to LPM now\n", __func__);
+ return 1;
+ }
+}
+EXPORT_SYMBOL(msm_bam_lpm_ok);
+
static int usb_bam_remove(struct platform_device *pdev)
{
destroy_workqueue(ctx.usb_bam_wq);
diff --git a/drivers/power/bq28400_battery.c b/drivers/power/bq28400_battery.c
index beab4e2..79ed2b1 100644
--- a/drivers/power/bq28400_battery.c
+++ b/drivers/power/bq28400_battery.c
@@ -164,6 +164,9 @@
u16 subcmd;
};
+static int fake_battery = -EINVAL;
+module_param(fake_battery, int, 0644);
+
#define BQ28400_DEBUG_REG(x) {#x, SBS_##x, 0}
#define BQ28400_DEBUG_SUBREG(x, y) {#y, SBS_##x, SUBCMD_##y}
@@ -403,6 +406,11 @@
{
int percentage = 0;
+ if (fake_battery != -EINVAL) {
+ pr_debug("Reporting Fake SOC = %d\n", fake_battery);
+ return fake_battery;
+ }
+
/* This register is only 1 byte */
percentage = i2c_smbus_read_byte_data(client, SBS_RSOC);
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index c09373a..9b3973b 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -177,6 +177,9 @@
int vbatt_cutoff_count;
int low_voltage_detect;
int vbatt_cutoff_retries;
+ bool first_report_after_suspend;
+ bool soc_updated_on_resume;
+ int last_soc_at_suspend;
};
/*
@@ -2387,10 +2390,11 @@
rbatt, fcc_uah, unusable_charge_uah, cc_uah);
pr_debug("calculated SOC = %d\n", new_calculated_soc);
- if (new_calculated_soc != calculated_soc)
+ if (new_calculated_soc != calculated_soc) {
+ calculated_soc = new_calculated_soc;
update_power_supply(chip);
+ }
- calculated_soc = new_calculated_soc;
firsttime = 0;
get_current_time(&chip->last_recalc_time);
@@ -2495,15 +2499,31 @@
/* last_soc < soc ... scale and catch up */
if (last_soc != -EINVAL && last_soc < soc && soc != 100)
- soc = scale_soc_while_chg(chip, delta_time_us,
- soc, last_soc);
+ soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
- /* restrict soc to 1% change */
if (last_soc != -EINVAL) {
- if (soc < last_soc && soc != 0)
+ if (chip->first_report_after_suspend) {
+ chip->first_report_after_suspend = false;
+ if (chip->soc_updated_on_resume) {
+ /* coming here after a long suspend */
+ chip->soc_updated_on_resume = false;
+ if (last_soc < soc)
+ /* if soc has falsely increased during
+ * suspend, set the soc_at_suspend
+ */
+ soc = chip->last_soc_at_suspend;
+ } else {
+ /*
+ * suspended for a short time
+ * report the last_soc before suspend
+ */
+ soc = chip->last_soc_at_suspend;
+ }
+ } else if (soc < last_soc && soc != 0) {
soc = last_soc - 1;
- if (soc > last_soc && soc != 100)
+ } else if (soc > last_soc && soc != 100) {
soc = last_soc + 1;
+ }
}
last_soc = bound_soc(soc);
@@ -3560,12 +3580,11 @@
static int pm8921_bms_suspend(struct device *dev)
{
- /*
- * set the last reported soc to invalid, so that
- * next time we resume we don't want to restrict
- * the decrease of soc by only 1%
- */
- last_soc = -EINVAL;
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+
+ cancel_delayed_work_sync(&chip->calculate_soc_delayed_work);
+
+ chip->last_soc_at_suspend = last_soc;
return 0;
}
@@ -3575,22 +3594,30 @@
int rc;
unsigned long time_since_last_recalc;
unsigned long tm_now_sec;
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
rc = get_current_time(&tm_now_sec);
if (rc) {
pr_err("Could not read current time: %d\n", rc);
return 0;
}
- if (tm_now_sec > the_chip->last_recalc_time) {
+
+ if (tm_now_sec > chip->last_recalc_time) {
time_since_last_recalc = tm_now_sec -
- the_chip->last_recalc_time;
+ chip->last_recalc_time;
pr_debug("Time since last recalc: %lu\n",
time_since_last_recalc);
- if (time_since_last_recalc >= the_chip->soc_calc_period) {
- the_chip->last_recalc_time = tm_now_sec;
- recalculate_soc(the_chip);
+ if ((time_since_last_recalc * 1000) >=
+ chip->soc_calc_period) {
+ chip->last_recalc_time = tm_now_sec;
+ recalculate_soc(chip);
+ chip->soc_updated_on_resume = true;
}
}
+ chip->first_report_after_suspend = true;
+ update_power_supply(chip);
+ schedule_delayed_work(&chip->calculate_soc_delayed_work,
+ msecs_to_jiffies(chip->soc_calc_period));
return 0;
}
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 63fb0a5..5cdb666 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -176,6 +176,7 @@
POWER_SUPPLY_ATTR(type),
POWER_SUPPLY_ATTR(scope),
POWER_SUPPLY_ATTR(system_temp_level),
+ POWER_SUPPLY_ATTR(resistance),
/* Properties of type `const char *' */
POWER_SUPPLY_ATTR(model_name),
POWER_SUPPLY_ATTR(manufacturer),
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index fd42c47..4f9254f 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -24,6 +24,7 @@
#include <linux/rtc.h>
#include <linux/delay.h>
#include <linux/qpnp/qpnp-adc.h>
+#include <linux/qpnp/power-on.h>
#include <linux/mfd/pm8xxx/batterydata-lib.h>
/* BMS Register Offsets */
@@ -127,7 +128,7 @@
int adjust_soc_low_threshold;
int chg_term_ua;
enum battery_type batt_type;
- unsigned int fcc;
+ unsigned int fcc_mah;
struct single_row_lut *fcc_temp_lut;
struct single_row_lut *fcc_sf_lut;
struct pc_temp_ocv_lut *pc_temp_ocv_lut;
@@ -135,13 +136,17 @@
struct sf_lut *rbatt_sf_lut;
int default_rbatt_mohm;
int rbatt_capacitive_mohm;
+ int rbatt_mohm;
struct delayed_work calculate_soc_delayed_work;
struct work_struct recalc_work;
+ struct work_struct battery_insertion_work;
struct mutex bms_output_lock;
struct mutex last_ocv_uv_mutex;
+ struct mutex vbat_monitor_mutex;
struct mutex soc_invalidation_mutex;
+ struct mutex last_soc_mutex;
bool use_external_rsense;
bool use_ocv_thresholds;
@@ -152,19 +157,21 @@
int shutdown_iavg_ma;
struct wake_lock low_voltage_wake_lock;
- bool low_voltage_wake_lock_held;
int low_voltage_threshold;
int low_soc_calc_threshold;
int low_soc_calculate_soc_ms;
int calculate_soc_ms;
struct wake_lock soc_wake_lock;
+ struct wake_lock cv_wake_lock;
uint16_t ocv_reading_at_100;
uint16_t prev_last_good_ocv_raw;
int last_ocv_uv;
int last_ocv_temp;
int last_cc_uah;
+ unsigned long last_soc_change_sec;
unsigned long tm_sec;
+ unsigned long report_tm_sec;
bool first_time_calc_soc;
bool first_time_calc_uuc;
int pon_ocv_uv;
@@ -176,15 +183,15 @@
int last_soc;
int last_soc_est;
int last_soc_unbound;
-
- int charge_time_us;
- int catch_up_time_us;
+ bool was_charging_at_sleep;
+ int charge_start_tm_sec;
+ int catch_up_time_sec;
struct single_row_lut *adjusted_fcc_temp_lut;
+ struct qpnp_adc_tm_btm_param vbat_monitor_params;
unsigned int vadc_v0625;
unsigned int vadc_v1250;
- int ibat_max_ua;
int prev_uuc_iavg_ma;
int prev_pc_unusable;
int ibat_at_cv_ua;
@@ -193,6 +200,7 @@
int calculated_soc;
int prev_voltage_based_soc;
bool use_voltage_soc;
+ bool in_cv_range;
int prev_batt_terminal_uv;
int high_ocv_correction_limit_uv;
@@ -218,7 +226,7 @@
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CURRENT_NOW,
- POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_RESISTANCE,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
};
@@ -375,7 +383,7 @@
#define CC_READING_RESOLUTION_N 542535
#define CC_READING_RESOLUTION_D 100000
-static int cc_reading_to_uv(int16_t reading)
+static s64 cc_reading_to_uv(s64 reading)
{
return div_s64(reading * CC_READING_RESOLUTION_N,
CC_READING_RESOLUTION_D);
@@ -582,7 +590,25 @@
return false;
}
-static bool is_batfet_open(struct qpnp_bms_chip *chip)
+static bool is_battery_present(struct qpnp_bms_chip *chip)
+{
+ union power_supply_propval ret = {0,};
+
+ if (chip->batt_psy == NULL)
+ chip->batt_psy = power_supply_get_by_name("battery");
+ if (chip->batt_psy) {
+ /* if battery has been registered, use the status property */
+ chip->batt_psy->get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_PRESENT, &ret);
+ return ret.intval;
+ }
+
+ /* Default to false if the battery power supply is not registered. */
+ pr_debug("battery power supply is not registered\n");
+ return false;
+}
+
+static bool is_battery_full(struct qpnp_bms_chip *chip)
{
union power_supply_propval ret = {0,};
@@ -610,18 +636,32 @@
iadc_channel = chip->use_external_rsense ?
EXTERNAL_RSENSE : INTERNAL_RSENSE;
- rc = qpnp_iadc_vadc_sync_read(iadc_channel, &i_result,
- VBAT_SNS, &v_result);
- if (rc) {
- pr_err("vadc read failed with rc: %d\n", rc);
- return rc;
+ if (is_battery_full(chip)) {
+ rc = get_battery_current(chip, ibat_ua);
+ if (rc) {
+ pr_err("bms current read failed with rc: %d\n", rc);
+ return rc;
+ }
+ rc = qpnp_vadc_read(VBAT_SNS, &v_result);
+ if (rc) {
+ pr_err("vadc read failed with rc: %d\n", rc);
+ return rc;
+ }
+ *vbat_uv = (int)v_result.physical;
+ } else {
+ rc = qpnp_iadc_vadc_sync_read(iadc_channel, &i_result,
+ VBAT_SNS, &v_result);
+ if (rc) {
+ pr_err("adc sync read failed with rc: %d\n", rc);
+ return rc;
+ }
+ /*
+ * reverse the current read by the iadc, since the bms uses
+ * flipped battery current polarity.
+ */
+ *ibat_ua = -1 * (int)i_result.result_ua;
+ *vbat_uv = (int)v_result.physical;
}
- /*
- * reverse the current read by the iadc, since the bms uses
- * flipped battery current polarity.
- */
- *ibat_ua = -1 * (int)i_result.result_ua;
- *vbat_uv = (int)v_result.physical;
return 0;
}
@@ -647,7 +687,10 @@
static void reset_for_new_battery(struct qpnp_bms_chip *chip, int batt_temp)
{
chip->last_ocv_uv = estimate_ocv(chip);
+ mutex_lock(&chip->last_soc_mutex);
chip->last_soc = -EINVAL;
+ chip->last_soc_invalid = true;
+ mutex_unlock(&chip->last_soc_mutex);
chip->soc_at_cv = -EINVAL;
chip->shutdown_soc_invalid = true;
chip->shutdown_soc = 0;
@@ -656,15 +699,16 @@
reset_cc(chip);
chip->last_cc_uah = INT_MIN;
chip->last_ocv_temp = batt_temp;
- chip->last_soc_invalid = true;
chip->prev_batt_terminal_uv = 0;
}
#define OCV_RAW_UNINITIALIZED 0xFFFF
+#define MIN_OCV_UV 2000000
static int read_soc_params_raw(struct qpnp_bms_chip *chip,
struct raw_soc_params *raw,
int batt_temp)
{
+ bool warm_reset = false;
int rc;
mutex_lock(&chip->bms_output_lock);
@@ -697,7 +741,18 @@
if (chip->prev_last_good_ocv_raw == OCV_RAW_UNINITIALIZED) {
convert_and_store_ocv(chip, raw, batt_temp);
- pr_debug("PON_OCV_UV = %d\n", chip->last_ocv_uv);
+ pr_debug("PON_OCV_UV = %d, cc = %llx\n",
+ chip->last_ocv_uv, raw->cc);
+ warm_reset = qpnp_pon_is_warm_reset();
+ if (raw->last_good_ocv_uv < MIN_OCV_UV
+ || warm_reset > 0) {
+ pr_debug("OCV is stale or bad, estimating new OCV.\n");
+ chip->last_ocv_uv = estimate_ocv(chip);
+ raw->last_good_ocv_uv = chip->last_ocv_uv;
+ reset_cc(chip);
+ pr_debug("New PON_OCV_UV = %d, cc = %llx\n",
+ chip->last_ocv_uv, raw->cc);
+ }
} else if (chip->new_battery) {
/* if a new battery was inserted, estimate the ocv */
reset_for_new_battery(chip, batt_temp);
@@ -774,14 +829,6 @@
return (fcc_uah * pc) / 100;
}
-#define CC_RESOLUTION_N 542535
-#define CC_RESOLUTION_D 100000
-
-static s64 cc_to_uv(s64 cc)
-{
- return div_s64(cc * CC_RESOLUTION_N, CC_RESOLUTION_D);
-}
-
#define CC_READING_TICKS 56
#define SLEEP_CLK_HZ 32764
#define SECONDS_PER_HOUR 3600
@@ -817,7 +864,7 @@
qpnp_iadc_get_gain_and_offset(&calibration);
pr_debug("cc = %lld\n", cc);
- cc_voltage_uv = cc_to_uv(cc);
+ cc_voltage_uv = cc_reading_to_uv(cc);
cc_voltage_uv = cc_adjust_for_gain(cc_voltage_uv,
calibration.gain_raw
- calibration.offset_raw);
@@ -836,7 +883,6 @@
int rbatt_mohm, scalefactor;
rbatt_mohm = chip->default_rbatt_mohm;
- pr_debug("rbatt before scaling = %d\n", rbatt_mohm);
if (chip->rbatt_sf_lut == NULL) {
pr_debug("RBATT = %d\n", rbatt_mohm);
return rbatt_mohm;
@@ -845,18 +891,10 @@
batt_temp = batt_temp / 10;
scalefactor = interpolate_scalingfactor(chip->rbatt_sf_lut,
batt_temp, soc_rbatt_mohm);
- pr_debug("rbatt sf = %d for batt_temp = %d, soc_rbatt = %d\n",
- scalefactor, batt_temp, soc_rbatt_mohm);
rbatt_mohm = (rbatt_mohm * scalefactor) / 100;
rbatt_mohm += chip->r_conn_mohm;
- pr_debug("adding r_conn_mohm = %d rbatt = %d\n",
- chip->r_conn_mohm, rbatt_mohm);
rbatt_mohm += chip->rbatt_capacitive_mohm;
- pr_debug("adding rbatt_capacitive_mohm = %d rbatt = %d\n",
- chip->rbatt_capacitive_mohm, rbatt_mohm);
-
- pr_debug("RBATT = %d\n", rbatt_mohm);
return rbatt_mohm;
}
@@ -909,9 +947,6 @@
+ (chip->v_cutoff_uv);
delta_uv = ocv_mv * 1000 - unusable_uv;
- pr_debug("soc = %d ocv = %d rbat = %d u_uv = %d delta_v = %d\n",
- i, ocv_mv, rbatt_mohm, unusable_uv, delta_uv);
-
if (delta_uv > 0)
break;
@@ -927,10 +962,10 @@
pc_unusable = calculate_pc(chip, unusable_uv, batt_temp);
uuc_uah = (params->fcc_uah * pc_unusable) / 100;
- pr_debug("For uuc_iavg_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d uuc = %d\n",
+ pr_debug("For uuc_iavg_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d rbatt_pc = %d uuc = %d\n",
uuc_iavg_ma,
uuc_rbatt_mohm, unusable_uv,
- pc_unusable, uuc_uah);
+ pc_unusable, i, uuc_uah);
*ret_pc_unusable = pc_unusable;
return uuc_uah;
}
@@ -1106,8 +1141,7 @@
if (rtc == NULL) {
pr_err("%s: unable to open rtc device (%s)\n",
__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
- rc = -EINVAL;
- goto close_time;
+ return -EINVAL;
}
rc = rtc_read_time(rtc, &tm);
@@ -1130,21 +1164,22 @@
return rc;
}
-static int calculate_delta_time(struct qpnp_bms_chip *chip, int *delta_time_s)
+static int calculate_delta_time(unsigned long *time_stamp, int *delta_time_s)
{
unsigned long now_tm_sec = 0;
/* default to delta time = 0 if anything fails */
*delta_time_s = 0;
- get_current_time(&now_tm_sec);
+ if (get_current_time(&now_tm_sec)) {
+ pr_err("RTC read failed\n");
+ return 0;
+ }
- *delta_time_s = (now_tm_sec - chip->tm_sec);
- pr_debug("tm_sec = %ld, now_tm_sec = %ld delta_s = %d\n",
- chip->tm_sec, now_tm_sec, *delta_time_s);
+ *delta_time_s = (now_tm_sec - *time_stamp);
/* remember this time */
- chip->tm_sec = now_tm_sec;
+ *time_stamp = now_tm_sec;
return 0;
}
@@ -1155,7 +1190,9 @@
{
int soc_rbatt;
- calculate_delta_time(chip, ¶ms->delta_time_s);
+ calculate_delta_time(&chip->tm_sec, ¶ms->delta_time_s);
+ pr_debug("tm_sec = %ld, delta_s = %d\n",
+ chip->tm_sec, params->delta_time_s);
params->fcc_uah = calculate_fcc(chip, batt_temp);
pr_debug("FCC = %uuAh batt_temp = %d\n", params->fcc_uah, batt_temp);
@@ -1174,6 +1211,13 @@
if (soc_rbatt < 0)
soc_rbatt = 0;
params->rbatt_mohm = get_rbatt(chip, soc_rbatt, batt_temp);
+ pr_debug("rbatt_mohm = %d\n", params->rbatt_mohm);
+
+ if (params->rbatt_mohm != chip->rbatt_mohm
+ && chip->bms_psy.name != NULL) {
+ chip->rbatt_mohm = params->rbatt_mohm;
+ power_supply_changed(&chip->bms_psy);
+ }
calculate_iavg(chip, params->cc_uah, ¶ms->iavg_ua,
params->delta_time_s);
@@ -1240,8 +1284,10 @@
ocv_est_uv = vbat_uv + (ibat_ua * chip->r_conn_mohm) / 1000;
pr_debug("forcing ocv to be %d due to bms reset mode\n", ocv_est_uv);
chip->last_ocv_uv = ocv_est_uv;
+ mutex_lock(&chip->last_soc_mutex);
chip->last_soc = -EINVAL;
chip->last_soc_invalid = true;
+ mutex_unlock(&chip->last_soc_mutex);
reset_cc(chip);
chip->last_cc_uah = INT_MIN;
stop_ocv_updates(chip);
@@ -1283,25 +1329,26 @@
module_param_cb(bms_reset, &bms_reset_ops, &bms_reset, 0644);
+#define VBATT_ERROR_MARGIN 20000
static int charging_adjustments(struct qpnp_bms_chip *chip,
struct soc_params *params, int soc,
int vbat_uv, int ibat_ua, int batt_temp)
{
- int chg_soc;
- int batt_terminal_uv = vbat_uv + (ibat_ua * chip->r_conn_mohm) / 1000;
+ int chg_soc, batt_terminal_uv;
+
+ batt_terminal_uv = vbat_uv + VBATT_ERROR_MARGIN
+ + (ibat_ua * chip->r_conn_mohm) / 1000;
if (chip->soc_at_cv == -EINVAL) {
- /* In constant current charging return the calc soc */
- if (batt_terminal_uv <= chip->max_voltage_uv)
- pr_debug("CC CHG SOC %d\n", soc);
-
- /* Note the CC to CV point */
if (batt_terminal_uv >= chip->max_voltage_uv) {
chip->soc_at_cv = soc;
chip->prev_chg_soc = soc;
chip->ibat_at_cv_ua = ibat_ua;
pr_debug("CC_TO_CV ibat_ua = %d CHG SOC %d\n",
ibat_ua, soc);
+ } else {
+ /* In constant current charging return the calc soc */
+ pr_debug("CC CHG SOC %d\n", soc);
}
chip->prev_batt_terminal_uv = batt_terminal_uv;
@@ -1355,18 +1402,40 @@
* a wakelock untill soc = 0%
*/
if (vbat_uv <= chip->low_voltage_threshold
- && !chip->low_voltage_wake_lock_held) {
+ && !wake_lock_active(&chip->low_voltage_wake_lock)) {
pr_debug("voltage = %d low holding wakelock\n", vbat_uv);
wake_lock(&chip->low_voltage_wake_lock);
- chip->low_voltage_wake_lock_held = 1;
} else if (vbat_uv > chip->low_voltage_threshold
- && chip->low_voltage_wake_lock_held) {
+ && wake_lock_active(&chip->low_voltage_wake_lock)) {
pr_debug("voltage = %d releasing wakelock\n", vbat_uv);
- chip->low_voltage_wake_lock_held = 0;
wake_unlock(&chip->low_voltage_wake_lock);
}
}
+#define VBATT_ERROR_MARGIN 20000
+static void cv_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv)
+{
+ /*
+ * if battery is very low (v_cutoff voltage + 20mv) hold
+ * a wakelock untill soc = 0%
+ */
+ if (wake_lock_active(&chip->cv_wake_lock)) {
+ if (chip->soc_at_cv != -EINVAL) {
+ pr_debug("hit CV, releasing cv wakelock\n");
+ wake_unlock(&chip->cv_wake_lock);
+ } else if (!is_battery_charging(chip)) {
+ pr_debug("charging stopped, releasing cv wakelock\n");
+ wake_unlock(&chip->cv_wake_lock);
+ }
+ } else if (vbat_uv > chip->max_voltage_uv - VBATT_ERROR_MARGIN
+ && chip->soc_at_cv == -EINVAL
+ && is_battery_charging(chip)
+ && !wake_lock_active(&chip->cv_wake_lock)) {
+ pr_debug("voltage = %d holding cv wakelock\n", vbat_uv);
+ wake_lock(&chip->cv_wake_lock);
+ }
+}
+
#define NO_ADJUST_HIGH_SOC_THRESHOLD 90
static int adjust_soc(struct qpnp_bms_chip *chip, struct soc_params *params,
int soc, int batt_temp)
@@ -1390,14 +1459,12 @@
}
very_low_voltage_check(chip, vbat_uv);
+ cv_voltage_check(chip, vbat_uv);
delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
ocv_est_uv = vbat_uv + (ibat_ua * params->rbatt_mohm)/1000;
- chip->ibat_max_ua = (ocv_est_uv - chip->v_cutoff_uv) * 1000
- / (params->rbatt_mohm);
-
pc_est = calculate_pc(chip, ocv_est_uv, batt_temp);
soc_est = div_s64((s64)params->fcc_uah * pc_est - params->uuc_uah*100,
(s64)params->fcc_uah - params->uuc_uah);
@@ -1409,7 +1476,7 @@
goto out;
}
- if (ibat_ua < 0 && !is_batfet_open(chip)) {
+ if (ibat_ua < 0 && !is_battery_full(chip)) {
soc = charging_adjustments(chip, params, soc, vbat_uv, ibat_ua,
batt_temp);
goto out;
@@ -1528,10 +1595,6 @@
pr_debug("clamping soc to 1, vbat (%d) > cutoff (%d)\n",
vbat_uv, chip->v_cutoff_uv);
return 1;
- } else if (soc > 0 && vbat_uv < chip->v_cutoff_uv) {
- pr_debug("forcing soc to 0, vbat (%d) < cutoff (%d)\n",
- vbat_uv, chip->v_cutoff_uv);
- return 0;
} else {
pr_debug("not clamping, using soc = %d, vbat = %d and cutoff = %d\n",
soc, vbat_uv, chip->v_cutoff_uv);
@@ -1539,6 +1602,7 @@
}
}
+#define SLEEP_RECALC_INTERVAL 3
static int calculate_state_of_charge(struct qpnp_bms_chip *chip,
struct raw_soc_params *raw,
int batt_temp)
@@ -1547,7 +1611,7 @@
int shutdown_soc, new_calculated_soc, remaining_usable_charge_uah;
struct soc_params params;
- if (!chip->battery_present) {
+ if (!is_battery_present(chip)) {
pr_debug("battery gone, reporting 100\n");
new_calculated_soc = 100;
goto done_calculating;
@@ -1650,13 +1714,30 @@
}
chip->calculated_soc = new_calculated_soc;
+ pr_debug("CC based calculated SOC = %d\n", chip->calculated_soc);
+ mutex_lock(&chip->last_soc_mutex);
if (chip->last_soc_invalid) {
chip->last_soc_invalid = false;
chip->last_soc = -EINVAL;
}
- pr_debug("CC based calculated SOC = %d\n", chip->calculated_soc);
- chip->first_time_calc_soc = 0;
+ /*
+ * Check if more than a long time has passed since the last
+ * calculation (more than n times compared to the soc recalculation
+ * rate, where n is defined by SLEEP_RECALC_INTERVAL). If this is true,
+ * then the system must have gone through a long sleep, and SoC can be
+ * allowed to become unbounded by the last reported SoC
+ */
+ if (params.delta_time_s * 1000 >
+ chip->calculate_soc_ms * SLEEP_RECALC_INTERVAL
+ && !chip->first_time_calc_soc) {
+ chip->last_soc_unbound = true;
+ chip->last_soc_change_sec = chip->last_recalc_time;
+ pr_debug("last_soc unbound because elapsed time = %d\n",
+ params.delta_time_s);
+ }
+ mutex_unlock(&chip->last_soc_mutex);
get_current_time(&chip->last_recalc_time);
+ chip->first_time_calc_soc = 0;
return chip->calculated_soc;
}
@@ -1694,7 +1775,11 @@
struct qpnp_vadc_result result;
struct raw_soc_params raw;
- wake_lock(&chip->soc_wake_lock);
+ if (!wake_lock_active(&chip->soc_wake_lock))
+ wake_lock(&chip->soc_wake_lock);
+ mutex_lock(&chip->vbat_monitor_mutex);
+ qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ mutex_unlock(&chip->vbat_monitor_mutex);
if (chip->use_voltage_soc) {
soc = calculate_soc_from_voltage(chip);
} else {
@@ -1736,7 +1821,7 @@
int soc = recalculate_soc(chip);
if (soc < chip->low_soc_calc_threshold
- || chip->low_voltage_wake_lock_held)
+ || wake_lock_active(&chip->low_voltage_wake_lock))
schedule_delayed_work(&chip->calculate_soc_delayed_work,
round_jiffies_relative(msecs_to_jiffies
(chip->low_soc_calculate_soc_ms)));
@@ -1772,32 +1857,20 @@
#define SOC_CATCHUP_SEC_MAX 600
#define SOC_CATCHUP_SEC_PER_PERCENT 60
#define MAX_CATCHUP_SOC (SOC_CATCHUP_SEC_MAX/SOC_CATCHUP_SEC_PER_PERCENT)
-static int scale_soc_while_chg(struct qpnp_bms_chip *chip,
- int delta_time_us, int new_soc, int prev_soc)
+static int scale_soc_while_chg(struct qpnp_bms_chip *chip, int chg_time_sec,
+ int catch_up_sec, int new_soc, int prev_soc)
{
- int chg_time_sec;
- int catch_up_sec;
int scaled_soc;
int numerator;
/*
- * The device must be charging for reporting a higher soc, if
- * not ignore this soc and continue reporting the prev_soc.
- * Also don't report a high value immediately slowly scale the
+ * Don't report a high value immediately slowly scale the
* value from prev_soc to the new soc based on a charge time
* weighted average
*/
-
- /* if not charging, return last soc */
- if (!is_battery_charging(chip))
- return prev_soc;
-
- chg_time_sec = DIV_ROUND_UP(chip->charge_time_us, USEC_PER_SEC);
- catch_up_sec = DIV_ROUND_UP(chip->catch_up_time_us, USEC_PER_SEC);
+ pr_debug("cts = %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
if (catch_up_sec == 0)
return new_soc;
- pr_debug("cts= %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
-
/*
* if charging for more than catch_up time, simply return
* new soc
@@ -1830,14 +1903,17 @@
return chip->prev_voltage_based_soc;
}
+#define SOC_CHANGE_PER_SEC 20
static int report_cc_based_soc(struct qpnp_bms_chip *chip)
{
- int soc;
- int delta_time_us;
+ int soc, soc_change;
+ int time_since_last_change_sec, charge_time_sec = 0;
+ unsigned long last_change_sec;
struct timespec now;
struct qpnp_vadc_result result;
int batt_temp;
int rc;
+ bool charging, charging_since_last_report;
soc = chip->calculated_soc;
@@ -1852,68 +1928,84 @@
result.measurement);
batt_temp = (int)result.physical;
- do_posix_clock_monotonic_gettime(&now);
- if (chip->t_soc_queried.tv_sec != 0) {
- delta_time_us
- = (now.tv_sec - chip->t_soc_queried.tv_sec) * USEC_PER_SEC
- + (now.tv_nsec - chip->t_soc_queried.tv_nsec) / 1000;
- } else {
- /* calculation for the first time */
- delta_time_us = 0;
- }
+ mutex_lock(&chip->last_soc_mutex);
+ last_change_sec = chip->last_soc_change_sec;
+ calculate_delta_time(&last_change_sec, &time_since_last_change_sec);
+ charging = is_battery_charging(chip);
+ charging_since_last_report = charging || (chip->last_soc_unbound
+ && chip->was_charging_at_sleep);
/*
* account for charge time - limit it to SOC_CATCHUP_SEC to
* avoid overflows when charging continues for extended periods
*/
- if (is_battery_charging(chip)) {
- if (chip->charge_time_us == 0) {
+ if (charging) {
+ if (chip->charge_start_tm_sec == 0) {
/*
* calculating soc for the first time
* after start of chg. Initialize catchup time
*/
if (abs(soc - chip->last_soc) < MAX_CATCHUP_SOC)
- chip->catch_up_time_us =
+ chip->catch_up_time_sec =
(soc - chip->last_soc)
- * SOC_CATCHUP_SEC_PER_PERCENT
- * USEC_PER_SEC;
+ * SOC_CATCHUP_SEC_PER_PERCENT;
else
- chip->catch_up_time_us =
- SOC_CATCHUP_SEC_MAX * USEC_PER_SEC;
+ chip->catch_up_time_sec = SOC_CATCHUP_SEC_MAX;
- if (chip->catch_up_time_us < 0)
- chip->catch_up_time_us = 0;
+ if (chip->catch_up_time_sec < 0)
+ chip->catch_up_time_sec = 0;
+ chip->charge_start_tm_sec = last_change_sec;
}
- /* add charge time */
- if (chip->charge_time_us < SOC_CATCHUP_SEC_MAX * USEC_PER_SEC)
- chip->charge_time_us += delta_time_us;
+ charge_time_sec = min(SOC_CATCHUP_SEC_MAX, (int)last_change_sec
+ - chip->charge_start_tm_sec);
/* end catchup if calculated soc and last soc are same */
if (chip->last_soc == soc)
- chip->catch_up_time_us = 0;
+ chip->catch_up_time_sec = 0;
}
- /* last_soc < soc ... scale and catch up */
- if (chip->last_soc != -EINVAL && chip->last_soc < soc && soc != 100)
- soc = scale_soc_while_chg(chip, delta_time_us,
- soc, chip->last_soc);
+ if (chip->last_soc != -EINVAL) {
+ /* last_soc < soc ... if we have not been charging at all
+ * since the last time this was called, report previous SoC.
+ * Otherwise, scale and catch up.
+ */
+ if (chip->last_soc < soc && !charging_since_last_report)
+ soc = chip->last_soc;
+ else if (chip->last_soc < soc && soc != 100)
+ soc = scale_soc_while_chg(chip, charge_time_sec,
+ chip->catch_up_time_sec,
+ soc, chip->last_soc);
- if (chip->last_soc_unbound)
- chip->last_soc_unbound = false;
- else if (chip->last_soc != -EINVAL) {
+ soc_change = min((int)abs(chip->last_soc - soc),
+ time_since_last_change_sec / SOC_CHANGE_PER_SEC);
+ if (chip->last_soc_unbound) {
+ chip->last_soc_unbound = false;
+ } else {
+ /*
+ * if soc have not been unbound by resume,
+ * only change reported SoC by 1.
+ */
+ soc_change = min(1, soc_change);
+ }
+
if (soc < chip->last_soc && soc != 0)
- soc = chip->last_soc - 1;
+ soc = chip->last_soc - soc_change;
if (soc > chip->last_soc && soc != 100)
- soc = chip->last_soc + 1;
+ soc = chip->last_soc + soc_change;
}
- pr_debug("last_soc = %d, calculated_soc = %d, soc = %d\n",
- chip->last_soc, chip->calculated_soc, soc);
+ if (chip->last_soc != soc)
+ chip->last_soc_change_sec = last_change_sec;
+
+ pr_debug("last_soc = %d, calculated_soc = %d, soc = %d, time since last change = %d\n",
+ chip->last_soc, chip->calculated_soc,
+ soc, time_since_last_change_sec);
chip->last_soc = bound_soc(soc);
backup_soc_and_iavg(chip, batt_temp, chip->last_soc);
pr_debug("Reported SOC = %d\n", chip->last_soc);
chip->t_soc_queried = now;
+ mutex_unlock(&chip->last_soc_mutex);
return soc;
}
@@ -1929,16 +2021,236 @@
return report_cc_based_soc(chip);
}
+static void configure_vbat_monitor_low(struct qpnp_bms_chip *chip)
+{
+ mutex_lock(&chip->vbat_monitor_mutex);
+ if (chip->vbat_monitor_params.state_request
+ == ADC_TM_HIGH_LOW_THR_ENABLE) {
+ /*
+ * Battery is now around or below v_cutoff
+ */
+ pr_debug("battery entered cutoff range\n");
+ if (!wake_lock_active(&chip->low_voltage_wake_lock)) {
+ pr_debug("voltage low, holding wakelock\n");
+ wake_lock(&chip->low_voltage_wake_lock);
+ cancel_delayed_work_sync(
+ &chip->calculate_soc_delayed_work);
+ schedule_delayed_work(
+ &chip->calculate_soc_delayed_work, 0);
+ }
+ chip->vbat_monitor_params.state_request =
+ ADC_TM_HIGH_THR_ENABLE;
+ chip->vbat_monitor_params.high_thr =
+ (chip->low_voltage_threshold + VBATT_ERROR_MARGIN);
+ pr_debug("set low thr to %d and high to %d\n",
+ chip->vbat_monitor_params.low_thr,
+ chip->vbat_monitor_params.high_thr);
+ chip->vbat_monitor_params.low_thr = 0;
+ } else if (chip->vbat_monitor_params.state_request
+ == ADC_TM_LOW_THR_ENABLE) {
+ /*
+ * Battery is in normal operation range.
+ */
+ pr_debug("battery entered normal range\n");
+ if (wake_lock_active(&chip->cv_wake_lock)) {
+ wake_unlock(&chip->cv_wake_lock);
+ pr_debug("releasing cv wake lock\n");
+ }
+ chip->in_cv_range = false;
+ chip->vbat_monitor_params.state_request =
+ ADC_TM_HIGH_LOW_THR_ENABLE;
+ chip->vbat_monitor_params.high_thr = chip->max_voltage_uv
+ - VBATT_ERROR_MARGIN;
+ chip->vbat_monitor_params.low_thr =
+ chip->low_voltage_threshold;
+ pr_debug("set low thr to %d and high to %d\n",
+ chip->vbat_monitor_params.low_thr,
+ chip->vbat_monitor_params.high_thr);
+ }
+ qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ mutex_unlock(&chip->vbat_monitor_mutex);
+}
+
+#define CV_LOW_THRESHOLD_HYST_UV 100000
+static void configure_vbat_monitor_high(struct qpnp_bms_chip *chip)
+{
+ mutex_lock(&chip->vbat_monitor_mutex);
+ if (chip->vbat_monitor_params.state_request
+ == ADC_TM_HIGH_LOW_THR_ENABLE) {
+ /*
+ * Battery is around vddmax
+ */
+ pr_debug("battery entered vddmax range\n");
+ chip->in_cv_range = true;
+ if (!wake_lock_active(&chip->cv_wake_lock)) {
+ wake_lock(&chip->cv_wake_lock);
+ pr_debug("holding cv wake lock\n");
+ }
+ schedule_work(&chip->recalc_work);
+ chip->vbat_monitor_params.state_request =
+ ADC_TM_LOW_THR_ENABLE;
+ chip->vbat_monitor_params.low_thr =
+ (chip->max_voltage_uv - CV_LOW_THRESHOLD_HYST_UV);
+ chip->vbat_monitor_params.high_thr = chip->max_voltage_uv * 2;
+ pr_debug("set low thr to %d and high to %d\n",
+ chip->vbat_monitor_params.low_thr,
+ chip->vbat_monitor_params.high_thr);
+ } else if (chip->vbat_monitor_params.state_request
+ == ADC_TM_HIGH_THR_ENABLE) {
+ /*
+ * Battery is in normal operation range.
+ */
+ pr_debug("battery entered normal range\n");
+ if (wake_lock_active(&chip->low_voltage_wake_lock)) {
+ pr_debug("voltage high, releasing wakelock\n");
+ wake_unlock(&chip->low_voltage_wake_lock);
+ }
+ chip->vbat_monitor_params.state_request =
+ ADC_TM_HIGH_LOW_THR_ENABLE;
+ chip->vbat_monitor_params.high_thr =
+ chip->max_voltage_uv - VBATT_ERROR_MARGIN;
+ chip->vbat_monitor_params.low_thr =
+ chip->low_voltage_threshold;
+ pr_debug("set low thr to %d and high to %d\n",
+ chip->vbat_monitor_params.low_thr,
+ chip->vbat_monitor_params.high_thr);
+ }
+ qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ mutex_unlock(&chip->vbat_monitor_mutex);
+}
+
+static void btm_notify_vbat(enum qpnp_tm_state state, void *ctx)
+{
+ struct qpnp_bms_chip *chip = ctx;
+ int vbat_uv;
+ struct qpnp_vadc_result result;
+ int rc;
+
+ rc = qpnp_vadc_read(VBAT_SNS, &result);
+ pr_debug("vbat = %lld, raw = 0x%x\n", result.physical, result.adc_code);
+
+ get_battery_voltage(&vbat_uv);
+ pr_debug("vbat is at %d, state is at %d\n", vbat_uv, state);
+
+ if (state == ADC_TM_LOW_STATE) {
+ pr_debug("low voltage btm notification triggered\n");
+ if (vbat_uv - VBATT_ERROR_MARGIN
+ < chip->vbat_monitor_params.low_thr) {
+ configure_vbat_monitor_low(chip);
+ } else {
+ pr_debug("faulty btm trigger, discarding\n");
+ qpnp_adc_tm_channel_measure(
+ &chip->vbat_monitor_params);
+ }
+ } else if (state == ADC_TM_HIGH_STATE) {
+ pr_debug("high voltage btm notification triggered\n");
+ if (vbat_uv + VBATT_ERROR_MARGIN
+ > chip->vbat_monitor_params.high_thr) {
+ configure_vbat_monitor_high(chip);
+ } else {
+ pr_debug("faulty btm trigger, discarding\n");
+ qpnp_adc_tm_channel_measure(
+ &chip->vbat_monitor_params);
+ }
+ } else {
+ pr_debug("unknown voltage notification state: %d\n", state);
+ }
+ power_supply_changed(&chip->bms_psy);
+}
+
+static int reset_vbat_monitoring(struct qpnp_bms_chip *chip)
+{
+ int rc;
+
+ chip->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_DISABLE;
+ rc = qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ if (rc) {
+ pr_err("tm measure failed: %d\n", rc);
+ return rc;
+ }
+ mutex_lock(&chip->vbat_monitor_mutex);
+ if (wake_lock_active(&chip->low_voltage_wake_lock)) {
+ pr_debug("battery removed, releasing wakelock\n");
+ wake_unlock(&chip->low_voltage_wake_lock);
+ }
+ if (chip->in_cv_range) {
+ pr_debug("battery removed, removing in_cv_range state\n");
+ chip->in_cv_range = false;
+ }
+ mutex_unlock(&chip->vbat_monitor_mutex);
+ return 0;
+}
+
+static int setup_vbat_monitoring(struct qpnp_bms_chip *chip)
+{
+ int rc;
+
+ rc = qpnp_adc_tm_is_ready();
+ if (rc) {
+ pr_info("adc tm is not ready yet: %d, defer probe\n", rc);
+ return -EPROBE_DEFER;
+ }
+
+ if (!is_battery_present(chip)) {
+ pr_debug("no battery inserted, do not setup vbat monitoring\n");
+ return 0;
+ }
+
+ chip->vbat_monitor_params.low_thr = chip->low_voltage_threshold;
+ chip->vbat_monitor_params.high_thr = chip->max_voltage_uv
+ - VBATT_ERROR_MARGIN;
+ chip->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
+ chip->vbat_monitor_params.channel = VBAT_SNS;
+ chip->vbat_monitor_params.btm_ctx = (void *)chip;
+ chip->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
+ chip->vbat_monitor_params.threshold_notification = &btm_notify_vbat;
+ pr_debug("set low thr to %d and high to %d\n",
+ chip->vbat_monitor_params.low_thr,
+ chip->vbat_monitor_params.high_thr);
+ rc = qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ if (rc) {
+ pr_err("tm setup failed: %d\n", rc);
+ return rc;
+ }
+ pr_debug("setup complete\n");
+ return 0;
+}
+
+static void battery_insertion_work(struct work_struct *work)
+{
+ struct qpnp_bms_chip *chip = container_of(work,
+ struct qpnp_bms_chip,
+ battery_insertion_work);
+ bool present = is_battery_present(chip);
+
+ mutex_lock(&chip->vbat_monitor_mutex);
+ if (chip->battery_present != present) {
+ if (chip->battery_present != -EINVAL) {
+ if (present) {
+ setup_vbat_monitoring(chip);
+ chip->new_battery = true;
+ } else {
+ reset_vbat_monitoring(chip);
+ }
+ }
+ chip->battery_present = present;
+ /* a new battery was inserted or removed, so force a soc
+ * recalculation to update the SoC */
+ schedule_work(&chip->recalc_work);
+ }
+ mutex_unlock(&chip->vbat_monitor_mutex);
+}
+
/* Returns capacity as a SoC percentage between 0 and 100 */
static int get_prop_bms_capacity(struct qpnp_bms_chip *chip)
{
return report_state_of_charge(chip);
}
-/* Returns estimated max current that the battery can supply in uA */
-static int get_prop_bms_current_max(struct qpnp_bms_chip *chip)
+/* Returns estimated battery resistance */
+static int get_prop_bms_batt_resistance(struct qpnp_bms_chip *chip)
{
- return chip->ibat_max_ua;
+ return chip->rbatt_mohm * 1000;
}
/* Returns instantaneous current in uA */
@@ -1957,24 +2269,17 @@
/* Returns full charge design in uAh */
static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
{
- return chip->fcc;
+ return chip->fcc_mah * 1000;
}
static int get_prop_bms_present(struct qpnp_bms_chip *chip)
{
- return chip->battery_present;
+ return is_battery_present(chip);
}
static void set_prop_bms_present(struct qpnp_bms_chip *chip, int present)
{
- if (chip->battery_present != present) {
- chip->battery_present = present;
- if (present)
- chip->new_battery = true;
- /* a new battery was inserted or removed, so force a soc
- * recalculation to update the SoC */
- schedule_work(&chip->recalc_work);
- }
+ schedule_work(&chip->battery_insertion_work);
}
static void qpnp_bms_external_power_changed(struct power_supply *psy)
@@ -1995,8 +2300,8 @@
case POWER_SUPPLY_PROP_CURRENT_NOW:
val->intval = get_prop_bms_current_now(chip);
break;
- case POWER_SUPPLY_PROP_CURRENT_MAX:
- val->intval = get_prop_bms_current_max(chip);
+ case POWER_SUPPLY_PROP_RESISTANCE:
+ val->intval = get_prop_bms_batt_resistance(chip);
break;
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
val->intval = get_prop_bms_charge_full_design(chip);
@@ -2169,7 +2474,7 @@
}
}
- chip->fcc = batt_data->fcc;
+ chip->fcc_mah = batt_data->fcc;
chip->fcc_temp_lut = batt_data->fcc_temp_lut;
chip->fcc_sf_lut = batt_data->fcc_sf_lut;
chip->pc_temp_ocv_lut = batt_data->pc_temp_ocv_lut;
@@ -2265,6 +2570,7 @@
chip->calculated_soc = -EINVAL;
chip->last_soc = -EINVAL;
chip->last_soc_est = -EINVAL;
+ chip->battery_present = -EINVAL;
chip->last_cc_uah = INT_MIN;
chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED;
chip->prev_last_good_ocv_raw = OCV_RAW_UNINITIALIZED;
@@ -2412,7 +2718,7 @@
static int __devinit qpnp_bms_probe(struct spmi_device *spmi)
{
struct qpnp_bms_chip *chip;
- union power_supply_propval retval = {0,};
+ bool warm_reset;
int rc, vbatt;
chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -2425,15 +2731,22 @@
rc = qpnp_vadc_is_ready();
if (rc) {
pr_info("vadc not ready: %d, deferring probe\n", rc);
+ rc = -EPROBE_DEFER;
goto error_read;
}
rc = qpnp_iadc_is_ready();
if (rc) {
pr_info("iadc not ready: %d, deferring probe\n", rc);
+ rc = -EPROBE_DEFER;
goto error_read;
}
+ warm_reset = qpnp_pon_is_warm_reset();
+ rc = warm_reset;
+ if (rc < 0)
+ goto error_read;
+
rc = register_spmi(chip, spmi);
if (rc) {
pr_err("error registering spmi resource %d\n", rc);
@@ -2488,30 +2801,30 @@
mutex_init(&chip->bms_output_lock);
mutex_init(&chip->last_ocv_uv_mutex);
+ mutex_init(&chip->vbat_monitor_mutex);
mutex_init(&chip->soc_invalidation_mutex);
+ mutex_init(&chip->last_soc_mutex);
wake_lock_init(&chip->soc_wake_lock, WAKE_LOCK_SUSPEND,
"qpnp_soc_lock");
wake_lock_init(&chip->low_voltage_wake_lock, WAKE_LOCK_SUSPEND,
"qpnp_low_voltage_lock");
+ wake_lock_init(&chip->cv_wake_lock, WAKE_LOCK_SUSPEND,
+ "qpnp_cv_lock");
INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
calculate_soc_work);
INIT_WORK(&chip->recalc_work, recalculate_work);
+ INIT_WORK(&chip->battery_insertion_work, battery_insertion_work);
read_shutdown_soc_and_iavg(chip);
dev_set_drvdata(&spmi->dev, chip);
device_init_wakeup(&spmi->dev, 1);
- if (!chip->batt_psy)
- chip->batt_psy = power_supply_get_by_name("battery");
- if (chip->batt_psy) {
- chip->batt_psy->get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_PRESENT, &retval);
- chip->battery_present = retval.intval;
- pr_debug("present = %d\n", chip->battery_present);
- } else {
- chip->battery_present = 1;
+ rc = setup_vbat_monitoring(chip);
+ if (rc < 0) {
+ pr_err("failed to set up voltage notifications: %d\n", rc);
+ goto error_setup;
}
calculate_soc_work(&(chip->calculate_soc_delayed_work.work));
@@ -2543,16 +2856,18 @@
goto unregister_dc;
}
- pr_info("probe success: soc =%d vbatt = %d ocv = %d r_sense_uohm = %u\n",
- get_prop_bms_capacity(chip),
- vbatt, chip->last_ocv_uv, chip->r_sense_uohm);
+ pr_info("probe success: soc =%d vbatt = %d ocv = %d r_sense_uohm = %u warm_reset = %d\n",
+ get_prop_bms_capacity(chip), vbatt, chip->last_ocv_uv,
+ chip->r_sense_uohm, warm_reset);
return 0;
unregister_dc:
+ power_supply_unregister(&chip->bms_psy);
+error_setup:
+ dev_set_drvdata(&spmi->dev, NULL);
wake_lock_destroy(&chip->soc_wake_lock);
wake_lock_destroy(&chip->low_voltage_wake_lock);
- power_supply_unregister(&chip->bms_psy);
- dev_set_drvdata(&spmi->dev, NULL);
+ wake_lock_destroy(&chip->cv_wake_lock);
error_resource:
error_read:
kfree(chip);
@@ -2569,10 +2884,20 @@
return 0;
}
+static int bms_suspend(struct device *dev)
+{
+ struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+
+ cancel_delayed_work_sync(&chip->calculate_soc_delayed_work);
+ chip->was_charging_at_sleep = is_battery_charging(chip);
+ return 0;
+}
+
static int bms_resume(struct device *dev)
{
int rc;
- unsigned long soc_calc_period;
+ int soc_calc_period;
+ int time_until_next_recalc;
unsigned long time_since_last_recalc;
unsigned long tm_now_sec;
struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
@@ -2581,11 +2906,6 @@
if (rc) {
pr_err("Could not read current time: %d\n", rc);
} else if (tm_now_sec > chip->last_recalc_time) {
- /*
- * unbind the last soc so that the next
- * recalculation is not limited to changing by 1%
- */
- chip->last_soc_unbound = true;
time_since_last_recalc = tm_now_sec - chip->last_recalc_time;
pr_debug("Time since last recalc: %lu\n",
time_since_last_recalc);
@@ -2594,16 +2914,23 @@
else
soc_calc_period = chip->calculate_soc_ms;
- if (time_since_last_recalc >= soc_calc_period) {
- chip->last_recalc_time = tm_now_sec;
- recalculate_soc(chip);
- }
+ time_until_next_recalc = max(0, soc_calc_period
+ - (int)(time_since_last_recalc * 1000));
+
+ if (!wake_lock_active(&chip->soc_wake_lock)
+ && time_until_next_recalc == 0)
+ wake_lock(&chip->soc_wake_lock);
+
+ schedule_delayed_work(&chip->calculate_soc_delayed_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (time_until_next_recalc)));
}
return 0;
}
static const struct dev_pm_ops qpnp_bms_pm_ops = {
.resume = bms_resume,
+ .suspend = bms_suspend,
};
static struct spmi_driver qpnp_bms_driver = {
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 6a2ce8d..4be1760 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -81,6 +81,7 @@
#define CHGR_BAT_IF_VCP 0x42
#define CHGR_BAT_IF_BATFET_CTRL1 0x90
#define CHGR_MISC_BOOT_DONE 0x42
+#define CHGR_BUCK_COMPARATOR_OVRIDE_1 0xEB
#define CHGR_BUCK_COMPARATOR_OVRIDE_3 0xED
#define CHGR_BUCK_BCK_VBAT_REG_MODE 0x74
#define MISC_REVISION2 0x01
@@ -242,6 +243,7 @@
unsigned int chg_fastchg_irq;
unsigned int chg_trklchg_irq;
unsigned int chg_failed_irq;
+ unsigned int chg_vbatdet_lo_irq;
unsigned int batt_pres_irq;
bool bat_is_cool;
bool bat_is_warm;
@@ -260,7 +262,7 @@
unsigned int warm_bat_mv;
unsigned int cool_bat_mv;
unsigned int resume_delta_mv;
- unsigned int term_current;
+ int term_current;
unsigned int maxinput_usb_ma;
unsigned int maxinput_dc_ma;
unsigned int warm_bat_decidegc;
@@ -280,6 +282,8 @@
struct qpnp_adc_tm_btm_param adc_param;
struct work_struct adc_measure_work;
struct delayed_work arb_stop_work;
+ struct delayed_work eoc_work;
+ struct wake_lock eoc_wake_lock;
};
static struct of_device_id qpnp_charger_match_table[] = {
@@ -546,6 +550,9 @@
/* Don't run on battery for batteryless hardware */
if (chip->use_default_batt_values)
return 0;
+ /* Don't force on battery if battery is not present */
+ if (!qpnp_chg_is_batt_present(chip))
+ return 0;
/* This bit forces the charger to run off of the battery rather
* than a connected charger */
@@ -554,6 +561,53 @@
disable ? CHGR_ON_BAT_FORCE_BIT : 0, 1);
}
+#define COMPATATOR_OVERRIDE_0 0x80
+static int
+qpnp_chg_toggle_chg_done_logic(struct qpnp_chg_chip *chip, int enable)
+{
+ int rc;
+
+ pr_debug("toggle: %d\n", enable);
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->buck_base + SEC_ACCESS, 0xA5, 0xA5, 1);
+ if (rc) {
+ pr_debug("failed to write sec access rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->buck_base + CHGR_BUCK_COMPARATOR_OVRIDE_1,
+ 0xC0, enable ? 0x00 : COMPATATOR_OVERRIDE_0, 1);
+ if (rc) {
+ pr_debug("failed to toggle chg done override rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+#define QPNP_CHG_VBATDET_MIN_MV 3240
+#define QPNP_CHG_VBATDET_MAX_MV 5780
+#define QPNP_CHG_VBATDET_STEP_MV 20
+static int
+qpnp_chg_vbatdet_set(struct qpnp_chg_chip *chip, int vbatdet_mv)
+{
+ u8 temp;
+
+ if (vbatdet_mv < QPNP_CHG_VBATDET_MIN_MV
+ || vbatdet_mv > QPNP_CHG_VBATDET_MAX_MV) {
+ pr_err("bad mV=%d asked to set\n", vbatdet_mv);
+ return -EINVAL;
+ }
+ temp = (vbatdet_mv - QPNP_CHG_VBATDET_MIN_MV)
+ / QPNP_CHG_VBATDET_STEP_MV;
+
+ pr_debug("voltage=%d setting %02x\n", vbatdet_mv, temp);
+ return qpnp_chg_write(chip, &temp,
+ chip->chgr_base + CHGR_VBAT_DET, 1);
+}
+
static void
qpnp_arb_stop_work(struct work_struct *work)
{
@@ -561,7 +615,8 @@
struct qpnp_chg_chip *chip = container_of(dwork,
struct qpnp_chg_chip, arb_stop_work);
- qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ if (!chip->chg_done)
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
}
@@ -575,6 +630,36 @@
pr_err("request ADC error\n");
}
+#define EOC_CHECK_PERIOD_MS 10000
+static irqreturn_t
+qpnp_chg_vbatdet_lo_irq_handler(int irq, void *_chip)
+{
+ struct qpnp_chg_chip *chip = _chip;
+ u8 chg_sts = 0;
+ int rc;
+
+ pr_debug("vbatdet-lo triggered\n");
+
+ rc = qpnp_chg_read(chip, &chg_sts, INT_RT_STS(chip->chgr_base), 1);
+ if (rc)
+ pr_err("failed to read chg_sts rc=%d\n", rc);
+
+ pr_debug("chg_done chg_sts: 0x%x triggered\n", chg_sts);
+ if (!chip->charging_disabled && (chg_sts & FAST_CHG_ON_IRQ)) {
+ schedule_delayed_work(&chip->eoc_work,
+ msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+ wake_lock(&chip->eoc_wake_lock);
+ disable_irq_nosync(chip->chg_vbatdet_lo_irq);
+ } else {
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ }
+
+ power_supply_changed(chip->usb_psy);
+ power_supply_changed(&chip->dc_psy);
+ power_supply_changed(&chip->batt_psy);
+ return IRQ_HANDLED;
+}
+
#define ARB_STOP_WORK_MS 1000
static irqreturn_t
qpnp_chg_usb_chg_gone_irq_handler(int irq, void *_chip)
@@ -584,7 +669,7 @@
pr_debug("chg_gone triggered\n");
if (qpnp_chg_is_usb_chg_plugged_in(chip)) {
qpnp_chg_charge_en(chip, 0);
- qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
+ qpnp_chg_force_run_on_batt(chip, 1);
schedule_delayed_work(&chip->arb_stop_work,
msecs_to_jiffies(ARB_STOP_WORK_MS));
}
@@ -610,11 +695,15 @@
if (chip->usb_present ^ usb_present) {
chip->usb_present = usb_present;
- if (!usb_present)
+ if (!usb_present) {
qpnp_chg_usb_suspend_enable(chip, 1);
+ chip->chg_done = false;
+ } else {
+ schedule_delayed_work(&chip->eoc_work,
+ msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+ }
- power_supply_set_present(chip->usb_psy,
- chip->usb_present);
+ power_supply_set_present(chip->usb_psy, chip->usb_present);
}
return IRQ_HANDLED;
@@ -632,6 +721,7 @@
if (chip->batt_present ^ batt_present) {
chip->batt_present = batt_present;
power_supply_changed(&chip->batt_psy);
+ power_supply_changed(chip->usb_psy);
if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
&& batt_present) {
@@ -656,7 +746,13 @@
if (chip->dc_present ^ dc_present) {
chip->dc_present = dc_present;
+ if (!dc_present)
+ chip->chg_done = false;
+ else
+ schedule_delayed_work(&chip->eoc_work,
+ msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
power_supply_changed(&chip->dc_psy);
+ power_supply_changed(&chip->batt_psy);
}
return IRQ_HANDLED;
@@ -669,6 +765,8 @@
struct qpnp_chg_chip *chip = _chip;
int rc;
+ pr_debug("chg_failed triggered\n");
+
rc = qpnp_chg_masked_write(chip,
chip->chgr_base + CHGR_CHG_FAILED,
CHGR_CHG_FAILED_BIT,
@@ -676,6 +774,9 @@
if (rc)
pr_err("Failed to write chg_fail clear bit!\n");
+ power_supply_changed(&chip->batt_psy);
+ power_supply_changed(chip->usb_psy);
+ power_supply_changed(&chip->dc_psy);
return IRQ_HANDLED;
}
@@ -698,9 +799,11 @@
struct qpnp_chg_chip *chip = _chip;
pr_debug("FAST_CHG IRQ triggered\n");
-
chip->chg_done = false;
power_supply_changed(&chip->batt_psy);
+ power_supply_changed(chip->usb_psy);
+ power_supply_changed(&chip->dc_psy);
+ enable_irq(chip->chg_vbatdet_lo_irq);
return IRQ_HANDLED;
}
@@ -815,7 +918,6 @@
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CAPACITY,
- POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_TEMP,
@@ -938,11 +1040,12 @@
int rc;
u8 chgr_sts;
- if (chip->chg_done)
+ if ((qpnp_chg_is_usb_chg_plugged_in(chip) ||
+ qpnp_chg_is_dc_chg_plugged_in(chip)) && chip->chg_done) {
return POWER_SUPPLY_STATUS_FULL;
+ }
- rc = qpnp_chg_read(chip, &chgr_sts,
- INT_RT_STS(chip->chgr_base), 1);
+ rc = qpnp_chg_read(chip, &chgr_sts, INT_RT_STS(chip->chgr_base), 1);
if (rc) {
pr_err("failed to read interrupt sts %d\n", rc);
return POWER_SUPPLY_CHARGE_TYPE_NONE;
@@ -955,21 +1058,6 @@
return POWER_SUPPLY_STATUS_DISCHARGING;
}
-static int
-get_prop_current_max(struct qpnp_chg_chip *chip)
-{
- union power_supply_propval ret = {0,};
-
- if (chip->bms_psy) {
- chip->bms_psy->get_property(chip->bms_psy,
- POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
- return ret.intval;
- } else {
- pr_debug("No BMS supply registered return 0\n");
- }
-
- return 0;
-}
static int
get_prop_current_now(struct qpnp_chg_chip *chip)
@@ -1148,9 +1236,6 @@
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = get_prop_capacity(chip);
break;
- case POWER_SUPPLY_PROP_CURRENT_MAX:
- val->intval = get_prop_current_max(chip);
- break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
val->intval = get_prop_current_now(chip);
break;
@@ -1279,27 +1364,7 @@
temp = (minutes - 1)/QPNP_CHG_TCHG_STEP;
return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_TCHG_MAX,
- QPNP_CHG_I_MASK, temp, 1);
-}
-#define QPNP_CHG_VBATDET_MIN_MV 3240
-#define QPNP_CHG_VBATDET_MAX_MV 5780
-#define QPNP_CHG_VBATDET_STEP_MV 20
-static int
-qpnp_chg_vbatdet_set(struct qpnp_chg_chip *chip, int vbatdet_mv)
-{
- u8 temp;
-
- if (vbatdet_mv < QPNP_CHG_VBATDET_MIN_MV
- || vbatdet_mv > QPNP_CHG_VBATDET_MAX_MV) {
- pr_err("bad mV=%d asked to set\n", vbatdet_mv);
- return -EINVAL;
- }
- temp = (vbatdet_mv - QPNP_CHG_VBATDET_MIN_MV)
- / QPNP_CHG_VBATDET_STEP_MV;
-
- pr_debug("voltage=%d setting %02x\n", vbatdet_mv, temp);
- return qpnp_chg_write(chip, &temp,
- chip->chgr_base + CHGR_VBAT_DET, 1);
+ QPNP_CHG_TCHG_MASK, temp, 1);
}
#define QPNP_CHG_V_MIN_MV 3240
@@ -1401,6 +1466,88 @@
}
}
+#define CONSECUTIVE_COUNT 3
+static void
+qpnp_eoc_work(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct qpnp_chg_chip *chip = container_of(dwork,
+ struct qpnp_chg_chip, eoc_work);
+ static int count;
+ int ibat_ma, vbat_mv, rc = 0;
+ u8 batt_sts = 0, buck_sts = 0, chg_sts = 0;
+
+ wake_lock(&chip->eoc_wake_lock);
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+
+ rc = qpnp_chg_read(chip, &batt_sts, INT_RT_STS(chip->bat_if_base), 1);
+ if (rc) {
+ pr_err("failed to read batt_if rc=%d\n", rc);
+ return;
+ }
+
+ rc = qpnp_chg_read(chip, &buck_sts, INT_RT_STS(chip->buck_base), 1);
+ if (rc) {
+ pr_err("failed to read buck rc=%d\n", rc);
+ return;
+ }
+
+ rc = qpnp_chg_read(chip, &chg_sts, INT_RT_STS(chip->chgr_base), 1);
+ if (rc) {
+ pr_err("failed to read chg_sts rc=%d\n", rc);
+ return;
+ }
+
+ pr_debug("chgr: 0x%x, bat_if: 0x%x, buck: 0x%x\n",
+ chg_sts, batt_sts, buck_sts);
+
+ if (!qpnp_chg_is_usb_chg_plugged_in(chip) &&
+ !qpnp_chg_is_dc_chg_plugged_in(chip)) {
+ pr_debug("no chg connected, stopping\n");
+ goto stop_eoc;
+ }
+
+ if ((batt_sts & BAT_FET_ON_IRQ) && (chg_sts & FAST_CHG_ON_IRQ
+ || chg_sts & TRKL_CHG_ON_IRQ)) {
+ ibat_ma = get_prop_current_now(chip) / 1000;
+ vbat_mv = get_prop_battery_voltage_now(chip) / 1000;
+ pr_debug("ibat_ma: %d term_current =%d\n",
+ ibat_ma, chip->term_current);
+ if (ibat_ma > chip->term_current) {
+ pr_debug("charging but increase in current demand\n");
+ count = 0;
+ } else if ((ibat_ma * -1) < chip->term_current) {
+ if (count == CONSECUTIVE_COUNT) {
+ pr_info("End of Charging\n");
+ qpnp_chg_charge_en(chip, 0);
+ chip->chg_done = true;
+ power_supply_changed(&chip->batt_psy);
+ enable_irq(chip->chg_vbatdet_lo_irq);
+ goto stop_eoc;
+ } else {
+ count += 1;
+ pr_debug("EOC count = %d\n", count);
+ }
+ } else if ((!(chg_sts & VBAT_DET_LOW_IRQ)) && (vbat_mv <
+ (chip->max_voltage_mv - chip->resume_delta_mv))) {
+ pr_debug("woke up too early\n");
+ enable_irq(chip->chg_vbatdet_lo_irq);
+ goto stop_eoc;
+ }
+ } else {
+ pr_debug("not charging\n");
+ goto stop_eoc;
+ }
+
+ schedule_delayed_work(&chip->eoc_work,
+ msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+ return;
+
+stop_eoc:
+ count = 0;
+ wake_unlock(&chip->eoc_wake_lock);
+}
+
#define HYSTERISIS_DECIDEGC 20
static void
qpnp_chg_adc_notification(enum qpnp_tm_state state, void *ctx)
@@ -1562,11 +1709,18 @@
return rc;
}
+ chip->chg_vbatdet_lo_irq = spmi_get_irq_byname(spmi,
+ spmi_resource, "vbat-det-lo");
+ if (chip->chg_vbatdet_lo_irq < 0) {
+ pr_err("Unable to get fast-chg-on irq\n");
+ return rc;
+ }
+
rc |= devm_request_irq(chip->dev, chip->chg_failed_irq,
qpnp_chg_chgr_chg_failed_irq_handler,
- IRQF_TRIGGER_RISING, "chg_failed", chip);
+ IRQF_TRIGGER_RISING, "chg-failed", chip);
if (rc < 0) {
- pr_err("Can't request %d chg_failed chg: %d\n",
+ pr_err("Can't request %d chg-failed: %d\n",
chip->chg_failed_irq, rc);
return rc;
}
@@ -1584,15 +1738,29 @@
rc |= devm_request_irq(chip->dev, chip->chg_trklchg_irq,
qpnp_chg_chgr_chg_trklchg_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "fast-chg-on", chip);
+ "trkl-chg-on", chip);
if (rc < 0) {
pr_err("Can't request %d trkl-chg-on: %d\n",
chip->chg_trklchg_irq, rc);
return rc;
}
+
+ rc |= devm_request_irq(chip->dev,
+ chip->chg_vbatdet_lo_irq,
+ qpnp_chg_vbatdet_lo_irq_handler,
+ IRQF_TRIGGER_RISING,
+ "vbat-det-lo", chip);
+ if (rc < 0) {
+ pr_err("Can't request %d vbat-det-lo: %d\n",
+ chip->chg_vbatdet_lo_irq, rc);
+ return rc;
+ }
+
enable_irq_wake(chip->chg_fastchg_irq);
enable_irq_wake(chip->chg_trklchg_irq);
enable_irq_wake(chip->chg_failed_irq);
+ disable_irq_nosync(chip->chg_vbatdet_lo_irq);
+ enable_irq_wake(chip->chg_vbatdet_lo_irq);
break;
case SMBB_BAT_IF_SUBTYPE:
@@ -1607,7 +1775,7 @@
rc = devm_request_irq(chip->dev, chip->batt_pres_irq,
qpnp_chg_bat_if_batt_pres_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "bat_if_batt_pres", chip);
+ "batt-pres", chip);
if (rc < 0) {
pr_err("Can't request %d batt-pres irq: %d\n",
chip->batt_pres_irq, rc);
@@ -1628,9 +1796,9 @@
rc = devm_request_irq(chip->dev, chip->usbin_valid_irq,
qpnp_chg_usb_usbin_valid_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "chg_usbin_valid", chip);
+ "usbin-valid", chip);
if (rc < 0) {
- pr_err("Can't request %d usbinvalid: %d\n",
+ pr_err("Can't request %d usbin-valid: %d\n",
chip->usbin_valid_irq, rc);
return rc;
}
@@ -1644,9 +1812,9 @@
rc = devm_request_irq(chip->dev, chip->chg_gone_irq,
qpnp_chg_usb_chg_gone_irq_handler,
IRQF_TRIGGER_RISING,
- "chg_gone_irq", chip);
+ "chg-gone", chip);
if (rc < 0) {
- pr_err("Can't request %d chg_gone: %d\n",
+ pr_err("Can't request %d chg-gone: %d\n",
chip->chg_gone_irq, rc);
return rc;
}
@@ -1663,9 +1831,9 @@
rc = devm_request_irq(chip->dev, chip->dcin_valid_irq,
qpnp_chg_dc_dcin_valid_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "chg_dcin_valid", chip);
+ "dcin-valid", chip);
if (rc < 0) {
- pr_err("Can't request %d dcinvalid: %d\n",
+ pr_err("Can't request %d dcin-valid: %d\n",
chip->dcin_valid_irq, rc);
return rc;
}
@@ -1741,12 +1909,16 @@
/* HACK: use analog EOC */
rc = qpnp_chg_masked_write(chip, chip->chgr_base +
CHGR_IBAT_TERM_CHGR,
- 0x80, 0x00, 1);
+ 0xFF, 0x08, 1);
break;
case SMBB_BUCK_SUBTYPE:
case SMBBP_BUCK_SUBTYPE:
case SMBCL_BUCK_SUBTYPE:
+ rc = qpnp_chg_toggle_chg_done_logic(chip, 0);
+ if (rc)
+ return rc;
+
rc = qpnp_chg_masked_write(chip,
chip->chgr_base + CHGR_BUCK_BCK_VBAT_REG_MODE,
BUCK_VBAT_REG_NODE_SEL_BIT,
@@ -1772,8 +1944,7 @@
case SMBB_USB_CHGPTH_SUBTYPE:
case SMBBP_USB_CHGPTH_SUBTYPE:
case SMBCL_USB_CHGPTH_SUBTYPE:
- chip->usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
- if (chip->usb_present) {
+ if (qpnp_chg_is_usb_chg_plugged_in(chip)) {
rc = qpnp_chg_masked_write(chip,
chip->usb_chgpth_base + CHGR_USB_ENUM_T_STOP,
ENUM_T_STOP_BIT,
@@ -1811,11 +1982,15 @@
case SMBBP_BOOST_SUBTYPE:
break;
case SMBB_MISC_SUBTYPE:
- chip->type = SMBB;
case SMBBP_MISC_SUBTYPE:
- chip->type = SMBBP;
case SMBCL_MISC_SUBTYPE:
- chip->type = SMBCL;
+ if (subtype == SMBB_MISC_SUBTYPE)
+ chip->type = SMBB;
+ else if (subtype == SMBBP_MISC_SUBTYPE)
+ chip->type = SMBBP;
+ else if (subtype == SMBCL_MISC_SUBTYPE)
+ chip->type = SMBCL;
+
pr_debug("Setting BOOT_DONE\n");
rc = qpnp_chg_masked_write(chip,
chip->misc_base + CHGR_MISC_BOOT_DONE,
@@ -2120,9 +2295,13 @@
}
INIT_WORK(&chip->adc_measure_work,
qpnp_bat_if_adc_measure_work);
- INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
}
+ wake_lock_init(&chip->eoc_wake_lock,
+ WAKE_LOCK_SUSPEND, "qpnp-chg-eoc-lock");
+ INIT_DELAYED_WORK(&chip->eoc_work, qpnp_eoc_work);
+ INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
+
if (chip->dc_chgpth_base) {
chip->dc_psy.name = "qpnp-dc";
chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
@@ -2142,9 +2321,6 @@
/* Turn on appropriate workaround flags */
qpnp_chg_setup_flags(chip);
- power_supply_set_present(chip->usb_psy,
- qpnp_chg_is_usb_chg_plugged_in(chip));
-
if (chip->maxinput_dc_ma && chip->dc_chgpth_base) {
rc = qpnp_chg_idcmax_set(chip, chip->maxinput_dc_ma);
if (rc) {
@@ -2181,6 +2357,10 @@
goto unregister_batt;
}
+ qpnp_chg_usb_usbin_valid_irq_handler(USBIN_VALID_IRQ, chip);
+ power_supply_set_present(chip->usb_psy,
+ qpnp_chg_is_usb_chg_plugged_in(chip));
+
pr_info("success chg_dis = %d, usb = %d, dc = %d b_health = %d batt_present = %d\n",
chip->charging_disabled,
qpnp_chg_is_usb_chg_plugged_in(chip),
@@ -2208,6 +2388,7 @@
qpnp_adc_tm_disable_chan_meas(&chip->adc_param);
}
cancel_work_sync(&chip->adc_measure_work);
+ cancel_delayed_work_sync(&chip->eoc_work);
dev_set_drvdata(&spmi->dev, NULL);
kfree(chip);
@@ -2245,7 +2426,7 @@
return rc;
}
-static const struct dev_pm_ops qpnp_bms_pm_ops = {
+static const struct dev_pm_ops qpnp_chg_pm_ops = {
.resume = qpnp_chg_resume,
.suspend = qpnp_chg_suspend,
};
@@ -2254,9 +2435,10 @@
.probe = qpnp_charger_probe,
.remove = __devexit_p(qpnp_charger_remove),
.driver = {
- .name = QPNP_CHARGER_DEV_NAME,
- .owner = THIS_MODULE,
- .of_match_table = qpnp_charger_match_table,
+ .name = QPNP_CHARGER_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = qpnp_charger_match_table,
+ .pm = &qpnp_chg_pm_ops,
},
};
diff --git a/drivers/power/smb350_charger.c b/drivers/power/smb350_charger.c
index 21d7aea..11fff43 100644
--- a/drivers/power/smb350_charger.c
+++ b/drivers/power/smb350_charger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -263,6 +263,9 @@
if (!chg_enabled) {
pr_warn("Charging not enabled.\n");
+ /* release the wake-lock when DC power removed */
+ if (wake_lock_active(&dev->chg_wake_lock))
+ wake_unlock(&dev->chg_wake_lock);
return POWER_SUPPLY_CHARGE_TYPE_NONE;
}
diff --git a/drivers/regulator/qpnp-regulator.c b/drivers/regulator/qpnp-regulator.c
index 2d10f89..c9d0500 100644
--- a/drivers/regulator/qpnp-regulator.c
+++ b/drivers/regulator/qpnp-regulator.c
@@ -514,8 +514,10 @@
{
struct qpnp_regulator *vreg = rdev_get_drvdata(rdev);
- if (vreg->ocp_irq)
+ if (vreg->ocp_irq) {
+ vreg->ocp_count = 0;
vreg->vs_enable_time = ktime_get();
+ }
return qpnp_regulator_common_enable(rdev);
}
diff --git a/drivers/rtc/qpnp-rtc.c b/drivers/rtc/qpnp-rtc.c
index 6d8985e..e0bffb9 100644
--- a/drivers/rtc/qpnp-rtc.c
+++ b/drivers/rtc/qpnp-rtc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-13, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -503,12 +503,17 @@
}
}
- rtc_dd->rtc_ctrl_reg = BIT_RTC_ENABLE;
- rc = qpnp_write_wrapper(rtc_dd, &rtc_dd->rtc_ctrl_reg,
+ rc = qpnp_read_wrapper(rtc_dd, &rtc_dd->rtc_ctrl_reg,
rtc_dd->rtc_base + REG_OFFSET_RTC_CTRL, 1);
if (rc) {
dev_err(&spmi->dev,
- "Write to RTC control reg failed\n");
+ "Read from RTC control reg failed\n");
+ goto fail_rtc_enable;
+ }
+
+ if (!(rtc_dd->rtc_ctrl_reg & BIT_RTC_ENABLE)) {
+ dev_err(&spmi->dev,
+ "RTC h/w disabled, rtc not registered\n");
goto fail_rtc_enable;
}
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 139bc06..086ff03 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -36,10 +36,20 @@
#ifndef _UFS_H
#define _UFS_H
+#include <linux/mutex.h>
+#include <linux/types.h>
+
#define MAX_CDB_SIZE 16
+#define GENERAL_UPIU_REQUEST_SIZE 32
+#define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE ((ALIGNED_UPIU_SIZE) - \
+ (GENERAL_UPIU_REQUEST_SIZE))
+#define QUERY_OSF_SIZE ((GENERAL_UPIU_REQUEST_SIZE) - \
+ (sizeof(struct utp_upiu_header)))
+#define UFS_QUERY_RESERVED_SCSI_CMD 0xCC
+#define UFS_QUERY_CMD_SIZE 10
#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
- ((byte3 << 24) | (byte2 << 16) |\
+ cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
(byte1 << 8) | (byte0))
/*
@@ -62,7 +72,7 @@
UPIU_TRANSACTION_COMMAND = 0x01,
UPIU_TRANSACTION_DATA_OUT = 0x02,
UPIU_TRANSACTION_TASK_REQ = 0x04,
- UPIU_TRANSACTION_QUERY_REQ = 0x26,
+ UPIU_TRANSACTION_QUERY_REQ = 0x16,
};
/* UTP UPIU Transaction Codes Target to Initiator */
@@ -73,6 +83,7 @@
UPIU_TRANSACTION_TASK_RSP = 0x24,
UPIU_TRANSACTION_READY_XFER = 0x31,
UPIU_TRANSACTION_QUERY_RSP = 0x36,
+ UPIU_TRANSACTION_REJECT_UPIU = 0x3F,
};
/* UPIU Read/Write flags */
@@ -90,6 +101,12 @@
UPIU_TASK_ATTR_ACA = 0x03,
};
+/* UPIU Query request function */
+enum {
+ UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01,
+ UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
+};
+
/* UTP QUERY Transaction Specific Fields OpCode */
enum {
UPIU_QUERY_OPCODE_NOP = 0x0,
@@ -103,6 +120,21 @@
UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
};
+/* Query response result code */
+enum {
+ QUERY_RESULT_SUCCESS = 0x00,
+ QUERY_RESULT_NOT_READABLE = 0xF6,
+ QUERY_RESULT_NOT_WRITEABLE = 0xF7,
+ QUERY_RESULT_ALREADY_WRITTEN = 0xF8,
+ QUERY_RESULT_INVALID_LENGTH = 0xF9,
+ QUERY_RESULT_INVALID_VALUE = 0xFA,
+ QUERY_RESULT_INVALID_SELECTOR = 0xFB,
+ QUERY_RESULT_INVALID_INDEX = 0xFC,
+ QUERY_RESULT_INVALID_IDN = 0xFD,
+ QUERY_RESULT_INVALID_OPCODE = 0xFE,
+ QUERY_RESULT_GENERAL_FAILURE = 0xFF,
+};
+
/* UTP Transfer Request Command Type (CT) */
enum {
UPIU_COMMAND_SET_TYPE_SCSI = 0x0,
@@ -110,10 +142,17 @@
UPIU_COMMAND_SET_TYPE_QUERY = 0x2,
};
+/* UTP Transfer Request Command Offset */
+#define UPIU_COMMAND_TYPE_OFFSET 28
+
+/* Offset of the response code in the UPIU header */
+#define UPIU_RSP_CODE_OFFSET 8
+
enum {
MASK_SCSI_STATUS = 0xFF,
MASK_TASK_RESPONSE = 0xFF00,
MASK_RSP_UPIU_RESULT = 0xFFFF,
+ MASK_QUERY_DATA_SEG_LEN = 0xFFFF,
};
/* Task management service response */
@@ -138,26 +177,59 @@
/**
* struct utp_upiu_cmd - Command UPIU structure
- * @header: UPIU header structure DW-0 to DW-2
* @data_transfer_len: Data Transfer Length DW-3
* @cdb: Command Descriptor Block CDB DW-4 to DW-7
*/
struct utp_upiu_cmd {
- struct utp_upiu_header header;
u32 exp_data_transfer_len;
u8 cdb[MAX_CDB_SIZE];
};
/**
- * struct utp_upiu_rsp - Response UPIU structure
- * @header: UPIU header DW-0 to DW-2
+ * struct utp_upiu_query - upiu request buffer structure for
+ * query request.
+ * @opcode: command to perform B-0
+ * @idn: a value that indicates the particular type of data B-1
+ * @index: Index to further identify data B-2
+ * @selector: Index to further identify data B-3
+ * @reserved_osf: spec reserved field B-4,5
+ * @length: number of descriptor bytes to read/write B-6,7
+ * @value: Attribute value to be written DW-6
+ * @reserved: spec reserved DW-7,8
+ */
+struct utp_upiu_query {
+ u8 opcode;
+ u8 idn;
+ u8 index;
+ u8 selector;
+ u16 reserved_osf;
+ u16 length;
+ u32 value;
+ u32 reserved[2];
+};
+
+/**
+ * struct utp_upiu_req - general upiu request structure
+ * @header:UPIU header structure DW-0 to DW-2
+ * @sc: fields structure for scsi command
+ * @qr: fields structure for query request
+ */
+struct utp_upiu_req {
+ struct utp_upiu_header header;
+ union {
+ struct utp_upiu_cmd sc;
+ struct utp_upiu_query qr;
+ };
+};
+
+/**
+ * struct utp_cmd_rsp - Response UPIU structure
* @residual_transfer_count: Residual transfer count DW-3
* @reserved: Reserved double words DW-4 to DW-7
* @sense_data_len: Sense data length DW-8 U16
* @sense_data: Sense data field DW-8 to DW-12
*/
-struct utp_upiu_rsp {
- struct utp_upiu_header header;
+struct utp_cmd_rsp {
u32 residual_transfer_count;
u32 reserved[4];
u16 sense_data_len;
@@ -165,6 +237,20 @@
};
/**
+ * struct utp_upiu_rsp - general upiu response structure
+ * @header: UPIU header structure DW-0 to DW-2
+ * @sc: fields structure for scsi command
+ * @qr: fields structure for query request
+ */
+struct utp_upiu_rsp {
+ struct utp_upiu_header header;
+ union {
+ struct utp_cmd_rsp sc;
+ struct utp_upiu_query qr;
+ };
+};
+
+/**
* struct utp_upiu_task_req - Task request UPIU structure
* @header - UPIU header structure DW0 to DW-2
* @input_param1: Input parameter 1 DW-3
@@ -194,4 +280,24 @@
u32 reserved[3];
};
+/**
+ * struct ufs_query_req - parameters for building a query request
+ * @query_func: UPIU header query function
+ * @upiu_req: the query request data
+ */
+struct ufs_query_req {
+ u8 query_func;
+ struct utp_upiu_query upiu_req;
+};
+
+/**
+ * struct ufs_query_resp - UPIU QUERY
+ * @response: device response code
+ * @upiu_res: query response data
+ */
+struct ufs_query_res {
+ u8 response;
+ struct utp_upiu_query upiu_res;
+};
+
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c32a478..c8fdc6b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -202,18 +202,13 @@
}
/**
- * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
+ * ufshcd_get_req_rsp - returns the TR response
* @ucd_rsp_ptr: pointer to response UPIU
- *
- * This function checks the response UPIU for valid transaction type in
- * response field
- * Returns 0 on success, non-zero on failure
*/
static inline int
-ufshcd_is_valid_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
+ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
{
- return ((be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24) ==
- UPIU_TRANSACTION_RESPONSE) ? 0 : DID_ERROR << 16;
+ return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24;
}
/**
@@ -316,14 +311,71 @@
{
int len;
if (lrbp->sense_buffer) {
- len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
+ len = be16_to_cpu(lrbp->ucd_rsp_ptr->sc.sense_data_len);
memcpy(lrbp->sense_buffer,
- lrbp->ucd_rsp_ptr->sense_data,
+ lrbp->ucd_rsp_ptr->sc.sense_data,
min_t(int, len, SCSI_SENSE_BUFFERSIZE));
}
}
/**
+ * ufshcd_query_to_cpu() - formats the received buffer in to the native cpu
+ * endian
+ * @response: upiu query response to convert
+ */
+static inline void ufshcd_query_to_cpu(struct utp_upiu_query *response)
+{
+ response->length = be16_to_cpu(response->length);
+ response->value = be32_to_cpu(response->value);
+}
+
+/**
+ * ufshcd_query_to_be() - formats the buffer before sending in to big endian
+ * @response: upiu query request to convert
+ */
+static inline void ufshcd_query_to_be(struct utp_upiu_query *request)
+{
+ request->length = cpu_to_be16(request->length);
+ request->value = cpu_to_be32(request->value);
+}
+
+/**
+ * ufshcd_copy_query_response() - Copy Query Response and descriptor
+ * @lrb - pointer to local reference block
+ * @query_res - pointer to the query result
+ */
+static
+void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+ struct ufs_query_res *query_res = hba->query.response;
+
+ /* Get the UPIU response */
+ if (query_res) {
+ query_res->response = ufshcd_get_rsp_upiu_result(
+ lrbp->ucd_rsp_ptr) >> UPIU_RSP_CODE_OFFSET;
+
+ memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr,
+ QUERY_OSF_SIZE);
+ ufshcd_query_to_cpu(&query_res->upiu_res);
+ }
+
+ /* Get the descriptor */
+ if (hba->query.descriptor && lrbp->ucd_rsp_ptr->qr.opcode ==
+ UPIU_QUERY_OPCODE_READ_DESC) {
+ u8 *descp = (u8 *)&lrbp->ucd_rsp_ptr +
+ GENERAL_UPIU_REQUEST_SIZE;
+ u16 len;
+
+ /* data segment length */
+ len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) &
+ MASK_QUERY_DATA_SEG_LEN;
+
+ memcpy(hba->query.descriptor, descp,
+ min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
+ }
+}
+
+/**
* ufshcd_hba_capabilities - Read controller capabilities
* @hba: per adapter instance
*/
@@ -423,76 +475,159 @@
}
/**
+ * ufshcd_prepare_req_desc - Fills the requests header
+ * descriptor according to request
+ * lrbp: pointer to local reference block
+ * upiu_flags: flags required in the header
+ */
+static void ufshcd_prepare_req_desc(struct ufshcd_lrb *lrbp, u32 *upiu_flags)
+{
+ struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
+ enum dma_data_direction cmd_dir =
+ lrbp->cmd->sc_data_direction;
+ u32 data_direction;
+ u32 dword_0;
+
+ if (cmd_dir == DMA_FROM_DEVICE) {
+ data_direction = UTP_DEVICE_TO_HOST;
+ *upiu_flags = UPIU_CMD_FLAGS_READ;
+ } else if (cmd_dir == DMA_TO_DEVICE) {
+ data_direction = UTP_HOST_TO_DEVICE;
+ *upiu_flags = UPIU_CMD_FLAGS_WRITE;
+ } else {
+ data_direction = UTP_NO_DATA_TRANSFER;
+ *upiu_flags = UPIU_CMD_FLAGS_NONE;
+ }
+
+ dword_0 = data_direction | (lrbp->command_type
+ << UPIU_COMMAND_TYPE_OFFSET);
+
+ /* Transfer request descriptor header fields */
+ req_desc->header.dword_0 = cpu_to_le32(dword_0);
+
+ /*
+ * assigning invalid value for command status. Controller
+ * updates OCS on command completion, with the command
+ * status
+ */
+ req_desc->header.dword_2 =
+ cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+}
+
+static inline bool ufshcd_is_query_req(struct ufshcd_lrb *lrbp)
+{
+ return lrbp->cmd ? lrbp->cmd->cmnd[0] == UFS_QUERY_RESERVED_SCSI_CMD :
+ false;
+}
+
+/**
+ * ufshcd_prepare_utp_scsi_cmd_upiu() - fills the utp_transfer_req_desc,
+ * for scsi commands
+ * @lrbp - local reference block pointer
+ * @upiu_flags - flags
+ */
+static
+void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
+{
+ struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+
+ /* command descriptor fields */
+ ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+ UPIU_TRANSACTION_COMMAND, upiu_flags,
+ lrbp->lun, lrbp->task_tag);
+ ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+ UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0);
+
+ /* Total EHS length and Data segment length will be zero */
+ ucd_req_ptr->header.dword_2 = 0;
+
+ ucd_req_ptr->sc.exp_data_transfer_len =
+ cpu_to_be32(lrbp->cmd->sdb.length);
+
+ memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd,
+ (min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
+}
+
+/**
+ * ufshcd_prepare_utp_query_req_upiu() - fills the utp_transfer_req_desc,
+ * for query requsts
+ * @hba: UFS hba
+ * @lrbp: local reference block pointer
+ * @upiu_flags: flags
+ */
+static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
+ struct ufshcd_lrb *lrbp,
+ u32 upiu_flags)
+{
+ struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+ u16 len = hba->query.request->upiu_req.length;
+ u8 *descp = (u8 *)lrbp->ucd_req_ptr + GENERAL_UPIU_REQUEST_SIZE;
+
+ /* Query request header */
+ ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+ UPIU_TRANSACTION_QUERY_REQ, upiu_flags,
+ lrbp->lun, lrbp->task_tag);
+ ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+ 0, hba->query.request->query_func, 0, 0);
+
+ /* Data segment length */
+ ucd_req_ptr->header.dword_2 = UPIU_HEADER_DWORD(
+ 0, 0, len >> 8, (u8)len);
+
+ /* Copy the Query Request buffer as is */
+ memcpy(&lrbp->ucd_req_ptr->qr, &hba->query.request->upiu_req,
+ QUERY_OSF_SIZE);
+ ufshcd_query_to_be(&lrbp->ucd_req_ptr->qr);
+
+ /* Copy the Descriptor */
+ if (hba->query.descriptor != NULL && len > 0 &&
+ (hba->query.request->upiu_req.opcode ==
+ UPIU_QUERY_OPCODE_WRITE_DESC)) {
+ memcpy(descp, hba->query.descriptor,
+ min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
+ }
+
+}
+
+/**
* ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU)
+ * @hba - UFS hba
* @lrb - pointer to local reference block
*/
-static void ufshcd_compose_upiu(struct ufshcd_lrb *lrbp)
+static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
{
- struct utp_transfer_req_desc *req_desc;
- struct utp_upiu_cmd *ucd_cmd_ptr;
- u32 data_direction;
u32 upiu_flags;
-
- ucd_cmd_ptr = lrbp->ucd_cmd_ptr;
- req_desc = lrbp->utr_descriptor_ptr;
+ int ret = 0;
switch (lrbp->command_type) {
case UTP_CMD_TYPE_SCSI:
- if (lrbp->cmd->sc_data_direction == DMA_FROM_DEVICE) {
- data_direction = UTP_DEVICE_TO_HOST;
- upiu_flags = UPIU_CMD_FLAGS_READ;
- } else if (lrbp->cmd->sc_data_direction == DMA_TO_DEVICE) {
- data_direction = UTP_HOST_TO_DEVICE;
- upiu_flags = UPIU_CMD_FLAGS_WRITE;
- } else {
- data_direction = UTP_NO_DATA_TRANSFER;
- upiu_flags = UPIU_CMD_FLAGS_NONE;
- }
-
- /* Transfer request descriptor header fields */
- req_desc->header.dword_0 =
- cpu_to_le32(data_direction | UTP_SCSI_COMMAND);
-
- /*
- * assigning invalid value for command status. Controller
- * updates OCS on command completion, with the command
- * status
- */
- req_desc->header.dword_2 =
- cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
-
- /* command descriptor fields */
- ucd_cmd_ptr->header.dword_0 =
- cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND,
- upiu_flags,
- lrbp->lun,
- lrbp->task_tag));
- ucd_cmd_ptr->header.dword_1 =
- cpu_to_be32(
- UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI,
- 0,
- 0,
- 0));
-
- /* Total EHS length and Data segment length will be zero */
- ucd_cmd_ptr->header.dword_2 = 0;
-
- ucd_cmd_ptr->exp_data_transfer_len =
- cpu_to_be32(lrbp->cmd->sdb.length);
-
- memcpy(ucd_cmd_ptr->cdb,
- lrbp->cmd->cmnd,
- (min_t(unsigned short,
- lrbp->cmd->cmd_len,
- MAX_CDB_SIZE)));
- break;
case UTP_CMD_TYPE_DEV_MANAGE:
- /* For query function implementation */
+ ufshcd_prepare_req_desc(lrbp, &upiu_flags);
+ if (lrbp->cmd && lrbp->command_type == UTP_CMD_TYPE_SCSI)
+ ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
+ else if (lrbp->cmd)
+ ufshcd_prepare_utp_query_req_upiu(hba, lrbp,
+ upiu_flags);
+ else {
+ dev_err(hba->dev, "%s: Invalid UPIU request\n",
+ __func__);
+ ret = -EINVAL;
+ }
break;
case UTP_CMD_TYPE_UFS:
/* For UFS native command implementation */
+ dev_err(hba->dev, "%s: UFS native command are not supported\n",
+ __func__);
+ ret = -ENOTSUPP;
+ break;
+ default:
+ ret = -ENOTSUPP;
+ dev_err(hba->dev, "%s: unknown command type: 0x%x\n",
+ __func__, lrbp->command_type);
break;
} /* end of switch */
+
+ return ret;
}
/**
@@ -527,10 +662,13 @@
lrbp->task_tag = tag;
lrbp->lun = cmd->device->lun;
- lrbp->command_type = UTP_CMD_TYPE_SCSI;
+ if (ufshcd_is_query_req(lrbp))
+ lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
+ else
+ lrbp->command_type = UTP_CMD_TYPE_SCSI;
/* form UPIU before issuing the command */
- ufshcd_compose_upiu(lrbp);
+ ufshcd_compose_upiu(hba, lrbp);
err = ufshcd_map_sg(lrbp);
if (err)
goto out;
@@ -544,6 +682,110 @@
}
/**
+ * ufshcd_query_request() - Entry point for issuing query request to a
+ * ufs device.
+ * @hba: ufs driver context
+ * @query: params for query request
+ * @descriptor: buffer for sending/receiving descriptor
+ * @response: pointer to a buffer that will contain the response code and
+ * response upiu
+ * @timeout: time limit for the command in seconds
+ * @retries: number of times to try executing the command
+ *
+ * The query request is submitted to the same request queue as the rest of
+ * the scsi commands passed to the UFS controller. In order to use this
+ * queue, we need to receive a tag, same as all other commands. The tags
+ * are issued from the block layer. To simulate a request from the block
+ * layer, we use the same interface as the SCSI layer does when it issues
+ * commands not generated by users. To distinguish a query request from
+ * the SCSI commands, we use a vendor specific unused SCSI command
+ * op-code. This op-code is not part of the SCSI command subset used in
+ * UFS. In such way it is easy to check the command in the driver and
+ * handle it appropriately.
+ *
+ * All necessary fields for issuing a query and receiving its response are
+ * stored in the UFS hba struct. We can use this method since we know
+ * there is only one active query request at all times.
+ *
+ * The request that will pass to the device is stored in "query" argument
+ * passed to this function, while the "response" argument (which is output
+ * field) will hold the query response from the device along with the
+ * response code.
+ */
+int ufshcd_query_request(struct ufs_hba *hba,
+ struct ufs_query_req *query,
+ u8 *descriptor,
+ struct ufs_query_res *response,
+ int timeout,
+ int retries)
+{
+ struct scsi_device *sdev;
+ u8 cmd[UFS_QUERY_CMD_SIZE] = {0};
+ int result;
+ bool sdev_lookup = true;
+
+ if (!hba || !query || !response) {
+ dev_err(hba->dev,
+ "%s: NULL pointer hba = %p, query = %p response = %p\n",
+ __func__, hba, query, response);
+ return -EINVAL;
+ }
+
+ /*
+ * A SCSI command structure is composed from opcode at the
+ * begining and 0 at the end.
+ */
+ cmd[0] = UFS_QUERY_RESERVED_SCSI_CMD;
+
+ /* extracting the SCSI Device */
+ sdev = scsi_device_lookup(hba->host, 0, 0, 0);
+ if (!sdev) {
+ /**
+ * There are some Query Requests that are sent during device
+ * initialization, this happens before the scsi device was
+ * initialized. If there is no scsi device, we generate a
+ * temporary device to allow the Query Request flow.
+ */
+ sdev_lookup = false;
+ sdev = scsi_get_host_dev(hba->host);
+ }
+
+ if (!sdev) {
+ dev_err(hba->dev, "%s: Could not fetch scsi device\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ mutex_lock(&hba->query.lock_ufs_query);
+ hba->query.request = query;
+ hba->query.descriptor = descriptor;
+ hba->query.response = response;
+
+ /* wait until request is completed */
+ result = scsi_execute(sdev, cmd, DMA_NONE, NULL, 0, NULL,
+ timeout, retries, 0, NULL);
+ if (result) {
+ dev_err(hba->dev,
+ "%s: Query with opcode 0x%x, failed with result %d\n",
+ __func__, query->upiu_req.opcode, result);
+ result = -EIO;
+ }
+
+ hba->query.request = NULL;
+ hba->query.descriptor = NULL;
+ hba->query.response = NULL;
+ mutex_unlock(&hba->query.lock_ufs_query);
+
+ /* Releasing scsi device resource */
+ if (sdev_lookup)
+ scsi_device_put(sdev);
+ else
+ scsi_free_host_dev(sdev);
+
+ return result;
+}
+
+/**
* ufshcd_memory_alloc - allocate memory for host memory space data structures
* @hba: per adapter instance
*
@@ -677,8 +919,8 @@
cpu_to_le16(ALIGNED_UPIU_SIZE);
hba->lrb[i].utr_descriptor_ptr = (utrdlp + i);
- hba->lrb[i].ucd_cmd_ptr =
- (struct utp_upiu_cmd *)(cmd_descp + i);
+ hba->lrb[i].ucd_req_ptr =
+ (struct utp_upiu_req *)(cmd_descp + i);
hba->lrb[i].ucd_rsp_ptr =
(struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
hba->lrb[i].ucd_prdt_ptr =
@@ -1101,7 +1343,9 @@
* @hba: per adapter instance
* @lrb: pointer to local reference block of completed command
*
- * Returns result of the command to notify SCSI midlayer
+ * Returns result of the command to notify SCSI midlayer. In
+ * case of query request specific result, returns DID_OK, and
+ * the error will be handled by the dispatcher.
*/
static inline int
ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
@@ -1115,27 +1359,46 @@
switch (ocs) {
case OCS_SUCCESS:
-
/* check if the returned transfer response is valid */
- result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
- if (result) {
- dev_err(hba->dev,
- "Invalid response = %x\n", result);
+ result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
+
+ switch (result) {
+ case UPIU_TRANSACTION_RESPONSE:
+ /*
+ * get the response UPIU result to extract
+ * the SCSI command status
+ */
+ result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
+
+ /*
+ * get the result based on SCSI status response
+ * to notify the SCSI midlayer of the command status
+ */
+ scsi_status = result & MASK_SCSI_STATUS;
+ result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
break;
+ case UPIU_TRANSACTION_QUERY_RSP:
+ /*
+ * Return result = ok, since SCSI layer wouldn't
+ * know how to handle errors from query requests.
+ * The result is saved with the response so that
+ * the ufs_core layer will handle it.
+ */
+ result = DID_OK << 16;
+ ufshcd_copy_query_response(hba, lrbp);
+ break;
+ case UPIU_TRANSACTION_REJECT_UPIU:
+ /* TODO: handle Reject UPIU Response */
+ result = DID_ERROR << 16;
+ dev_err(hba->dev,
+ "Reject UPIU not fully implemented\n");
+ break;
+ default:
+ result = DID_ERROR << 16;
+ dev_err(hba->dev,
+ "Unexpected request response code = %x\n",
+ result);
}
-
- /*
- * get the response UPIU result to extract
- * the SCSI command status
- */
- result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
-
- /*
- * get the result based on SCSI status response
- * to notify the SCSI midlayer of the command status
- */
- scsi_status = result & MASK_SCSI_STATUS;
- result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
break;
case OCS_ABORTED:
result |= DID_ABORT << 16;
@@ -1364,10 +1627,10 @@
task_req_upiup =
(struct utp_upiu_task_req *) task_req_descp->task_req_upiu;
task_req_upiup->header.dword_0 =
- cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
- lrbp->lun, lrbp->task_tag));
+ UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
+ lrbp->lun, lrbp->task_tag);
task_req_upiup->header.dword_1 =
- cpu_to_be32(UPIU_HEADER_DWORD(0, tm_function, 0, 0));
+ UPIU_HEADER_DWORD(0, tm_function, 0, 0);
task_req_upiup->input_param1 = lrbp->lun;
task_req_upiup->input_param1 =
@@ -1670,6 +1933,9 @@
INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler);
INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
+ /* Initialize mutex for query requests */
+ mutex_init(&hba->query.lock_ufs_query);
+
/* IRQ registration */
err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
if (err) {
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 6b99a42..336980b 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -60,6 +60,7 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
+#include <scsi/scsi_device.h>
#include "ufs.h"
#include "ufshci.h"
@@ -88,7 +89,7 @@
/**
* struct ufshcd_lrb - local reference block
* @utr_descriptor_ptr: UTRD address of the command
- * @ucd_cmd_ptr: UCD address of the command
+ * @ucd_req_ptr: UCD address of the command
* @ucd_rsp_ptr: Response UPIU address for this command
* @ucd_prdt_ptr: PRDT address of the command
* @cmd: pointer to SCSI command
@@ -101,7 +102,7 @@
*/
struct ufshcd_lrb {
struct utp_transfer_req_desc *utr_descriptor_ptr;
- struct utp_upiu_cmd *ucd_cmd_ptr;
+ struct utp_upiu_req *ucd_req_ptr;
struct utp_upiu_rsp *ucd_rsp_ptr;
struct ufshcd_sg_entry *ucd_prdt_ptr;
@@ -115,6 +116,19 @@
unsigned int lun;
};
+/**
+ * struct ufs_query - keeps the query request information
+ * @request: request upiu and function
+ * @descriptor: buffer for sending/receiving descriptor
+ * @response: response upiu and response
+ * @mutex: lock to allow one query at a time
+ */
+struct ufs_query {
+ struct ufs_query_req *request;
+ u8 *descriptor;
+ struct ufs_query_res *response;
+ struct mutex lock_ufs_query;
+};
/**
* struct ufs_hba - per adapter private structure
@@ -143,6 +157,7 @@
* @uic_workq: Work queue for UIC completion handling
* @feh_workq: Work queue for fatal controller error handling
* @errors: HBA errors
+ * @query: query request information
*/
struct ufs_hba {
void __iomem *mmio_base;
@@ -184,6 +199,9 @@
/* HBA Errors */
u32 errors;
+
+ /* Query Request */
+ struct ufs_query query;
};
int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 0c16484..4a86247 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -39,7 +39,7 @@
enum {
TASK_REQ_UPIU_SIZE_DWORDS = 8,
TASK_RSP_UPIU_SIZE_DWORDS = 8,
- ALIGNED_UPIU_SIZE = 128,
+ ALIGNED_UPIU_SIZE = 512,
};
/* UFSHCI Registers */
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index a0179cb..86ae8db 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -471,6 +471,8 @@
DECLARE_COMPLETION_ONSTACK(done);
u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
+ *clkgear = ctrl->clkgear;
+ *subfrmc = 0;
txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
txn.dt = SLIM_MSG_DEST_LOGICALADDR;
txn.la = SLIM_LA_MGR;
@@ -479,6 +481,34 @@
txn.wbuf = wbuf;
txn.rbuf = NULL;
+ if (ctrl->sched.msgsl != ctrl->sched.pending_msgsl) {
+ pr_debug("slim reserve BW for messaging: req: %d",
+ ctrl->sched.pending_msgsl);
+ txn.mc = SLIM_USR_MC_REQ_BW;
+ wbuf[txn.len++] = ((sb->laddr & 0x1f) |
+ ((u8)(ctrl->sched.pending_msgsl & 0x7) << 5));
+ wbuf[txn.len++] = (u8)(ctrl->sched.pending_msgsl >> 3);
+ ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
+ if (ret)
+ return ret;
+ txn.rl = txn.len + 4;
+ ret = ngd_xferandwait_ack(ctrl, &txn);
+ if (ret)
+ return ret;
+
+ txn.mc = SLIM_USR_MC_RECONFIG_NOW;
+ txn.len = 2;
+ wbuf[1] = sb->laddr;
+ txn.rl = txn.len + 4;
+ ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
+ if (ret)
+ return ret;
+ ret = ngd_xferandwait_ack(ctrl, &txn);
+ if (ret)
+ return ret;
+
+ txn.len = 0;
+ }
list_for_each_entry(pch, &sb->mark_define, pending) {
struct slim_ich *slc;
slc = &ctrl->chans[pch->chan];
@@ -1039,8 +1069,6 @@
dev->ctrl.config_port = msm_config_port;
dev->ctrl.port_xfer = msm_slim_port_xfer;
dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
- /* Reserve some messaging BW for satellite-apps driver communication */
- dev->ctrl.sched.pending_msgsl = 30;
dev->bam_mem = bam_mem;
init_completion(&dev->reconf);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index b89f608..c5aa7e5 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -2280,7 +2280,7 @@
bam_props.phys_addr = dd->bam.phys_addr;
bam_props.virt_addr = dd->bam.base;
bam_props.irq = dd->bam.irq;
- bam_props.manage = SPS_BAM_MGR_LOCAL;
+ bam_props.manage = SPS_BAM_MGR_DEVICE_REMOTE;
bam_props.summing_threshold = 0x10;
rc = sps_register_bam_device(&bam_props, &bam_handle);
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 6cd30f1..3abc3b9 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -2525,14 +2525,38 @@
struct binder_transaction *t;
t = container_of(w, struct binder_transaction, work);
- if (t->buffer->target_node && !(t->flags & TF_ONE_WAY))
+ if (t->buffer->target_node &&
+ !(t->flags & TF_ONE_WAY)) {
binder_send_failed_reply(t, BR_DEAD_REPLY);
+ } else {
+ binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
+ "binder: undelivered transaction %d\n",
+ t->debug_id);
+ t->buffer->transaction = NULL;
+ kfree(t);
+ binder_stats_deleted(BINDER_STAT_TRANSACTION);
+ }
} break;
case BINDER_WORK_TRANSACTION_COMPLETE: {
+ binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
+ "binder: undelivered TRANSACTION_COMPLETE\n");
kfree(w);
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
} break;
+ case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
+ case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
+ struct binder_ref_death *death;
+
+ death = container_of(w, struct binder_ref_death, work);
+ binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
+ "binder: undelivered death notification, %p\n",
+ death->cookie);
+ kfree(death);
+ binder_stats_deleted(BINDER_STAT_DEATH);
+ } break;
default:
+ pr_err("binder: unexpected work type, %d, not freed\n",
+ w->type);
break;
}
}
@@ -3009,6 +3033,7 @@
nodes++;
rb_erase(&node->rb_node, &proc->nodes);
list_del_init(&node->work.entry);
+ binder_release_work(&node->async_todo);
if (hlist_empty(&node->refs)) {
kfree(node);
binder_stats_deleted(BINDER_STAT_NODE);
@@ -3047,6 +3072,7 @@
binder_delete_ref(ref);
}
binder_release_work(&proc->todo);
+ binder_release_work(&proc->delivered_death);
buffers = 0;
while ((n = rb_first(&proc->allocated_buffers))) {
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 991cf2e..f01a078 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -199,8 +199,8 @@
#define TSENS0_8X10_POINT1_SHIFT 16
#define TSENS0_8X10_POINT2_SHIFT 22
#define TSENS1_8X10_POINT2_SHIFT 6
-#define TSENS_8X10_BASE0_MASK 0xf
-#define TSENS_8X10_BASE1_MASK 0xf0
+#define TSENS_8X10_BASE0_MASK 0xff
+#define TSENS_8X10_BASE1_MASK 0xff00
#define TSENS0_8X10_POINT1_MASK 0x3f0000
#define TSENS0_8X10_POINT2_MASK 0xfc00000
#define TSENS_8X10_TSENS_CAL_SEL 0x70000000
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 12ac3bc..814817b 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -28,6 +28,7 @@
#include <linux/of.h>
#include <linux/sysfs.h>
#include <linux/types.h>
+#include <linux/android_alarm.h>
#include <mach/cpufreq.h>
#include <mach/rpm-regulator.h>
#include <mach/rpm-regulator-smd.h>
@@ -41,6 +42,10 @@
static bool core_control_enabled;
static uint32_t cpus_offlined;
static DEFINE_MUTEX(core_control_mutex);
+static uint32_t wakeup_ms;
+static struct alarm thermal_rtc;
+static struct kobject *tt_kobj;
+static struct work_struct timer_work;
static int enabled;
static int rails_cnt;
@@ -58,6 +63,7 @@
static bool psm_enabled;
static bool psm_nodes_called;
static bool psm_probed;
+static int *tsens_id_map;
static DEFINE_MUTEX(vdd_rstr_mutex);
static DEFINE_MUTEX(psm_mutex);
@@ -66,7 +72,7 @@
uint32_t freq_req;
uint32_t min_level;
uint32_t num_levels;
- uint32_t curr_level;
+ int32_t curr_level;
uint32_t levels[3];
struct kobj_attribute value_attr;
struct kobj_attribute level_attr;
@@ -103,6 +109,7 @@
ko_attr.attr.mode = 444; \
ko_attr.show = vdd_rstr_reg_##_name##_show; \
ko_attr.store = NULL; \
+ sysfs_attr_init(&ko_attr.attr); \
_rail.attr_gp.attrs[j] = &ko_attr.attr;
#define VDD_RES_RW_ATTRIB(_rail, ko_attr, j, _name) \
@@ -110,6 +117,7 @@
ko_attr.attr.mode = 644; \
ko_attr.show = vdd_rstr_reg_##_name##_show; \
ko_attr.store = vdd_rstr_reg_##_name##_store; \
+ sysfs_attr_init(&ko_attr.attr); \
_rail.attr_gp.attrs[j] = &ko_attr.attr;
#define VDD_RSTR_ENABLE_FROM_ATTRIBS(attr) \
@@ -126,6 +134,7 @@
ko_attr.attr.mode = 644; \
ko_attr.show = psm_reg_##_name##_show; \
ko_attr.store = psm_reg_##_name##_store; \
+ sysfs_attr_init(&ko_attr.attr); \
_rail.attr_gp.attrs[j] = &ko_attr.attr;
#define PSM_REG_MODE_FROM_ATTRIBS(attr) \
@@ -150,6 +159,7 @@
{
int cpu = 0;
int ret = 0;
+ struct cpufreq_policy *policy = NULL;
if (!freq_table_get) {
ret = check_freq_table();
@@ -165,16 +175,20 @@
for_each_possible_cpu(cpu) {
ret = msm_cpufreq_set_freq_limits(cpu, min, limited_max_freq);
-
if (ret) {
pr_err("%s:Fail to set limits for cpu%d\n",
__func__, cpu);
return ret;
}
- if (cpufreq_update_policy(cpu))
- pr_debug("%s: Cannot update policy for cpu%d\n",
- __func__, cpu);
+ if (cpu_online(cpu)) {
+ policy = cpufreq_cpu_get(cpu);
+ if (!policy)
+ continue;
+ cpufreq_driver_target(policy, policy->cur,
+ CPUFREQ_RELATION_L);
+ cpufreq_cpu_put(policy);
+ }
}
return ret;
@@ -184,6 +198,9 @@
{
int ret = 0;
+ if (level == r->curr_level)
+ return ret;
+
/* level = -1: disable, level = 0,1,2..n: enable */
if (level == -1) {
ret = update_cpu_min_freq_all(r->min_level);
@@ -214,6 +231,9 @@
r->name);
return -EFAULT;
}
+ if (level == r->curr_level)
+ return ret;
+
/* level = -1: disable, level = 0,1,2..n: enable */
if (level == -1) {
ret = regulator_set_voltage(r->reg, r->min_level,
@@ -232,32 +252,6 @@
return ret;
}
-/* 1:enable, 0:disable */
-static int vdd_restriction_apply_all(int en)
-{
- int i = 0;
- int fail_cnt = 0;
- int ret = 0;
-
- for (i = 0; i < rails_cnt; i++) {
- if (rails[i].freq_req == 1 && freq_table_get)
- ret = vdd_restriction_apply_freq(&rails[i],
- en ? 0 : -1);
- else
- ret = vdd_restriction_apply_voltage(&rails[i],
- en ? 0 : -1);
- if (ret) {
- pr_err("Cannot set voltage for %s", rails[i].name);
- fail_cnt++;
- }
- }
- /* Check fail_cnt again to make sure all of the rails are applied
- * restriction successfully or not */
- if (fail_cnt)
- return -EFAULT;
-
- return ret;
-}
/* Setting all rails the same mode */
static int psm_set_mode_all(int mode)
@@ -319,8 +313,10 @@
ret = vdd_restriction_apply_voltage(&rails[i],
(val) ? 0 : -1);
- /* Even if fail to set one rail, still try to set the
- * others. Continue the loop */
+ /*
+ * Even if fail to set one rail, still try to set the
+ * others. Continue the loop
+ */
if (ret)
pr_err("Set vdd restriction for %s failed\n",
rails[i].name);
@@ -370,7 +366,7 @@
else
val = reg->levels[reg->curr_level];
- return snprintf(buf, PAGE_SIZE, "%d\n", reg->levels[reg->curr_level]);
+ return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static int vdd_rstr_reg_level_show(
@@ -392,7 +388,7 @@
if (vdd_rstr_en.enabled == 0)
goto done_store_level;
- ret = kstrtoint(buf, 10, &val);
+ ret = kstrtouint(buf, 10, &val);
if (ret) {
pr_err("Invalid input %s for level\n", buf);
goto done_store_level;
@@ -465,6 +461,103 @@
return count;
}
+static int check_sensor_id(int sensor_id)
+{
+ int i = 0;
+ bool hw_id_found;
+ int ret = 0;
+
+ for (i = 0; i < max_tsens_num; i++) {
+ if (sensor_id == tsens_id_map[i]) {
+ hw_id_found = true;
+ break;
+ }
+ }
+ if (!hw_id_found) {
+ pr_err("%s: Invalid sensor hw id :%d\n", __func__, sensor_id);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int create_sensor_id_map(void)
+{
+ int i = 0;
+ int ret = 0;
+
+ tsens_id_map = kzalloc(sizeof(int) * max_tsens_num,
+ GFP_KERNEL);
+ if (!tsens_id_map) {
+ pr_err("%s: Cannot allocate memory for tsens_id_map\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < max_tsens_num; i++) {
+ ret = tsens_get_hw_id_mapping(i, &tsens_id_map[i]);
+ /* If return -ENXIO, hw_id is default in sequence */
+ if (ret) {
+ if (ret == -ENXIO) {
+ tsens_id_map[i] = i;
+ ret = 0;
+ } else {
+ pr_err( \
+ "%s: Failed to get hw id for sw id %d\n",
+ __func__, i);
+ goto fail;
+ }
+ }
+ }
+
+ return ret;
+fail:
+ kfree(tsens_id_map);
+ return ret;
+}
+
+/* 1:enable, 0:disable */
+static int vdd_restriction_apply_all(int en)
+{
+ int i = 0;
+ int en_cnt = 0;
+ int dis_cnt = 0;
+ int fail_cnt = 0;
+ int ret = 0;
+
+ for (i = 0; i < rails_cnt; i++) {
+ if (rails[i].freq_req == 1 && freq_table_get)
+ ret = vdd_restriction_apply_freq(&rails[i],
+ en ? 0 : -1);
+ else
+ ret = vdd_restriction_apply_voltage(&rails[i],
+ en ? 0 : -1);
+ if (ret) {
+ pr_err("Cannot set voltage for %s", rails[i].name);
+ fail_cnt++;
+ } else {
+ if (en)
+ en_cnt++;
+ else
+ dis_cnt++;
+ }
+ }
+
+ /* As long as one rail is enabled, vdd rstr is enabled */
+ if (en && en_cnt)
+ vdd_rstr_en.enabled = 1;
+ else if (!en && (dis_cnt == rails_cnt))
+ vdd_rstr_en.enabled = 0;
+
+ /*
+ * Check fail_cnt again to make sure all of the rails are applied
+ * restriction successfully or not
+ */
+ if (fail_cnt)
+ return -EFAULT;
+ return ret;
+}
+
static int msm_thermal_get_freq_table(void)
{
int ret = 0;
@@ -542,7 +635,8 @@
cpus_offlined &= ~BIT(i);
pr_info("%s: Allow Online CPU%d Temp: %ld\n",
KBUILD_MODNAME, i, temp);
- /* If this core is already online, then bring up the
+ /*
+ * If this core is already online, then bring up the
* next offlined core.
*/
if (cpu_online(i))
@@ -575,7 +669,7 @@
mutex_lock(&vdd_rstr_mutex);
for (i = 0; i < max_tsens_num; i++) {
- tsens_dev.sensor_num = i;
+ tsens_dev.sensor_num = tsens_id_map[i];
ret = tsens_get_temp(&tsens_dev, &temp);
if (ret) {
pr_debug("%s: Unable to read TSENS sensor %d\n",
@@ -583,18 +677,15 @@
dis_cnt++;
continue;
}
- if (temp <= msm_thermal_info.vdd_rstr_temp_hyst_degC &&
- vdd_rstr_en.enabled == 0) {
+ if (temp <= msm_thermal_info.vdd_rstr_temp_degC) {
ret = vdd_restriction_apply_all(1);
if (ret) {
pr_err( \
"Enable vdd rstr votlage for all failed\n");
goto exit;
}
- vdd_rstr_en.enabled = 1;
goto exit;
- } else if (temp > msm_thermal_info.vdd_rstr_temp_degC &&
- vdd_rstr_en.enabled == 1)
+ } else if (temp > msm_thermal_info.vdd_rstr_temp_hyst_degC)
dis_cnt++;
}
if (dis_cnt == max_tsens_num) {
@@ -603,7 +694,6 @@
pr_err("Disable vdd rstr votlage for all failed\n");
goto exit;
}
- vdd_rstr_en.enabled = 0;
}
exit:
mutex_unlock(&vdd_rstr_mutex);
@@ -620,7 +710,7 @@
mutex_lock(&psm_mutex);
for (i = 0; i < max_tsens_num; i++) {
- tsens_dev.sensor_num = i;
+ tsens_dev.sensor_num = tsens_id_map[i];
ret = tsens_get_temp(&tsens_dev, &temp);
if (ret) {
pr_debug("%s: Unable to read TSENS sensor %d\n",
@@ -629,9 +719,11 @@
continue;
}
- /* As long as one sensor is above the threshold, set PWM mode
+ /*
+ * As long as one sensor is above the threshold, set PWM mode
* on all rails, and loop stops. Set auto mode when all rails
- * are below thershold */
+ * are below thershold
+ */
if (temp > msm_thermal_info.psm_temp_degC) {
ret = psm_set_mode_all(PMIC_PWM_MODE);
if (ret) {
@@ -746,7 +838,40 @@
.notifier_call = msm_thermal_cpu_callback,
};
-/**
+static void thermal_rtc_setup(void)
+{
+ ktime_t wakeup_time;
+ ktime_t curr_time;
+
+ curr_time = alarm_get_elapsed_realtime();
+ wakeup_time = ktime_add_us(curr_time,
+ (wakeup_ms * USEC_PER_MSEC));
+ alarm_start_range(&thermal_rtc, wakeup_time,
+ wakeup_time);
+ pr_debug("%s: Current Time: %ld %ld, Alarm set to: %ld %ld\n",
+ KBUILD_MODNAME,
+ ktime_to_timeval(curr_time).tv_sec,
+ ktime_to_timeval(curr_time).tv_usec,
+ ktime_to_timeval(wakeup_time).tv_sec,
+ ktime_to_timeval(wakeup_time).tv_usec);
+
+}
+
+static void timer_work_fn(struct work_struct *work)
+{
+ sysfs_notify(tt_kobj, NULL, "wakeup_ms");
+}
+
+static void thermal_rtc_callback(struct alarm *al)
+{
+ struct timeval ts;
+ ts = ktime_to_timeval(alarm_get_elapsed_realtime());
+ schedule_work(&timer_work);
+ pr_debug("%s: Time on alarm expiry: %ld %ld\n", KBUILD_MODNAME,
+ ts.tv_sec, ts.tv_usec);
+}
+
+/*
* We will reset the cpu frequencies limits here. The core online/offline
* status will be carried over to the process stopping the msm_thermal, as
* we dont want to online a core and bring in the thermal issues.
@@ -902,6 +1027,52 @@
.attrs = cc_attrs,
};
+static ssize_t show_wakeup_ms(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", wakeup_ms);
+}
+
+static ssize_t store_wakeup_ms(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ ret = kstrtouint(buf, 10, &wakeup_ms);
+
+ if (ret) {
+ pr_err("%s: Trying to set invalid wakeup timer\n",
+ KBUILD_MODNAME);
+ return ret;
+ }
+
+ if (wakeup_ms > 0) {
+ thermal_rtc_setup();
+ pr_debug("%s: Timer started for %ums\n", KBUILD_MODNAME,
+ wakeup_ms);
+ } else {
+ ret = alarm_cancel(&thermal_rtc);
+ if (ret)
+ pr_debug("%s: Timer canceled\n", KBUILD_MODNAME);
+ else
+ pr_debug("%s: No active timer present to cancel\n",
+ KBUILD_MODNAME);
+
+ }
+ return count;
+}
+
+static __cpuinitdata struct kobj_attribute timer_attr =
+__ATTR(wakeup_ms, 0644, show_wakeup_ms, store_wakeup_ms);
+
+static __cpuinitdata struct attribute *tt_attrs[] = {
+ &timer_attr.attr,
+ NULL,
+};
+
+static __cpuinitdata struct attribute_group tt_attr_group = {
+ .attrs = tt_attrs,
+};
+
static __init int msm_thermal_add_cc_nodes(void)
{
struct kobject *module_kobj = NULL;
@@ -938,15 +1109,54 @@
return ret;
}
+static __init int msm_thermal_add_timer_nodes(void)
+{
+ struct kobject *module_kobj = NULL;
+ int ret = 0;
+
+ module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+ if (!module_kobj) {
+ pr_err("%s: cannot find kobject for module\n",
+ KBUILD_MODNAME);
+ ret = -ENOENT;
+ goto failed;
+ }
+
+ tt_kobj = kobject_create_and_add("thermal_timer", module_kobj);
+ if (!tt_kobj) {
+ pr_err("%s: cannot create timer kobj\n",
+ KBUILD_MODNAME);
+ ret = -ENOMEM;
+ goto failed;
+ }
+
+ ret = sysfs_create_group(tt_kobj, &tt_attr_group);
+ if (ret) {
+ pr_err("%s: cannot create group\n", KBUILD_MODNAME);
+ goto failed;
+ }
+
+ return 0;
+
+failed:
+ if (tt_kobj)
+ kobject_del(tt_kobj);
+ return ret;
+}
+
int __devinit msm_thermal_init(struct msm_thermal_data *pdata)
{
int ret = 0;
BUG_ON(!pdata);
tsens_get_max_sensor_num(&max_tsens_num);
- BUG_ON(msm_thermal_info.sensor_id >= max_tsens_num);
memcpy(&msm_thermal_info, pdata, sizeof(struct msm_thermal_data));
+ if (create_sensor_id_map())
+ return -EINVAL;
+ if (check_sensor_id(msm_thermal_info.sensor_id))
+ return -EINVAL;
+
enabled = 1;
core_control_enabled = 1;
INIT_DELAYED_WORK(&check_temp_work, check_temp);
@@ -966,8 +1176,10 @@
if (rails[i].freq_req == 1) {
usefreq |= BIT(i);
check_freq_table();
- /* Restrict frequency by default until we have made
- * our first temp reading */
+ /*
+ * Restrict frequency by default until we have made
+ * our first temp reading
+ */
if (freq_table_get)
ret = vdd_restriction_apply_freq(&rails[i], 0);
else
@@ -988,8 +1200,10 @@
}
return ret;
}
- /* Restrict votlage by default until we have made
- * our first temp reading */
+ /*
+ * Restrict votlage by default until we have made
+ * our first temp reading
+ */
ret = vdd_restriction_apply_voltage(&rails[i], 0);
}
}
@@ -1252,17 +1466,18 @@
if (ret)
goto read_node_fail;
- key = "qcom,min-level";
- ret = of_property_read_u32(child_node, key,
- &rails[i].min_level);
- if (ret)
- goto read_node_fail;
-
key = "qcom,freq-req";
rails[i].freq_req = of_property_read_bool(child_node, key);
+ if (rails[i].freq_req)
+ rails[i].min_level = MSM_CPUFREQ_NO_LIMIT;
+ else {
+ key = "qcom,min-level";
+ ret = of_property_read_u32(child_node, key,
+ &rails[i].min_level);
+ if (ret)
+ goto read_node_fail;
+ }
- if (ret)
- goto read_node_fail;
rails[i].curr_level = 0;
rails[i].reg = NULL;
i++;
@@ -1393,9 +1608,11 @@
key = "qcom,core-control-mask";
ret = of_property_read_u32(node, key, &data.core_control_mask);
- /* Probe optional properties below. Call probe_psm before
+ /*
+ * Probe optional properties below. Call probe_psm before
* probe_vdd_rstr because rpm_regulator_get has to be called
- * before devm_regulator_get*/
+ * before devm_regulator_get
+ */
ret = probe_psm(node, &data, pdev);
if (ret == -EPROBE_DEFER)
goto fail;
@@ -1403,8 +1620,10 @@
if (ret == -EPROBE_DEFER)
goto fail;
- /* In case sysfs add nodes get called before probe function.
- * Need to make sure sysfs node is created again */
+ /*
+ * In case sysfs add nodes get called before probe function.
+ * Need to make sure sysfs node is created again
+ */
if (psm_nodes_called) {
msm_thermal_add_psm_nodes();
psm_nodes_called = false;
@@ -1449,6 +1668,10 @@
msm_thermal_add_cc_nodes();
msm_thermal_add_psm_nodes();
msm_thermal_add_vdd_rstr_nodes();
+ alarm_init(&thermal_rtc, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+ thermal_rtc_callback);
+ INIT_WORK(&timer_work, timer_work_fn);
+ msm_thermal_add_timer_nodes();
return 0;
}
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index d848a18..26a12d0 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1200,22 +1200,28 @@
}
}
- rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
- sensor_mask, false);
- if (rc < 0) {
- pr_err("multi meas disable for channel failed\n");
- goto fail;
- }
+ if (adc_tm_high_enable || adc_tm_low_enable) {
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("multi meas disable for channel failed\n");
+ goto fail;
+ }
- rc = qpnp_adc_tm_enable_if_channel_meas();
- if (rc < 0) {
- pr_err("re-enabling measurement failed\n");
- return rc;
- }
+ rc = qpnp_adc_tm_enable_if_channel_meas();
+ if (rc < 0) {
+ pr_err("re-enabling measurement failed\n");
+ return rc;
+ }
+ } else
+ pr_debug("No threshold status enable %d for high/low??\n",
+ sensor_mask);
+
fail:
mutex_unlock(&adc_tm->adc->adc_lock);
- schedule_work(&adc_tm->sensor[sensor_num].work);
+ if (adc_tm_high_enable || adc_tm_low_enable)
+ schedule_work(&adc_tm->sensor[sensor_num].work);
return rc;
}
@@ -1528,6 +1534,7 @@
dev_err(&spmi->dev, "failed to read device tree\n");
goto fail;
}
+ mutex_init(&adc_tm->adc->adc_lock);
/* Register the ADC peripheral interrupt */
adc_tm->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index ad7c702..890a897 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -2340,9 +2340,7 @@
msm_hs_start_rx_locked(uport);
spin_unlock_irqrestore(&uport->lock, flags);
- ret = pm_runtime_set_active(uport->dev);
- if (ret)
- dev_err(uport->dev, "set active error:%d\n", ret);
+
pm_runtime_enable(uport->dev);
return 0;
@@ -2741,7 +2739,7 @@
/* SPS driver wll handle the UART BAM IRQ */
bam.irq = (u32)msm_uport->bam_irq;
- bam.manage = SPS_BAM_MGR_LOCAL;
+ bam.manage = SPS_BAM_MGR_DEVICE_REMOTE;
pr_debug("msm_serial_hs: bam physical base=0x%x\n",
(u32)bam.phys_addr);
@@ -3180,7 +3178,6 @@
cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work);
flush_workqueue(msm_uport->hsuart_wq);
pm_runtime_disable(uport->dev);
- pm_runtime_set_suspended(uport->dev);
/* Disable the transmitter */
msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK);
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 7aa14de..d520253 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -364,6 +364,22 @@
return msm_hsl_port->uart.line;
}
+static int bus_vote(uint32_t client, int vector)
+{
+ int ret = 0;
+
+ if (!client)
+ return ret;
+
+ pr_debug("Voting for bus scaling:%d\n", vector);
+
+ ret = msm_bus_scale_client_update_request(client, vector);
+ if (ret)
+ pr_err("Failed to request bus bw vector %d\n", vector);
+
+ return ret;
+}
+
static int clk_en(struct uart_port *port, int enable)
{
struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
@@ -372,9 +388,13 @@
if (enable) {
msm_hsl_port->clk_enable_count++;
- ret = clk_prepare_enable(msm_hsl_port->clk);
+ ret = bus_vote(msm_hsl_port->bus_perf_client,
+ !!msm_hsl_port->clk_enable_count);
if (ret)
goto err;
+ ret = clk_prepare_enable(msm_hsl_port->clk);
+ if (ret)
+ goto err_bus;
if (msm_hsl_port->pclk) {
ret = clk_prepare_enable(msm_hsl_port->pclk);
if (ret)
@@ -386,23 +406,17 @@
clk_disable_unprepare(msm_hsl_port->clk);
if (msm_hsl_port->pclk)
clk_disable_unprepare(msm_hsl_port->pclk);
- }
-
- if (msm_hsl_port->bus_perf_client) {
- pr_debug("Voting for bus scaling:%d\n",
- !!msm_hsl_port->clk_enable_count);
- ret = msm_bus_scale_client_update_request(
- msm_hsl_port->bus_perf_client,
+ ret = bus_vote(msm_hsl_port->bus_perf_client,
!!msm_hsl_port->clk_enable_count);
- if (ret)
- pr_err("Failed to request bus bw vector %d\n",
- !!msm_hsl_port->clk_enable_count);
}
return ret;
err_clk_disable:
clk_disable_unprepare(msm_hsl_port->clk);
+err_bus:
+ bus_vote(msm_hsl_port->bus_perf_client,
+ !!(msm_hsl_port->clk_enable_count - 1));
err:
msm_hsl_port->clk_enable_count--;
return ret;
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index ede2ef1..1d02e32 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -110,6 +110,34 @@
wake_up_interruptible(&vt_event_waitqueue);
}
+static void __vt_event_queue(struct vt_event_wait *vw)
+{
+ unsigned long flags;
+ /* Prepare the event */
+ INIT_LIST_HEAD(&vw->list);
+ vw->done = 0;
+ /* Queue our event */
+ spin_lock_irqsave(&vt_event_lock, flags);
+ list_add(&vw->list, &vt_events);
+ spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
+static void __vt_event_wait(struct vt_event_wait *vw)
+{
+ /* Wait for it to pass */
+ wait_event_interruptible(vt_event_waitqueue, vw->done);
+}
+
+static void __vt_event_dequeue(struct vt_event_wait *vw)
+{
+ unsigned long flags;
+
+ /* Dequeue it */
+ spin_lock_irqsave(&vt_event_lock, flags);
+ list_del(&vw->list);
+ spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
/**
* vt_event_wait - wait for an event
* @vw: our event
@@ -121,20 +149,9 @@
static void vt_event_wait(struct vt_event_wait *vw)
{
- unsigned long flags;
- /* Prepare the event */
- INIT_LIST_HEAD(&vw->list);
- vw->done = 0;
- /* Queue our event */
- spin_lock_irqsave(&vt_event_lock, flags);
- list_add(&vw->list, &vt_events);
- spin_unlock_irqrestore(&vt_event_lock, flags);
- /* Wait for it to pass */
- wait_event_interruptible(vt_event_waitqueue, vw->done);
- /* Dequeue it */
- spin_lock_irqsave(&vt_event_lock, flags);
- list_del(&vw->list);
- spin_unlock_irqrestore(&vt_event_lock, flags);
+ __vt_event_queue(vw);
+ __vt_event_wait(vw);
+ __vt_event_dequeue(vw);
}
/**
@@ -177,10 +194,14 @@
{
struct vt_event_wait vw;
do {
- if (n == fg_console + 1)
- break;
vw.event.event = VT_EVENT_SWITCH;
- vt_event_wait(&vw);
+ __vt_event_queue(&vw);
+ if (n == fg_console + 1) {
+ __vt_event_dequeue(&vw);
+ break;
+ }
+ __vt_event_wait(&vw);
+ __vt_event_dequeue(&vw);
if (vw.done == 0)
return -EINTR;
} while (vw.event.newev != n);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 924e8f4..a27eb09 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1309,8 +1309,14 @@
data |= (0x7F | (1 << 14));
dwc3_msm_ssusb_write_phycreg(msm->base, 0x1002, data);
- /* Set LOS_BIAS to 0x5 */
- dwc3_msm_write_readback(msm->base, SS_PHY_PARAM_CTRL_1, 0x07, 0x5);
+ /*
+ * Set the QSCRATCH SS_PHY_PARAM_CTRL1 parameters as follows
+ * TX_FULL_SWING [26:20] amplitude to 127
+ * TX_DEEMPH_3_5DB [13:8] to 22
+ * LOS_BIAS [2:0] to 0x5
+ */
+ dwc3_msm_write_readback(msm->base, SS_PHY_PARAM_CTRL_1,
+ 0x07f03f07, 0x07f01605);
}
/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
@@ -2433,6 +2439,8 @@
msm->charger.charging_disabled = of_property_read_bool(node,
"qcom,charging-disabled");
+ msm->charger.skip_chg_detect = of_property_read_bool(node,
+ "qcom,skip-charger-detection");
/*
* DWC3 has separate IRQ line for OTG events (ID/BSV) and for
* DP and DM linestate transitions during low power mode.
@@ -2606,12 +2614,17 @@
msm->otg_xceiv = usb_get_transceiver();
/* Register with OTG if present, ignore USB2 OTG using other PHY */
if (msm->otg_xceiv && !(msm->otg_xceiv->flags & ENABLE_SECONDARY_PHY)) {
- msm->charger.start_detection = dwc3_start_chg_det;
- ret = dwc3_set_charger(msm->otg_xceiv->otg, &msm->charger);
- if (ret || !msm->charger.notify_detection_complete) {
- dev_err(&pdev->dev, "failed to register charger: %d\n",
- ret);
- goto put_xcvr;
+ /* Skip charger detection for simulator targets */
+ if (!msm->charger.skip_chg_detect) {
+ msm->charger.start_detection = dwc3_start_chg_det;
+ ret = dwc3_set_charger(msm->otg_xceiv->otg,
+ &msm->charger);
+ if (ret || !msm->charger.notify_detection_complete) {
+ dev_err(&pdev->dev,
+ "failed to register charger: %d\n",
+ ret);
+ goto put_xcvr;
+ }
}
if (msm->ext_xceiv.otg_capability)
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index c2fab53..90e26cf 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -77,6 +77,8 @@
unsigned max_power;
bool charging_disabled;
+ bool skip_chg_detect;
+
/* start/stop charger detection, provided by external charger module */
void (*start_detection)(struct dwc3_charger *charger, bool start);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 8d2ec97..bb0b2fb 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -751,6 +751,9 @@
dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
r = next_request(&ep0->request_list);
+ if (r == NULL)
+ return;
+
ur = &r->request;
if ((epnum & 1) && ur->zero &&
(ur->length % ep0->endpoint.maxpacket == 0)) {
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 705600d..bc1fa07 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -426,6 +426,7 @@
struct adb_data {
bool opened;
bool enabled;
+ struct android_dev *dev;
};
static int
@@ -459,6 +460,7 @@
data->enabled = true;
+
/* Disable the gadget until adbd is ready */
if (!data->opened)
android_disable(dev);
@@ -490,27 +492,45 @@
struct android_dev *dev = adb_function.android_dev;
struct adb_data *data = adb_function.config;
+ /* dev is null in case ADB is not in the composition */
+ if (dev)
+ mutex_lock(&dev->mutex);
+
+ /* Save dev in case the adb function will get disabled */
+ data->dev = dev;
data->opened = true;
- if (data->enabled && dev) {
- mutex_lock(&dev->mutex);
+ if (data->enabled && dev)
android_enable(dev);
+
+ if (dev)
mutex_unlock(&dev->mutex);
- }
}
static void adb_closed_callback(void)
{
- struct android_dev *dev = adb_function.android_dev;
struct adb_data *data = adb_function.config;
+ struct android_dev *dev = adb_function.android_dev;
+
+ /* In case new composition is without ADB, use saved one */
+ if (!dev)
+ dev = data->dev;
+
+ if (!dev)
+ pr_err("adb_closed_callback: data->dev is NULL");
+
+ if (dev)
+ mutex_lock(&dev->mutex);
data->opened = false;
- if (data->enabled) {
- mutex_lock(&dev->mutex);
+ if (data->enabled)
android_disable(dev);
+
+ data->dev = NULL;
+
+ if (dev)
mutex_unlock(&dev->mutex);
- }
}
@@ -2689,6 +2709,8 @@
of_property_read_u32(pdev->dev.of_node,
"qcom,android-usb-swfi-latency",
&pdata->swfi_latency);
+ pdata->cdrom = of_property_read_bool(pdev->dev.of_node,
+ "qcom,android-usb-cdrom");
} else {
pdata = pdev->dev.platform_data;
}
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index d0ebda1..38f08fc 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -338,14 +338,17 @@
*/
static int hw_device_reset(struct ci13xxx *udc)
{
+ int delay_count = 25; /* 250 usec */
+
/* should flush & stop before reset */
hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0);
hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST);
- while (hw_cread(CAP_USBCMD, USBCMD_RST))
- udelay(10); /* not RTOS friendly */
-
+ while (delay_count-- && hw_cread(CAP_USBCMD, USBCMD_RST))
+ udelay(10);
+ if (delay_count < 0)
+ pr_err("USB controller reset failed\n");
if (udc->udc_driver->notify_event)
udc->udc_driver->notify_event(udc,
@@ -814,6 +817,8 @@
*/
static int hw_usb_reset(void)
{
+ int delay_count = 10; /* 100 usec delay */
+
hw_usb_set_address(0);
/* ESS flushes only at end?!? */
@@ -826,8 +831,10 @@
hw_cwrite(CAP_ENDPTCOMPLETE, 0, 0); /* writes its content */
/* wait until all bits cleared */
- while (hw_cread(CAP_ENDPTPRIME, ~0))
- udelay(10); /* not RTOS friendly */
+ while (delay_count-- && hw_cread(CAP_ENDPTPRIME, ~0))
+ udelay(10);
+ if (delay_count < 0)
+ pr_err("ENDPTPRIME is not cleared during bus reset\n");
/* reset all endpoints ? */
@@ -2268,8 +2275,8 @@
gadget->otg_srp_reqd = 0;
udc->driver->disconnect(gadget);
- usb_ep_fifo_flush(&udc->ep0out.ep);
- usb_ep_fifo_flush(&udc->ep0in.ep);
+ _ep_nuke(&udc->ep0out);
+ _ep_nuke(&udc->ep0in);
if (udc->ep0in.last_zptr) {
dma_pool_free(udc->ep0in.td_pool, udc->ep0in.last_zptr,
@@ -3023,21 +3030,24 @@
trace("%p, %p, %X", ep, req, gfp_flags);
- if (ep == NULL || req == NULL || mEp->desc == NULL)
- return -EINVAL;
-
- if (!udc->softconnect)
- return -ENODEV;
-
spin_lock_irqsave(mEp->lock, flags);
+ if (ep == NULL || req == NULL || mEp->desc == NULL) {
+ retval = -EINVAL;
+ goto done;
+ }
+
+ if (!udc->softconnect) {
+ retval = -ENODEV;
+ goto done;
+ }
if (!udc->configured && mEp->type !=
USB_ENDPOINT_XFER_CONTROL) {
- spin_unlock_irqrestore(mEp->lock, flags);
trace("usb is not configured"
"ept #%d, ept name#%s\n",
mEp->num, mEp->ep.name);
- return -ESHUTDOWN;
+ retval = -ESHUTDOWN;
+ goto done;
}
if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
@@ -3117,12 +3127,19 @@
trace("%p, %p", ep, req);
+ spin_lock_irqsave(mEp->lock, flags);
+ /*
+ * Only ep0 IN is exposed to composite. When a req is dequeued
+ * on ep0, check both ep0 IN and ep0 OUT queues.
+ */
if (ep == NULL || req == NULL || mReq->req.status != -EALREADY ||
mEp->desc == NULL || list_empty(&mReq->queue) ||
- list_empty(&mEp->qh.queue))
+ (list_empty(&mEp->qh.queue) && ((mEp->type !=
+ USB_ENDPOINT_XFER_CONTROL) ||
+ list_empty(&_udc->ep0out.qh.queue)))) {
+ spin_unlock_irqrestore(mEp->lock, flags);
return -EINVAL;
-
- spin_lock_irqsave(mEp->lock, flags);
+ }
dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index bac8b68..87a3fd5 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2510,7 +2510,8 @@
goto reset_bulk_int;
fsg->bulk_out->driver_data = common;
fsg->bulk_out_enabled = 1;
- common->bulk_out_maxpacket = le16_to_cpu(fsg->bulk_in->desc->wMaxPacketSize);
+ common->bulk_out_maxpacket =
+ le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize);
clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
csw_hack_sent = 0;
write_error_after_csw_sent = 0;
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 8e7cbb2..a395d15 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -77,15 +77,7 @@
bool is_open;
};
-struct f_ecm_qc_ipa_params {
- u8 dev_mac[ETH_ALEN];
- u8 host_mac[ETH_ALEN];
- ecm_ipa_callback ipa_rx_cb;
- ecm_ipa_callback ipa_tx_cb;
- void *ipa_priv;
-};
-
-static struct f_ecm_qc_ipa_params ipa_params;
+static struct ecm_ipa_params ipa_params;
static inline struct f_ecm_qc *func_to_ecm_qc(struct usb_function *f)
{
@@ -435,17 +427,17 @@
void *ecm_qc_get_ipa_rx_cb(void)
{
- return ipa_params.ipa_rx_cb;
+ return ipa_params.ecm_ipa_rx_dp_notify;
}
void *ecm_qc_get_ipa_tx_cb(void)
{
- return ipa_params.ipa_tx_cb;
+ return ipa_params.ecm_ipa_tx_dp_notify;
}
void *ecm_qc_get_ipa_priv(void)
{
- return ipa_params.ipa_priv;
+ return ipa_params.private;
}
/*-------------------------------------------------------------------------*/
@@ -849,7 +841,7 @@
ecm_qc_string_defs[1].s = NULL;
if (ecm->xport == USB_GADGET_XPORT_BAM2BAM_IPA)
- ecm_ipa_cleanup(ipa_params.ipa_priv);
+ ecm_ipa_cleanup(ipa_params.private);
kfree(ecm);
}
@@ -920,12 +912,13 @@
/* export host's Ethernet address in CDC format */
if (ecm->xport == USB_GADGET_XPORT_BAM2BAM_IPA) {
- gether_qc_get_macs(ipa_params.dev_mac, ipa_params.host_mac);
+ gether_qc_get_macs(ipa_params.device_ethaddr,
+ ipa_params.host_ethaddr);
snprintf(ecm->ethaddr, sizeof ecm->ethaddr,
"%02X%02X%02X%02X%02X%02X",
- ipa_params.host_mac[0], ipa_params.host_mac[1],
- ipa_params.host_mac[2], ipa_params.host_mac[3],
- ipa_params.host_mac[4], ipa_params.host_mac[5]);
+ ipa_params.host_ethaddr[0], ipa_params.host_ethaddr[1],
+ ipa_params.host_ethaddr[2], ipa_params.host_ethaddr[3],
+ ipa_params.host_ethaddr[4], ipa_params.host_ethaddr[5]);
} else
snprintf(ecm->ethaddr, sizeof ecm->ethaddr,
"%02X%02X%02X%02X%02X%02X",
@@ -957,21 +950,15 @@
if (ecm->xport != USB_GADGET_XPORT_BAM2BAM_IPA)
return status;
- status = ecm_ipa_init(&ipa_params.ipa_rx_cb, &ipa_params.ipa_tx_cb,
- &ipa_params.ipa_priv);
+ pr_debug("setting ecm_ipa, host_ethaddr=%pM, device_ethaddr=%pM",
+ ipa_params.host_ethaddr, ipa_params.device_ethaddr);
+ status = ecm_ipa_init(&ipa_params);
if (status) {
- pr_err("failed to initialize ECM IPA Driver");
+ pr_err("failed to initialize ecm_ipa");
ecm_qc_string_defs[1].s = NULL;
kfree(ecm);
- return status;
- }
-
- status = ecm_ipa_configure(ipa_params.host_mac, ipa_params.dev_mac,
- ipa_params.ipa_priv);
- if (status) {
- pr_err("failed to configure ECM IPA Driver");
- ecm_qc_string_defs[1].s = NULL;
- kfree(ecm);
+ } else {
+ pr_debug("ecm_ipa successful created");
}
return status;
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index f3c6481..1017900 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -25,11 +25,6 @@
#include "u_ether.h"
#include "rndis.h"
-static bool rndis_multipacket_dl_disable;
-module_param(rndis_multipacket_dl_disable, bool, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(rndis_multipacket_dl_disable,
- "Disable RNDIS Multi-packet support in DownLink");
-
/*
* This function is an RNDIS Ethernet port -- a Microsoft protocol that's
* been promoted instead of the standard CDC Ethernet. The published RNDIS
@@ -71,6 +66,16 @@
* - MS-Windows drivers sometimes emit undocumented requests.
*/
+static bool rndis_multipacket_dl_disable;
+module_param(rndis_multipacket_dl_disable, bool, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(rndis_multipacket_dl_disable,
+ "Disable RNDIS Multi-packet support in DownLink");
+
+static unsigned int rndis_ul_max_pkt_per_xfer = 1;
+module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer,
+ "Disable RNDIS Multi-packet support in DownLink");
+
struct f_rndis {
struct gether port;
u8 ctrl_id, data_id;
@@ -799,6 +804,7 @@
rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0);
rndis_set_host_mac(rndis->config, rndis->ethaddr);
+ rndis_set_max_pkt_xfer(rndis->config, rndis_ul_max_pkt_per_xfer);
if (rndis->manufacturer && rndis->vendorID &&
rndis_set_param_vendor(rndis->config, rndis->vendorID,
@@ -945,6 +951,7 @@
rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
rndis->port.wrap = rndis_add_header;
rndis->port.unwrap = rndis_rm_hdr;
+ rndis->port.ul_max_pkts_per_xfer = rndis_ul_max_pkt_per_xfer;
rndis->port.func.name = "rndis";
rndis->port.func.strings = rndis_strings;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 7ac5b64..07f4d26 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -59,6 +59,16 @@
#define RNDIS_MAX_CONFIGS 1
+int rndis_ul_max_pkt_per_xfer_rcvd;
+module_param(rndis_ul_max_pkt_per_xfer_rcvd, int, S_IRUGO);
+MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer_rcvd,
+ "Max num of REMOTE_NDIS_PACKET_MSGs received in a single transfer");
+
+int rndis_ul_max_xfer_size_rcvd;
+module_param(rndis_ul_max_xfer_size_rcvd, int, S_IRUGO);
+MODULE_PARM_DESC(rndis_ul_max_xfer_size_rcvd,
+ "Max size of bus transfer received");
+
static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS];
@@ -590,7 +600,6 @@
(params->dev->mtu
+ sizeof(struct ethhdr)
+ sizeof(struct rndis_packet_msg_type)
-
+ 22));
resp->PacketAlignmentFactor = cpu_to_le32(params->pkt_alignment_factor);
resp->AFListOffset = cpu_to_le32(0);
@@ -1051,25 +1060,77 @@
struct sk_buff *skb,
struct sk_buff_head *list)
{
- /* tmp points to a struct rndis_packet_msg_type */
- __le32 *tmp = (void *)skb->data;
+ int num_pkts = 1;
- /* MessageType, MessageLength */
- if (cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
- != get_unaligned(tmp++)) {
- dev_kfree_skb_any(skb);
- return -EINVAL;
- }
- tmp++;
+ if (skb->len > rndis_ul_max_xfer_size_rcvd)
+ rndis_ul_max_xfer_size_rcvd = skb->len;
- /* DataOffset, DataLength */
- if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) {
- dev_kfree_skb_any(skb);
- return -EOVERFLOW;
+ while (skb->len) {
+ struct rndis_packet_msg_type *hdr;
+ struct sk_buff *skb2;
+ u32 msg_len, data_offset, data_len;
+
+ /* some rndis hosts send extra byte to avoid zlp, ignore it */
+ if (skb->len == 1) {
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+
+ if (skb->len < sizeof *hdr) {
+ pr_err("invalid rndis pkt: skblen:%u hdr_len:%u",
+ skb->len, sizeof *hdr);
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
+
+ hdr = (void *)skb->data;
+ msg_len = le32_to_cpu(hdr->MessageLength);
+ data_offset = le32_to_cpu(hdr->DataOffset);
+ data_len = le32_to_cpu(hdr->DataLength);
+
+ if (skb->len < msg_len ||
+ ((data_offset + data_len + 8) > msg_len)) {
+ pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
+ le32_to_cpu(hdr->MessageType),
+ msg_len, data_offset, data_len, skb->len);
+ dev_kfree_skb_any(skb);
+ return -EOVERFLOW;
+ }
+
+ if (le32_to_cpu(hdr->MessageType) != REMOTE_NDIS_PACKET_MSG) {
+ pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
+ le32_to_cpu(hdr->MessageType),
+ msg_len, data_offset, data_len, skb->len);
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
+
+ skb_pull(skb, data_offset + 8);
+
+ if (msg_len == skb->len) {
+ skb_trim(skb, data_len);
+ break;
+ }
+
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (!skb2) {
+ pr_err("%s:skb clone failed\n", __func__);
+ dev_kfree_skb_any(skb);
+ return -ENOMEM;
+ }
+
+ skb_pull(skb, msg_len - sizeof *hdr);
+ skb_trim(skb2, data_len);
+ skb_queue_tail(list, skb2);
+
+ num_pkts++;
}
- skb_trim(skb, get_unaligned_le32(tmp++));
+
+ if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
+ rndis_ul_max_pkt_per_xfer_rcvd = num_pkts;
skb_queue_tail(list, skb);
+
return 0;
}
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
index 8a6a630..d00f81f 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -252,6 +252,7 @@
int rndis_set_param_vendor (u8 configNr, u32 vendorID,
const char *vendorDescr);
int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
+void rndis_set_max_pkt_xfer(u8 configNr, u8 max_pkt_per_xfer);
void rndis_add_hdr (struct sk_buff *skb);
int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
struct sk_buff_head *list);
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index c601000..c05f683 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -667,11 +667,11 @@
int ret;
if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ teth_bridge_disconnect();
ret = usb_bam_disconnect_ipa(&d->ipa_params);
if (ret)
pr_err("%s: usb_bam_disconnect_ipa failed: err:%d\n",
__func__, ret);
- teth_bridge_disconnect();
}
}
@@ -742,8 +742,8 @@
d->ipa_params.priv = priv;
d->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC;
- d->ipa_params.client = IPA_CLIENT_USB_CONS;
- d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
+ d->ipa_params.client = IPA_CLIENT_USB_PROD;
+ d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
ret = usb_bam_connect_ipa(&d->ipa_params);
if (ret) {
pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
@@ -751,8 +751,8 @@
return;
}
- d->ipa_params.client = IPA_CLIENT_USB_PROD;
- d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
+ d->ipa_params.client = IPA_CLIENT_USB_CONS;
+ d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
ret = usb_bam_connect_ipa(&d->ipa_params);
if (ret) {
pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index eec9e37..2abe2ef 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -219,10 +219,10 @@
d->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC;
}
- d->ipa_params.client = IPA_CLIENT_USB_CONS;
- d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
+ d->ipa_params.client = IPA_CLIENT_USB_PROD;
+ d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
if (d->func_type == USB_FUNC_ECM) {
- d->ipa_params.notify = ecm_qc_get_ipa_tx_cb();
+ d->ipa_params.notify = ecm_qc_get_ipa_rx_cb();
d->ipa_params.priv = ecm_qc_get_ipa_priv();
}
ret = usb_bam_connect_ipa(&d->ipa_params);
@@ -232,10 +232,10 @@
return;
}
- d->ipa_params.client = IPA_CLIENT_USB_PROD;
- d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
+ d->ipa_params.client = IPA_CLIENT_USB_CONS;
+ d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
if (d->func_type == USB_FUNC_ECM) {
- d->ipa_params.notify = ecm_qc_get_ipa_rx_cb();
+ d->ipa_params.notify = ecm_qc_get_ipa_tx_cb();
d->ipa_params.priv = ecm_qc_get_ipa_priv();
}
ret = usb_bam_connect_ipa(&d->ipa_params);
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 2d974ab..d4c21dd 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -70,6 +70,7 @@
struct sk_buff_head rx_frames;
unsigned header_len;
+ unsigned ul_max_pkts_per_xfer;
struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb);
int (*unwrap)(struct gether *,
struct sk_buff *skb,
@@ -233,9 +234,13 @@
size += out->maxpacket - 1;
size -= size % out->maxpacket;
+ if (dev->ul_max_pkts_per_xfer)
+ size *= dev->ul_max_pkts_per_xfer;
+
if (dev->port_usb->is_fixed)
size = max_t(size_t, size, dev->port_usb->fixed_out_len);
+ pr_debug("%s: size: %d", __func__, size);
skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
if (skb == NULL) {
DBG(dev, "no rx skb\n");
@@ -1076,6 +1081,7 @@
dev->header_len = link->header_len;
dev->unwrap = link->unwrap;
dev->wrap = link->wrap;
+ dev->ul_max_pkts_per_xfer = link->ul_max_pkts_per_xfer;
spin_lock(&dev->lock);
dev->tx_skb_hold_count = 0;
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index faa9a3b..7040ab0 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -53,6 +53,8 @@
bool is_fixed;
u32 fixed_out_len;
u32 fixed_in_len;
+
+ unsigned ul_max_pkts_per_xfer;
/* Max number of SKB packets to be used to create Multi Packet RNDIS */
#define TX_SKB_HOLD_THRESHOLD 3
bool multi_pkt_xfer;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 4865b03..d4d7ee9 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -869,6 +869,9 @@
if (atomic_read(&motg->in_lpm))
return 0;
+ if (motg->pdata->delay_lpm_hndshk_on_disconnect && !msm_bam_lpm_ok())
+ return 0;
+
disable_irq(motg->irq);
host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
!test_bit(ID, &motg->inputs);
@@ -3802,6 +3805,8 @@
"qcom,hsusb-otg-clk-always-on-workaround");
pdata->delay_lpm_on_disconnect = of_property_read_bool(node,
"qcom,hsusb-otg-delay-lpm");
+ pdata->delay_lpm_hndshk_on_disconnect = of_property_read_bool(node,
+ "qcom,hsusb-otg-delay-lpm-hndshk-on-disconnect");
pdata->dp_manual_pullup = of_property_read_bool(node,
"qcom,dp-manual-pullup");
pdata->enable_sec_phy = of_property_read_bool(node,
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index f68527c..54b772b 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -181,7 +181,7 @@
struct dsi_panel_cmds_list {
struct dsi_cmd_desc *buf;
- char size;
+ int size;
char ctrl_state;
};
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 52243eb..290e317 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -32,6 +32,8 @@
#include <linux/spinlock.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
+#include <linux/file.h>
+#include <linux/msm_kgsl.h>
#include <mach/board.h>
#include <mach/clk.h>
@@ -125,7 +127,7 @@
pr_debug("mdp3_irq_handler irq=%d\n", mdp_interrupt);
spin_lock(&mdata->irq_lock);
- mdp_interrupt &= mdata->irqMask;
+ mdp_interrupt &= mdata->irq_mask;
while (mdp_interrupt && i < MDP3_MAX_INTR) {
if ((mdp_interrupt & 0x1) && mdata->callbacks[i].cb)
@@ -145,14 +147,15 @@
pr_debug("mdp3_irq_enable type=%d\n", type);
spin_lock_irqsave(&mdp3_res->irq_lock, flag);
- if (mdp3_res->irqMask & BIT(type)) {
+ mdp3_res->irq_ref_count[type] += 1;
+ if (mdp3_res->irq_ref_count[type] > 1) {
pr_debug("interrupt %d already enabled\n", type);
spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
return;
}
- irqEnabled = mdp3_res->irqMask;
- mdp3_res->irqMask |= BIT(type);
- MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irqMask);
+ irqEnabled = mdp3_res->irq_mask;
+ mdp3_res->irq_mask |= BIT(type);
+ MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask);
if (!irqEnabled)
enable_irq(mdp3_res->irq);
spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
@@ -163,26 +166,33 @@
unsigned long flag;
spin_lock_irqsave(&mdp3_res->irq_lock, flag);
- if (mdp3_res->irqMask & BIT(type)) {
- mdp3_res->irqMask &= ~BIT(type);
- MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irqMask);
- if (!mdp3_res->irqMask)
- disable_irq(mdp3_res->irq);
- } else {
+ if (mdp3_res->irq_ref_count[type] <= 0) {
pr_debug("interrupt %d not enabled\n", type);
+ spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
+ return;
+ }
+ mdp3_res->irq_ref_count[type] -= 1;
+ if (mdp3_res->irq_ref_count[type] == 0) {
+ mdp3_res->irq_mask &= ~BIT(type);
+ MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask);
+ if (!mdp3_res->irq_mask)
+ disable_irq(mdp3_res->irq);
}
spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
}
void mdp3_irq_disable_nosync(int type)
{
- if (mdp3_res->irqMask & BIT(type)) {
- mdp3_res->irqMask &= ~BIT(type);
- MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irqMask);
- if (!mdp3_res->irqMask)
- disable_irq_nosync(mdp3_res->irq);
- } else {
+ if (mdp3_res->irq_ref_count[type] <= 0) {
pr_debug("interrupt %d not enabled\n", type);
+ return;
+ }
+ mdp3_res->irq_ref_count[type] -= 1;
+ if (mdp3_res->irq_ref_count[type] == 0) {
+ mdp3_res->irq_mask &= ~BIT(type);
+ MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask);
+ if (!mdp3_res->irq_mask)
+ disable_irq_nosync(mdp3_res->irq);
}
}
@@ -688,6 +698,108 @@
return 0;
}
+int mdp3_put_img(struct mdp3_img_data *data)
+{
+ struct ion_client *iclient = mdp3_res->ion_client;
+ int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
+
+ if (!data->srcp_file) {
+ pr_debug("No img to put\n");
+ return 0;
+ }
+ if (data->flags & MDP_BLIT_SRC_GEM) {
+ pr_debug("memory source MDP_BLIT_SRC_GEM\n");
+ } else if (data->flags & MDP_MEMORY_ID_TYPE_FB) {
+ pr_debug("fb mem buf=0x%x\n", data->addr);
+ fput_light(data->srcp_file, data->p_need);
+ data->srcp_file = NULL;
+ } else {
+ ion_unmap_iommu(iclient, data->srcp_ihdl, dom, 0);
+ ion_free(iclient, data->srcp_ihdl);
+ data->srcp_ihdl = NULL;
+ }
+ return 0;
+}
+
+int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data)
+{
+ struct file *file;
+ int ret = -EINVAL;
+ int fb_num;
+ unsigned long *start, *len;
+ struct ion_client *iclient = mdp3_res->ion_client;
+ int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
+
+ start = (unsigned long *) &data->addr;
+ len = (unsigned long *) &data->len;
+ data->flags |= img->flags;
+ data->p_need = 0;
+
+ if (img->flags & MDP_BLIT_SRC_GEM) {
+ data->srcp_file = NULL;
+ ret = kgsl_gem_obj_addr(img->memory_id, (int) img->priv,
+ &data->addr, &data->len);
+ if (!ret)
+ goto done;
+ }
+ if (img->flags & MDP_MEMORY_ID_TYPE_FB) {
+ file = fget_light(img->memory_id, &data->p_need);
+ if (file == NULL) {
+ pr_err("invalid framebuffer file (%d)\n",
+ img->memory_id);
+ return -EINVAL;
+ }
+ if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
+ fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
+ ret = mdss_fb_get_phys_info(start, len, fb_num);
+ if (ret) {
+ pr_err("mdss_fb_get_phys_info() failed\n");
+ fput_light(file, data->p_need);
+ file = NULL;
+ }
+ } else {
+ pr_err("invalid FB_MAJOR\n");
+ fput_light(file, data->p_need);
+ file = NULL;
+ ret = -EINVAL;
+ }
+ data->srcp_file = file;
+ if (!ret)
+ goto done;
+ }
+ if (iclient) {
+ data->srcp_ihdl = ion_import_dma_buf(iclient, img->memory_id);
+ if (IS_ERR_OR_NULL(data->srcp_ihdl)) {
+ pr_err("error on ion_import_fd\n");
+ ret = PTR_ERR(data->srcp_ihdl);
+ data->srcp_ihdl = NULL;
+ return ret;
+ }
+
+ ret = ion_map_iommu(iclient, data->srcp_ihdl, dom,
+ 0, SZ_4K, 0, start, len, 0, 0);
+
+ if (IS_ERR_VALUE(ret)) {
+ ion_free(iclient, data->srcp_ihdl);
+ pr_err("failed to map ion handle (%d)\n", ret);
+ return ret;
+ }
+ }
+done:
+ if (!ret && (img->offset < data->len)) {
+ data->addr += img->offset;
+ data->len -= img->offset;
+
+ pr_debug("mem=%d ihdl=%p buf=0x%x len=0x%x\n", img->memory_id,
+ data->srcp_ihdl, data->addr, data->len);
+ } else {
+ mdp3_put_img(data);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
static int mdp3_init(struct msm_fb_data_type *mfd)
{
return mdp3_ctrl_init(mfd);
@@ -708,45 +820,6 @@
return xres * bpp;
}
-/*
- * physical contiguous memory should be allocated in mdss_fb, and SMMU
- * virtual address mapping can be done in the MDP h/w specific code. It
- * should have a reference count, if none is current mapped, the SMMU context
- * can bedetached, thus allowing power saving in SMMU.
- */
-static int mdp3_fbmem_alloc(struct msm_fb_data_type *mfd)
-{
- int dom;
- void *virt = NULL;
- unsigned long phys = 0;
- size_t size;
- u32 yres = mfd->fbi->var.yres_virtual;
-
- size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
-
- if (mfd->index == 0) {
- virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
- if (!virt) {
- pr_err("unable to alloc fbmem size=%u\n", size);
- return -ENOMEM;
- }
- phys = memory_pool_node_paddr(virt);
- dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
- msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
- &mfd->iova);
-
- pr_debug("allocating %u bytes at %p (%lx phys) for fb %d\n",
- size, virt, phys, mfd->index);
- } else {
- size = 0;
- }
-
- mfd->fbi->screen_base = virt;
- mfd->fbi->fix.smem_start = phys;
- mfd->fbi->fix.smem_len = size;
- return 0;
-}
-
struct mdp3_dma *mdp3_get_dma_pipe(int capability)
{
int i;
@@ -775,12 +848,19 @@
return NULL;
}
+static int mdp3_fb_mem_get_iommu_domain(void)
+{
+ if (!mdp3_res)
+ return -ENODEV;
+ return mdp3_res->domains[MDP3_IOMMU_DOMAIN].domain_idx;
+}
+
static int mdp3_probe(struct platform_device *pdev)
{
int rc;
static struct msm_mdp_interface mdp3_interface = {
.init_fnc = mdp3_init,
- .fb_mem_alloc_fnc = mdp3_fbmem_alloc,
+ .fb_mem_get_iommu_domain = mdp3_fb_mem_get_iommu_domain,
.fb_stride = mdp3_fb_stride,
};
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 5774e5a..7e395e1 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -23,6 +23,7 @@
#include <mach/iommu_domains.h>
#include "mdp3_dma.h"
+#include "mdss_fb.h"
enum {
MDP3_CLK_AHB,
@@ -100,12 +101,22 @@
struct mdp3_intf intf[MDP3_DMA_OUTPUT_SEL_MAX];
spinlock_t irq_lock;
- u32 irqMask;
+ u32 irq_ref_count[MDP3_MAX_INTR];
+ u32 irq_mask;
struct mdp3_intr_cb callbacks[MDP3_MAX_INTR];
struct early_suspend suspend_handler;
};
+struct mdp3_img_data {
+ u32 addr;
+ u32 len;
+ u32 flags;
+ int p_need;
+ struct file *srcp_file;
+ struct ion_handle *srcp_ihdl;
+};
+
extern struct mdp3_hw_resource *mdp3_res;
struct mdp3_dma *mdp3_get_dma_pipe(int capability);
@@ -117,6 +128,8 @@
int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate);
int mdp3_clk_enable(int enable);
int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
+int mdp3_put_img(struct mdp3_img_data *data);
+int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data);
#define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
#define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 929e5f8..f5ac5e9 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -26,37 +26,108 @@
#define MDP_VSYNC_CLK_RATE 19200000
#define VSYNC_PERIOD 16
+static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd);
+
+static void mdp3_bufq_init(struct mdp3_buffer_queue *bufq)
+{
+ bufq->count = 0;
+ bufq->push_idx = 0;
+ bufq->pop_idx = 0;
+}
+
+static void mdp3_bufq_deinit(struct mdp3_buffer_queue *bufq)
+{
+ int count = bufq->count;
+
+ if (!count)
+ return;
+
+ while (count--) {
+ struct mdp3_img_data *data = &bufq->img_data[bufq->pop_idx];
+ bufq->pop_idx = (bufq->pop_idx + 1) % MDP3_MAX_BUF_QUEUE;
+ mdp3_put_img(data);
+ }
+ bufq->count = 0;
+ bufq->push_idx = 0;
+ bufq->pop_idx = 0;
+}
+
+static int mdp3_bufq_push(struct mdp3_buffer_queue *bufq,
+ struct mdp3_img_data *data)
+{
+ if (bufq->count >= MDP3_MAX_BUF_QUEUE) {
+ pr_err("bufq full\n");
+ return -EPERM;
+ }
+
+ bufq->img_data[bufq->push_idx] = *data;
+ bufq->push_idx = (bufq->push_idx + 1) % MDP3_MAX_BUF_QUEUE;
+ bufq->count++;
+ return 0;
+}
+
+static struct mdp3_img_data *mdp3_bufq_pop(struct mdp3_buffer_queue *bufq)
+{
+ struct mdp3_img_data *data;
+ if (bufq->count == 0)
+ return NULL;
+
+ data = &bufq->img_data[bufq->pop_idx];
+ bufq->count--;
+ bufq->pop_idx = (bufq->pop_idx + 1) % MDP3_MAX_BUF_QUEUE;
+ return data;
+}
+
+static int mdp3_bufq_count(struct mdp3_buffer_queue *bufq)
+{
+ return bufq->count;
+}
+
void vsync_notify_handler(void *arg)
{
struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
+ spin_lock(&session->vsync_lock);
+ session->vsync_time = ktime_get();
complete(&session->vsync_comp);
+ spin_unlock(&session->vsync_lock);
}
static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
{
struct mdp3_session_data *mdp3_session;
struct mdp3_vsync_notification vsync_client;
+ struct mdp3_vsync_notification *arg = NULL;
+ unsigned long flag;
+ pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable);
mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
!mdp3_session->intf)
return -ENODEV;
- vsync_client.handler = vsync_notify_handler;
- vsync_client.arg = mdp3_session;
-
- mutex_lock(&mdp3_session->lock);
if (!mdp3_session->status) {
pr_debug("fb%d is not on yet", mfd->index);
- mutex_unlock(&mdp3_session->lock);
return -EINVAL;
}
+ if (enable) {
+ vsync_client.handler = vsync_notify_handler;
+ vsync_client.arg = mdp3_session;
+ arg = &vsync_client;
+ }
- mdp3_session->dma->vsync_enable(mdp3_session->dma, &vsync_client);
+ mutex_lock(&mdp3_session->lock);
+ mdp3_session->dma->vsync_enable(mdp3_session->dma, arg);
mutex_unlock(&mdp3_session->lock);
+ spin_lock_irqsave(&mdp3_session->vsync_lock, flag);
+ if (enable)
+ INIT_COMPLETION(mdp3_session->vsync_comp);
+ else
+ complete_all(&mdp3_session->vsync_comp);
+ spin_unlock_irqrestore(&mdp3_session->vsync_lock, flag);
return 0;
}
+
static ssize_t mdp3_vsync_show_event(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -64,8 +135,8 @@
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
struct mdp3_session_data *mdp3_session = NULL;
u64 vsync_ticks;
- ktime_t vsync_time;
int rc;
+ unsigned long flag;
if (!mfd || !mfd->mdp.private1)
return 0;
@@ -78,11 +149,11 @@
if (rc <= 0) {
pr_warn("vsync wait on fb%d interrupted (%d)\n",
mfd->index, rc);
- return -EBUSY;
}
- vsync_time = mdp3_session->dma->get_vsync_time(mdp3_session->dma);
- vsync_ticks = ktime_to_ns(vsync_time);
+ spin_lock_irqsave(&mdp3_session->vsync_lock, flag);
+ vsync_ticks = ktime_to_ns(mdp3_session->vsync_time);
+ spin_unlock_irqrestore(&mdp3_session->vsync_lock, flag);
pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks);
rc = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks);
@@ -395,6 +466,148 @@
return 0;
}
+static int mdp3_overlay_get(struct msm_fb_data_type *mfd,
+ struct mdp_overlay *req)
+{
+ int rc = 0;
+ struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+
+ mutex_lock(&mdp3_session->lock);
+
+ if (mdp3_session->overlay.id == req->id)
+ *req = mdp3_session->overlay;
+ else
+ rc = -EINVAL;
+
+ mutex_unlock(&mdp3_session->lock);
+
+ return rc;
+}
+
+static int mdp3_overlay_set(struct msm_fb_data_type *mfd,
+ struct mdp_overlay *req)
+{
+ int rc = 0;
+ struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+
+ mutex_lock(&mdp3_session->lock);
+
+ if (mdp3_session->overlay.id == req->id) {
+ mdp3_session->overlay = *req;
+ if (req->id == MSMFB_NEW_REQUEST) {
+ mdp3_session->overlay.id = 1;
+ req->id = 1;
+ }
+ } else {
+ rc = -EINVAL;
+ }
+ mutex_unlock(&mdp3_session->lock);
+
+ return rc;
+}
+
+static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
+{
+ int rc = 0;
+ struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+
+ mdp3_ctrl_pan_display(mfd);
+
+ mutex_lock(&mdp3_session->lock);
+
+ if (mdp3_session->overlay.id == ndx && ndx == 1) {
+ mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
+ mdp3_bufq_deinit(&mdp3_session->bufq_in);
+ mdp3_bufq_deinit(&mdp3_session->bufq_out);
+ } else {
+ rc = -EINVAL;
+ }
+
+ mutex_unlock(&mdp3_session->lock);
+
+ return rc;
+}
+
+static int mdp3_overlay_queue_buffer(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_data *req)
+{
+ int rc;
+ struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+ struct msmfb_data *img = &req->data;
+ struct mdp3_img_data data;
+
+ rc = mdp3_get_img(img, &data);
+ if (rc) {
+ pr_err("fail to get overlay buffer\n");
+ return rc;
+ }
+
+ rc = mdp3_bufq_push(&mdp3_session->bufq_in, &data);
+ if (rc) {
+ pr_err("fail to queue the overlay buffer, buffer drop\n");
+ mdp3_put_img(&data);
+ return rc;
+ }
+ return 0;
+}
+
+static int mdp3_overlay_play(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_data *req)
+{
+ struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+ int rc = 0;
+
+ pr_debug("mdp3_overlay_play req id=%x mem_id=%d\n",
+ req->id, req->data.memory_id);
+
+ mutex_lock(&mdp3_session->lock);
+
+ if (mfd->panel_power_on)
+ rc = mdp3_overlay_queue_buffer(mfd, req);
+ else
+ rc = -EPERM;
+
+ mutex_unlock(&mdp3_session->lock);
+
+ return rc;
+}
+
+static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd)
+{
+ struct mdp3_session_data *mdp3_session;
+ struct mdp3_img_data *data;
+ int rc = 0;
+
+ if (!mfd || !mfd->mdp.private1)
+ return -EINVAL;
+
+ mdp3_session = mfd->mdp.private1;
+ if (!mdp3_session || !mdp3_session->dma)
+ return -EINVAL;
+
+ if (!mdp3_session->status) {
+ pr_err("%s, display off!\n", __func__);
+ return -EPERM;
+ }
+
+ mutex_lock(&mdp3_session->lock);
+
+ data = mdp3_bufq_pop(&mdp3_session->bufq_in);
+ if (data) {
+ mdp3_session->dma->update(mdp3_session->dma,
+ (void *)data->addr);
+ mdp3_bufq_push(&mdp3_session->bufq_out, data);
+ }
+
+ if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) {
+ data = mdp3_bufq_pop(&mdp3_session->bufq_out);
+ mdp3_put_img(data);
+ }
+
+ mutex_unlock(&mdp3_session->lock);
+ return rc;
+}
+
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
{
struct fb_info *fbi;
@@ -445,6 +658,9 @@
break;
case metadata_op_get_caps:
metadata->data.caps.mdp_rev = 304;
+ metadata->data.caps.rgb_pipes = 0;
+ metadata->data.caps.vig_pipes = 0;
+ metadata->data.caps.dma_pipes = 1;
break;
default:
pr_warn("Unsupported request to MDP META IOCTL.\n");
@@ -460,6 +676,8 @@
int rc = -EINVAL;
struct mdp3_session_data *mdp3_session;
struct msmfb_metadata metadata;
+ struct mdp_overlay req;
+ struct msmfb_overlay_data ov_data;
int val;
pr_debug("mdp3_ctrl_ioctl_handler\n");
@@ -478,8 +696,6 @@
case MSMFB_OVERLAY_VSYNC_CTRL:
if (!copy_from_user(&val, argp, sizeof(val))) {
rc = mdp3_ctrl_vsync_enable(mfd, val);
- if (!val)
- init_completion(&mdp3_session->vsync_comp);
} else {
pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed\n");
rc = -EFAULT;
@@ -493,10 +709,42 @@
if (!rc)
rc = copy_to_user(argp, &metadata, sizeof(metadata));
break;
+ case MSMFB_OVERLAY_GET:
+ rc = copy_from_user(&req, argp, sizeof(req));
+ if (!rc) {
+ rc = mdp3_overlay_get(mfd, &req);
+
+ if (!IS_ERR_VALUE(rc))
+ rc = copy_to_user(argp, &req, sizeof(req));
+ }
+ if (rc)
+ pr_err("OVERLAY_GET failed (%d)\n", rc);
+ break;
+ case MSMFB_OVERLAY_SET:
+ rc = copy_from_user(&req, argp, sizeof(req));
+ if (!rc) {
+ rc = mdp3_overlay_set(mfd, &req);
+
+ if (!IS_ERR_VALUE(rc))
+ rc = copy_to_user(argp, &req, sizeof(req));
+ }
+ if (rc)
+ pr_err("OVERLAY_SET failed (%d)\n", rc);
+ break;
+ case MSMFB_OVERLAY_UNSET:
+ if (!IS_ERR_VALUE(copy_from_user(&val, argp, sizeof(val))))
+ rc = mdp3_overlay_unset(mfd, val);
+ break;
+ case MSMFB_OVERLAY_PLAY:
+ rc = copy_from_user(&ov_data, argp, sizeof(ov_data));
+ if (!rc)
+ rc = mdp3_overlay_play(mfd, &ov_data);
+ if (rc)
+ pr_err("OVERLAY_PLAY failed (%d)\n", rc);
+ break;
default:
break;
}
-
return rc;
}
@@ -515,7 +763,7 @@
mdp3_interface->cursor_update = NULL;
mdp3_interface->dma_fnc = mdp3_ctrl_pan_display;
mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler;
- mdp3_interface->kickoff_fnc = NULL;
+ mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff;
mdp3_session = kmalloc(sizeof(struct mdp3_session_data), GFP_KERNEL);
if (!mdp3_session) {
@@ -525,6 +773,7 @@
memset(mdp3_session, 0, sizeof(struct mdp3_session_data));
mutex_init(&mdp3_session->lock);
init_completion(&mdp3_session->vsync_comp);
+ spin_lock_init(&mdp3_session->vsync_lock);
mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
if (!mdp3_session->dma) {
rc = -ENODEV;
@@ -540,6 +789,9 @@
mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
mdp3_session->status = 0;
+ mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
+ mdp3_bufq_init(&mdp3_session->bufq_in);
+ mdp3_bufq_init(&mdp3_session->bufq_out);
mfd->mdp.private1 = mdp3_session;
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index d42ece7..fb3bd36 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -18,10 +18,20 @@
#include <linux/mutex.h>
#include <linux/completion.h>
+#include "mdp3.h"
#include "mdp3_dma.h"
#include "mdss_fb.h"
#include "mdss_panel.h"
+#define MDP3_MAX_BUF_QUEUE 8
+
+struct mdp3_buffer_queue {
+ struct mdp3_img_data img_data[MDP3_MAX_BUF_QUEUE];
+ int count;
+ int push_idx;
+ int pop_idx;
+};
+
struct mdp3_session_data {
struct mutex lock;
int status;
@@ -29,7 +39,12 @@
struct mdss_panel_data *panel;
struct mdp3_intf *intf;
struct msm_fb_data_type *mfd;
+ ktime_t vsync_time;
+ spinlock_t vsync_lock;
struct completion vsync_comp;
+ struct mdp_overlay overlay;
+ struct mdp3_buffer_queue bufq_in;
+ struct mdp3_buffer_queue bufq_out;
};
int mdp3_ctrl_init(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 69e3d7e..a09f503 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -20,17 +20,6 @@
#define DMA_STOP_POLL_SLEEP_US 1000
#define DMA_STOP_POLL_TIMEOUT_US 16000
-static ktime_t mdp3_get_vsync_time(struct mdp3_dma *dma)
-{
- unsigned long flag;
- ktime_t time;
-
- spin_lock_irqsave(&dma->dma_lock, flag);
- time = dma->vsync_time;
- spin_unlock_irqrestore(&dma->dma_lock, flag);
- return time;
-}
-
static void mdp3_vsync_intr_handler(int type, void *arg)
{
struct mdp3_dma *dma = (struct mdp3_dma *)arg;
@@ -41,13 +30,11 @@
vsync_client = dma->vsync_client;
if (!vsync_client.handler)
dma->cb_type &= ~MDP3_DMA_CALLBACK_TYPE_VSYNC;
- dma->vsync_time = ktime_get();
complete(&dma->vsync_comp);
+ spin_unlock(&dma->dma_lock);
if (vsync_client.handler)
vsync_client.handler(vsync_client.arg);
- spin_unlock(&dma->dma_lock);
-
- if (!vsync_client.handler)
+ else
mdp3_irq_disable_nosync(type);
}
@@ -186,7 +173,7 @@
updated = 1;
}
} else {
- if (!dma->vsync_client.handler) {
+ if (dma->vsync_client.handler) {
dma->vsync_client.handler = NULL;
dma->vsync_client.arg = NULL;
updated = 1;
@@ -696,7 +683,6 @@
dma->histo_intr_enable = mdp3_dmap_histo_intr_enable;
dma->histo_intr_clear = mdp3_dmap_histo_intr_clear;
dma->vsync_enable = mdp3_dma_vsync_enable;
- dma->get_vsync_time = mdp3_get_vsync_time;
dma->start = mdp3_dma_start;
dma->stop = mdp3_dma_stop;
break;
@@ -717,7 +703,6 @@
dma->histo_intr_enable = NULL;
dma->histo_intr_clear = NULL;
dma->vsync_enable = mdp3_dma_vsync_enable;
- dma->get_vsync_time = mdp3_get_vsync_time;
dma->start = mdp3_dma_start;
dma->stop = mdp3_dma_stop;
break;
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 2fb8427..cef749b 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -231,7 +231,6 @@
spinlock_t dma_lock;
struct completion vsync_comp;
struct completion dma_comp;
- ktime_t vsync_time;
struct mdp3_vsync_notification vsync_client;
u32 cb_type;
@@ -275,9 +274,6 @@
void (*vsync_enable)(struct mdp3_dma *dma,
struct mdp3_vsync_notification *vsync_client);
-
- ktime_t (*get_vsync_time)(struct mdp3_dma *dma);
-
};
struct mdp3_video_intf_cfg {
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 5be0173..3bb4bdc 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -110,6 +110,10 @@
void *video_intf;
u32 nintf;
+ struct mdss_ad_info *ad_cfgs;
+ u32 nad_cfgs;
+ struct workqueue_struct *ad_calc_wq;
+
struct ion_client *iclient;
int iommu_attached;
struct mdss_iommu_map_type *iommu_map;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index acac6b9..5d56df4 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -414,6 +414,8 @@
/* disable DSI controller */
mdss_dsi_controller_cfg(0, pdata);
+ /* disable DSI phy */
+ mdss_dsi_phy_enable(ctrl_pdata->ctrl_base, 0);
ret = mdss_dsi_panel_power_on(pdata, 0);
if (ret) {
pr_err("%s: Panel power off failed\n", __func__);
@@ -1078,12 +1080,12 @@
cont_splash_enabled = of_property_read_bool(pdev->dev.of_node,
"qcom,cont-splash-enabled");
if (!cont_splash_enabled) {
- pr_info("%s:%d Continous splash flag not found.\n",
+ pr_info("%s:%d Continuous splash flag not found.\n",
__func__, __LINE__);
ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 0;
ctrl_pdata->panel_data.panel_info.panel_power_on = 0;
} else {
- pr_info("%s:%d Continous splash flag enabled.\n",
+ pr_info("%s:%d Continuous splash flag enabled.\n",
__func__, __LINE__);
ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 1a64be4..3c0dfc2 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -52,6 +52,8 @@
void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl)
{
+ int ret;
+
if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) {
mdss_dsi0_hw.ptr = (void *)(ctrl);
ctrl->mdss_hw = &mdss_dsi0_hw;
@@ -60,7 +62,8 @@
ctrl->mdss_hw = &mdss_dsi1_hw;
}
- if (!mdss_register_irq(ctrl->mdss_hw))
+ ret = mdss_register_irq(ctrl->mdss_hw);
+ if (ret)
pr_err("%s: mdss_register_irq failed.\n", __func__);
}
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index a7ea948..28f61f9 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -42,9 +42,13 @@
#include <linux/sync.h>
#include <linux/sw_sync.h>
#include <linux/file.h>
+#include <linux/memory_alloc.h>
#include <mach/board.h>
#include <mach/memory.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/msm_memtypes.h>
#include "mdss_fb.h"
@@ -143,9 +147,9 @@
if (!bl_lvl && value)
bl_lvl = 1;
- mutex_lock(&mfd->lock);
+ mutex_lock(&mfd->bl_lock);
mdss_fb_set_backlight(mfd, bl_lvl);
- mutex_unlock(&mfd->lock);
+ mutex_unlock(&mfd->bl_lock);
}
static struct led_classdev backlight_led = {
@@ -263,6 +267,7 @@
mfd->mdp = *mdp_instance;
mutex_init(&mfd->lock);
+ mutex_init(&mfd->bl_lock);
fbi_list[fbi_list_index++] = fbi;
@@ -524,7 +529,7 @@
(*bl_lvl) = temp;
}
-/* must call this function from within mfd->lock */
+/* must call this function from within mfd->bl_lock */
void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
{
struct mdss_panel_data *pdata;
@@ -566,11 +571,11 @@
if (unset_bl_level && !bl_updated) {
pdata = dev_get_platdata(&mfd->pdev->dev);
if ((pdata) && (pdata->set_backlight)) {
- mutex_lock(&mfd->lock);
+ mutex_lock(&mfd->bl_lock);
mfd->bl_level = unset_bl_level;
pdata->set_backlight(pdata, mfd->bl_level);
bl_level_old = unset_bl_level;
- mutex_unlock(&mfd->lock);
+ mutex_unlock(&mfd->bl_lock);
bl_updated = 1;
}
}
@@ -626,12 +631,7 @@
static int mdss_fb_blank(int blank_mode, struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- if (blank_mode == FB_BLANK_POWERDOWN) {
- struct fb_event event;
- event.info = info;
- event.data = &blank_mode;
- fb_notifier_call_chain(FB_EVENT_BLANK, &event);
- }
+
mdss_fb_pan_idle(mfd);
if (mfd->op_enable == 0) {
if (blank_mode == FB_BLANK_UNBLANK)
@@ -656,6 +656,11 @@
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ if (!start) {
+ pr_warn("No framebuffer memory is allocated.\n");
+ return -ENOMEM;
+ }
+
mdss_fb_pan_idle(mfd);
if (off >= len) {
/* memory mapped io */
@@ -713,13 +718,68 @@
.fb_mmap = mdss_fb_mmap,
};
+static int mdss_fb_alloc_fbmem_iommu(struct msm_fb_data_type *mfd, int dom)
+{
+ void *virt = NULL;
+ unsigned long phys = 0;
+ size_t size = 0;
+ struct platform_device *pdev = mfd->pdev;
+
+ if (!pdev || !pdev->dev.of_node) {
+ pr_err("Invalid device node\n");
+ return -ENODEV;
+ }
+
+ if (of_property_read_u32(pdev->dev.of_node,
+ "qcom,memory-reservation-size",
+ &size) || !size) {
+ mfd->fbi->screen_base = NULL;
+ mfd->fbi->fix.smem_start = 0;
+ mfd->fbi->fix.smem_len = 0;
+ return 0;
+ }
+
+ pr_info("%s frame buffer reserve_size=0x%x\n", __func__, size);
+
+ if (size < PAGE_ALIGN(mfd->fbi->fix.line_length *
+ mfd->fbi->var.yres_virtual))
+ pr_warn("reserve size is smaller than framebuffer size\n");
+
+ virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
+ if (!virt) {
+ pr_err("unable to alloc fbmem size=%u\n", size);
+ return -ENOMEM;
+ }
+
+ phys = memory_pool_node_paddr(virt);
+
+ msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
+ &mfd->iova);
+ pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
+ size, virt, phys, mfd->index);
+
+ mfd->fbi->screen_base = virt;
+ mfd->fbi->fix.smem_start = phys;
+ mfd->fbi->fix.smem_len = size;
+
+ return 0;
+}
+
static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
{
- if (!mfd->mdp.fb_mem_alloc_fnc) {
+
+ if (mfd->mdp.fb_mem_alloc_fnc)
+ return mfd->mdp.fb_mem_alloc_fnc(mfd);
+ else if (mfd->mdp.fb_mem_get_iommu_domain) {
+ int dom = mfd->mdp.fb_mem_get_iommu_domain();
+ if (dom >= 0)
+ return mdss_fb_alloc_fbmem_iommu(mfd, dom);
+ else
+ return -ENOMEM;
+ } else {
pr_err("no fb memory allocator function defined\n");
return -ENOMEM;
}
- return mfd->mdp.fb_mem_alloc_fnc(mfd);
}
static int mdss_fb_register(struct msm_fb_data_type *mfd)
@@ -956,6 +1016,7 @@
result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
mfd->op_enable);
if (result) {
+ pm_runtime_put(info->dev);
pr_err("mdss_fb_open: can't turn on display!\n");
return result;
}
@@ -1537,12 +1598,15 @@
static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct msm_fb_data_type *mfd;
void __user *argp = (void __user *)arg;
struct mdp_page_protection fb_page_protection;
int ret = -ENOSYS;
struct mdp_buf_sync buf_sync;
+ if (!info || !info->par)
+ return -EINVAL;
+ mfd = (struct msm_fb_data_type *)info->par;
mdss_fb_power_setting_idle(mfd);
mdss_fb_pan_idle(mfd);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index fdbbea9..5682f0b 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -56,6 +56,7 @@
struct msm_mdp_interface {
int (*fb_mem_alloc_fnc)(struct msm_fb_data_type *mfd);
+ int (*fb_mem_get_iommu_domain)(void);
int (*init_fnc)(struct msm_fb_data_type *mfd);
int (*on_fnc)(struct msm_fb_data_type *mfd);
int (*off_fnc)(struct msm_fb_data_type *mfd);
@@ -102,6 +103,7 @@
u32 bl_level;
u32 bl_scale;
u32 bl_min_lvl;
+ struct mutex bl_lock;
struct mutex lock;
struct platform_device *pdev;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index e87f028..1876057 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -119,6 +119,12 @@
89909, 119880, 148352, 119880, false},
{HDMI_VFRMT_1280x720p120_16_9, 1280, 720, false, 1650, 370, 750, 30,
90000, 120000, 148500, 120000, false},
+ {HDMI_VFRMT_1280x1024p60_5_4, 1280, 1024, false, 1688, 408, 1066, 42,
+ 63981, 60020, 108000, 60000, false},
+
+ /* All 1024 H Active */
+ {HDMI_VFRMT_1024x768p60_4_3, 1024, 768, false, 1344, 320, 806, 38,
+ 48363, 60004, 65000, 60000, false},
/* All 1440 H Active */
{HDMI_VFRMT_1440x576i50_4_3, 1440, 576, true, 1728, 288, 625, 24,
@@ -1016,7 +1022,7 @@
static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl,
const u8 *data_buf, u32 num_of_cea_blocks)
{
- u8 i = 0;
+ u8 i = 0, offset = 0, std_blk = 0;
u32 video_format = HDMI_VFRMT_640x480p60_4_3;
u32 has480p = false;
u8 len;
@@ -1175,6 +1181,72 @@
}
}
+ std_blk = 0;
+ offset = 0;
+ while (std_blk < 8) {
+ if ((edid_blk0[0x26 + offset] == 0x81) &&
+ (edid_blk0[0x26 + offset + 1] == 0x80)) {
+ pr_debug("%s: 108MHz: off=[%x] stdblk=[%x]\n",
+ __func__, offset, std_blk);
+ hdmi_edid_add_sink_video_format(sink_data,
+ HDMI_VFRMT_1280x1024p60_5_4);
+ }
+ if ((edid_blk0[0x26 + offset] == 0x61) &&
+ (edid_blk0[0x26 + offset + 1] == 0x40)) {
+ pr_debug("%s: 65MHz: off=[%x] stdblk=[%x]\n",
+ __func__, offset, std_blk);
+ hdmi_edid_add_sink_video_format(sink_data,
+ HDMI_VFRMT_1024x768p60_4_3);
+ break;
+ } else {
+ offset += 2;
+ }
+ std_blk++;
+ }
+ /* check if the EDID revision is 4 (version 1.4) */
+ if (edid_blk0[0x13] == 4) {
+ u8 start = 0x36;
+ i = 0;
+ /* Check each of 4 - 18 bytes descriptors */
+ while (i < 4) {
+ u8 iter = start;
+ u32 header_1 = 0;
+ u8 header_2 = 0;
+ header_1 = edid_blk0[iter++];
+ header_1 = header_1 << 8 | edid_blk0[iter++];
+ header_1 = header_1 << 8 | edid_blk0[iter++];
+ header_1 = header_1 << 8 | edid_blk0[iter++];
+ header_2 = edid_blk0[iter];
+ if (header_1 == 0x000000F7 &&
+ header_2 == 0x00) {
+ iter++;
+ /* VESA DMT Standard Version (0x0A)*/
+ iter++;
+ /* First set of supported formats */
+ iter++;
+ /* Second set of supported formats */
+ if (edid_blk0[iter] & 0x02) {
+ pr_debug("%s: DMT 1280x1024@60\n",
+ __func__);
+ hdmi_edid_add_sink_video_format(
+ sink_data,
+ HDMI_VFRMT_1280x1024p60_5_4);
+ break;
+ }
+ }
+ i++;
+ start += 0x12;
+ }
+ }
+
+ /* Established Timing I and II */
+ if (edid_blk0[0x24] & BIT(3)) {
+ pr_debug("%s: 65MHz: off=[%x] stdblk=[%x]\n",
+ __func__, offset, std_blk);
+ hdmi_edid_add_sink_video_format(sink_data,
+ HDMI_VFRMT_1024x768p60_4_3);
+ }
+
hdmi_edid_get_extended_video_formats(edid_ctrl, data_buf+0x80);
/* mandaroty 3d format */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_mhl.h b/drivers/video/msm/mdss/mdss_hdmi_mhl.h
index 8fef63e..8a9d4fc 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_mhl.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_mhl.h
@@ -19,9 +19,9 @@
struct msm_hdmi_mhl_ops {
u8 (*tmds_enabled)(struct platform_device *pdev);
int (*set_mhl_max_pclk)(struct platform_device *pdev, u32 max_val);
+ int (*set_upstream_hpd)(struct platform_device *pdev, uint8_t on);
};
int msm_hdmi_register_mhl(struct platform_device *pdev,
- struct msm_hdmi_mhl_ops *ops);
-
+ struct msm_hdmi_mhl_ops *ops, void *data);
#endif /* __MDSS_HDMI_MHL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 1ff8acf..12552bc 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -81,9 +81,12 @@
struct hdmi_tx_audio_acr lut[AUDIO_SAMPLE_RATE_MAX];
};
+static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on);
static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on);
static irqreturn_t hdmi_tx_isr(int irq, void *data);
static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl);
+static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl,
+ enum hdmi_tx_power_module_type module, int enable);
struct mdss_hw hdmi_tx_hw = {
.hw_ndx = MDSS_HW_HDMI,
@@ -93,12 +96,15 @@
struct dss_gpio hpd_gpio_config[] = {
{0, 1, COMPATIBLE_NAME "-hpd"},
- {0, 1, COMPATIBLE_NAME "-ddc-clk"},
- {0, 1, COMPATIBLE_NAME "-ddc-data"},
{0, 1, COMPATIBLE_NAME "-mux-en"},
{0, 0, COMPATIBLE_NAME "-mux-sel"}
};
+struct dss_gpio ddc_gpio_config[] = {
+ {0, 1, COMPATIBLE_NAME "-ddc-clk"},
+ {0, 1, COMPATIBLE_NAME "-ddc-data"}
+};
+
struct dss_gpio core_gpio_config[] = {
};
@@ -110,6 +116,7 @@
{
switch (module) {
case HDMI_TX_HPD_PM: return "HDMI_TX_HPD_PM";
+ case HDMI_TX_DDC_PM: return "HDMI_TX_DDC_PM";
case HDMI_TX_CORE_PM: return "HDMI_TX_CORE_PM";
case HDMI_TX_CEC_PM: return "HDMI_TX_CEC_PM";
default: return "???";
@@ -183,10 +190,19 @@
{20480, 247500} } },
};
+static bool is_cea_format(int mode)
+{
+ if ((mode > 0) && (mode < HDMI_EVFRMT_END))
+ return true;
+ else
+ return false;
+}
+
const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module)
{
switch (module) {
case HDMI_TX_HPD_PM: return "HDMI_TX_HPD_PM";
+ case HDMI_TX_DDC_PM: return "HDMI_TX_DDC_PM";
case HDMI_TX_CORE_PM: return "HDMI_TX_CORE_PM";
case HDMI_TX_CEC_PM: return "HDMI_TX_CEC_PM";
default: return "???";
@@ -810,11 +826,19 @@
DEV_DBG("%s: Got HPD interrupt\n", __func__);
if (hdmi_ctrl->hpd_state) {
+ if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, true)) {
+ DEV_ERR("%s: Failed to enable ddc power\n", __func__);
+ return;
+ }
+
hdmi_tx_read_sink_info(hdmi_ctrl);
hdmi_tx_send_cable_notification(hdmi_ctrl, 1);
DEV_INFO("%s: sense cable CONNECTED: state switch to %d\n",
__func__, hdmi_ctrl->sdev.state);
} else {
+ if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, false))
+ DEV_WARN("%s: Failed to disable ddc power\n", __func__);
+
hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
DEV_INFO("%s: sense cable DISCONNECTED: state switch to %d\n",
__func__, hdmi_ctrl->sdev.state);
@@ -1935,7 +1959,7 @@
}
int msm_hdmi_register_mhl(struct platform_device *pdev,
- struct msm_hdmi_mhl_ops *ops)
+ struct msm_hdmi_mhl_ops *ops, void *data)
{
struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
@@ -1951,6 +1975,8 @@
ops->tmds_enabled = hdmi_tx_tmds_enabled;
ops->set_mhl_max_pclk = hdmi_tx_set_mhl_max_pclk;
+ ops->set_upstream_hpd = hdmi_tx_set_mhl_hpd;
+
return 0;
}
@@ -2082,7 +2108,8 @@
return rc;
}
- if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) {
+ if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) &&
+ is_cea_format(hdmi_ctrl->video_resolution)) {
rc = hdmi_tx_audio_setup(hdmi_ctrl);
if (rc) {
DEV_ERR("%s: hdmi_msm_audio_setup failed. rc=%d\n",
@@ -2316,6 +2343,9 @@
return;
}
+ /* finish the ongoing hpd work if any */
+ flush_work_sync(&hdmi_ctrl->hpd_int_work);
+
/* Turn off HPD interrupts */
DSS_REG_W(io, HDMI_HPD_INT_CTRL, 0);
@@ -2323,6 +2353,13 @@
hdmi_tx_set_mode(hdmi_ctrl, false);
+ if (hdmi_ctrl->hpd_state) {
+ rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, 0);
+ if (rc)
+ DEV_INFO("%s: Failed to disable ddc power. Error=%d\n",
+ __func__, rc);
+ }
+
rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
if (rc)
DEV_INFO("%s: Failed to disable hpd power. Error=%d\n",
@@ -2416,6 +2453,41 @@
return rc;
} /* hdmi_tx_sysfs_enable_hpd */
+static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on)
+{
+ int rc = 0;
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+ hdmi_ctrl = platform_get_drvdata(pdev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!on && hdmi_ctrl->hpd_feature_on) {
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
+ } else if (on && !hdmi_ctrl->hpd_feature_on) {
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
+ } else {
+ DEV_DBG("%s: hpd is already '%s'. return\n", __func__,
+ hdmi_ctrl->hpd_feature_on ? "enabled" : "disabled");
+ return rc;
+ }
+
+ if (!rc) {
+ hdmi_ctrl->hpd_feature_on =
+ (~hdmi_ctrl->hpd_feature_on) & BIT(0);
+ DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_feature_on);
+ } else {
+ DEV_ERR("%s: failed to '%s' hpd. rc = %d\n", __func__,
+ on ? "enable" : "disable", rc);
+ }
+
+ return rc;
+
+}
+
static irqreturn_t hdmi_tx_isr(int irq, void *data)
{
struct dss_io_data *io = NULL;
@@ -2846,7 +2918,7 @@
switch (module_type) {
case HDMI_TX_HPD_PM:
- mp->num_clk = 2;
+ mp->num_clk = 3;
mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) *
mp->num_clk, GFP_KERNEL);
if (!mp->clk_config) {
@@ -2862,6 +2934,16 @@
snprintf(mp->clk_config[1].clk_name, 32, "%s", "core_clk");
mp->clk_config[1].type = DSS_CLK_OTHER;
mp->clk_config[1].rate = 19200000;
+
+ /*
+ * This clock is required to clock MDSS interrupt registers
+ * when HDMI is the only block turned on within MDSS. Since
+ * rate for this clock is controlled by MDP driver, treat this
+ * similar to AHB clock and do not set rate for it.
+ */
+ snprintf(mp->clk_config[2].clk_name, 32, "%s", "mdp_core_clk");
+ mp->clk_config[2].type = DSS_CLK_AHB;
+ mp->clk_config[2].rate = 0;
break;
case HDMI_TX_CORE_PM:
@@ -2884,6 +2966,7 @@
mp->clk_config[1].rate = 0;
break;
+ case HDMI_TX_DDC_PM:
case HDMI_TX_CEC_PM:
mp->num_clk = 0;
DEV_DBG("%s: no clk\n", __func__);
@@ -2943,6 +3026,9 @@
case HDMI_TX_HPD_PM:
mod_name = "hpd";
break;
+ case HDMI_TX_DDC_PM:
+ mod_name = "ddc";
+ break;
case HDMI_TX_CORE_PM:
mod_name = "core";
break;
@@ -3139,6 +3225,10 @@
gpio_list_size = ARRAY_SIZE(hpd_gpio_config);
gpio_list = hpd_gpio_config;
break;
+ case HDMI_TX_DDC_PM:
+ gpio_list_size = ARRAY_SIZE(ddc_gpio_config);
+ gpio_list = ddc_gpio_config;
+ break;
case HDMI_TX_CORE_PM:
gpio_list_size = ARRAY_SIZE(core_gpio_config);
gpio_list = core_gpio_config;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 8d9a477..ce3c00c 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -25,6 +25,7 @@
enum hdmi_tx_power_module_type {
HDMI_TX_HPD_PM,
+ HDMI_TX_DDC_PM,
HDMI_TX_CORE_PM,
HDMI_TX_CEC_PM,
HDMI_TX_MAX_PM
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
index 0c8b0f8..53dfc71 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -109,8 +109,8 @@
hdmi_supported_video_mode_lut, MSM_HDMI_MODES_XTND);
/* Add any other specific DVI timings (DVI modes, etc.) */
- MSM_HDMI_MODES_SET_TIMING(hdmi_supported_video_mode_lut,
- HDMI_VFRMT_2560x1600p60_16_9);
+ MSM_HDMI_MODES_SET_SUPP_TIMINGS(
+ hdmi_supported_video_mode_lut, MSM_HDMI_MODES_DVI);
} /* hdmi_setup_video_mode_lut */
const char *hdmi_get_single_video_3d_fmt_2string(u32 format)
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 2f09fee..772545f 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -55,9 +55,15 @@
#include "mdss_debug.h"
struct mdss_data_type *mdss_res;
+
+static int mdss_fb_mem_get_iommu_domain(void)
+{
+ return mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
+}
+
struct msm_mdp_interface mdp5 = {
.init_fnc = mdss_mdp_overlay_init,
- .fb_mem_alloc_fnc = mdss_mdp_alloc_fb_mem,
+ .fb_mem_get_iommu_domain = mdss_fb_mem_get_iommu_domain,
.panel_register_done = mdss_panel_register_done,
.fb_stride = mdss_mdp_fb_stride,
};
@@ -134,39 +140,7 @@
char *prop_name);
static int mdss_mdp_parse_dt_smp(struct platform_device *pdev);
static int mdss_mdp_parse_dt_misc(struct platform_device *pdev);
-
-int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd)
-{
- int dom;
- void *virt = NULL;
- unsigned long phys = 0;
- size_t size;
- u32 yres = mfd->fbi->var.yres_virtual;
-
- size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
-
- if (mfd->index == 0) {
- virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
- if (!virt) {
- pr_err("unable to alloc fbmem size=%u\n", size);
- return -ENOMEM;
- }
- phys = memory_pool_node_paddr(virt);
- dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
- msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
- &mfd->iova);
-
- pr_debug("allocating %u bytes at %p (%lx phys) for fb %d\n",
- size, virt, phys, mfd->index);
- } else
- size = 0;
-
- mfd->fbi->screen_base = virt;
- mfd->fbi->fix.smem_start = phys;
- mfd->fbi->fix.smem_len = size;
-
- return 0;
-}
+static int mdss_mdp_parse_dt_ad_cfg(struct platform_device *pdev);
u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp)
{
@@ -387,12 +361,11 @@
bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
- /* aligning to avoid performing updates for small changes */
- ab_quota = ALIGN(ab_quota, SZ_64M);
- ib_quota = ALIGN(ib_quota, SZ_64M);
-
vect = mdp_bus_scale_table.usecase[current_bus_idx].vectors;
- if ((ab_quota == vect->ab) && (ib_quota == vect->ib)) {
+
+ /* avoid performing updates for small changes */
+ if ((ALIGN(ab_quota, SZ_64M) == ALIGN(vect->ab, SZ_64M)) &&
+ (ALIGN(ib_quota, SZ_64M) == ALIGN(vect->ib, SZ_64M))) {
pr_debug("skip bus scaling, no change in vectors\n");
return 0;
}
@@ -1161,6 +1134,12 @@
return rc;
}
+ rc = mdss_mdp_parse_dt_ad_cfg(pdev);
+ if (rc) {
+ pr_err("Error in device tree : ad\n");
+ return rc;
+ }
+
return 0;
}
@@ -1483,6 +1462,41 @@
return 0;
}
+static int mdss_mdp_parse_dt_ad_cfg(struct platform_device *pdev)
+{
+ struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+ u32 *ad_offsets = NULL;
+ int rc;
+
+ mdata->nad_cfgs = mdss_mdp_parse_dt_prop_len(pdev, "qcom,mdss-ad-off");
+
+ if (mdata->nad_cfgs == 0) {
+ mdata->ad_cfgs = NULL;
+ return 0;
+ }
+ if (mdata->nad_cfgs > mdata->nmixers_intf)
+ return -EINVAL;
+
+ ad_offsets = kzalloc(sizeof(u32) * mdata->nad_cfgs, GFP_KERNEL);
+ if (!ad_offsets) {
+ pr_err("no mem assigned: kzalloc fail\n");
+ return -ENOMEM;
+ }
+
+ rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-ad-off", ad_offsets,
+ mdata->nad_cfgs);
+ if (rc)
+ goto parse_done;
+
+ rc = mdss_mdp_ad_addr_setup(mdata, ad_offsets);
+ if (rc)
+ pr_err("unable to setup assertive display\n");
+
+parse_done:
+ kfree(ad_offsets);
+ return rc;
+}
+
static int mdss_mdp_parse_dt_handler(struct platform_device *pdev,
char *prop_name, u32 *offsets, int len)
{
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 6018e6f..122dcb9 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -109,6 +109,12 @@
struct mdss_mdp_ctl;
typedef void (*mdp_vsync_handler_t)(struct mdss_mdp_ctl *, ktime_t);
+struct mdss_mdp_vsync_handler {
+ bool enabled;
+ mdp_vsync_handler_t vsync_handler;
+ struct list_head list;
+};
+
struct mdss_mdp_ctl {
u32 num;
char __iomem *base;
@@ -144,14 +150,18 @@
struct mutex lock;
struct mdss_panel_data *panel_data;
+ struct mdss_mdp_vsync_handler vsync_handler;
int (*start_fnc) (struct mdss_mdp_ctl *ctl);
int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
int (*wait_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
- int (*set_vsync_handler) (struct mdss_mdp_ctl *, mdp_vsync_handler_t);
u32 (*read_line_cnt_fnc) (struct mdss_mdp_ctl *);
+ int (*add_vsync_handler) (struct mdss_mdp_ctl *,
+ struct mdss_mdp_vsync_handler *);
+ int (*remove_vsync_handler) (struct mdss_mdp_ctl *,
+ struct mdss_mdp_vsync_handler *);
void *priv_data;
};
@@ -237,6 +247,25 @@
spinlock_t hist_lock;
};
+struct mdss_ad_info {
+ char __iomem *base;
+ u8 num;
+ u32 sts;
+ u32 state;
+ u32 ad_data;
+ u32 ad_data_mode;
+ struct mdss_ad_init init;
+ struct mdss_ad_cfg cfg;
+ struct mutex lock;
+ struct work_struct calc_work;
+ struct msm_fb_data_type *mfd;
+ struct mdss_mdp_vsync_handler handle;
+ struct completion comp;
+ u32 last_str;
+ u32 last_bl;
+ u32 calc_itr;
+};
+
struct pp_sts_type {
u32 pa_sts;
u32 pcc_sts;
@@ -356,7 +385,7 @@
irqreturn_t mdss_mdp_isr(int irq, void *ptr);
int mdss_iommu_attach(struct mdss_data_type *mdata);
-int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata);
+int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
u32 intr_type, u32 intf_num);
int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
@@ -386,6 +415,10 @@
struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
struct msm_fb_data_type *mfd);
+int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
+void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata);
+int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
struct mdss_panel_data *pdata);
@@ -413,7 +446,7 @@
int mdss_mdp_pp_init(struct device *dev);
void mdss_mdp_pp_term(struct device *dev);
-int mdss_mdp_pp_resume(u32 mixer_num);
+int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 mixer_num);
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl);
int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl);
@@ -432,7 +465,7 @@
u32 *copyback);
int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
struct mdp_igc_lut_data *config,
- u32 *copyback);
+ u32 *copyback, u32 copy_from_kernel);
int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
struct mdp_pgc_lut_data *config,
u32 *copyback);
@@ -453,6 +486,13 @@
struct mdp_histogram_data *hist);
void mdss_mdp_hist_intr_done(u32 isr);
+int mdss_ad_init_checks(struct msm_fb_data_type *mfd);
+int mdss_mdp_ad_config(struct msm_fb_data_type *mfd,
+ struct mdss_ad_init_cfg *init_cfg);
+int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
+ struct mdss_ad_input *input);
+int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_off);
+
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer,
u32 type);
struct mdss_mdp_pipe *mdss_mdp_pipe_get(struct mdss_data_type *mdata, u32 ndx);
@@ -493,10 +533,10 @@
int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
int mdss_mdp_get_ctl_mixers(u32 fb_num, u32 *mixer_id);
-int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd);
u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp);
int mdss_panel_register_done(struct mdss_panel_data *pdata);
+int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl);
#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
#define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 6c9cce2..e346082 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -248,13 +248,14 @@
return ret;
}
-static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata)
+static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata,
+ u32 off)
{
struct mdss_mdp_ctl *ctl = NULL;
- int cnum;
+ u32 cnum;
mutex_lock(&mdss_mdp_ctl_lock);
- for (cnum = 0; cnum < mdata->nctl; cnum++) {
+ for (cnum = off; cnum < mdata->nctl; cnum++) {
ctl = mdata->ctl_off + cnum;
if (ctl->ref_cnt == 0) {
ctl->ref_cnt++;
@@ -300,8 +301,9 @@
ctl->prepare_fnc = NULL;
ctl->display_fnc = NULL;
ctl->wait_fnc = NULL;
- ctl->set_vsync_handler = NULL;
ctl->read_line_cnt_fnc = NULL;
+ ctl->add_vsync_handler = NULL;
+ ctl->remove_vsync_handler = NULL;
mutex_unlock(&mdss_mdp_ctl_lock);
return 0;
@@ -390,7 +392,7 @@
struct mdss_mdp_ctl *ctl = NULL;
struct mdss_mdp_mixer *mixer = NULL;
- ctl = mdss_mdp_ctl_alloc(mdss_res);
+ ctl = mdss_mdp_ctl_alloc(mdss_res, mdss_res->nmixers_intf);
if (!ctl)
return NULL;
@@ -450,6 +452,29 @@
return 0;
}
+void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata)
+{
+ switch (pdata->panel_info.type) {
+ case MIPI_VIDEO_PANEL:
+ mdss_mdp_video_copy_splash_screen(pdata);
+ break;
+ case MIPI_CMD_PANEL:
+ default:
+ break;
+ }
+}
+
+int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl)
+{
+ switch (ctl->panel_data->panel_info.type) {
+ case MIPI_VIDEO_PANEL:
+ return mdss_mdp_video_reconfigure_splash_done(ctl);
+ case MIPI_CMD_PANEL:
+ default:
+ return 0;
+ }
+}
+
static inline int mdss_mdp_set_split_ctl(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_ctl *split_ctl)
{
@@ -645,7 +670,7 @@
int ret = 0;
struct mdss_data_type *mdata = mfd_to_mdata(mfd);
- ctl = mdss_mdp_ctl_alloc(mdata);
+ ctl = mdss_mdp_ctl_alloc(mdata, MDSS_MDP_CTL0);
if (!ctl) {
pr_err("unable to allocate ctl\n");
return ERR_PTR(-ENOMEM);
@@ -687,6 +712,9 @@
ctl->intf_type = MDSS_INTF_HDMI;
ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
ctl->start_fnc = mdss_mdp_video_start;
+ ret = mdss_mdp_limited_lut_igc_config(ctl);
+ if (ret)
+ pr_err("Unable to config IGC LUT data");
break;
case WRITEBACK_PANEL:
ctl->intf_num = MDSS_MDP_NO_INTF;
@@ -890,7 +918,7 @@
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(i), 0);
mixer = ctl->mixer_left;
- mdss_mdp_pp_resume(mixer->num);
+ mdss_mdp_pp_resume(ctl, mixer->num);
mixer->params_changed++;
temp = MDSS_MDP_REG_READ(MDSS_MDP_REG_DISP_INTF_SEL);
@@ -937,7 +965,7 @@
ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_RESET, NULL);
if (ret) {
pr_err("panel power on failed ctl=%d\n", ctl->num);
- return ret;
+ goto error;
}
ret = mdss_mdp_ctl_start_sub(ctl);
@@ -950,7 +978,7 @@
struct mdss_mdp_mixer *mixer = ctl->mixer_right;
u32 out, off;
- mdss_mdp_pp_resume(mixer->num);
+ mdss_mdp_pp_resume(ctl, mixer->num);
mixer->params_changed++;
out = (mixer->height << 16) | mixer->width;
off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
@@ -960,6 +988,7 @@
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+error:
mutex_unlock(&ctl->lock);
return ret;
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index a59560e..6ec5b63 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -351,6 +351,41 @@
#define MDSS_MDP_REG_WB_DST_ADDR_SW_STATUS 0x2B0
+#define MDSS_MDP_REG_AD_BYPASS 0x000
+#define MDSS_MDP_REG_AD_CTRL_0 0x004
+#define MDSS_MDP_REG_AD_CTRL_1 0x008
+#define MDSS_MDP_REG_AD_FRAME_SIZE 0x00C
+#define MDSS_MDP_REG_AD_CON_CTRL_0 0x010
+#define MDSS_MDP_REG_AD_CON_CTRL_1 0x014
+#define MDSS_MDP_REG_AD_STR_MAN 0x018
+#define MDSS_MDP_REG_AD_VAR 0x01C
+#define MDSS_MDP_REG_AD_DITH 0x020
+#define MDSS_MDP_REG_AD_DITH_CTRL 0x024
+#define MDSS_MDP_REG_AD_AMP_LIM 0x028
+#define MDSS_MDP_REG_AD_SLOPE 0x02C
+#define MDSS_MDP_REG_AD_BW_LVL 0x030
+#define MDSS_MDP_REG_AD_LOGO_POS 0x034
+#define MDSS_MDP_REG_AD_LUT_FI 0x038
+#define MDSS_MDP_REG_AD_LUT_CC 0x07C
+#define MDSS_MDP_REG_AD_STR_LIM 0x0C8
+#define MDSS_MDP_REG_AD_CALIB_AB 0x0CC
+#define MDSS_MDP_REG_AD_CALIB_CD 0x0D0
+#define MDSS_MDP_REG_AD_MODE_SEL 0x0D4
+#define MDSS_MDP_REG_AD_TFILT_CTRL 0x0D8
+#define MDSS_MDP_REG_AD_BL_MINMAX 0x0DC
+#define MDSS_MDP_REG_AD_BL 0x0E0
+#define MDSS_MDP_REG_AD_BL_MAX 0x0E8
+#define MDSS_MDP_REG_AD_AL 0x0EC
+#define MDSS_MDP_REG_AD_AL_MIN 0x0F0
+#define MDSS_MDP_REG_AD_AL_FILT 0x0F4
+#define MDSS_MDP_REG_AD_CFG_BUF 0x0F8
+#define MDSS_MDP_REG_AD_LUT_AL 0x100
+#define MDSS_MDP_REG_AD_TARG_STR 0x144
+#define MDSS_MDP_REG_AD_START_CALC 0x148
+#define MDSS_MDP_REG_AD_STR_OUT 0x14C
+#define MDSS_MDP_REG_AD_BL_OUT 0x154
+#define MDSS_MDP_REG_AD_CALC_DONE 0x158
+
enum mdss_mdp_dspp_index {
MDSS_MDP_DSPP0,
MDSS_MDP_DSPP1,
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index fff8a6e..eb2bd21 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -44,13 +44,21 @@
/* te config */
u8 tear_check;
- u16 total_lcd_lines;
- u16 v_porch; /* vertical porches */
- u32 vsync_cnt;
+ u16 height; /* panel height */
+ u16 vporch; /* vertical porches */
+ u32 vclk_line; /* vsync clock per line */
};
struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
+/*
+ * TE configuration:
+ * dsi byte clock calculated base on 70 fps
+ * around 14 ms to complete a kickoff cycle if te disabled
+ * vclk_line base on 60 fps
+ * write is faster than read
+ * init == start == rdptr
+ */
static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
struct mdss_mdp_cmd_ctx *ctx, int enable)
{
@@ -59,15 +67,21 @@
cfg = BIT(19); /* VSYNC_COUNTER_EN */
if (ctx->tear_check)
cfg |= BIT(20); /* VSYNC_IN_EN */
- cfg |= ctx->vsync_cnt;
+ cfg |= ctx->vclk_line;
mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg);
mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT,
0xfff0); /* set to verh height */
- mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_VSYNC_INIT_VAL, 0);
- mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_RD_PTR_IRQ, 0);
- mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_START_POS, ctx->v_porch);
+ mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_VSYNC_INIT_VAL,
+ ctx->height);
+
+ mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_RD_PTR_IRQ,
+ ctx->height + 1);
+
+ mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_START_POS,
+ ctx->height);
+
mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_THRESH,
(CONTINUE_TRESHOLD << 16) | (START_THRESHOLD));
@@ -85,7 +99,6 @@
if (pinfo->mipi.vsync_enable && enable) {
u32 mdp_vsync_clk_speed_hz, total_lines;
- u32 vsync_cnt_cfg_dem;
mdss_mdp_vsync_clk_enable(1);
@@ -100,21 +113,18 @@
}
ctx->tear_check = pinfo->mipi.hw_vsync_mode;
-
- total_lines = pinfo->lcdc.v_back_porch +
- pinfo->lcdc.v_front_porch +
- pinfo->lcdc.v_pulse_width + pinfo->yres;
-
- vsync_cnt_cfg_dem =
- mult_frac(pinfo->mipi.frame_rate * total_lines,
- 1, 100);
-
- ctx->vsync_cnt = mdp_vsync_clk_speed_hz / vsync_cnt_cfg_dem;
-
- ctx->v_porch = pinfo->lcdc.v_back_porch +
+ ctx->height = pinfo->yres;
+ ctx->vporch = pinfo->lcdc.v_back_porch +
pinfo->lcdc.v_front_porch +
pinfo->lcdc.v_pulse_width;
- ctx->total_lcd_lines = total_lines;
+
+ total_lines = ctx->height + ctx->vporch;
+ total_lines *= pinfo->mipi.frame_rate;
+ ctx->vclk_line = mdp_vsync_clk_speed_hz / total_lines;
+
+ pr_debug("%s: fr=%d tline=%d vcnt=%d vrate=%d\n",
+ __func__, pinfo->mipi.frame_rate, total_lines,
+ ctx->vclk_line, mdp_vsync_clk_speed_hz);
} else {
enable = 0;
}
@@ -225,7 +235,7 @@
}
static int mdss_mdp_cmd_vsync_ctrl(struct mdss_mdp_ctl *ctl,
- mdp_vsync_handler_t send_vsync)
+ struct mdss_mdp_vsync_handler *handler)
{
struct mdss_mdp_cmd_ctx *ctx;
unsigned long flags;
@@ -237,7 +247,7 @@
return -ENODEV;
}
- enable = (send_vsync != NULL);
+ enable = (handler->vsync_handler != NULL);
pr_debug("%s: ctx=%p ctx=%d enabled=%d %d clk_enabled=%d clk_ctrl=%d\n",
__func__, ctx, ctx->pp_num, ctx->vsync_enabled, enable,
@@ -253,7 +263,7 @@
spin_lock_irqsave(&ctx->clk_lock, flags);
ctx->clk_control = 0;
ctx->expire = 0;
- ctx->send_vsync = send_vsync;
+ ctx->send_vsync = handler->vsync_handler;
spin_unlock_irqrestore(&ctx->clk_lock, flags);
if (ctx->clk_enabled == 0) {
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
@@ -366,6 +376,7 @@
{
struct mdss_mdp_cmd_ctx *ctx;
int need_wait = 0;
+ struct mdss_mdp_vsync_handler null_handle;
int ret;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
@@ -389,7 +400,8 @@
ctx->panel_on = 0;
- mdss_mdp_cmd_vsync_ctrl(ctl, NULL);
+ null_handle.vsync_handler = NULL;
+ mdss_mdp_cmd_vsync_ctrl(ctl, &null_handle);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctl->intf_num,
NULL, NULL);
@@ -468,7 +480,8 @@
ctl->stop_fnc = mdss_mdp_cmd_stop;
ctl->display_fnc = mdss_mdp_cmd_kickoff;
ctl->wait_fnc = mdss_mdp_cmd_wait4comp;
- ctl->set_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
+ ctl->add_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
+ ctl->remove_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
pr_debug("%s:-\n", __func__);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 94ae710..72cbed9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -13,11 +13,18 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+
#include "mdss_fb.h"
#include "mdss_mdp.h"
-/* wait for at most 2 vsync for lowest refresh rate (24hz) */
-#define VSYNC_TIMEOUT msecs_to_jiffies(84)
+/* wait for at least 2 vsyncs for lowest refresh rate (24hz) */
+#define VSYNC_TIMEOUT_US 100000
+
+#define MDP_INTR_MASK_INTF_VSYNC(intf_num) \
+ (1 << (2 * (intf_num - MDSS_MDP_INTF0) + MDSS_MDP_IRQ_INTF_VSYNC))
/* intf timing settings */
struct intf_timing_params {
@@ -45,12 +52,14 @@
u8 ref_cnt;
u8 timegen_en;
+ bool polling_en;
+ u32 poll_cnt;
struct completion vsync_comp;
int wait_pending;
atomic_t vsync_ref;
spinlock_t vsync_lock;
- mdp_vsync_handler_t vsync_handler;
+ struct list_head vsync_handlers;
};
static inline void mdp_video_write(struct mdss_mdp_video_ctx *ctx,
@@ -92,6 +101,7 @@
offsets[i], head[i].base);
head[i].ref_cnt = 0;
head[i].intf_num = i + MDSS_MDP_INTF0;
+ INIT_LIST_HEAD(&head[i].vsync_handlers);
}
mdata->video_intf = head;
@@ -193,13 +203,13 @@
}
-static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl)
+static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl, bool clear)
{
struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
if (atomic_inc_return(&ctx->vsync_ref) == 1)
mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
- else
+ else if (clear)
mdss_mdp_irq_clear(ctl->mdata, MDSS_MDP_IRQ_INTF_VSYNC,
ctl->intf_num);
}
@@ -212,12 +222,45 @@
mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
}
-static int mdss_mdp_video_set_vsync_handler(struct mdss_mdp_ctl *ctl,
- mdp_vsync_handler_t vsync_handler)
+static int mdss_mdp_video_add_vsync_handler(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_vsync_handler *handle)
{
struct mdss_mdp_video_ctx *ctx;
unsigned long flags;
- int need_update;
+ int ret = 0;
+ bool irq_en = false;
+
+ if (!handle || !(handle->vsync_handler)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+ if (!ctx) {
+ pr_err("invalid ctx for ctl=%d\n", ctl->num);
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ spin_lock_irqsave(&ctx->vsync_lock, flags);
+ if (!handle->enabled) {
+ handle->enabled = true;
+ list_add(&handle->list, &ctx->vsync_handlers);
+ irq_en = true;
+ }
+ spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+ if (irq_en)
+ video_vsync_irq_enable(ctl, false);
+exit:
+ return ret;
+}
+
+static int mdss_mdp_video_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_vsync_handler *handle)
+{
+ struct mdss_mdp_video_ctx *ctx;
+ unsigned long flags;
+ bool irq_dis = false;
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
if (!ctx) {
@@ -226,24 +269,21 @@
}
spin_lock_irqsave(&ctx->vsync_lock, flags);
- need_update = (!ctx->vsync_handler && vsync_handler) ||
- (ctx->vsync_handler && !vsync_handler);
- ctx->vsync_handler = vsync_handler;
- spin_unlock_irqrestore(&ctx->vsync_lock, flags);
-
- if (need_update) {
- if (vsync_handler)
- video_vsync_irq_enable(ctl);
- else
- video_vsync_irq_disable(ctl);
+ if (handle->enabled) {
+ handle->enabled = false;
+ list_del_init(&handle->list);
+ irq_dis = true;
}
-
+ spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+ if (irq_dis)
+ video_vsync_irq_disable(ctl);
return 0;
}
static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_video_ctx *ctx;
+ struct mdss_mdp_vsync_handler *tmp, *handle;
int rc;
pr_debug("stop ctl=%d\n", ctl->num);
@@ -274,7 +314,8 @@
ctl->intf_num);
}
- mdss_mdp_video_set_vsync_handler(ctl, NULL);
+ list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
+ mdss_mdp_video_remove_vsync_handler(ctl, handle);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
NULL, NULL);
@@ -291,6 +332,7 @@
{
struct mdss_mdp_ctl *ctl = arg;
struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+ struct mdss_mdp_vsync_handler *tmp;
ktime_t vsync_time;
if (!ctx) {
@@ -304,13 +346,53 @@
pr_debug("intr ctl=%d vsync cnt=%u vsync_time=%d\n",
ctl->num, ctl->vsync_cnt, (int)ktime_to_ms(vsync_time));
+ ctx->polling_en = false;
complete_all(&ctx->vsync_comp);
spin_lock(&ctx->vsync_lock);
- if (ctx->vsync_handler)
- ctx->vsync_handler(ctl, vsync_time);
+ list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
+ tmp->vsync_handler(ctl, vsync_time);
+ }
spin_unlock(&ctx->vsync_lock);
}
+static int mdss_mdp_video_pollwait(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+ u32 mask, status;
+ int rc;
+
+ mask = MDP_INTR_MASK_INTF_VSYNC(ctl->intf_num);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ rc = readl_poll_timeout(ctl->mdata->mdp_base + MDSS_MDP_REG_INTR_STATUS,
+ status,
+ (status & mask) || try_wait_for_completion(&ctx->vsync_comp),
+ 1000,
+ VSYNC_TIMEOUT_US);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ if (rc == 0) {
+ pr_debug("vsync poll successful! rc=%d status=0x%x\n",
+ rc, status);
+ ctx->poll_cnt++;
+ if (status) {
+ struct mdss_mdp_vsync_handler *tmp;
+ unsigned long flags;
+ ktime_t vsync_time = ktime_get();
+
+ spin_lock_irqsave(&ctx->vsync_lock, flags);
+ list_for_each_entry(tmp, &ctx->vsync_handlers, list)
+ tmp->vsync_handler(ctl, vsync_time);
+ spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+ }
+ } else {
+ pr_warn("vsync poll timed out! rc=%d status=0x%x mask=0x%x\n",
+ rc, status, mask);
+ }
+
+ return rc;
+}
+
static int mdss_mdp_video_wait4comp(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_video_ctx *ctx;
@@ -324,9 +406,22 @@
WARN(!ctx->wait_pending, "waiting without commit! ctl=%d", ctl->num);
- rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
- VSYNC_TIMEOUT);
- WARN(rc <= 0, "vsync timed out (%d) ctl=%d\n", rc, ctl->num);
+ if (ctx->polling_en) {
+ rc = mdss_mdp_video_pollwait(ctl);
+ } else {
+ rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
+ usecs_to_jiffies(VSYNC_TIMEOUT_US));
+ if (rc < 0) {
+ pr_warn("vsync wait interrupted ctl=%d\n", ctl->num);
+ } else if (rc == 0) {
+ pr_warn("vsync wait timeout %d, fallback to poll mode\n",
+ ctl->num);
+ ctx->polling_en++;
+ rc = mdss_mdp_video_pollwait(ctl);
+ } else {
+ rc = 0;
+ }
+ }
if (ctx->wait_pending) {
ctx->wait_pending = 0;
@@ -343,7 +438,7 @@
return;
ctl->underrun_cnt++;
- pr_warn("display underrun detected for ctl=%d count=%d\n", ctl->num,
+ pr_debug("display underrun detected for ctl=%d count=%d\n", ctl->num,
ctl->underrun_cnt);
}
@@ -362,7 +457,7 @@
if (!ctx->wait_pending) {
ctx->wait_pending++;
- video_vsync_irq_enable(ctl);
+ video_vsync_irq_enable(ctl, true);
INIT_COMPLETION(ctx->vsync_comp);
} else {
WARN(1, "commit without wait! ctl=%d", ctl->num);
@@ -370,7 +465,13 @@
if (!ctx->timegen_en) {
rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
- WARN(rc, "intf %d unblank error (%d)\n", ctl->intf_num, rc);
+ if (rc) {
+ pr_warn("intf #%d unblank error (%d)\n",
+ ctl->intf_num, rc);
+ video_vsync_irq_disable(ctl);
+ ctx->wait_pending = 0;
+ return rc;
+ }
pr_debug("enabling timing gen for intf=%d\n", ctl->intf_num);
@@ -381,7 +482,7 @@
wmb();
rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
- VSYNC_TIMEOUT);
+ usecs_to_jiffies(VSYNC_TIMEOUT_US));
WARN(rc <= 0, "timeout (%d) enabling timegen on ctl=%d\n",
rc, ctl->num);
@@ -393,6 +494,92 @@
return 0;
}
+int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata)
+{
+ void *virt = NULL;
+ unsigned long bl_fb_addr = 0;
+ unsigned long *bl_fb_addr_va;
+ unsigned long pipe_addr, pipe_src_size;
+ u32 height, width, rgb_size, bpp;
+ size_t size;
+ static struct ion_handle *ihdl;
+ struct ion_client *iclient = mdss_get_ionclient();
+ static ion_phys_addr_t phys;
+
+ pipe_addr = MDSS_MDP_REG_SSPP_OFFSET(3) +
+ MDSS_MDP_REG_SSPP_SRC0_ADDR;
+ pipe_src_size =
+ MDSS_MDP_REG_SSPP_OFFSET(3) + MDSS_MDP_REG_SSPP_SRC_SIZE;
+
+ bpp = 3;
+ rgb_size = MDSS_MDP_REG_READ(pipe_src_size);
+ bl_fb_addr = MDSS_MDP_REG_READ(pipe_addr);
+
+ height = (rgb_size >> 16) & 0xffff;
+ width = rgb_size & 0xffff;
+ size = PAGE_ALIGN(height * width * bpp);
+ pr_debug("%s:%d splash_height=%d splash_width=%d Buffer size=%d\n",
+ __func__, __LINE__, height, width, size);
+
+ ihdl = ion_alloc(iclient, size, SZ_1M,
+ ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(ihdl)) {
+ pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
+ return -ENOMEM;
+ }
+
+ pdata->panel_info.splash_ihdl = ihdl;
+
+ virt = ion_map_kernel(iclient, ihdl);
+ ion_phys(iclient, ihdl, &phys, &size);
+
+ pr_debug("%s %d Allocating %u bytes at 0x%lx (%pa phys)\n",
+ __func__, __LINE__, size,
+ (unsigned long int)virt, &phys);
+
+ bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
+
+ memcpy(virt, bl_fb_addr_va, size);
+
+ MDSS_MDP_REG_WRITE(pipe_addr, phys);
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_CTL_FLUSH + MDSS_MDP_REG_CTL_OFFSET(0),
+ 0x48);
+
+ return 0;
+}
+
+int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
+{
+ struct ion_client *iclient = mdss_get_ionclient();
+ struct mdss_panel_data *pdata;
+ int ret = 0, off;
+ int mdss_mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
+ int mdss_v2_intf_off = 0;
+
+ off = 0;
+
+ pdata = ctl->panel_data;
+
+ pdata->panel_info.cont_splash_enabled = 0;
+
+
+ mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
+ off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
+
+ if (mdss_mdp_rev == MDSS_MDP_HW_REV_102)
+ mdss_v2_intf_off = 0xEC00;
+
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN -
+ mdss_v2_intf_off, 0);
+ /* wait for 1 VSYNC for the pipe to be unstaged */
+ msleep(20);
+ ion_free(iclient, pdata->panel_info.splash_ihdl);
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
+ NULL);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ return ret;
+}
+
int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl)
{
struct mdss_data_type *mdata;
@@ -471,8 +658,9 @@
ctl->stop_fnc = mdss_mdp_video_stop;
ctl->display_fnc = mdss_mdp_video_display;
ctl->wait_fnc = mdss_mdp_video_wait4comp;
- ctl->set_vsync_handler = mdss_mdp_video_set_vsync_handler;
ctl->read_line_cnt_fnc = mdss_mdp_video_line_count;
+ ctl->add_vsync_handler = mdss_mdp_video_add_vsync_handler;
+ ctl->remove_vsync_handler = mdss_mdp_video_remove_vsync_handler;
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 6c90794..3cb23f3 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -39,6 +39,7 @@
static atomic_t ov_active_panels = ATOMIC_INIT(0);
static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd);
static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd);
+static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd);
static int mdss_mdp_overlay_get(struct msm_fb_data_type *mfd,
struct mdp_overlay *req)
@@ -64,11 +65,19 @@
{
u32 xres, yres;
u32 min_src_size, min_dst_size;
+ int content_secure;
struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
xres = mfd->fbi->var.xres;
yres = mfd->fbi->var.yres;
+ content_secure = (req->flags & MDP_SECURE_OVERLAY_SESSION);
+ if (!ctl->is_secure && content_secure &&
+ (mfd->panel.type == WRITEBACK_PANEL)) {
+ pr_debug("return due to security concerns\n");
+ return -EPERM;
+ }
if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
min_src_size = fmt->is_yuv ? 2 : 1;
min_dst_size = 1;
@@ -179,6 +188,14 @@
req->src_rect.h, req->dst_rect.h);
return -EINVAL;
}
+
+ if (req->flags & MDP_BWC_EN) {
+ if ((req->src.width != req->src_rect.w) ||
+ (req->src.height != req->src_rect.h)) {
+ pr_err("BWC: unequal src img and rect w,h\n");
+ return -EINVAL;
+ }
+ }
}
if (fmt->is_yuv) {
@@ -189,6 +206,13 @@
}
}
+ if (req->flags & MDP_DEINTERLACE) {
+ if ((req->src.width % 4 != 0) || (req->src.height % 4 != 0)) {
+ pr_err("interlaced fmt w,h need to be even post div\n");
+ return -EINVAL;
+ }
+ }
+
return 0;
}
@@ -322,7 +346,7 @@
if (pipe && pipe->ndx != req->id) {
pr_debug("replacing pnum=%d at stage=%d mux=%d\n",
pipe->num, req->z_order, mixer_mux);
- pipe->params_changed = true;
+ mdss_mdp_mixer_pipe_unstage(pipe);
}
mixer = mdss_mdp_mixer_get(mdp5_data->ctl, mixer_mux);
@@ -588,7 +612,7 @@
return 0;
}
-static int mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
+static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
{
struct mdss_mdp_pipe *pipe, *tmp;
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
@@ -613,96 +637,6 @@
mutex_unlock(&mfd->lock);
list_for_each_entry_safe(pipe, tmp, &destroy_pipes, cleanup_list)
mdss_mdp_pipe_destroy(pipe);
-
- return 0;
-}
-
-int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata)
-{
- void *virt = NULL;
- unsigned long bl_fb_addr = 0;
- unsigned long *bl_fb_addr_va;
- unsigned long pipe_addr, pipe_src_size;
- u32 height, width, rgb_size, bpp;
- size_t size;
- static struct ion_handle *ihdl;
- struct ion_client *iclient = mdss_get_ionclient();
- static ion_phys_addr_t phys;
-
- pipe_addr = MDSS_MDP_REG_SSPP_OFFSET(3) +
- MDSS_MDP_REG_SSPP_SRC0_ADDR;
- pipe_src_size =
- MDSS_MDP_REG_SSPP_OFFSET(3) + MDSS_MDP_REG_SSPP_SRC_SIZE;
-
- bpp = 3;
- rgb_size = MDSS_MDP_REG_READ(pipe_src_size);
- bl_fb_addr = MDSS_MDP_REG_READ(pipe_addr);
-
- height = (rgb_size >> 16) & 0xffff;
- width = rgb_size & 0xffff;
- size = PAGE_ALIGN(height * width * bpp);
- pr_debug("%s:%d splash_height=%d splash_width=%d Buffer size=%d\n",
- __func__, __LINE__, height, width, size);
-
- ihdl = ion_alloc(iclient, size, SZ_1M,
- ION_HEAP(ION_QSECOM_HEAP_ID), 0);
- if (IS_ERR_OR_NULL(ihdl)) {
- pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
- return -ENOMEM;
- }
-
- pdata->panel_info.splash_ihdl = ihdl;
-
- virt = ion_map_kernel(iclient, ihdl);
- ion_phys(iclient, ihdl, &phys, &size);
-
- pr_debug("%s %d Allocating %u bytes at 0x%lx (%pa phys)\n",
- __func__, __LINE__, size,
- (unsigned long int)virt, &phys);
-
- bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
-
- memcpy(virt, bl_fb_addr_va, size);
-
- MDSS_MDP_REG_WRITE(pipe_addr, phys);
- MDSS_MDP_REG_WRITE(MDSS_MDP_REG_CTL_FLUSH + MDSS_MDP_REG_CTL_OFFSET(0),
- 0x48);
-
- return 0;
-
-}
-
-int mdss_mdp_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
-{
- struct ion_client *iclient = mdss_get_ionclient();
- struct mdss_panel_data *pdata;
- int ret = 0, off;
- int mdss_mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
- int mdss_v2_intf_off = 0;
-
- off = 0;
-
- pdata = ctl->panel_data;
-
- pdata->panel_info.cont_splash_enabled = 0;
-
- ion_free(iclient, pdata->panel_info.splash_ihdl);
-
- mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
- off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
-
- if (mdss_mdp_rev == MDSS_MDP_HW_REV_102)
- mdss_v2_intf_off = 0xEC00;
-
- /* wait for 1 VSYNC for the pipe to be unstaged */
- msleep(20);
- MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN -
- mdss_v2_intf_off, 0);
- ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
- NULL);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
- mdss_mdp_footswitch_ctrl_splash(0);
- return ret;
}
static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
@@ -721,8 +655,10 @@
return rc;
}
- if (mfd->panel_info->cont_splash_enabled)
- mdss_mdp_reconfigure_splash_done(mdp5_data->ctl);
+ if (mfd->panel_info->cont_splash_enabled) {
+ mdss_mdp_ctl_splash_finish(mdp5_data->ctl);
+ mdss_mdp_footswitch_ctrl_splash(0);
+ }
if (!is_mdss_iommu_attached()) {
mdss_iommu_attach(mdss_res);
@@ -811,7 +747,7 @@
mutex_unlock(&mfd->no_update.lock);
commit_fail:
- ret = mdss_mdp_overlay_cleanup(mfd);
+ mdss_mdp_overlay_cleanup(mfd);
mutex_unlock(&mdp5_data->ov_lock);
@@ -1006,7 +942,7 @@
return ret;
}
-static int mdss_mdp_overlay_force_cleanup(struct msm_fb_data_type *mfd)
+static void mdss_mdp_overlay_force_cleanup(struct msm_fb_data_type *mfd)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
@@ -1024,9 +960,7 @@
mdss_mdp_display_wait4comp(ctl);
}
- ret = mdss_mdp_overlay_cleanup(mfd);
-
- return ret;
+ mdss_mdp_overlay_cleanup(mfd);
}
static void mdss_mdp_overlay_force_dma_cleanup(struct mdss_data_type *mdata)
@@ -1185,7 +1119,8 @@
fbi = mfd->fbi;
- if (fbi->fix.smem_len == 0 || mdp5_data->borderfill_enable) {
+ if (!fbi->fix.smem_start || fbi->fix.smem_len == 0 ||
+ mdp5_data->borderfill_enable) {
mfd->mdp.kickoff_fnc(mfd);
return;
}
@@ -1216,9 +1151,13 @@
goto pan_display_error;
}
- if (is_mdss_iommu_attached())
+ if (is_mdss_iommu_attached()) {
+ if (!mfd->iova) {
+ pr_err("mfd iova is zero\n");
+ goto pan_display_error;
+ }
data.p[0].addr = mfd->iova;
- else
+ } else
data.p[0].addr = fbi->fix.smem_start;
data.p[0].addr += offset;
@@ -1302,7 +1241,7 @@
if (!ctl)
return -ENODEV;
- if (!ctl->set_vsync_handler)
+ if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
return -ENOTSUPP;
rc = mutex_lock_interruptible(&ctl->lock);
@@ -1325,9 +1264,9 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (en)
- rc = ctl->set_vsync_handler(ctl, mdss_mdp_overlay_handle_vsync);
+ rc = ctl->add_vsync_handler(ctl, &ctl->vsync_handler);
else
- rc = ctl->set_vsync_handler(ctl, NULL);
+ rc = ctl->remove_vsync_handler(ctl, &ctl->vsync_handler);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
mutex_unlock(&ctl->lock);
@@ -1517,7 +1456,7 @@
{
int ret = 0;
int curr_bl;
- mutex_lock(&mfd->lock);
+ mutex_lock(&mfd->bl_lock);
curr_bl = mfd->bl_level;
mfd->bl_scale = data->scale;
mfd->bl_min_lvl = data->min_lvl;
@@ -1526,7 +1465,7 @@
/* update current backlight to use new scaling*/
mdss_fb_set_backlight(mfd, curr_bl);
- mutex_unlock(&mfd->lock);
+ mutex_unlock(&mfd->bl_lock);
return ret;
}
@@ -1536,6 +1475,7 @@
int ret;
struct msmfb_mdp_pp mdp_pp;
u32 copyback = 0;
+ u32 copy_from_kernel = 0;
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
@@ -1562,7 +1502,7 @@
mdp5_data->ctl,
(struct mdp_igc_lut_data *)
&mdp_pp.data.lut_cfg_data.data,
- ©back);
+ ©back, copy_from_kernel);
break;
case mdp_lut_pgc:
@@ -1600,6 +1540,16 @@
ret = mdss_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
&mdp_pp.data.bl_scale_data);
break;
+ case mdp_op_ad_cfg:
+ ret = mdss_mdp_ad_config(mfd, &mdp_pp.data.ad_init_cfg);
+ break;
+ case mdp_op_ad_input:
+ ret = mdss_mdp_ad_input(mfd, &mdp_pp.data.ad_input);
+ if (ret > 0) {
+ ret = 0;
+ copyback = 1;
+ }
+ break;
default:
pr_err("Unsupported request to MDP_PP IOCTL.\n");
ret = -EINVAL;
@@ -1865,6 +1815,8 @@
mfd->index);
return PTR_ERR(ctl);
}
+ ctl->vsync_handler.vsync_handler =
+ mdss_mdp_overlay_handle_vsync;
if (mfd->split_display && pdata->next) {
/* enable split display */
@@ -1887,7 +1839,10 @@
return rc;
}
- if (!IS_ERR_VALUE(rc) && mdp5_data->vsync_pending) {
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("Failed to turn on fb%d\n", mfd->index);
+ mdss_mdp_overlay_off(mfd);
+ } else if (mdp5_data->vsync_pending) {
mdp5_data->vsync_pending = 0;
mdss_mdp_overlay_vsync_ctrl(mfd, mdp5_data->vsync_pending);
}
@@ -1944,7 +1899,7 @@
if (pdata->panel_info.cont_splash_enabled) {
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mdss_mdp_footswitch_ctrl_splash(1);
- mdss_mdp_copy_splash_screen(pdata);
+ mdss_mdp_ctl_splash_start(pdata);
}
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 8bd5674..65b5fc4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -93,6 +93,72 @@
static u32 dither_depth_map[9] = {
0, 0, 0, 0, 0, 1, 2, 3, 3};
+static u32 igc_limited[IGC_LUT_ENTRIES] = {
+ 16777472, 17826064, 18874656, 19923248,
+ 19923248, 20971840, 22020432, 23069024,
+ 24117616, 25166208, 26214800, 26214800,
+ 27263392, 28311984, 29360576, 30409168,
+ 31457760, 32506352, 32506352, 33554944,
+ 34603536, 35652128, 36700720, 37749312,
+ 38797904, 38797904, 39846496, 40895088,
+ 41943680, 42992272, 44040864, 45089456,
+ 45089456, 46138048, 47186640, 48235232,
+ 49283824, 50332416, 51381008, 51381008,
+ 52429600, 53478192, 54526784, 55575376,
+ 56623968, 57672560, 58721152, 58721152,
+ 59769744, 60818336, 61866928, 62915520,
+ 63964112, 65012704, 65012704, 66061296,
+ 67109888, 68158480, 69207072, 70255664,
+ 71304256, 71304256, 72352848, 73401440,
+ 74450032, 75498624, 76547216, 77595808,
+ 77595808, 78644400, 79692992, 80741584,
+ 81790176, 82838768, 83887360, 83887360,
+ 84935952, 85984544, 87033136, 88081728,
+ 89130320, 90178912, 90178912, 91227504,
+ 92276096, 93324688, 94373280, 95421872,
+ 96470464, 96470464, 97519056, 98567648,
+ 99616240, 100664832, 101713424, 102762016,
+ 102762016, 103810608, 104859200, 105907792,
+ 106956384, 108004976, 109053568, 109053568,
+ 110102160, 111150752, 112199344, 113247936,
+ 114296528, 115345120, 115345120, 116393712,
+ 117442304, 118490896, 119539488, 120588080,
+ 121636672, 121636672, 122685264, 123733856,
+ 124782448, 125831040, 126879632, 127928224,
+ 127928224, 128976816, 130025408, 131074000,
+ 132122592, 133171184, 134219776, 135268368,
+ 135268368, 136316960, 137365552, 138414144,
+ 139462736, 140511328, 141559920, 141559920,
+ 142608512, 143657104, 144705696, 145754288,
+ 146802880, 147851472, 147851472, 148900064,
+ 149948656, 150997248, 152045840, 153094432,
+ 154143024, 154143024, 155191616, 156240208,
+ 157288800, 158337392, 159385984, 160434576,
+ 160434576, 161483168, 162531760, 163580352,
+ 164628944, 165677536, 166726128, 166726128,
+ 167774720, 168823312, 169871904, 170920496,
+ 171969088, 173017680, 173017680, 174066272,
+ 175114864, 176163456, 177212048, 178260640,
+ 179309232, 179309232, 180357824, 181406416,
+ 182455008, 183503600, 184552192, 185600784,
+ 185600784, 186649376, 187697968, 188746560,
+ 189795152, 190843744, 191892336, 191892336,
+ 192940928, 193989520, 195038112, 196086704,
+ 197135296, 198183888, 198183888, 199232480,
+ 200281072, 201329664, 202378256, 203426848,
+ 204475440, 204475440, 205524032, 206572624,
+ 207621216, 208669808, 209718400, 210766992,
+ 211815584, 211815584, 212864176, 213912768,
+ 214961360, 216009952, 217058544, 218107136,
+ 218107136, 219155728, 220204320, 221252912,
+ 222301504, 223350096, 224398688, 224398688,
+ 225447280, 226495872, 227544464, 228593056,
+ 229641648, 230690240, 230690240, 231738832,
+ 232787424, 233836016, 234884608, 235933200,
+ 236981792, 236981792, 238030384, 239078976,
+ 240127568, 241176160, 242224752, 243273344,
+ 243273344, 244321936, 245370528, 246419120};
+
#define GAMUT_T0_SIZE 125
#define GAMUT_T1_SIZE 100
#define GAMUT_T2_SIZE 80
@@ -119,6 +185,39 @@
#define PP_STS_ENABLE 0x1
#define PP_STS_GAMUT_FIRST 0x2
+#define PP_AD_STATE_INIT 0x2
+#define PP_AD_STATE_CFG 0x4
+#define PP_AD_STATE_DATA 0x8
+#define PP_AD_STATE_RUN 0x10
+#define PP_AD_STATE_VSYNC 0x20
+
+#define PP_AD_STATE_IS_INITCFG(st) (((st) & PP_AD_STATE_INIT) &&\
+ ((st) & PP_AD_STATE_CFG))
+
+#define PP_AD_STATE_IS_READY(st) (((st) & PP_AD_STATE_INIT) &&\
+ ((st) & PP_AD_STATE_CFG) &&\
+ ((st) & PP_AD_STATE_DATA))
+
+#define PP_AD_STS_DIRTY_INIT 0x2
+#define PP_AD_STS_DIRTY_CFG 0x4
+#define PP_AD_STS_DIRTY_DATA 0x8
+#define PP_AD_STS_DIRTY_VSYNC 0x10
+
+#define PP_AD_STS_IS_DIRTY(sts) (((sts) & PP_AD_STS_DIRTY_INIT) ||\
+ ((sts) & PP_AD_STS_DIRTY_CFG))
+
+/* Bits 0 and 1 */
+#define MDSS_AD_INPUT_AMBIENT (0x03)
+/* Bits 3 and 7 */
+#define MDSS_AD_INPUT_STRENGTH (0x88)
+/*
+ * Check data by shifting by mode to see if it matches to the
+ * MDSS_AD_INPUT_* bitfields
+ */
+#define MDSS_AD_MODE_DATA_MATCH(mode, data) ((1 << (mode)) & (data))
+#define MDSS_AD_RUNNING_AUTO_BL(ad) (((ad)->state & PP_AD_STATE_RUN) &&\
+ ((ad)->cfg.mode == MDSS_AD_MODE_AUTO_BL))
+
#define SHARP_STRENGTH_DEFAULT 32
#define SHARP_EDGE_THR_DEFAULT 112
#define SHARP_SMOOTH_THR_DEFAULT 8
@@ -145,11 +244,9 @@
struct mdp_dither_cfg_data dither_disp_cfg[MDSS_BLOCK_DISP_NUM];
struct mdp_gamut_cfg_data gamut_disp_cfg[MDSS_BLOCK_DISP_NUM];
uint16_t gamut_tbl[MDSS_BLOCK_DISP_NUM][GAMUT_TOTAL_TABLE_SIZE];
- struct pp_hist_col_info
- *hist_col[MDSS_BLOCK_DISP_NUM][MDSS_MDP_MAX_DSPP];
u32 hist_data[MDSS_BLOCK_DISP_NUM][HIST_V_SIZE];
/* physical info */
- struct pp_sts_type pp_dspp_sts[MDSS_MDP_MAX_DSPP];
+ struct pp_sts_type pp_disp_sts[MDSS_BLOCK_DISP_NUM];
struct pp_hist_col_info dspp_hist[MDSS_MDP_MAX_DSPP];
};
@@ -187,7 +284,14 @@
static void pp_sharp_config(char __iomem *offset,
struct pp_sts_type *pp_sts,
struct mdp_sharp_cfg *sharp_config);
+static void pp_ad_vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t);
+static void pp_ad_cfg_write(struct mdss_ad_info *ad);
+static void pp_ad_init_write(struct mdss_ad_info *ad);
+static void pp_ad_input_write(struct mdss_ad_info *ad, u32 bl_lvl);
+static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd);
+static void pp_ad_cfg_lut(char __iomem *offset, u32 *data);
+static u32 last_sts, last_state;
int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
struct mdp_csc_cfg *data)
@@ -631,7 +735,7 @@
else
scale_config |= /* RGB, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
- (MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+ (MDSS_MDP_SCALE_FILTER_PCMN << 18);
}
phasey_step = mdss_mdp_scale_phase_step(
@@ -688,7 +792,7 @@
else
scale_config |= /* RGB, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
- (MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+ (MDSS_MDP_SCALE_FILTER_PCMN << 16);
}
phasex_step = mdss_mdp_scale_phase_step(
@@ -798,7 +902,7 @@
else
flags = 0;
- pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
+ pp_sts = &mdss_pp_res->pp_disp_sts[disp_num];
/* GC_LUT is in layer mixer */
if (flags & PP_FLAGS_DIRTY_ARGC) {
pgc_config = &mdss_pp_res->argc_disp_cfg[disp_num];
@@ -906,8 +1010,11 @@
u32 data;
char __iomem *basel;
int i, ret = 0;
+ struct mdss_data_type *mdata;
- if (!mixer || !ctl)
+ mdata = ctl->mdata;
+
+ if (!mixer || !ctl || !mdata)
return -EINVAL;
dspp_num = mixer->num;
@@ -929,11 +1036,17 @@
else
flags = 0;
+ if (dspp_num < mdata->nad_cfgs) {
+ ret = mdss_mdp_ad_setup(ctl->mfd);
+ if (ret < 0)
+ pr_warn("ad_setup(dspp%d) returns %d", dspp_num, ret);
+ }
/* nothing to update */
- if ((!flags) && (!(opmode)))
+ if ((!flags) && (!(opmode)) && (ret <= 0))
goto dspp_exit;
+ ret = 0;
- pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
+ pp_sts = &mdss_pp_res->pp_disp_sts[disp_num];
pp_pa_config(flags, base + MDSS_MDP_REG_DSPP_PA_BASE, pp_sts,
&mdss_pp_res->pa_disp_cfg[disp_num]);
@@ -1077,76 +1190,91 @@
* Set dirty and write bits on features that were enabled so they will be
* reconfigured
*/
-int mdss_mdp_pp_resume(u32 mixer_num)
+int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 dspp_num)
{
- u32 flags = 0;
+ u32 flags = 0, disp_num;
struct pp_sts_type pp_sts;
-
- if (mixer_num >= MDSS_MDP_MAX_DSPP) {
- pr_warn("invalid mixer_num");
+ struct mdss_ad_info *ad;
+ struct mdss_data_type *mdata = ctl->mdata;
+ if (dspp_num >= MDSS_MDP_MAX_DSPP) {
+ pr_warn("invalid dspp_num");
return -EINVAL;
}
+ disp_num = ctl->mfd->index;
- pp_sts = mdss_pp_res->pp_dspp_sts[mixer_num];
+ if (dspp_num < mdata->nad_cfgs) {
+ ad = &mdata->ad_cfgs[dspp_num];
+
+ if (PP_AD_STATE_CFG & ad->state)
+ pp_ad_cfg_write(ad);
+ if (PP_AD_STATE_INIT & ad->state)
+ pp_ad_init_write(ad);
+ if (PP_AD_STATE_DATA & ad->state)
+ pp_ad_input_write(ad, ctl->mfd->bl_level);
+ if ((PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr)
+ ctl->add_vsync_handler(ctl, &ad->handle);
+ }
+
+ pp_sts = mdss_pp_res->pp_disp_sts[disp_num];
if (pp_sts.pa_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_PA;
- if (!(mdss_pp_res->pa_disp_cfg[mixer_num].flags
+ if (!(mdss_pp_res->pa_disp_cfg[disp_num].flags
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->pa_disp_cfg[mixer_num].flags |=
+ mdss_pp_res->pa_disp_cfg[disp_num].flags |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.pcc_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_PCC;
- if (!(mdss_pp_res->pcc_disp_cfg[mixer_num].ops
+ if (!(mdss_pp_res->pcc_disp_cfg[disp_num].ops
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->pcc_disp_cfg[mixer_num].ops |=
+ mdss_pp_res->pcc_disp_cfg[disp_num].ops |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.igc_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_IGC;
- if (!(mdss_pp_res->igc_disp_cfg[mixer_num].ops
+ if (!(mdss_pp_res->igc_disp_cfg[disp_num].ops
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->igc_disp_cfg[mixer_num].ops |=
+ mdss_pp_res->igc_disp_cfg[disp_num].ops |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.argc_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_ARGC;
- if (!(mdss_pp_res->argc_disp_cfg[mixer_num].flags
+ if (!(mdss_pp_res->argc_disp_cfg[disp_num].flags
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->argc_disp_cfg[mixer_num].flags |=
+ mdss_pp_res->argc_disp_cfg[disp_num].flags |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.enhist_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_ENHIST;
- if (!(mdss_pp_res->enhist_disp_cfg[mixer_num].ops
+ if (!(mdss_pp_res->enhist_disp_cfg[disp_num].ops
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->enhist_disp_cfg[mixer_num].ops |=
+ mdss_pp_res->enhist_disp_cfg[disp_num].ops |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.dither_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_DITHER;
- if (!(mdss_pp_res->dither_disp_cfg[mixer_num].flags
+ if (!(mdss_pp_res->dither_disp_cfg[disp_num].flags
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->dither_disp_cfg[mixer_num].flags |=
+ mdss_pp_res->dither_disp_cfg[disp_num].flags |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.gamut_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_GAMUT;
- if (!(mdss_pp_res->gamut_disp_cfg[mixer_num].flags
+ if (!(mdss_pp_res->gamut_disp_cfg[disp_num].flags
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->gamut_disp_cfg[mixer_num].flags |=
+ mdss_pp_res->gamut_disp_cfg[disp_num].flags |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.pgc_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_PGC;
- if (!(mdss_pp_res->pgc_disp_cfg[mixer_num].flags
+ if (!(mdss_pp_res->pgc_disp_cfg[disp_num].flags
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->pgc_disp_cfg[mixer_num].flags |=
+ mdss_pp_res->pgc_disp_cfg[disp_num].flags |=
MDP_PP_OPS_WRITE;
}
- mdss_pp_res->pp_disp_flags[mixer_num] = flags;
+ mdss_pp_res->pp_disp_flags[disp_num] |= flags;
return 0;
}
@@ -1481,9 +1609,30 @@
MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[i] & 0xFFF) | data);
}
+int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl)
+{
+ int ret = 0;
+ u32 copyback = 0;
+ u32 copy_from_kernel = 1;
+ struct mdp_igc_lut_data config;
+
+ if (!ctl)
+ return -EINVAL;
+
+ config.len = IGC_LUT_ENTRIES;
+ config.ops = MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
+ config.block = (ctl->mfd->index) + MDP_LOGICAL_BLOCK_DISP_0;
+ config.c0_c1_data = igc_limited;
+ config.c2_data = igc_limited;
+
+ ret = mdss_mdp_igc_lut_config(ctl, &config, ©back,
+ copy_from_kernel);
+ return ret;
+}
+
int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
struct mdp_igc_lut_data *config,
- u32 *copyback)
+ u32 *copyback, u32 copy_from_kernel)
{
int ret = 0;
u32 tbl_idx, igc_offset, disp_num, dspp_num = 0;
@@ -1535,15 +1684,25 @@
*copyback = 1;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
} else {
- if (copy_from_user(&mdss_pp_res->igc_lut_c0c1[disp_num][0],
- config->c0_c1_data, config->len * sizeof(u32))) {
- ret = -EFAULT;
- goto igc_config_exit;
- }
- if (copy_from_user(&mdss_pp_res->igc_lut_c2[disp_num][0],
- config->c2_data, config->len * sizeof(u32))) {
- ret = -EFAULT;
- goto igc_config_exit;
+ if (copy_from_kernel) {
+ memcpy(&mdss_pp_res->igc_lut_c0c1[disp_num][0],
+ config->c0_c1_data, config->len * sizeof(u32));
+ memcpy(&mdss_pp_res->igc_lut_c2[disp_num][0],
+ config->c2_data, config->len * sizeof(u32));
+ } else {
+ if (copy_from_user(
+ &mdss_pp_res->igc_lut_c0c1[disp_num][0],
+ config->c0_c1_data,
+ config->len * sizeof(u32))) {
+ ret = -EFAULT;
+ goto igc_config_exit;
+ }
+ if (copy_from_user(
+ &mdss_pp_res->igc_lut_c2[disp_num][0],
+ config->c2_data, config->len * sizeof(u32))) {
+ ret = -EFAULT;
+ goto igc_config_exit;
+ }
}
mdss_pp_res->igc_disp_cfg[disp_num] = *config;
mdss_pp_res->igc_disp_cfg[disp_num].c0_c1_data =
@@ -2519,3 +2678,472 @@
}
};
}
+
+#define MDSS_AD_MAX_MIXERS 1
+int mdss_ad_init_checks(struct msm_fb_data_type *mfd)
+{
+ u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+ u32 mixer_num;
+ u32 ret = -EINVAL;
+ int i = 0;
+ struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+
+ if (!mfd || !mdata)
+ return ret;
+
+ if (mdata->nad_cfgs == 0) {
+ pr_debug("Assertive Display not supported by device");
+ return -ENODEV;
+ }
+
+ if (mfd->panel_info->type == MIPI_CMD_PANEL) {
+ pr_debug("Command panel not supported");
+ return -EINVAL;
+ }
+
+ mixer_num = mdss_mdp_get_ctl_mixers(mfd->index, mixer_id);
+ if (!mixer_num || mixer_num > MDSS_AD_MAX_MIXERS) {
+ pr_err("invalid mixer_num, %d", mixer_num);
+ return ret;
+ }
+
+ do {
+ if (mixer_id[i] >= mdata->nad_cfgs) {
+ pr_err("invalid mixer input, %d", mixer_id[i]);
+ return ret;
+ }
+ i++;
+ } while (i < mixer_num);
+
+ return mixer_id[0];
+}
+
+int mdss_mdp_ad_config(struct msm_fb_data_type *mfd,
+ struct mdss_ad_init_cfg *init_cfg)
+{
+ int ad_num;
+ struct mdss_ad_info *ad;
+ struct mdss_data_type *mdata;
+ struct mdss_mdp_ctl *ctl;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+ ctl = mdp5_data->ctl;
+
+ ad_num = mdss_ad_init_checks(mfd);
+ if (ad_num < 0)
+ return ad_num;
+
+ mdata = mdss_mdp_get_mdata();
+ ad = &mdata->ad_cfgs[ad_num];
+
+ mutex_lock(&ad->lock);
+ if (init_cfg->ops & MDP_PP_AD_INIT) {
+ memcpy(&ad->init, &init_cfg->params.init,
+ sizeof(struct mdss_ad_init));
+ ad->sts |= PP_AD_STS_DIRTY_INIT;
+ } else if (init_cfg->ops & MDP_PP_AD_CFG) {
+ memcpy(&ad->cfg, &init_cfg->params.cfg,
+ sizeof(struct mdss_ad_cfg));
+ /*
+ * TODO: specify panel independent range of input from cfg,
+ * scale input backlight_scale to panel bl_max's range
+ */
+ ad->cfg.backlight_scale = mfd->panel_info->bl_max;
+ ad->sts |= PP_AD_STS_DIRTY_CFG;
+ }
+
+ if (init_cfg->ops & MDP_PP_OPS_DISABLE) {
+ ad->sts &= ~PP_STS_ENABLE;
+ ad->mfd = NULL;
+ } else if (init_cfg->ops & MDP_PP_OPS_ENABLE) {
+ ad->sts |= PP_STS_ENABLE;
+ ad->mfd = mfd;
+ }
+ mutex_unlock(&ad->lock);
+ mdss_mdp_pp_setup(ctl);
+ return 0;
+}
+
+int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
+ struct mdss_ad_input *input) {
+ int ad_num, ret = 0;
+ struct mdss_ad_info *ad;
+ struct mdss_data_type *mdata;
+ struct mdss_mdp_ctl *ctl;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+ ctl = mdp5_data->ctl;
+
+ ad_num = mdss_ad_init_checks(mfd);
+ if (ad_num < 0)
+ return ad_num;
+
+ mdata = mdss_mdp_get_mdata();
+ ad = &mdata->ad_cfgs[ad_num];
+
+ mutex_lock(&ad->lock);
+ if (!PP_AD_STATE_IS_INITCFG(ad->state) &&
+ !PP_AD_STS_IS_DIRTY(ad->sts)) {
+ pr_warn("AD not initialized or configured.");
+ ret = -EPERM;
+ goto error;
+ }
+ switch (input->mode) {
+ case MDSS_AD_MODE_AUTO_BL:
+ case MDSS_AD_MODE_AUTO_STR:
+ if (!MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode,
+ MDSS_AD_INPUT_AMBIENT)) {
+ ret = -EINVAL;
+ goto error;
+ }
+ ad->ad_data_mode = MDSS_AD_INPUT_AMBIENT;
+
+ ad->ad_data = input->in.amb_light;
+ ad->calc_itr = ad->cfg.stab_itr;
+ ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+ ad->sts |= PP_AD_STS_DIRTY_DATA;
+ break;
+ case MDSS_AD_MODE_TARG_STR:
+ case MDSS_AD_MODE_MAN_STR:
+ if (!MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode,
+ MDSS_AD_INPUT_STRENGTH)) {
+ ret = -EINVAL;
+ goto error;
+ }
+ ad->ad_data_mode = MDSS_AD_INPUT_STRENGTH;
+ ad->ad_data = input->in.strength;
+ ad->calc_itr = ad->cfg.stab_itr;
+ ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+ ad->sts |= PP_AD_STS_DIRTY_DATA;
+ break;
+ default:
+ pr_warn("invalid default %d", input->mode);
+ ret = -EINVAL;
+ goto error;
+ }
+error:
+ mutex_unlock(&ad->lock);
+ if (!ret) {
+ mutex_lock(&ad->lock);
+ init_completion(&ad->comp);
+ mutex_unlock(&ad->lock);
+ mdss_mdp_pp_setup(ctl);
+ ret = wait_for_completion_interruptible_timeout(&ad->comp,
+ HIST_WAIT_TIMEOUT(1));
+ if (ret == 0)
+ ret = -ETIMEDOUT;
+ else if (ret > 0)
+ input->output = ad->last_str;
+ }
+ return ret;
+}
+
+static void pp_ad_input_write(struct mdss_ad_info *ad, u32 bl_lvl)
+{
+ char __iomem *base = ad->base;
+ switch (ad->cfg.mode) {
+ case MDSS_AD_MODE_AUTO_BL:
+ writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_AL);
+ break;
+ case MDSS_AD_MODE_AUTO_STR:
+ writel_relaxed(bl_lvl, base + MDSS_MDP_REG_AD_BL);
+ writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_AL);
+ break;
+ case MDSS_AD_MODE_TARG_STR:
+ writel_relaxed(bl_lvl, base + MDSS_MDP_REG_AD_BL);
+ writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_TARG_STR);
+ break;
+ case MDSS_AD_MODE_MAN_STR:
+ writel_relaxed(bl_lvl, base + MDSS_MDP_REG_AD_BL);
+ writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_STR_MAN);
+ break;
+ default:
+ pr_warn("Invalid mode! %d", ad->cfg.mode);
+ break;
+ }
+}
+
+static void pp_ad_init_write(struct mdss_ad_info *ad)
+{
+ u32 temp;
+ char __iomem *base = ad->base;
+ writel_relaxed(ad->init.i_control[0] & 0x1F,
+ base + MDSS_MDP_REG_AD_CON_CTRL_0);
+ writel_relaxed(ad->init.i_control[1] << 8,
+ base + MDSS_MDP_REG_AD_CON_CTRL_1);
+
+ temp = ad->init.white_lvl << 16;
+ temp |= ad->init.black_lvl & 0xFFFF;
+ writel_relaxed(temp, base + MDSS_MDP_REG_AD_BW_LVL);
+
+ writel_relaxed(ad->init.var, base + MDSS_MDP_REG_AD_VAR);
+
+ writel_relaxed(ad->init.limit_ampl, base + MDSS_MDP_REG_AD_AMP_LIM);
+
+ writel_relaxed(ad->init.i_dither, base + MDSS_MDP_REG_AD_DITH);
+
+ temp = ad->init.slope_max << 8;
+ temp |= ad->init.slope_min & 0xFF;
+ writel_relaxed(temp, base + MDSS_MDP_REG_AD_SLOPE);
+
+ writel_relaxed(ad->init.dither_ctl, base + MDSS_MDP_REG_AD_DITH_CTRL);
+
+ writel_relaxed(ad->init.format, base + MDSS_MDP_REG_AD_CTRL_0);
+ writel_relaxed(ad->init.auto_size, base + MDSS_MDP_REG_AD_CTRL_1);
+
+ temp = ad->init.frame_w << 16;
+ temp |= ad->init.frame_h & 0xFFFF;
+ writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
+
+ temp = ad->init.logo_v << 8;
+ temp |= ad->init.logo_h & 0xFF;
+ writel_relaxed(temp, base + MDSS_MDP_REG_AD_LOGO_POS);
+
+ pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_FI, ad->init.asym_lut);
+ pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_CC, ad->init.color_corr_lut);
+}
+
+#define MDSS_PP_AD_DEF_CALIB 0x6E
+static void pp_ad_cfg_write(struct mdss_ad_info *ad)
+{
+ char __iomem *base = ad->base;
+ u32 temp, temp_calib = MDSS_PP_AD_DEF_CALIB;
+ switch (ad->cfg.mode) {
+ case MDSS_AD_MODE_AUTO_BL:
+ temp = ad->cfg.backlight_max << 16;
+ temp |= ad->cfg.backlight_min & 0xFFFF;
+ writel_relaxed(temp, base + MDSS_MDP_REG_AD_BL_MINMAX);
+ writel_relaxed(ad->cfg.amb_light_min,
+ base + MDSS_MDP_REG_AD_AL_MIN);
+ temp = ad->cfg.filter[1] << 16;
+ temp |= ad->cfg.filter[0] & 0xFFFF;
+ writel_relaxed(temp, base + MDSS_MDP_REG_AD_AL_FILT);
+ case MDSS_AD_MODE_AUTO_STR:
+ pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_AL,
+ ad->cfg.al_calib_lut);
+ writel_relaxed(ad->cfg.strength_limit,
+ base + MDSS_MDP_REG_AD_STR_LIM);
+ temp = ad->cfg.calib[3] << 16;
+ temp |= ad->cfg.calib[2] & 0xFFFF;
+ writel_relaxed(temp, base + MDSS_MDP_REG_AD_CALIB_CD);
+ writel_relaxed(ad->cfg.t_filter_recursion,
+ base + MDSS_MDP_REG_AD_TFILT_CTRL);
+ temp_calib = ad->cfg.calib[0] & 0xFFFF;
+ case MDSS_AD_MODE_TARG_STR:
+ temp = ad->cfg.calib[1] << 16;
+ temp |= temp_calib;
+ writel_relaxed(temp, base + MDSS_MDP_REG_AD_CALIB_AB);
+ case MDSS_AD_MODE_MAN_STR:
+ writel_relaxed(ad->cfg.backlight_scale,
+ base + MDSS_MDP_REG_AD_BL_MAX);
+ writel_relaxed(ad->cfg.mode, base + MDSS_MDP_REG_AD_MODE_SEL);
+ pr_debug("stab_itr = %d", ad->cfg.stab_itr);
+ break;
+ default:
+ break;
+ }
+}
+
+static void pp_ad_vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t)
+{
+ struct mdss_data_type *mdata = ctl->mdata;
+ struct mdss_ad_info *ad;
+
+ if (ctl->mixer_left && ctl->mixer_left->num < mdata->nad_cfgs) {
+ ad = &mdata->ad_cfgs[ctl->mixer_left->num];
+ queue_work(mdata->ad_calc_wq, &ad->calc_work);
+ }
+}
+
+#define MDSS_PP_AD_BYPASS_DEF 0x101
+static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)
+{
+ int ad_num, ret = 0;
+ struct mdss_ad_info *ad;
+ struct mdss_data_type *mdata;
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+ char __iomem *base;
+ u32 bypass = MDSS_PP_AD_BYPASS_DEF;
+
+ ad_num = mdss_ad_init_checks(mfd);
+ if (ad_num < 0)
+ return ad_num;
+
+ mdata = mdss_mdp_get_mdata();
+ ad = &mdata->ad_cfgs[ad_num];
+ base = ad->base;
+
+ mutex_lock(&ad->lock);
+ if (ad->sts != last_sts || ad->state != last_state) {
+ last_sts = ad->sts;
+ last_state = ad->state;
+ pr_debug("begining: ad->sts = 0x%08x, state = 0x%08x", ad->sts,
+ ad->state);
+ }
+ if (!PP_AD_STS_IS_DIRTY(ad->sts) &&
+ (ad->sts & PP_AD_STS_DIRTY_DATA ||
+ (ad->state & PP_AD_STATE_RUN &&
+ (ad->cfg.mode == MDSS_AD_MODE_AUTO_STR)))) {
+ /*
+ * Write inputs to regs when the data has been updated or
+ * Assertive Display is up and running as long as there are
+ * no updates to AD init or cfg
+ */
+ ad->sts &= ~PP_AD_STS_DIRTY_DATA;
+ ad->state |= PP_AD_STATE_DATA;
+ if (mfd->bl_level != ad->last_bl) {
+ ad->last_bl = mfd->bl_level;
+ ad->calc_itr = ad->cfg.stab_itr;
+ ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+ }
+ pp_ad_input_write(ad, mfd->bl_level);
+ }
+
+ if (ad->sts & PP_AD_STS_DIRTY_CFG) {
+ ad->sts &= ~PP_AD_STS_DIRTY_CFG;
+ ad->state |= PP_AD_STATE_CFG;
+
+ pp_ad_cfg_write(ad);
+
+ if (!MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode, ad->ad_data_mode)) {
+ ad->sts &= ~PP_AD_STS_DIRTY_DATA;
+ ad->state &= ~PP_AD_STATE_DATA;
+ pr_debug("Mode switched, data invalidated!");
+ }
+ }
+ if (ad->sts & PP_AD_STS_DIRTY_INIT) {
+ ad->sts &= ~PP_AD_STS_DIRTY_INIT;
+ ad->state |= PP_AD_STATE_INIT;
+ pp_ad_init_write(ad);
+ }
+
+ if ((ad->sts & PP_STS_ENABLE) && PP_AD_STATE_IS_READY(ad->state)) {
+ bypass = 0;
+ ret = 1;
+ ad->state |= PP_AD_STATE_RUN;
+ } else {
+ if (ad->state & PP_AD_STATE_RUN) {
+ ret = 1;
+ ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+ }
+ ad->state &= ~PP_AD_STATE_RUN;
+ }
+ writel_relaxed(bypass, base);
+
+ if (PP_AD_STS_DIRTY_VSYNC & ad->sts) {
+ pr_debug("dirty vsync, calc_itr = %d", ad->calc_itr);
+ ad->sts &= ~PP_AD_STS_DIRTY_VSYNC;
+ if (!(PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr) {
+ ctl->add_vsync_handler(ctl, &ad->handle);
+ ad->state |= PP_AD_STATE_VSYNC;
+ } else if ((PP_AD_STATE_VSYNC & ad->state) &&
+ (!ad->calc_itr || !(PP_AD_STATE_RUN & ad->state))) {
+ ctl->remove_vsync_handler(ctl, &ad->handle);
+ ad->state &= ~PP_AD_STATE_VSYNC;
+ }
+ }
+
+ if (ad->sts != last_sts || ad->state != last_state) {
+ last_sts = ad->sts;
+ last_state = ad->state;
+ pr_debug("end: ad->sts = 0x%08x, state = 0x%08x", ad->sts,
+ ad->state);
+ }
+ mutex_unlock(&ad->lock);
+ return ret;
+}
+
+#define MDSS_PP_AD_SLEEP 10
+static void pp_ad_calc_worker(struct work_struct *work)
+{
+ struct mdss_ad_info *ad;
+ struct mdss_mdp_ctl *ctl;
+ u32 bl, calc_done = 0;
+ ad = container_of(work, struct mdss_ad_info, calc_work);
+ ctl = mfd_to_ctl(ad->mfd);
+
+ mutex_lock(&ad->lock);
+ if (PP_AD_STATE_RUN & ad->state) {
+ /* Kick off calculation */
+ ad->calc_itr--;
+ writel_relaxed(1, ad->base + MDSS_MDP_REG_AD_START_CALC);
+ }
+ if (ad->state & PP_AD_STATE_RUN) {
+ do {
+ calc_done = readl_relaxed(ad->base +
+ MDSS_MDP_REG_AD_CALC_DONE);
+ if (!calc_done)
+ usleep(MDSS_PP_AD_SLEEP);
+ } while (!calc_done && (ad->state & PP_AD_STATE_RUN));
+ if (calc_done) {
+ ad->last_str = 0xFF & readl_relaxed(ad->base +
+ MDSS_MDP_REG_AD_STR_OUT);
+ if (MDSS_AD_RUNNING_AUTO_BL(ad)) {
+ bl = 0xFFFF & readl_relaxed(ad->base +
+ MDSS_MDP_REG_AD_BL_OUT);
+ pr_debug("calc bl = %d", bl);
+ ad->last_str |= bl << 16;
+ mutex_lock(&ad->mfd->bl_lock);
+ mdss_fb_set_backlight(ad->mfd, bl);
+ mutex_unlock(&ad->mfd->bl_lock);
+ }
+ pr_debug("calc_str = %d, calc_itr %d",
+ ad->last_str & 0xFF,
+ ad->calc_itr);
+ } else {
+ ad->last_str = 0xFFFFFFFF;
+ }
+ }
+ complete(&ad->comp);
+
+ if (!ad->calc_itr) {
+ ad->state &= ~PP_AD_STATE_VSYNC;
+ ctl->remove_vsync_handler(ctl, &ad->handle);
+ }
+ mutex_unlock(&ad->lock);
+ mutex_lock(&ad->mfd->lock);
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, BIT(13 + ad->num));
+ mutex_unlock(&ad->mfd->lock);
+}
+
+#define PP_AD_LUT_LEN 33
+static void pp_ad_cfg_lut(char __iomem *offset, u32 *data)
+{
+ int i;
+ u32 temp;
+
+ for (i = 0; i < PP_AD_LUT_LEN - 1; i += 2) {
+ temp = data[i+1] << 16;
+ temp |= (data[i] & 0xFFFF);
+ writel_relaxed(temp, offset + (i*2));
+ }
+ writel_relaxed(data[PP_AD_LUT_LEN - 1] << 16,
+ offset + ((PP_AD_LUT_LEN - 1) * 2));
+}
+
+int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_off)
+{
+ u32 i;
+ int rc = 0;
+
+ mdata->ad_cfgs = devm_kzalloc(&mdata->pdev->dev,
+ sizeof(struct mdss_ad_info) * mdata->nad_cfgs,
+ GFP_KERNEL);
+
+ if (!mdata->ad_cfgs) {
+ pr_err("unable to setup assertive display:devm_kzalloc fail\n");
+ return -ENOMEM;
+ }
+
+ mdata->ad_calc_wq = create_singlethread_workqueue("ad_calc_wq");
+ for (i = 0; i < mdata->nad_cfgs; i++) {
+ mdata->ad_cfgs[i].base = mdata->mdp_base + ad_off[i];
+ mdata->ad_cfgs[i].num = i;
+ mdata->ad_cfgs[i].calc_itr = 0;
+ mdata->ad_cfgs[i].last_str = 0xFFFFFFFF;
+ mutex_init(&mdata->ad_cfgs[i].lock);
+ mdata->ad_cfgs[i].handle.vsync_handler = pp_ad_vsync_handler;
+ INIT_WORK(&mdata->ad_cfgs[i].calc_work, pp_ad_calc_worker);
+ }
+ return rc;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 016c973..5d9396a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -367,6 +367,7 @@
int mdss_mdp_rotator_release(u32 ndx)
{
+ int rc = 0;
struct mdss_mdp_rotator_session *rot;
mutex_lock(&rotator_lock);
rot = mdss_mdp_rotator_session_get(ndx);
@@ -374,11 +375,11 @@
mdss_mdp_rotator_finish(rot);
} else {
pr_warn("unknown session id=%x\n", ndx);
- return -ENOENT;
+ rc = -ENOENT;
}
mutex_unlock(&rotator_lock);
- return 0;
+ return rc;
}
int mdss_mdp_rotator_release_all(void)
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 60f05ca..d1f0c8d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -520,6 +520,11 @@
}
}
+ if (!*start) {
+ pr_err("start address is zero!\n");
+ return -ENOMEM;
+ }
+
if (!ret && (img->offset < data->len)) {
data->addr += img->offset;
data->len -= img->offset;
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 7ccf1b9..1f8244d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -194,6 +194,7 @@
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
+ int rc = 0;
mutex_lock(&mdss_mdp_wb_buf_lock);
if (wb == NULL) {
@@ -202,7 +203,8 @@
mdp5_data->wb = wb;
} else if (mfd->index != wb->fb_ndx) {
pr_err("only one writeback intf supported at a time\n");
- return -EMLINK;
+ rc = -EMLINK;
+ goto error;
} else {
pr_debug("writeback already initialized\n");
}
@@ -217,8 +219,9 @@
init_waitqueue_head(&wb->wait_q);
mdp5_data->wb = wb;
+error:
mutex_unlock(&mdss_mdp_wb_buf_lock);
- return 0;
+ return rc;
}
static int mdss_mdp_wb_terminate(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index d230100..9e8cfa7 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -55,8 +55,35 @@
MAX_PHYS_TARGET_NUM,
};
+/**
+ * enum mdss_intf_events - Different events generated by MDP core
+ *
+ * @MDSS_EVENT_RESET: MDP control path is being (re)initialized.
+ * @MDSS_EVENT_UNBLANK: Sent before first frame update from MDP is
+ * sent to panel.
+ * @MDSS_EVENT_PANEL_ON: After first frame update from MDP.
+ * @MDSS_EVENT_BLANK: MDP has no contents to display only blank screen
+ * is shown in panel. Sent before panel off.
+ * @MDSS_EVENT_PANEL_OFF: MDP has suspended frame updates, panel should be
+ * completely shutdown after this call.
+ * @MDSS_EVENT_CLOSE: MDP has tore down entire session.
+ * @MDSS_EVENT_SUSPEND: Propagation of power suspend event.
+ * @MDSS_EVENT_RESUME: Propagation of power resume event.
+ * @MDSS_EVENT_CHECK_PARAMS: Event generated when a panel reconfiguration is
+ * requested including when resolution changes.
+ * The event handler receives pointer to
+ * struct mdss_panel_info and should return one of:
+ * - negative if the configuration is invalid
+ * - 0 if there is no panel reconfig needed
+ * - 1 if reconfig is needed to take effect
+ * @MDSS_EVENT_CONT_SPLASH_FINISH: Special event used to handle transition of
+ * display state from boot loader to panel driver.
+ * @MDSS_EVENT_FB_REGISTERED: Called after fb dev driver has been registered,
+ * panel driver gets ptr to struct fb_info which
+ * holds fb dev information.
+ */
enum mdss_intf_events {
- MDSS_EVENT_RESET,
+ MDSS_EVENT_RESET = 1,
MDSS_EVENT_UNBLANK,
MDSS_EVENT_PANEL_ON,
MDSS_EVENT_BLANK,
@@ -214,7 +241,18 @@
void (*set_backlight) (struct mdss_panel_data *pdata, u32 bl_level);
unsigned char *mmss_cc_base;
- /* function entry chain */
+ /**
+ * event_handler() - callback handler for MDP core events
+ * @pdata: Pointer refering to the panel struct associated to this
+ * event. Can be used to retrieve panel info.
+ * @e: Event being generated, see enum mdss_intf_events
+ * @arg: Optional argument to pass some info from some events.
+ *
+ * Used to register handler to be used to propagate different events
+ * happening in MDP core driver. Panel driver can listen for any of
+ * these events to perform appropriate actions for panel initialization
+ * and teardown.
+ */
int (*event_handler) (struct mdss_panel_data *pdata, int e, void *arg);
struct mdss_panel_data *next;
diff --git a/drivers/video/msm/mdss/mhl_msc.c b/drivers/video/msm/mdss/mhl_msc.c
index 96e8b67..08d0693 100644
--- a/drivers/video/msm/mdss/mhl_msc.c
+++ b/drivers/video/msm/mdss/mhl_msc.c
@@ -169,6 +169,7 @@
cmd_env = vmalloc(sizeof(struct msc_cmd_envelope));
if (!cmd_env) {
pr_err("%s: out of memory!\n", __func__);
+ mutex_unlock(&msc_send_workqueue_mutex);
return -ENOMEM;
}
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index a3a1a4e..3c11317 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -190,7 +190,7 @@
static irqreturn_t mhl_tx_isr(int irq, void *dev_id);
static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl,
- enum mhl_st_type to_mode);
+ enum mhl_st_type to_mode, bool hpd_off);
static void mhl_init_reg_settings(struct mhl_tx_ctrl *mhl_ctrl,
bool mhl_disc_en);
@@ -703,9 +703,18 @@
}
-static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl, enum mhl_st_type to_mode)
+static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl, enum mhl_st_type to_mode,
+ bool hpd_off)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ unsigned long flags;
+ int rc;
+ struct msm_hdmi_mhl_ops *hdmi_mhl_ops = mhl_ctrl->hdmi_mhl_ops;
+
+ pr_debug("%s: tx pwr on\n", __func__);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
switch (to_mode) {
case POWER_STATE_D0_NO_MHL:
@@ -722,8 +731,11 @@
mhl_ctrl->cur_state = to_mode;
break;
case POWER_STATE_D3:
- if (mhl_ctrl->cur_state == POWER_STATE_D3)
+ if (mhl_ctrl->cur_state == POWER_STATE_D3) {
+ pr_debug("%s: mhl tx already in low power mode\n",
+ __func__);
break;
+ }
/* Force HPD to 0 when not in MHL mode. */
mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
@@ -736,7 +748,12 @@
msleep(50);
if (!mhl_ctrl->disc_enabled)
MHL_SII_REG_NAME_MOD(REG_DISC_CTRL1, BIT1 | BIT0, 0x00);
- MHL_SII_PAGE3_MOD(0x003D, BIT0, 0x00);
+ if (hdmi_mhl_ops && hpd_off) {
+ rc = hdmi_mhl_ops->set_upstream_hpd(
+ mhl_ctrl->pdata->hdmi_pdev, 0);
+ pr_debug("%s: hdmi unset hpd %s\n", __func__,
+ rc ? "failed" : "passed");
+ }
mhl_ctrl->cur_state = POWER_STATE_D3;
break;
default:
@@ -744,6 +761,22 @@
}
}
+static bool is_mhl_powered(void *mhl_ctx)
+{
+ struct mhl_tx_ctrl *mhl_ctrl = (struct mhl_tx_ctrl *)mhl_ctx;
+ unsigned long flags;
+ bool r = false;
+
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ if (mhl_ctrl->tx_powered_off)
+ r = false;
+ else
+ r = true;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+ pr_debug("%s: ret pwr state as %x\n", __func__, r);
+ return r;
+}
void mhl_tmds_ctrl(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on)
{
@@ -759,6 +792,7 @@
void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl, uint8_t to_state)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ unsigned long flags;
pr_debug("%s: To state=[0x%x]\n", __func__, to_state);
if (to_state == HPD_UP) {
@@ -769,10 +803,13 @@
* propogate to src let HPD float by clearing
* HPD OUT OVRRD EN
*/
- MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, 0x00);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, 0);
} else {
/* Drive HPD to DOWN state */
- MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, BIT4);
+ MHL_SII_REG_NAME_MOD(REG_INT_CTRL, (BIT4 | BIT5), BIT4);
}
}
@@ -789,9 +826,7 @@
pr_err("%s: cur st not D0\n", __func__);
return;
}
- /* spin_lock_irqsave(&mhl_state_lock, flags); */
- switch_mode(mhl_ctrl, POWER_STATE_D0_MHL);
- /* spin_unlock_irqrestore(&mhl_state_lock, flags); */
+ switch_mode(mhl_ctrl, POWER_STATE_D0_MHL, true);
MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0x10);
MHL_SII_CBUS_WR(0x07, 0xF2);
@@ -823,19 +858,29 @@
static void mhl_msm_disconnection(struct mhl_tx_ctrl *mhl_ctrl)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
- /*
- * MHL TX CTL1
- * Disabling Tx termination
- */
- MHL_SII_PAGE3_WR(0x30, 0xD0);
+ unsigned long flags;
- switch_mode(mhl_ctrl, POWER_STATE_D3);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->dwnstream_hpd &= ~BIT6;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+ /* disabling Tx termination */
+ MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0xD0);
+ switch_mode(mhl_ctrl, POWER_STATE_D3, true);
}
static int mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl)
{
uint8_t rgnd_imp;
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ struct msm_hdmi_mhl_ops *hdmi_mhl_ops = mhl_ctrl->hdmi_mhl_ops;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
/* DISC STATUS REG 2 */
rgnd_imp = (mhl_i2c_reg_read(client, TX_PAGE_3, 0x001C) &
(BIT1 | BIT0));
@@ -843,6 +888,12 @@
if (0x02 == rgnd_imp) {
pr_debug("%s: mhl sink\n", __func__);
+ if (hdmi_mhl_ops) {
+ rc = hdmi_mhl_ops->set_upstream_hpd(
+ mhl_ctrl->pdata->hdmi_pdev, 1);
+ pr_debug("%s: hdmi set hpd %s\n", __func__,
+ rc ? "failed" : "passed");
+ }
mhl_ctrl->mhl_mode = 1;
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
@@ -850,7 +901,7 @@
} else {
pr_debug("%s: non-mhl sink\n", __func__);
mhl_ctrl->mhl_mode = 0;
- switch_mode(mhl_ctrl, POWER_STATE_D3);
+ switch_mode(mhl_ctrl, POWER_STATE_D3, true);
}
complete(&mhl_ctrl->rgnd_done);
return mhl_ctrl->mhl_mode ?
@@ -904,9 +955,9 @@
}
-static void dev_detect_isr(struct mhl_tx_ctrl *mhl_ctrl)
+static int dev_detect_isr(struct mhl_tx_ctrl *mhl_ctrl)
{
- uint8_t status, reg ;
+ uint8_t status, reg;
struct i2c_client *client = mhl_ctrl->i2c_handle;
/* INTR_STATUS4 */
@@ -916,13 +967,13 @@
if ((0x00 == status) &&\
(mhl_ctrl->cur_state == POWER_STATE_D3)) {
pr_err("%s: invalid intr\n", __func__);
- return;
+ return 0;
}
if (0xFF == status) {
pr_debug("%s: invalid intr 0xff\n", __func__);
MHL_SII_REG_NAME_WR(REG_INTR4, status);
- return;
+ return 0;
}
if ((status & BIT0) && (mhl_ctrl->chip_rev_id < 1)) {
@@ -940,31 +991,35 @@
mhl_msm_connection(mhl_ctrl);
} else if (status & BIT3) {
pr_debug("%s: uUSB-a type dev detct\n", __func__);
+
/* Short RGND */
MHL_SII_REG_NAME_MOD(REG_DISC_STAT2, BIT0 | BIT1, 0x00);
mhl_msm_disconnection(mhl_ctrl);
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
mhl_ctrl->notify_usb_online(0);
+ return -EACCES;
}
if (status & BIT5) {
/* clr intr - reg int4 */
pr_debug("%s: mhl discon: int4 st=%02X\n", __func__,
(int)status);
+
reg = MHL_SII_REG_NAME_RD(REG_INTR4);
MHL_SII_REG_NAME_WR(REG_INTR4, reg);
mhl_msm_disconnection(mhl_ctrl);
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
mhl_ctrl->notify_usb_online(0);
+ return -EACCES;
}
if ((mhl_ctrl->cur_state != POWER_STATE_D0_NO_MHL) &&\
(status & BIT6)) {
/* rgnd rdy Intr */
pr_debug("%s: rgnd ready intr\n", __func__);
- switch_mode(mhl_ctrl, POWER_STATE_D0_NO_MHL);
+ switch_mode(mhl_ctrl, POWER_STATE_D0_NO_MHL, true);
mhl_msm_read_rgnd_int(mhl_ctrl);
}
@@ -981,6 +1036,7 @@
release_usb_switch_open(mhl_ctrl);
}
MHL_SII_REG_NAME_WR(REG_INTR4, status);
+ return 0;
}
static void mhl_misc_isr(struct mhl_tx_ctrl *mhl_ctrl)
@@ -1000,10 +1056,13 @@
static void mhl_hpd_stat_isr(struct mhl_tx_ctrl *mhl_ctrl)
{
- uint8_t intr_1_stat;
- uint8_t cbus_stat;
+ uint8_t intr_1_stat, cbus_stat, t;
+ unsigned long flags;
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ if (!is_mhl_powered(mhl_ctrl))
+ return;
+
/* INTR STATUS 1 */
intr_1_stat = MHL_SII_PAGE0_RD(0x0071);
@@ -1012,6 +1071,7 @@
/* Clear interrupts */
MHL_SII_PAGE0_WR(0x0071, intr_1_stat);
+
if (BIT6 & intr_1_stat) {
/*
* HPD status change event is pending
@@ -1019,11 +1079,26 @@
* MSC REQ ABRT REASON
*/
cbus_stat = MHL_SII_CBUS_RD(0x0D);
- if (BIT6 & cbus_stat)
- mhl_drive_hpd(mhl_ctrl, HPD_UP);
- else
- mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
+ pr_debug("%s: cbus_stat=[0x%02x] cur_pwr=[%u]\n",
+ __func__, cbus_stat, mhl_ctrl->cur_state);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ t = mhl_ctrl->dwnstream_hpd;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+ if (BIT6 & (cbus_stat ^ t)) {
+ u8 status = cbus_stat & BIT6;
+ mhl_drive_hpd(mhl_ctrl, status ? HPD_UP : HPD_DOWN);
+ if (!status) {
+ MHL_SII_PAGE1_MOD(0x003D, BIT0, 0x00);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = true;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ }
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->dwnstream_hpd = cbus_stat;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ }
}
}
@@ -1257,122 +1332,9 @@
}
-static void clear_all_intrs(struct i2c_client *client)
-{
- uint8_t regval = 0x00;
-
- pr_debug_intr("********* exiting isr mask check ?? *************\n");
- pr_debug_intr("int1 mask = %02X\n",
- (int) MHL_SII_REG_NAME_RD(REG_INTR1));
- pr_debug_intr("int3 mask = %02X\n",
- (int) MHL_SII_PAGE0_RD(0x0077));
- pr_debug_intr("int4 mask = %02X\n",
- (int) MHL_SII_REG_NAME_RD(REG_INTR4));
- pr_debug_intr("int5 mask = %02X\n",
- (int) MHL_SII_REG_NAME_RD(REG_INTR5));
- pr_debug_intr("cbus1 mask = %02X\n",
- (int) MHL_SII_CBUS_RD(0x0009));
- pr_debug_intr("cbus2 mask = %02X\n",
- (int) MHL_SII_CBUS_RD(0x001F));
- pr_debug_intr("********* end of isr mask check *************\n");
-
- regval = MHL_SII_REG_NAME_RD(REG_INTR1);
- pr_debug_intr("int1 st = %02X\n", (int)regval);
- MHL_SII_REG_NAME_WR(REG_INTR1, regval);
-
- regval = MHL_SII_REG_NAME_RD(REG_INTR2);
- pr_debug_intr("int2 st = %02X\n", (int)regval);
- MHL_SII_REG_NAME_WR(REG_INTR2, regval);
-
- regval = MHL_SII_PAGE0_RD(0x0073);
- pr_debug_intr("int3 st = %02X\n", (int)regval);
- MHL_SII_PAGE0_WR(0x0073, regval);
-
- regval = MHL_SII_REG_NAME_RD(REG_INTR4);
- pr_debug_intr("int4 st = %02X\n", (int)regval);
- MHL_SII_REG_NAME_WR(REG_INTR4, regval);
-
- regval = MHL_SII_REG_NAME_RD(REG_INTR5);
- pr_debug_intr("int5 st = %02X\n", (int)regval);
- MHL_SII_REG_NAME_WR(REG_INTR5, regval);
-
- regval = MHL_SII_CBUS_RD(0x0008);
- pr_debug_intr("cbusInt st = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x0008, regval);
-
- regval = MHL_SII_CBUS_RD(0x001E);
- pr_debug_intr("CBUS intR_2: %d\n", (int)regval);
- MHL_SII_CBUS_WR(0x001E, regval);
-
- regval = MHL_SII_CBUS_RD(0x00A0);
- pr_debug_intr("A0 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00A0, regval);
-
- regval = MHL_SII_CBUS_RD(0x00A1);
- pr_debug_intr("A1 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00A1, regval);
-
- regval = MHL_SII_CBUS_RD(0x00A2);
- pr_debug_intr("A2 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00A2, regval);
-
- regval = MHL_SII_CBUS_RD(0x00A3);
- pr_debug_intr("A3 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00A3, regval);
-
- regval = MHL_SII_CBUS_RD(0x00B0);
- pr_debug_intr("B0 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00B0, regval);
-
- regval = MHL_SII_CBUS_RD(0x00B1);
- pr_debug_intr("B1 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00B1, regval);
-
- regval = MHL_SII_CBUS_RD(0x00B2);
- pr_debug_intr("B2 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00B2, regval);
-
- regval = MHL_SII_CBUS_RD(0x00B3);
- pr_debug_intr("B3 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00B3, regval);
-
- regval = MHL_SII_CBUS_RD(0x00E0);
- pr_debug_intr("E0 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00E0, regval);
-
- regval = MHL_SII_CBUS_RD(0x00E1);
- pr_debug_intr("E1 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00E1, regval);
-
- regval = MHL_SII_CBUS_RD(0x00E2);
- pr_debug_intr("E2 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00E2, regval);
-
- regval = MHL_SII_CBUS_RD(0x00E3);
- pr_debug_intr("E3 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00E3, regval);
-
- regval = MHL_SII_CBUS_RD(0x00F0);
- pr_debug_intr("F0 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00F0, regval);
-
- regval = MHL_SII_CBUS_RD(0x00F1);
- pr_debug_intr("F1 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00F1, regval);
-
- regval = MHL_SII_CBUS_RD(0x00F2);
- pr_debug_intr("F2 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00F2, regval);
-
- regval = MHL_SII_CBUS_RD(0x00F3);
- pr_debug_intr("F3 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00F3, regval);
- pr_debug_intr("********* end of exiting in isr *************\n");
-}
-
-
static irqreturn_t mhl_tx_isr(int irq, void *data)
{
+ int rc;
struct mhl_tx_ctrl *mhl_ctrl = (struct mhl_tx_ctrl *)data;
pr_debug("%s: Getting Interrupts\n", __func__);
@@ -1380,28 +1342,27 @@
* Check RGND, MHL_EST, CBUS_LOCKOUT, SCDT
* interrupts. In D3, we get only RGND
*/
- dev_detect_isr(mhl_ctrl);
+ rc = dev_detect_isr(mhl_ctrl);
+ if (rc)
+ pr_debug("%s: dev_detect_isr rc=[%d]\n", __func__, rc);
pr_debug("%s: cur pwr state is [0x%x]\n",
__func__, mhl_ctrl->cur_state);
- if (mhl_ctrl->cur_state == POWER_STATE_D0_MHL) {
- /*
- * If dev_detect_isr() didn't move the tx to D3
- * on disconnect, continue to check other
- * interrupt sources.
- */
- mhl_misc_isr(mhl_ctrl);
- /*
- * Check for any peer messages for DCAP_CHG, MSC etc
- * Dispatch to have the CBUS module working only
- * once connected.
- */
- mhl_cbus_isr(mhl_ctrl);
- mhl_hpd_stat_isr(mhl_ctrl);
- }
+ /*
+ * If dev_detect_isr() didn't move the tx to D3
+ * on disconnect, continue to check other
+ * interrupt sources.
+ */
+ mhl_misc_isr(mhl_ctrl);
- clear_all_intrs(mhl_ctrl->i2c_handle);
+ /*
+ * Check for any peer messages for DCAP_CHG, MSC etc
+ * Dispatch to have the CBUS module working only
+ * once connected.
+ */
+ mhl_cbus_isr(mhl_ctrl);
+ mhl_hpd_stat_isr(mhl_ctrl);
return IRQ_HANDLED;
}
@@ -1410,6 +1371,13 @@
{
uint8_t chip_rev_id = 0x00;
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ unsigned long flags;
+
+
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->dwnstream_hpd = 0;
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
/* Reset the TX chip */
mhl_sii_reset_pin(mhl_ctrl, 0);
@@ -1428,7 +1396,7 @@
* MHL-USB handshake is implemented
*/
mhl_init_reg_settings(mhl_ctrl, true);
- switch_mode(mhl_ctrl, POWER_STATE_D3);
+ switch_mode(mhl_ctrl, POWER_STATE_D3, true);
return 0;
}
@@ -1710,6 +1678,7 @@
mhl_ctrl->cur_state = POWER_STATE_D0_MHL;
INIT_LIST_HEAD(&mhl_ctrl->list_cmd);
init_completion(&mhl_ctrl->msc_cmd_done);
+ spin_lock_init(&mhl_ctrl->lock);
mhl_ctrl->msc_send_workqueue = create_singlethread_workqueue
("mhl_msc_cmd_queue");
@@ -1813,7 +1782,7 @@
pr_debug("%s: i2c client addr is [%x]\n", __func__, client->addr);
if (mhl_ctrl->pdata->hdmi_pdev) {
rc = msm_hdmi_register_mhl(mhl_ctrl->pdata->hdmi_pdev,
- hdmi_mhl_ops);
+ hdmi_mhl_ops, mhl_ctrl);
if (rc) {
pr_err("%s: register with hdmi failed\n", __func__);
rc = -EPROBE_DEFER;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 2b07e43..5564ceb 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -275,8 +275,8 @@
} else {
MIPI_OUTP(ctrl_base + 0x0220, 0x006);
- usleep(10);
MIPI_OUTP(ctrl_base + 0x0470, 0x000);
+ MIPI_OUTP(ctrl_base + 0x0598, 0x000);
wmb();
}
}
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 2f77d29..73b94af 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -286,7 +286,7 @@
MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_LOW,
- MSG_LVL_HIGH,
+ MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
@@ -725,7 +725,7 @@
/* LOG CODES */
#define LOG_0 0x0
-#define LOG_1 0x17F4
+#define LOG_1 0x17FA
#define LOG_2 0x0
#define LOG_3 0x0
#define LOG_4 0x4910
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index c219725..aa1eba5 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -229,7 +229,15 @@
DMX_EVENT_MARKER = 0x00000100,
/* New indexing entry is ready */
- DMX_EVENT_NEW_INDEX_ENTRY = 0x00000200
+ DMX_EVENT_NEW_INDEX_ENTRY = 0x00000200,
+
+ /*
+ * Section filter timer expired. This is notified
+ * when timeout is configured to section filter
+ * (dmx_sct_filter_params) and no sections were
+ * received for the given time.
+ */
+ DMX_EVENT_SECTION_TIMEOUT = 0x00000400
};
enum dmx_oob_cmd {
@@ -706,6 +714,46 @@
__u64 types;
};
+struct dmx_set_ts_insertion {
+ /*
+ * Unique identifier managed by the caller.
+ * This identifier can be used later to remove the
+ * insertion using DMX_ABORT_TS_INSERTION ioctl.
+ */
+ __u32 identifier;
+
+ /*
+ * Repetition time in msec, minimum allowed value is 25msec.
+ * 0 repetition time means one-shot insertion is done.
+ * Insertion done based on wall-clock.
+ */
+ __u32 repetition_time;
+
+ /*
+ * TS packets buffer to be inserted.
+ * The buffer is inserted as-is to the recording buffer
+ * without any modification.
+ * It is advised to set discontinuity flag in the very
+ * first TS packet in the buffer.
+ */
+ const __u8 *ts_packets;
+
+ /*
+ * Size in bytes of the TS packets buffer to be inserted.
+ * Should be in multiples of 188 or 192 bytes
+ * depending on recording filter output format.
+ */
+ size_t size;
+};
+
+struct dmx_abort_ts_insertion {
+ /*
+ * Identifier of the insertion buffer previously set
+ * using DMX_SET_TS_INSERTION.
+ */
+ __u32 identifier;
+};
+
#define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42)
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
@@ -734,5 +782,7 @@
#define DMX_GET_EVENTS_MASK _IOR('o', 67, struct dmx_events_mask)
#define DMX_PUSH_OOB_COMMAND _IOW('o', 68, struct dmx_oob_command)
#define DMX_SET_INDEXING_PARAMS _IOW('o', 69, struct dmx_indexing_params)
+#define DMX_SET_TS_INSERTION _IOW('o', 70, struct dmx_set_ts_insertion)
+#define DMX_ABORT_TS_INSERTION _IOW('o', 71, struct dmx_abort_ts_insertion)
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/input/gen_vkeys.h b/include/linux/input/gen_vkeys.h
index ce29351..a58158d 100644
--- a/include/linux/input/gen_vkeys.h
+++ b/include/linux/input/gen_vkeys.h
@@ -19,5 +19,6 @@
int panel_maxy;
int *keycodes;
int num_keys;
+ int y_offset;
};
#endif
diff --git a/include/linux/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
index c6e4ab3..b7ba6fb 100644
--- a/include/linux/mfd/wcd9xxx/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.h
@@ -126,6 +126,7 @@
u8 bias2_cap_mode;
u8 bias3_cap_mode;
u8 bias4_cap_mode;
+ bool bias2_is_headset_only;
};
struct wcd9xxx_ocp_setting {
diff --git a/include/linux/mfd/wcd9xxx/wcd9304_registers.h b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
index a7f9e4a..8e5e23a 100644
--- a/include/linux/mfd/wcd9xxx/wcd9304_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -473,17 +473,17 @@
#define SITAR_A_CDC_TX3_DMIC_CTL (0x235)
#define SITAR_A_CDC_TX3_DMIC_CTL__POR (0x00000000)
-#define SITAR_A_CDC_TX4_VOL_CTL_TIMER (0x239)
+#define SITAR_A_CDC_TX4_VOL_CTL_TIMER (0x238)
#define SITAR_A_CDC_TX4_VOL_CTL_TIMER__POR (0x00000000)
-#define SITAR_A_CDC_TX4_VOL_CTL_GAIN (0x23A)
+#define SITAR_A_CDC_TX4_VOL_CTL_GAIN (0x239)
#define SITAR_A_CDC_TX4_VOL_CTL_GAIN__POR (0x00000000)
-#define SITAR_A_CDC_TX4_VOL_CTL_CFG (0x23B)
+#define SITAR_A_CDC_TX4_VOL_CTL_CFG (0x23A)
#define SITAR_A_CDC_TX4_VOL_CTL_CFG__POR (0x00000000)
-#define SITAR_A_CDC_TX4_MUX_CTL (0x23C)
+#define SITAR_A_CDC_TX4_MUX_CTL (0x23B)
#define SITAR_A_CDC_TX4_MUX_CTL__POR (0x00000008)
-#define SITAR_A_CDC_TX4_CLK_FS_CTL (0x23D)
+#define SITAR_A_CDC_TX4_CLK_FS_CTL (0x23C)
#define SITAR_A_CDC_TX4_CLK_FS_CTL__POR (0x00000003)
-#define SITAR_A_CDC_TX4_DMIC_CTL (0x23E)
+#define SITAR_A_CDC_TX4_DMIC_CTL (0x23D)
#define SITAR_A_CDC_TX4_DMIC_CTL__POR (0x00000000)
#define SITAR_A_CDC_TX5_VOL_CTL_TIMER (0x240)
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index d8eb494..a66a411 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -158,6 +158,9 @@
int scrpd_busy;
int wr_burst_pending;
struct completion req_write_done;
+ spinlock_t lock;
+ bool tx_powered_off;
+ uint8_t dwnstream_hpd;
};
int mhl_i2c_reg_read(struct i2c_client *client,
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 9eef3a0..48be19a 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -82,6 +82,12 @@
#define MMC_SET_DRIVER_TYPE_D 3
};
+/* states to represent load on the host */
+enum mmc_load {
+ MMC_LOAD_HIGH,
+ MMC_LOAD_LOW,
+};
+
struct mmc_host_ops {
/*
* 'enable' is called when the host is claimed and 'disable' is called
@@ -140,6 +146,7 @@
void (*hw_reset)(struct mmc_host *host);
unsigned long (*get_max_frequency)(struct mmc_host *host);
unsigned long (*get_min_frequency)(struct mmc_host *host);
+ int (*notify_load)(struct mmc_host *, enum mmc_load);
int (*stop_request)(struct mmc_host *host);
unsigned int (*get_xfer_remain)(struct mmc_host *host);
};
@@ -401,6 +408,7 @@
bool initialized;
bool in_progress;
struct delayed_work work;
+ enum mmc_load state;
} clk_scaling;
unsigned long private[0] ____cacheline_aligned;
};
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ca7a586..d63232a 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -72,11 +72,9 @@
#ifdef CONFIG_CMA
bool is_cma_pageblock(struct page *page);
# define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
-# define cma_wmark_pages(zone) zone->min_cma_pages
#else
# define is_cma_pageblock(page) false
# define is_migrate_cma(migratetype) false
-# define cma_wmark_pages(zone) 0
#endif
#define for_each_migratetype_order(order, type) \
@@ -385,11 +383,6 @@
seqlock_t span_seqlock;
#endif
#ifdef CONFIG_CMA
- /*
- * CMA needs to increase watermark levels during the allocation
- * process to make sure that the system is not starved.
- */
- unsigned long min_cma_pages;
bool cma_alloc;
#endif
struct free_area free_area[MAX_ORDER];
diff --git a/include/linux/msm_audio_ion.h b/include/linux/msm_audio_ion.h
index 83e5dff..38b27bf 100644
--- a/include/linux/msm_audio_ion.h
+++ b/include/linux/msm_audio_ion.h
@@ -13,7 +13,12 @@
#ifndef _LINUX_MSM_AUDIO_ION_H
#define _LINUX_MSM_AUDIO_ION_H
-
+#ifdef CONFIG_SND_SOC_QDSP6V2
+#include <sound/q6asm-v2.h>
+#else
+#include <sound/q6asm.h>
+#endif
+#include <sound/pcm.h>
#include <linux/msm_ion.h>
@@ -26,9 +31,11 @@
unsigned long *ionflag, size_t bufsz,
ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr);
int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle);
-
+int msm_audio_ion_mmap(struct audio_buffer *substream,
+ struct vm_area_struct *vma);
bool msm_audio_ion_is_smmu_available(void);
+int msm_audio_ion_cache_operations(struct audio_buffer *abuff, int cache_op);
#ifdef CONFIG_SND_SOC_QDSP6V2
struct ion_client *msm_audio_ion_client_create(unsigned int heap_mask,
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 2ad040e..e8de769 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -769,7 +769,7 @@
struct kgsl_perfcounter_read_group {
unsigned int groupid;
unsigned int countable;
- uint64_t value;
+ unsigned long long value;
};
struct kgsl_perfcounter_read {
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index f9e483c..61e9cb1 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -613,6 +613,7 @@
uint16_t calib[4];
uint8_t strength_limit;
uint8_t t_filter_recursion;
+ uint16_t stab_itr;
};
/* ops uses standard MDP_PP_* flags */
@@ -631,6 +632,7 @@
uint32_t amb_light;
uint32_t strength;
} in;
+ uint32_t output;
};
enum {
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 6e30ca2..1de9aaa 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -127,6 +127,7 @@
POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */
POWER_SUPPLY_PROP_SCOPE,
POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
+ POWER_SUPPLY_PROP_RESISTANCE,
/* Properties of type `const char *' */
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
diff --git a/include/linux/qpnp/power-on.h b/include/linux/qpnp/power-on.h
index 85dbce9..6394988 100644
--- a/include/linux/qpnp/power-on.h
+++ b/include/linux/qpnp/power-on.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -17,8 +17,10 @@
#ifdef CONFIG_QPNP_POWER_ON
int qpnp_pon_system_pwr_off(bool reset);
+int qpnp_pon_is_warm_reset(void);
#else
static int qpnp_pon_system_pwr_off(bool reset) { return -ENODEV; }
+static inline int qpnp_pon_is_warm_reset(void) { return -ENODEV; }
#endif
#endif
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 15e5dc9..dfb156f 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -197,15 +197,18 @@
/**
* enum qpnp_adc_scale_fn_type - Scaling function for pm8941 pre calibrated
* digital data relative to ADC reference.
- * %ADC_SCALE_DEFAULT: Default scaling to convert raw adc code to voltage.
- * %ADC_SCALE_BATT_THERM: Conversion to temperature based on btm parameters.
- * %ADC_SCALE_THERM_100K_PULLUP: Returns temperature in degC.
+ * %SCALE_DEFAULT: Default scaling to convert raw adc code to voltage (uV).
+ * %SCALE_BATT_THERM: Conversion to temperature(decidegC) based on btm
+ * parameters.
+ * %SCALE_THERM_100K_PULLUP: Returns temperature in degC.
* Uses a mapping table with 100K pullup.
- * %ADC_SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
- * %ADC_SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade.
- * %ADC_SCALE_THERM_150K_PULLUP: Returns temperature in degC.
+ * %SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
+ * %SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade.
+ * %SCALE_THERM_150K_PULLUP: Returns temperature in degC.
* Uses a mapping table with 150K pullup.
- * %ADC_SCALE_NONE: Do not use this scaling type.
+ * %SCALE_QRD_BATT_THERM: Conversion to temperature(decidegC) based on
+ * btm parameters.
+ * %SCALE_NONE: Do not use this scaling type.
*/
enum qpnp_adc_scale_fn_type {
SCALE_DEFAULT = 0,
@@ -214,6 +217,7 @@
SCALE_PMIC_THERM,
SCALE_XOTHERM,
SCALE_THERM_150K_PULLUP,
+ SCALE_QRD_BATT_THERM,
SCALE_NONE,
};
@@ -598,6 +602,34 @@
QPNP_ADC_TM_CH_SELECT_NONE
};
+enum qpnp_comp_scheme_type {
+ COMP_ID_GF = 0,
+ COMP_ID_SMIC,
+ COMP_ID_TSMC,
+ COMP_ID_NUM,
+};
+
+enum qpnp_iadc_rev {
+ QPNP_IADC_VER_3_0 = 0x1,
+ QPNP_IADC_VER_3_1 = 0x3,
+};
+
+#define QPNP_VBAT_SNS_COEFF_1_TYPEA 3000
+#define QPNP_VBAT_SNS_COEFF_2_TYPEA 45810000
+#define QPNP_VBAT_SNS_COEFF_3 100000
+#define QPNP_VBAT_SNS_COEFF_1_TYPEB 3500
+#define QPNP_VBAT_SNS_COEFF_2_TYPEB 80000000
+
+#define QPNP_COEFF_1 969000
+#define QPNP_COEFF_2 34
+#define QPNP_COEFF_3_TYPEA 1700000
+#define QPNP_COEFF_3_TYPEB 1000000
+#define QPNP_COEFF_4 100
+#define QPNP_COEFF_5 15000
+#define QPNP_COEFF_6 100000
+#define QPNP_COEFF_7 21700
+#define QPNP_COEFF_8 100000000
+
/**
* struct qpnp_adc_tm_config - Represent ADC Thermal Monitor configuration.
* @channel: ADC channel for which thermal monitoring is requested.
@@ -1039,7 +1071,7 @@
/**
* qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
- * gain and offset. Returns the temperature in degC.
+ * gain and offset. Returns the temperature in decidegC.
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
@@ -1052,6 +1084,21 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
/**
+ * qpnp_adc_scale_qrd_batt_therm() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. Returns the temperature in decidegC.
+ * @adc_code: pre-calibrated digital ouput of the ADC.
+ * @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: physical result to be stored.
+ */
+int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
* qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset.
@@ -1233,6 +1280,11 @@
*/
int32_t qpnp_vadc_iadc_sync_complete_request(
enum qpnp_vadc_channels channel, struct qpnp_vadc_result *result);
+/**
+ * qpnp_vadc_sns_comp_result() - Compensate vbatt readings based on temperature
+ * @result: Voltage in uV that needs compensation.
+ */
+int32_t qpnp_vbat_sns_comp_result(int64_t *result);
#else
static inline int32_t qpnp_vadc_read(uint32_t channel,
struct qpnp_vadc_result *result)
@@ -1257,6 +1309,11 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+{ return -ENXIO; }
static inline int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
@@ -1312,6 +1369,8 @@
enum qpnp_vadc_channels channel,
struct qpnp_vadc_result *result)
{ return -ENXIO; }
+static inline int32_t qpnp_vbat_sns_comp_result(int64_t *result)
+{ return -ENXIO; }
#endif
/* Public API */
@@ -1365,6 +1424,7 @@
* @result: 0 on success.
*/
int32_t qpnp_iadc_calibrate_for_trim(void);
+int32_t qpnp_iadc_comp_result(int64_t *result);
#else
static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
struct qpnp_iadc_result *result)
@@ -1382,6 +1442,8 @@
{ return -ENXIO; }
static inline int32_t qpnp_iadc_calibrate_for_trim(void)
{ return -ENXIO; }
+static inline int32_t qpnp_iadc_comp_result(int64_t *result, int32_t sign)
+{ return -ENXIO; }
#endif
/* Public API */
diff --git a/include/linux/regulator/cpr-regulator.h b/include/linux/regulator/cpr-regulator.h
index b6fc091..6387913 100644
--- a/include/linux/regulator/cpr-regulator.h
+++ b/include/linux/regulator/cpr-regulator.h
@@ -35,7 +35,6 @@
CPR_CORNER_SVS = 1,
CPR_CORNER_NORMAL,
CPR_CORNER_TURBO,
- CPR_CORNER_SUPER_TURBO,
CPR_CORNER_MAX,
};
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 3622616..4ae3b79 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -222,6 +222,7 @@
bool enable_lpm_on_dev_suspend;
bool core_clk_always_on_workaround;
bool delay_lpm_on_disconnect;
+ bool delay_lpm_hndshk_on_disconnect;
bool dp_manual_pullup;
bool enable_sec_phy;
struct msm_bus_scale_pdata *bus_scale_table;
@@ -462,10 +463,13 @@
int (*notify)(void *, int, void (*)(int online));
void *ctxt;
};
-
+#ifdef CONFIG_USB_BAM
+bool msm_bam_lpm_ok(void);
+#else
+static inline bool msm_bam_lpm_ok(void) { return true; }
+#endif
#ifdef CONFIG_USB_CI13XXX_MSM
void msm_hw_bam_disable(bool bam_disable);
-
#else
static inline void msm_hw_bam_disable(bool bam_disable)
{
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 74b09cb..323f1e7 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -700,6 +700,9 @@
#define V4L2_QCOM_BUF_FLAG_CODECCONFIG 0x4000
#define V4L2_QCOM_BUF_FLAG_EOSEQ 0x8000
#define V4L2_QCOM_BUF_TIMESTAMP_INVALID 0x10000
+#define V4L2_QCOM_BUF_FLAG_IDRFRAME 0x20000 /* Image is a IDR-frame */
+#define V4L2_QCOM_BUF_FLAG_DECODEONLY 0x40000
+#define V4L2_QCOM_BUF_DATA_CORRUPT 0x80000
/*
* O V E R L A Y P R E V I E W
@@ -1837,6 +1840,7 @@
V4L2_MPEG_VIDC_INDEX_EXTRADATA_INPUT_CROP,
V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM,
V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
+ V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP
};
#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
(V4L2_CID_MPEG_MSM_VIDC_BASE + 23)
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 2319c48..da56df6 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -33,6 +33,7 @@
#define WCNSS_WLAN_IRQ_INVALID -1
#define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1
#define HAVE_WCNSS_RESET_INTR 1
+#define HAVE_WCNSS_CAL_DOWNLOAD 1
struct device *wcnss_wlan_get_device(void);
struct resource *wcnss_wlan_get_memory_map(struct device *dev);
@@ -65,7 +66,7 @@
void wcnss_resume_notify(void);
void wcnss_riva_log_debug_regs(void);
void wcnss_pronto_log_debug_regs(void);
-int wcnss_cold_boot_done(void);
+int wcnss_device_ready(void);
#define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
#define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 992649f..47cf184 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -289,8 +289,8 @@
enum eeprom_cfg_type_t {
CFG_EEPROM_GET_INFO,
- CFG_EEPROM_GET_DATA,
- CFG_EEPROM_READ_DATA,
+ CFG_EEPROM_GET_CAL_DATA,
+ CFG_EEPROM_READ_CAL_DATA,
CFG_EEPROM_WRITE_DATA,
};
struct eeprom_get_t {
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index f632ad6..2164275 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -73,6 +73,16 @@
unsigned int aspect_height;
};
+struct msm_vidc_mpeg2_seqdisp_payload {
+ unsigned int video_format;
+ bool color_descp;
+ unsigned int color_primaries;
+ unsigned int transfer_char;
+ unsigned int matrix_coeffs;
+ unsigned int disp_width;
+ unsigned int disp_height;
+};
+
struct msm_vidc_panscan_window {
unsigned int panscan_height_offset;
unsigned int panscan_width_offset;
@@ -94,6 +104,7 @@
EXTRADATA_FRAME_RATE = 0x00000007,
EXTRADATA_PANSCAN_WINDOW = 0x00000008,
EXTRADATA_RECOVERY_POINT_SEI = 0x00000009,
+ EXTRADATA_MPEG2_SEQDISP = 0x0000000D,
EXTRADATA_MULTISLICE_INFO = 0x7F100000,
EXTRADATA_NUM_CONCEALED_MB = 0x7F100001,
EXTRADATA_INDEX = 0x7F100002,
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index bf6b23b..3775ddd 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -64,6 +64,7 @@
EVERY_8FRAME,
EVERY_16FRAME,
EVERY_32FRAME,
+ SKIP_ALL,
MAX_SKIP,
};
diff --git a/include/media/radio-iris-commands.h b/include/media/radio-iris-commands.h
index d41baa9..0b3331a 100644
--- a/include/media/radio-iris-commands.h
+++ b/include/media/radio-iris-commands.h
@@ -71,6 +71,7 @@
V4L2_CID_PRIVATE_CF0TH12,
V4L2_CID_PRIVATE_SINRFIRSTSTAGE,
V4L2_CID_PRIVATE_RMSSIFIRSTSTAGE,
+ V4L2_CID_PRIVATE_RXREPEATCOUNT,
/*using private CIDs under userclass*/
V4L2_CID_PRIVATE_IRIS_READ_DEFAULT = 0x00980928,
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index 53602c5..d6151c0 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -73,6 +73,9 @@
#define CF0TH12_BYTE4_OFFSET 11
#define MAX_SINR_FIRSTSTAGE 127
#define MAX_RMSSI_FIRSTSTAGE 127
+#define RDS_PS0_XFR_MODE 0x01
+#define RDS_PS0_LEN 6
+#define RX_REPEATE_BYTE_OFFSET 5
/* HCI timeouts */
#define RADIO_HCI_TIMEOUT (10000) /* 10 seconds */
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 42c8823..35c57c0 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -1145,6 +1145,11 @@
__le16 opcode;
} __packed;
+#define HCI_EV_HARDWARE_ERROR 0x10
+struct hci_ev_hardware_error {
+ __u8 hw_err_code;
+} __packed;
+
#define HCI_EV_ROLE_CHANGE 0x12
struct hci_ev_role_change {
__u8 status;
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index fa4dedc..0d3b5a0 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -634,8 +634,6 @@
* when a new port is added here. */
#define PRIMARY_I2S_RX 0 /* index = 0 */
#define PRIMARY_I2S_TX 1 /* index = 1 */
-#define PCM_RX 2 /* index = 2 */
-#define PCM_TX 3 /* index = 3 */
#define SECONDARY_I2S_RX 4 /* index = 4 */
#define SECONDARY_I2S_TX 5 /* index = 5 */
#define MI2S_RX 6 /* index = 6 */
@@ -784,26 +782,6 @@
#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX 0x4008
/* SLIMbus Tx port on channel 4. */
#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX 0x4009
-/* SLIMbus Rx port on channel 0. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX 0x4000
-/* SLIMbus Tx port on channel 0. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX 0x4001
-/* SLIMbus Rx port on channel 1. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX 0x4002
-/* SLIMbus Tx port on channel 1. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX 0x4003
-/* SLIMbus Rx port on channel 2. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX 0x4004
-/* SLIMbus Tx port on channel 2. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX 0x4005
-/* SLIMbus Rx port on channel 3. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_RX 0x4006
-/* SLIMbus Tx port on channel 3. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX 0x4007
-/* SLIMbus Rx port on channel 4. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX 0x4008
-/* SLIMbus Tx port on channel 4. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX 0x4009
/* SLIMbus Rx port on channel 5. */
#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX 0x400a
/* SLIMbus Tx port on channel 5. */
@@ -2259,7 +2237,7 @@
*/
#define ADSP_MEMORY_MAP_PHYSICAL_MEMORY 0
-
+#define NULL_COPP_TOPOLOGY 0x00010312
#define DEFAULT_COPP_TOPOLOGY 0x00010be3
#define DEFAULT_POPP_TOPOLOGY 0x00010be4
#define VPM_TX_SM_ECNS_COPP_TOPOLOGY 0x00010F71
@@ -6538,6 +6516,11 @@
#define AANC_HW_BLOCK_VERSION_1 (1)
#define AANC_HW_BLOCK_VERSION_2 (2)
+/*Clip bank selection*/
+#define AFE_API_VERSION_CLIP_BANK_SEL_CFG 0x1
+#define AFE_CLIP_MAX_BANKS 4
+#define AFE_PARAM_ID_CLIP_BANK_SEL_CFG 0x00010242
+
struct afe_param_aanc_port_cfg {
/* Minor version used for tracking the version of the module's
* source port configuration.
@@ -6572,6 +6555,18 @@
uint32_t aanc_hw_version;
} __packed;
+struct afe_param_id_clip_bank_sel {
+ /* Minor version used for tracking the version of the module's
+ * hw version
+ */
+ uint32_t minor_version;
+
+ /* Number of banks to be read */
+ uint32_t num_banks;
+
+ uint32_t bank_map[AFE_CLIP_MAX_BANKS];
+} __packed;
+
/* ERROR CODES */
/* Success. The operation completed with no errors. */
#define ADSP_EOK 0x00000000
@@ -6804,6 +6799,8 @@
AFE_SLIMBUS_SLAVE_CONFIG,
AFE_CDC_REGISTERS_CONFIG,
AFE_AANC_VERSION,
+ AFE_CDC_CLIP_REGISTERS_CONFIG,
+ AFE_CLIP_BANK_SEL,
AFE_MAX_CONFIG_TYPES,
};
@@ -6925,4 +6922,16 @@
/* Dolby DAP topology */
#define DOLBY_ADM_COPP_TOPOLOGY_ID 0x0001033B
+struct afe_svc_cmd_set_clip_bank_selection {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_clip_bank_sel bank_sel;
+} __packed;
+
+/* Ultrasound supported formats */
+#define US_POINT_EPOS_FORMAT 0x00012310
+#define US_RAW_FORMAT 0x0001127C
+#define US_PROX_FORMAT 0x0001272B
+
#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 40b0e1e..a7933a4 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1262,7 +1262,7 @@
#define MPEG4_MULTI_AAC 0x00010D86
#define US_POINT_EPOS_FORMAT 0x00012310
#define US_RAW_FORMAT 0x0001127C
-#define US_PROX_FORMAT 0x00012721
+#define US_PROX_FORMAT 0x0001272B
#define MULTI_CHANNEL_PCM 0x00010C66
#define ASM_ENCDEC_SBCRATE 0x00010C13
@@ -1453,6 +1453,23 @@
u32 read_format;
} __attribute__((packed));
+#define ASM_STREAM_CMD_OPEN_LOOPBACK 0x00010D6E
+struct asm_stream_cmd_open_loopback {
+ struct apr_hdr hdr;
+ u32 mode_flags;
+/* Mode flags.
+ * Bit 0-31: reserved; client should set these bits to 0
+ */
+ u16 src_endpointype;
+ /* Endpoint type. 0 = Tx Matrix */
+ u16 sink_endpointype;
+ /* Endpoint type. 0 = Rx Matrix */
+ u32 postprocopo_id;
+/* Postprocessor topology ID. Specifies the topology of
+ * postprocessing algorithms.
+ */
+} __packed;
+
#define ADM_CMD_CONNECT_AFE_PORT 0x00010320
#define ADM_CMD_DISCONNECT_AFE_PORT 0x00010321
@@ -1909,5 +1926,4 @@
int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params);
/* SRS Studio Sound 3D end */
-
#endif /*_APR_AUDIO_H_*/
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 4bea1e1..449694e 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -47,10 +47,10 @@
int adm_memory_unmap_regions(int port_id, uint32_t *buf_add, uint32_t *bufsz,
uint32_t bufcnt);
-int adm_close(int port);
+int adm_close(int port, bool perf_mode);
int adm_matrix_map(int session_id, int path, int num_copps,
- unsigned int *port_id, int copp_id);
+ unsigned int *port_id, int copp_id, bool perf_mode);
int adm_connect_afe_port(int mode, int session_id, int port_id);
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 2a740f4..1389b2a 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -41,8 +41,8 @@
enum {
IDX_PRIMARY_I2S_RX = 0,
IDX_PRIMARY_I2S_TX = 1,
- IDX_PCM_RX = 2,
- IDX_PCM_TX = 3,
+ IDX_AFE_PORT_ID_PRIMARY_PCM_RX = 2,
+ IDX_AFE_PORT_ID_PRIMARY_PCM_TX = 3,
IDX_SECONDARY_I2S_RX = 4,
IDX_SECONDARY_I2S_TX = 5,
IDX_MI2S_RX = 6,
@@ -166,7 +166,7 @@
int afe_port_start(u16 port_id, union afe_port_config *afe_config,
u32 rate);
int afe_spk_prot_feed_back_cfg(int src_port, int dst_port,
- int l_ch, int r_ch);
+ int l_ch, int r_ch, u32 enable);
int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib);
int afe_port_stop_nowait(int port_id);
int afe_apply_gain(u16 port_id, u16 gain);
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 0dd14e6..2138689 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -70,7 +70,6 @@
#define COMPRESSED_IO 0x0040
#define NT_MODE 0x0400
-
#define NO_TIMESTAMP 0xFF00
#define SET_TIMESTAMP 0x0000
@@ -79,6 +78,19 @@
#define SESSION_MAX 0x08
+/* payload structure bytes */
+#define READDONE_IDX_STATUS 0
+#define READDONE_IDX_BUFADD_LSW 1
+#define READDONE_IDX_BUFADD_MSW 2
+#define READDONE_IDX_MEMMAP_HDL 3
+#define READDONE_IDX_SIZE 4
+#define READDONE_IDX_OFFSET 5
+#define READDONE_IDX_LSW_TS 6
+#define READDONE_IDX_MSW_TS 7
+#define READDONE_IDX_FLAGS 8
+#define READDONE_IDX_NUMFRAMES 9
+#define READDONE_IDX_SEQ_ID 10
+
#define SOFT_PAUSE_PERIOD 30 /* ramp up/down for 30ms */
#define SOFT_PAUSE_STEP 2000 /* Step value 2ms or 2000us */
enum {
@@ -153,6 +165,8 @@
wait_queue_head_t cmd_wait;
wait_queue_head_t time_wait;
bool perf_mode;
+ /* audio cache operations fptr*/
+ int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
};
void q6asm_audio_client_free(struct audio_client *ac);
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 406407d..41f875b 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -207,6 +207,8 @@
uint32_t rd_format,
uint32_t wr_format);
+int q6asm_open_loopack(struct audio_client *ac);
+
int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
uint32_t lsw_ts, uint32_t flags);
int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h
index e76e822..909e1b9 100644
--- a/include/trace/events/kmem.h
+++ b/include/trace/events/kmem.h
@@ -557,6 +557,46 @@
unsigned int order),
TP_ARGS(gfp_flags, order)
+
+ );
+
+DECLARE_EVENT_CLASS(smmu_map,
+
+ TP_PROTO(unsigned int va,
+ phys_addr_t pa,
+ unsigned int chunk_size,
+ size_t len),
+
+ TP_ARGS(va, pa, chunk_size, len),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, va)
+ __field(phys_addr_t, pa)
+ __field(unsigned int, chunk_size)
+ __field(size_t, len)
+ ),
+
+ TP_fast_assign(
+ __entry->va = va;
+ __entry->pa = pa;
+ __entry->chunk_size = chunk_size;
+ __entry->len = len;
+ ),
+
+ TP_printk("v_addr=%p p_addr=%pa chunk_size=0x%x len=%zu",
+ (void *)__entry->va,
+ &__entry->pa,
+ __entry->chunk_size,
+ __entry->len)
+ );
+
+DEFINE_EVENT(smmu_map, iommu_map_range,
+ TP_PROTO(unsigned int va,
+ phys_addr_t pa,
+ unsigned int chunk_size,
+ size_t len),
+
+ TP_ARGS(va, pa, chunk_size, len)
);
#endif /* _TRACE_KMEM_H */
diff --git a/include/trace/events/workqueue.h b/include/trace/events/workqueue.h
index 7d49729..82f61f4 100644
--- a/include/trace/events/workqueue.h
+++ b/include/trace/events/workqueue.h
@@ -54,7 +54,7 @@
__entry->function = work->func;
__entry->workqueue = cwq->wq;
__entry->req_cpu = req_cpu;
- __entry->cpu = cwq->gcwq->cpu;
+ __entry->cpu = cwq->pool->gcwq->cpu;
),
TP_printk("work struct=%p function=%pf workqueue=%p req_cpu=%u cpu=%u",
diff --git a/include/video/msm_hdmi_modes.h b/include/video/msm_hdmi_modes.h
index a15272b..ced6acb 100644
--- a/include/video/msm_hdmi_modes.h
+++ b/include/video/msm_hdmi_modes.h
@@ -122,9 +122,10 @@
#define HDMI_EVFRMT_END HDMI_VFRMT_4096x2160p24_16_9
/* VESA DMT TIMINGS */
-#define HDMI_VFRMT_2560x1600p60_16_9 (HDMI_EVFRMT_END + 1)
+#define HDMI_VFRMT_1024x768p60_4_3 (HDMI_EVFRMT_END + 1)
#define HDMI_VFRMT_1280x1024p60_5_4 (HDMI_EVFRMT_END + 2)
-#define VESA_DMT_VFRMT_END HDMI_VFRMT_1280x1024p60_5_4
+#define HDMI_VFRMT_2560x1600p60_16_9 (HDMI_EVFRMT_END + 3)
+#define VESA_DMT_VFRMT_END HDMI_VFRMT_2560x1600p60_16_9
#define HDMI_VFRMT_MAX (VESA_DMT_VFRMT_END + 1)
#define HDMI_VFRMT_FORCE_32BIT 0x7FFFFFFF
@@ -183,6 +184,9 @@
#define HDMI_VFRMT_1920x1080p30_16_9_TIMING \
{HDMI_VFRMT_1920x1080p30_16_9, 1920, 88, 44, 148, false, \
1080, 4, 5, 36, false, 74250, 30000, false, true}
+#define HDMI_VFRMT_1024x768p60_4_3_TIMING \
+ {HDMI_VFRMT_1024x768p60_4_3, 1024, 24, 136, 160, false, \
+ 768, 2, 6, 29, false, 65000, 60000, false, true}
#define HDMI_VFRMT_1280x1024p60_5_4_TIMING \
{HDMI_VFRMT_1280x1024p60_5_4, 1280, 48, 112, 248, false, \
1024, 1, 3, 38, false, 108000, 60000, false, true}
@@ -249,6 +253,7 @@
}
if (type & MSM_HDMI_MODES_DVI) {
+ MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1024x768p60_4_3);
MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_1280x1024p60_5_4);
MSM_HDMI_MODES_SET_TIMING(lut, HDMI_VFRMT_2560x1600p60_16_9);
}
@@ -326,8 +331,9 @@
case HDMI_VFRMT_3840x2160p25_16_9: return "3840x2160 p25 16/9";
case HDMI_VFRMT_3840x2160p24_16_9: return "3840x2160 p24 16/9";
case HDMI_VFRMT_4096x2160p24_16_9: return "4096x2160 p24 16/9";
+ case HDMI_VFRMT_1024x768p60_4_3: return "1024x768 p60 4/3";
+ case HDMI_VFRMT_1280x1024p60_5_4: return "1280x1024 p60 5/4";
case HDMI_VFRMT_2560x1600p60_16_9: return "2560x1600 p60 16/9";
- case HDMI_VFRMT_1280x1024p60_5_4: return "1280x1042 p60 5/4";
default: return "???";
}
}
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index e6a2e35..edd656c 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -224,13 +224,10 @@
raw_spin_unlock(&base->cpu_base->lock);
raw_spin_lock(&new_base->cpu_base->lock);
- this_cpu = smp_processor_id();
-
- if (cpu != this_cpu && (hrtimer_check_target(timer, new_base)
- || !cpu_online(cpu))) {
+ if (cpu != this_cpu && hrtimer_check_target(timer, new_base)) {
+ cpu = this_cpu;
raw_spin_unlock(&new_base->cpu_base->lock);
raw_spin_lock(&base->cpu_base->lock);
- cpu = smp_processor_id();
timer->base = base;
goto again;
}
diff --git a/kernel/timer.c b/kernel/timer.c
index 24c5d20..cf7217a 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1679,12 +1679,12 @@
boot_done = 1;
base = &boot_tvec_bases;
}
+ spin_lock_init(&base->lock);
tvec_base_done[cpu] = 1;
} else {
base = per_cpu(tvec_bases, cpu);
}
- spin_lock_init(&base->lock);
for (j = 0; j < TVN_SIZE; j++) {
INIT_LIST_HEAD(base->tv5.vec + j);
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 5abf42f..f1a6e9e 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -46,11 +46,12 @@
enum {
/* global_cwq flags */
- GCWQ_MANAGE_WORKERS = 1 << 0, /* need to manage workers */
- GCWQ_MANAGING_WORKERS = 1 << 1, /* managing workers */
- GCWQ_DISASSOCIATED = 1 << 2, /* cpu can't serve workers */
- GCWQ_FREEZING = 1 << 3, /* freeze in progress */
- GCWQ_HIGHPRI_PENDING = 1 << 4, /* highpri works on queue */
+ GCWQ_DISASSOCIATED = 1 << 0, /* cpu can't serve workers */
+ GCWQ_FREEZING = 1 << 1, /* freeze in progress */
+
+ /* pool flags */
+ POOL_MANAGE_WORKERS = 1 << 0, /* need to manage workers */
+ POOL_MANAGING_WORKERS = 1 << 1, /* managing workers */
/* worker flags */
WORKER_STARTED = 1 << 0, /* started */
@@ -72,6 +73,8 @@
TRUSTEE_RELEASE = 3, /* release workers */
TRUSTEE_DONE = 4, /* trustee is done */
+ NR_WORKER_POOLS = 2, /* # worker pools per gcwq */
+
BUSY_WORKER_HASH_ORDER = 6, /* 64 pointers */
BUSY_WORKER_HASH_SIZE = 1 << BUSY_WORKER_HASH_ORDER,
BUSY_WORKER_HASH_MASK = BUSY_WORKER_HASH_SIZE - 1,
@@ -91,6 +94,7 @@
* all cpus. Give -20.
*/
RESCUER_NICE_LEVEL = -20,
+ HIGHPRI_NICE_LEVEL = -20,
};
/*
@@ -115,6 +119,7 @@
*/
struct global_cwq;
+struct worker_pool;
/*
* The poor guys doing the actual heavy lifting. All on-duty workers
@@ -131,7 +136,7 @@
struct cpu_workqueue_struct *current_cwq; /* L: current_work's cwq */
struct list_head scheduled; /* L: scheduled works */
struct task_struct *task; /* I: worker task */
- struct global_cwq *gcwq; /* I: the associated gcwq */
+ struct worker_pool *pool; /* I: the associated pool */
/* 64 bytes boundary on 64bit, 32 on 32bit */
unsigned long last_active; /* L: last active timestamp */
unsigned int flags; /* X: flags */
@@ -139,6 +144,22 @@
struct work_struct rebind_work; /* L: rebind worker to cpu */
};
+struct worker_pool {
+ struct global_cwq *gcwq; /* I: the owning gcwq */
+ unsigned int flags; /* X: flags */
+
+ struct list_head worklist; /* L: list of pending works */
+ int nr_workers; /* L: total number of workers */
+ int nr_idle; /* L: currently idle ones */
+
+ struct list_head idle_list; /* X: list of idle workers */
+ struct timer_list idle_timer; /* L: worker idle timeout */
+ struct timer_list mayday_timer; /* L: SOS timer for workers */
+
+ struct ida worker_ida; /* L: for worker IDs */
+ struct worker *first_idle; /* L: first idle worker */
+};
+
/*
* Global per-cpu workqueue. There's one and only one for each cpu
* and all works are queued and processed here regardless of their
@@ -146,27 +167,18 @@
*/
struct global_cwq {
spinlock_t lock; /* the gcwq lock */
- struct list_head worklist; /* L: list of pending works */
unsigned int cpu; /* I: the associated cpu */
unsigned int flags; /* L: GCWQ_* flags */
- int nr_workers; /* L: total number of workers */
- int nr_idle; /* L: currently idle ones */
-
- /* workers are chained either in the idle_list or busy_hash */
- struct list_head idle_list; /* X: list of idle workers */
+ /* workers are chained either in busy_hash or pool idle_list */
struct hlist_head busy_hash[BUSY_WORKER_HASH_SIZE];
/* L: hash of busy workers */
- struct timer_list idle_timer; /* L: worker idle timeout */
- struct timer_list mayday_timer; /* L: SOS timer for dworkers */
-
- struct ida worker_ida; /* L: for worker IDs */
+ struct worker_pool pools[2]; /* normal and highpri pools */
struct task_struct *trustee; /* L: for gcwq shutdown */
unsigned int trustee_state; /* L: trustee state */
wait_queue_head_t trustee_wait; /* trustee wait */
- struct worker *first_idle; /* L: first idle worker */
} ____cacheline_aligned_in_smp;
/*
@@ -175,7 +187,7 @@
* aligned at two's power of the number of flag bits.
*/
struct cpu_workqueue_struct {
- struct global_cwq *gcwq; /* I: the associated gcwq */
+ struct worker_pool *pool; /* I: the associated pool */
struct workqueue_struct *wq; /* I: the owning workqueue */
int work_color; /* L: current color */
int flush_color; /* L: flushing color */
@@ -264,6 +276,10 @@
#define CREATE_TRACE_POINTS
#include <trace/events/workqueue.h>
+#define for_each_worker_pool(pool, gcwq) \
+ for ((pool) = &(gcwq)->pools[0]; \
+ (pool) < &(gcwq)->pools[NR_WORKER_POOLS]; (pool)++)
+
#define for_each_busy_worker(worker, i, pos, gcwq) \
for (i = 0; i < BUSY_WORKER_HASH_SIZE; i++) \
hlist_for_each_entry(worker, pos, &gcwq->busy_hash[i], hentry)
@@ -444,7 +460,7 @@
* try_to_wake_up(). Put it in a separate cacheline.
*/
static DEFINE_PER_CPU(struct global_cwq, global_cwq);
-static DEFINE_PER_CPU_SHARED_ALIGNED(atomic_t, gcwq_nr_running);
+static DEFINE_PER_CPU_SHARED_ALIGNED(atomic_t, pool_nr_running[NR_WORKER_POOLS]);
/*
* Global cpu workqueue and nr_running counter for unbound gcwq. The
@@ -452,10 +468,17 @@
* workers have WORKER_UNBOUND set.
*/
static struct global_cwq unbound_global_cwq;
-static atomic_t unbound_gcwq_nr_running = ATOMIC_INIT(0); /* always 0 */
+static atomic_t unbound_pool_nr_running[NR_WORKER_POOLS] = {
+ [0 ... NR_WORKER_POOLS - 1] = ATOMIC_INIT(0), /* always 0 */
+};
static int worker_thread(void *__worker);
+static int worker_pool_pri(struct worker_pool *pool)
+{
+ return pool - pool->gcwq->pools;
+}
+
static struct global_cwq *get_gcwq(unsigned int cpu)
{
if (cpu != WORK_CPU_UNBOUND)
@@ -464,12 +487,15 @@
return &unbound_global_cwq;
}
-static atomic_t *get_gcwq_nr_running(unsigned int cpu)
+static atomic_t *get_pool_nr_running(struct worker_pool *pool)
{
+ int cpu = pool->gcwq->cpu;
+ int idx = worker_pool_pri(pool);
+
if (cpu != WORK_CPU_UNBOUND)
- return &per_cpu(gcwq_nr_running, cpu);
+ return &per_cpu(pool_nr_running, cpu)[idx];
else
- return &unbound_gcwq_nr_running;
+ return &unbound_pool_nr_running[idx];
}
static struct cpu_workqueue_struct *get_cwq(unsigned int cpu,
@@ -555,7 +581,7 @@
if (data & WORK_STRUCT_CWQ)
return ((struct cpu_workqueue_struct *)
- (data & WORK_STRUCT_WQ_DATA_MASK))->gcwq;
+ (data & WORK_STRUCT_WQ_DATA_MASK))->pool->gcwq;
cpu = data >> WORK_STRUCT_FLAG_BITS;
if (cpu == WORK_CPU_NONE)
@@ -566,60 +592,62 @@
}
/*
- * Policy functions. These define the policies on how the global
- * worker pool is managed. Unless noted otherwise, these functions
- * assume that they're being called with gcwq->lock held.
+ * Policy functions. These define the policies on how the global worker
+ * pools are managed. Unless noted otherwise, these functions assume that
+ * they're being called with gcwq->lock held.
*/
-static bool __need_more_worker(struct global_cwq *gcwq)
+static bool __need_more_worker(struct worker_pool *pool)
{
- return !atomic_read(get_gcwq_nr_running(gcwq->cpu)) ||
- gcwq->flags & GCWQ_HIGHPRI_PENDING;
+ return !atomic_read(get_pool_nr_running(pool));
}
/*
* Need to wake up a worker? Called from anything but currently
* running workers.
+ *
+ * Note that, because unbound workers never contribute to nr_running, this
+ * function will always return %true for unbound gcwq as long as the
+ * worklist isn't empty.
*/
-static bool need_more_worker(struct global_cwq *gcwq)
+static bool need_more_worker(struct worker_pool *pool)
{
- return !list_empty(&gcwq->worklist) && __need_more_worker(gcwq);
+ return !list_empty(&pool->worklist) && __need_more_worker(pool);
}
/* Can I start working? Called from busy but !running workers. */
-static bool may_start_working(struct global_cwq *gcwq)
+static bool may_start_working(struct worker_pool *pool)
{
- return gcwq->nr_idle;
+ return pool->nr_idle;
}
/* Do I need to keep working? Called from currently running workers. */
-static bool keep_working(struct global_cwq *gcwq)
+static bool keep_working(struct worker_pool *pool)
{
- atomic_t *nr_running = get_gcwq_nr_running(gcwq->cpu);
+ atomic_t *nr_running = get_pool_nr_running(pool);
- return !list_empty(&gcwq->worklist) &&
- (atomic_read(nr_running) <= 1 ||
- gcwq->flags & GCWQ_HIGHPRI_PENDING);
+ return !list_empty(&pool->worklist) && atomic_read(nr_running) <= 1;
}
/* Do we need a new worker? Called from manager. */
-static bool need_to_create_worker(struct global_cwq *gcwq)
+static bool need_to_create_worker(struct worker_pool *pool)
{
- return need_more_worker(gcwq) && !may_start_working(gcwq);
+ return need_more_worker(pool) && !may_start_working(pool);
}
/* Do I need to be the manager? */
-static bool need_to_manage_workers(struct global_cwq *gcwq)
+static bool need_to_manage_workers(struct worker_pool *pool)
{
- return need_to_create_worker(gcwq) || gcwq->flags & GCWQ_MANAGE_WORKERS;
+ return need_to_create_worker(pool) ||
+ (pool->flags & POOL_MANAGE_WORKERS);
}
/* Do we have too many workers and should some go away? */
-static bool too_many_workers(struct global_cwq *gcwq)
+static bool too_many_workers(struct worker_pool *pool)
{
- bool managing = gcwq->flags & GCWQ_MANAGING_WORKERS;
- int nr_idle = gcwq->nr_idle + managing; /* manager is considered idle */
- int nr_busy = gcwq->nr_workers - nr_idle;
+ bool managing = pool->flags & POOL_MANAGING_WORKERS;
+ int nr_idle = pool->nr_idle + managing; /* manager is considered idle */
+ int nr_busy = pool->nr_workers - nr_idle;
return nr_idle > 2 && (nr_idle - 2) * MAX_IDLE_WORKERS_RATIO >= nr_busy;
}
@@ -629,26 +657,26 @@
*/
/* Return the first worker. Safe with preemption disabled */
-static struct worker *first_worker(struct global_cwq *gcwq)
+static struct worker *first_worker(struct worker_pool *pool)
{
- if (unlikely(list_empty(&gcwq->idle_list)))
+ if (unlikely(list_empty(&pool->idle_list)))
return NULL;
- return list_first_entry(&gcwq->idle_list, struct worker, entry);
+ return list_first_entry(&pool->idle_list, struct worker, entry);
}
/**
* wake_up_worker - wake up an idle worker
- * @gcwq: gcwq to wake worker for
+ * @pool: worker pool to wake worker from
*
- * Wake up the first idle worker of @gcwq.
+ * Wake up the first idle worker of @pool.
*
* CONTEXT:
* spin_lock_irq(gcwq->lock).
*/
-static void wake_up_worker(struct global_cwq *gcwq)
+static void wake_up_worker(struct worker_pool *pool)
{
- struct worker *worker = first_worker(gcwq);
+ struct worker *worker = first_worker(pool);
if (likely(worker))
wake_up_process(worker->task);
@@ -670,7 +698,7 @@
struct worker *worker = kthread_data(task);
if (!(worker->flags & WORKER_NOT_RUNNING))
- atomic_inc(get_gcwq_nr_running(cpu));
+ atomic_inc(get_pool_nr_running(worker->pool));
}
/**
@@ -692,8 +720,8 @@
unsigned int cpu)
{
struct worker *worker = kthread_data(task), *to_wakeup = NULL;
- struct global_cwq *gcwq = get_gcwq(cpu);
- atomic_t *nr_running = get_gcwq_nr_running(cpu);
+ struct worker_pool *pool = worker->pool;
+ atomic_t *nr_running = get_pool_nr_running(pool);
if (worker->flags & WORKER_NOT_RUNNING)
return NULL;
@@ -712,8 +740,8 @@
* could be manipulating idle_list, so dereferencing idle_list
* without gcwq lock is safe.
*/
- if (atomic_dec_and_test(nr_running) && !list_empty(&gcwq->worklist))
- to_wakeup = first_worker(gcwq);
+ if (atomic_dec_and_test(nr_running) && !list_empty(&pool->worklist))
+ to_wakeup = first_worker(pool);
return to_wakeup ? to_wakeup->task : NULL;
}
@@ -733,7 +761,7 @@
static inline void worker_set_flags(struct worker *worker, unsigned int flags,
bool wakeup)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
WARN_ON_ONCE(worker->task != current);
@@ -744,12 +772,12 @@
*/
if ((flags & WORKER_NOT_RUNNING) &&
!(worker->flags & WORKER_NOT_RUNNING)) {
- atomic_t *nr_running = get_gcwq_nr_running(gcwq->cpu);
+ atomic_t *nr_running = get_pool_nr_running(pool);
if (wakeup) {
if (atomic_dec_and_test(nr_running) &&
- !list_empty(&gcwq->worklist))
- wake_up_worker(gcwq);
+ !list_empty(&pool->worklist))
+ wake_up_worker(pool);
} else
atomic_dec(nr_running);
}
@@ -769,7 +797,7 @@
*/
static inline void worker_clr_flags(struct worker *worker, unsigned int flags)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
unsigned int oflags = worker->flags;
WARN_ON_ONCE(worker->task != current);
@@ -783,7 +811,7 @@
*/
if ((flags & WORKER_NOT_RUNNING) && (oflags & WORKER_NOT_RUNNING))
if (!(worker->flags & WORKER_NOT_RUNNING))
- atomic_inc(get_gcwq_nr_running(gcwq->cpu));
+ atomic_inc(get_pool_nr_running(pool));
}
/**
@@ -867,43 +895,6 @@
}
/**
- * gcwq_determine_ins_pos - find insertion position
- * @gcwq: gcwq of interest
- * @cwq: cwq a work is being queued for
- *
- * A work for @cwq is about to be queued on @gcwq, determine insertion
- * position for the work. If @cwq is for HIGHPRI wq, the work is
- * queued at the head of the queue but in FIFO order with respect to
- * other HIGHPRI works; otherwise, at the end of the queue. This
- * function also sets GCWQ_HIGHPRI_PENDING flag to hint @gcwq that
- * there are HIGHPRI works pending.
- *
- * CONTEXT:
- * spin_lock_irq(gcwq->lock).
- *
- * RETURNS:
- * Pointer to inserstion position.
- */
-static inline struct list_head *gcwq_determine_ins_pos(struct global_cwq *gcwq,
- struct cpu_workqueue_struct *cwq)
-{
- struct work_struct *twork;
-
- if (likely(!(cwq->wq->flags & WQ_HIGHPRI)))
- return &gcwq->worklist;
-
- list_for_each_entry(twork, &gcwq->worklist, entry) {
- struct cpu_workqueue_struct *tcwq = get_work_cwq(twork);
-
- if (!(tcwq->wq->flags & WQ_HIGHPRI))
- break;
- }
-
- gcwq->flags |= GCWQ_HIGHPRI_PENDING;
- return &twork->entry;
-}
-
-/**
* insert_work - insert a work into gcwq
* @cwq: cwq @work belongs to
* @work: work to insert
@@ -920,7 +911,7 @@
struct work_struct *work, struct list_head *head,
unsigned int extra_flags)
{
- struct global_cwq *gcwq = cwq->gcwq;
+ struct worker_pool *pool = cwq->pool;
/* we own @work, set data and link */
set_work_cwq(work, cwq, extra_flags);
@@ -940,8 +931,8 @@
*/
smp_mb();
- if (__need_more_worker(gcwq))
- wake_up_worker(gcwq);
+ if (__need_more_worker(pool))
+ wake_up_worker(pool);
}
/*
@@ -1040,7 +1031,7 @@
if (likely(cwq->nr_active < cwq->max_active)) {
trace_workqueue_activate_work(work);
cwq->nr_active++;
- worklist = gcwq_determine_ins_pos(gcwq, cwq);
+ worklist = &cwq->pool->worklist;
} else {
work_flags |= WORK_STRUCT_DELAYED;
worklist = &cwq->delayed_works;
@@ -1189,7 +1180,8 @@
*/
static void worker_enter_idle(struct worker *worker)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
BUG_ON(worker->flags & WORKER_IDLE);
BUG_ON(!list_empty(&worker->entry) &&
@@ -1197,22 +1189,27 @@
/* can't use worker_set_flags(), also called from start_worker() */
worker->flags |= WORKER_IDLE;
- gcwq->nr_idle++;
+ pool->nr_idle++;
worker->last_active = jiffies;
/* idle_list is LIFO */
- list_add(&worker->entry, &gcwq->idle_list);
+ list_add(&worker->entry, &pool->idle_list);
if (likely(!(worker->flags & WORKER_ROGUE))) {
- if (too_many_workers(gcwq) && !timer_pending(&gcwq->idle_timer))
- mod_timer(&gcwq->idle_timer,
+ if (too_many_workers(pool) && !timer_pending(&pool->idle_timer))
+ mod_timer(&pool->idle_timer,
jiffies + IDLE_WORKER_TIMEOUT);
} else
wake_up_all(&gcwq->trustee_wait);
- /* sanity check nr_running */
- WARN_ON_ONCE(gcwq->nr_workers == gcwq->nr_idle &&
- atomic_read(get_gcwq_nr_running(gcwq->cpu)));
+ /*
+ * Sanity check nr_running. Because trustee releases gcwq->lock
+ * between setting %WORKER_ROGUE and zapping nr_running, the
+ * warning may trigger spuriously. Check iff trustee is idle.
+ */
+ WARN_ON_ONCE(gcwq->trustee_state == TRUSTEE_DONE &&
+ pool->nr_workers == pool->nr_idle &&
+ atomic_read(get_pool_nr_running(pool)));
}
/**
@@ -1226,11 +1223,11 @@
*/
static void worker_leave_idle(struct worker *worker)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
BUG_ON(!(worker->flags & WORKER_IDLE));
worker_clr_flags(worker, WORKER_IDLE);
- gcwq->nr_idle--;
+ pool->nr_idle--;
list_del_init(&worker->entry);
}
@@ -1267,7 +1264,7 @@
static bool worker_maybe_bind_and_lock(struct worker *worker)
__acquires(&gcwq->lock)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct global_cwq *gcwq = worker->pool->gcwq;
struct task_struct *task = worker->task;
while (true) {
@@ -1309,7 +1306,7 @@
static void worker_rebind_fn(struct work_struct *work)
{
struct worker *worker = container_of(work, struct worker, rebind_work);
- struct global_cwq *gcwq = worker->gcwq;
+ struct global_cwq *gcwq = worker->pool->gcwq;
if (worker_maybe_bind_and_lock(worker))
worker_clr_flags(worker, WORKER_REBIND);
@@ -1334,10 +1331,10 @@
/**
* create_worker - create a new workqueue worker
- * @gcwq: gcwq the new worker will belong to
+ * @pool: pool the new worker will belong to
* @bind: whether to set affinity to @cpu or not
*
- * Create a new worker which is bound to @gcwq. The returned worker
+ * Create a new worker which is bound to @pool. The returned worker
* can be started by calling start_worker() or destroyed using
* destroy_worker().
*
@@ -1347,16 +1344,18 @@
* RETURNS:
* Pointer to the newly created worker.
*/
-static struct worker *create_worker(struct global_cwq *gcwq, bool bind)
+static struct worker *create_worker(struct worker_pool *pool, bool bind)
{
+ struct global_cwq *gcwq = pool->gcwq;
bool on_unbound_cpu = gcwq->cpu == WORK_CPU_UNBOUND;
+ const char *pri = worker_pool_pri(pool) ? "H" : "";
struct worker *worker = NULL;
int id = -1;
spin_lock_irq(&gcwq->lock);
- while (ida_get_new(&gcwq->worker_ida, &id)) {
+ while (ida_get_new(&pool->worker_ida, &id)) {
spin_unlock_irq(&gcwq->lock);
- if (!ida_pre_get(&gcwq->worker_ida, GFP_KERNEL))
+ if (!ida_pre_get(&pool->worker_ida, GFP_KERNEL))
goto fail;
spin_lock_irq(&gcwq->lock);
}
@@ -1366,20 +1365,22 @@
if (!worker)
goto fail;
- worker->gcwq = gcwq;
+ worker->pool = pool;
worker->id = id;
if (!on_unbound_cpu)
worker->task = kthread_create_on_node(worker_thread,
- worker,
- cpu_to_node(gcwq->cpu),
- "kworker/%u:%d", gcwq->cpu, id);
+ worker, cpu_to_node(gcwq->cpu),
+ "kworker/%u:%d%s", gcwq->cpu, id, pri);
else
worker->task = kthread_create(worker_thread, worker,
- "kworker/u:%d", id);
+ "kworker/u:%d%s", id, pri);
if (IS_ERR(worker->task))
goto fail;
+ if (worker_pool_pri(pool))
+ set_user_nice(worker->task, HIGHPRI_NICE_LEVEL);
+
/*
* A rogue worker will become a regular one if CPU comes
* online later on. Make sure every worker has
@@ -1397,7 +1398,7 @@
fail:
if (id >= 0) {
spin_lock_irq(&gcwq->lock);
- ida_remove(&gcwq->worker_ida, id);
+ ida_remove(&pool->worker_ida, id);
spin_unlock_irq(&gcwq->lock);
}
kfree(worker);
@@ -1416,7 +1417,7 @@
static void start_worker(struct worker *worker)
{
worker->flags |= WORKER_STARTED;
- worker->gcwq->nr_workers++;
+ worker->pool->nr_workers++;
worker_enter_idle(worker);
wake_up_process(worker->task);
}
@@ -1432,7 +1433,8 @@
*/
static void destroy_worker(struct worker *worker)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
int id = worker->id;
/* sanity check frenzy */
@@ -1440,9 +1442,9 @@
BUG_ON(!list_empty(&worker->scheduled));
if (worker->flags & WORKER_STARTED)
- gcwq->nr_workers--;
+ pool->nr_workers--;
if (worker->flags & WORKER_IDLE)
- gcwq->nr_idle--;
+ pool->nr_idle--;
list_del_init(&worker->entry);
worker->flags |= WORKER_DIE;
@@ -1453,29 +1455,30 @@
kfree(worker);
spin_lock_irq(&gcwq->lock);
- ida_remove(&gcwq->worker_ida, id);
+ ida_remove(&pool->worker_ida, id);
}
-static void idle_worker_timeout(unsigned long __gcwq)
+static void idle_worker_timeout(unsigned long __pool)
{
- struct global_cwq *gcwq = (void *)__gcwq;
+ struct worker_pool *pool = (void *)__pool;
+ struct global_cwq *gcwq = pool->gcwq;
spin_lock_irq(&gcwq->lock);
- if (too_many_workers(gcwq)) {
+ if (too_many_workers(pool)) {
struct worker *worker;
unsigned long expires;
/* idle_list is kept in LIFO order, check the last one */
- worker = list_entry(gcwq->idle_list.prev, struct worker, entry);
+ worker = list_entry(pool->idle_list.prev, struct worker, entry);
expires = worker->last_active + IDLE_WORKER_TIMEOUT;
if (time_before(jiffies, expires))
- mod_timer(&gcwq->idle_timer, expires);
+ mod_timer(&pool->idle_timer, expires);
else {
/* it's been idle for too long, wake up manager */
- gcwq->flags |= GCWQ_MANAGE_WORKERS;
- wake_up_worker(gcwq);
+ pool->flags |= POOL_MANAGE_WORKERS;
+ wake_up_worker(pool);
}
}
@@ -1492,7 +1495,7 @@
return false;
/* mayday mayday mayday */
- cpu = cwq->gcwq->cpu;
+ cpu = cwq->pool->gcwq->cpu;
/* WORK_CPU_UNBOUND can't be set in cpumask, use cpu 0 instead */
if (cpu == WORK_CPU_UNBOUND)
cpu = 0;
@@ -1501,37 +1504,38 @@
return true;
}
-static void gcwq_mayday_timeout(unsigned long __gcwq)
+static void gcwq_mayday_timeout(unsigned long __pool)
{
- struct global_cwq *gcwq = (void *)__gcwq;
+ struct worker_pool *pool = (void *)__pool;
+ struct global_cwq *gcwq = pool->gcwq;
struct work_struct *work;
spin_lock_irq(&gcwq->lock);
- if (need_to_create_worker(gcwq)) {
+ if (need_to_create_worker(pool)) {
/*
* We've been trying to create a new worker but
* haven't been successful. We might be hitting an
* allocation deadlock. Send distress signals to
* rescuers.
*/
- list_for_each_entry(work, &gcwq->worklist, entry)
+ list_for_each_entry(work, &pool->worklist, entry)
send_mayday(work);
}
spin_unlock_irq(&gcwq->lock);
- mod_timer(&gcwq->mayday_timer, jiffies + MAYDAY_INTERVAL);
+ mod_timer(&pool->mayday_timer, jiffies + MAYDAY_INTERVAL);
}
/**
* maybe_create_worker - create a new worker if necessary
- * @gcwq: gcwq to create a new worker for
+ * @pool: pool to create a new worker for
*
- * Create a new worker for @gcwq if necessary. @gcwq is guaranteed to
+ * Create a new worker for @pool if necessary. @pool is guaranteed to
* have at least one idle worker on return from this function. If
* creating a new worker takes longer than MAYDAY_INTERVAL, mayday is
- * sent to all rescuers with works scheduled on @gcwq to resolve
+ * sent to all rescuers with works scheduled on @pool to resolve
* possible allocation deadlock.
*
* On return, need_to_create_worker() is guaranteed to be false and
@@ -1546,52 +1550,54 @@
* false if no action was taken and gcwq->lock stayed locked, true
* otherwise.
*/
-static bool maybe_create_worker(struct global_cwq *gcwq)
+static bool maybe_create_worker(struct worker_pool *pool)
__releases(&gcwq->lock)
__acquires(&gcwq->lock)
{
- if (!need_to_create_worker(gcwq))
+ struct global_cwq *gcwq = pool->gcwq;
+
+ if (!need_to_create_worker(pool))
return false;
restart:
spin_unlock_irq(&gcwq->lock);
/* if we don't make progress in MAYDAY_INITIAL_TIMEOUT, call for help */
- mod_timer(&gcwq->mayday_timer, jiffies + MAYDAY_INITIAL_TIMEOUT);
+ mod_timer(&pool->mayday_timer, jiffies + MAYDAY_INITIAL_TIMEOUT);
while (true) {
struct worker *worker;
- worker = create_worker(gcwq, true);
+ worker = create_worker(pool, true);
if (worker) {
- del_timer_sync(&gcwq->mayday_timer);
+ del_timer_sync(&pool->mayday_timer);
spin_lock_irq(&gcwq->lock);
start_worker(worker);
- BUG_ON(need_to_create_worker(gcwq));
+ BUG_ON(need_to_create_worker(pool));
return true;
}
- if (!need_to_create_worker(gcwq))
+ if (!need_to_create_worker(pool))
break;
__set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(CREATE_COOLDOWN);
- if (!need_to_create_worker(gcwq))
+ if (!need_to_create_worker(pool))
break;
}
- del_timer_sync(&gcwq->mayday_timer);
+ del_timer_sync(&pool->mayday_timer);
spin_lock_irq(&gcwq->lock);
- if (need_to_create_worker(gcwq))
+ if (need_to_create_worker(pool))
goto restart;
return true;
}
/**
* maybe_destroy_worker - destroy workers which have been idle for a while
- * @gcwq: gcwq to destroy workers for
+ * @pool: pool to destroy workers for
*
- * Destroy @gcwq workers which have been idle for longer than
+ * Destroy @pool workers which have been idle for longer than
* IDLE_WORKER_TIMEOUT.
*
* LOCKING:
@@ -1602,19 +1608,19 @@
* false if no action was taken and gcwq->lock stayed locked, true
* otherwise.
*/
-static bool maybe_destroy_workers(struct global_cwq *gcwq)
+static bool maybe_destroy_workers(struct worker_pool *pool)
{
bool ret = false;
- while (too_many_workers(gcwq)) {
+ while (too_many_workers(pool)) {
struct worker *worker;
unsigned long expires;
- worker = list_entry(gcwq->idle_list.prev, struct worker, entry);
+ worker = list_entry(pool->idle_list.prev, struct worker, entry);
expires = worker->last_active + IDLE_WORKER_TIMEOUT;
if (time_before(jiffies, expires)) {
- mod_timer(&gcwq->idle_timer, expires);
+ mod_timer(&pool->idle_timer, expires);
break;
}
@@ -1647,23 +1653,24 @@
*/
static bool manage_workers(struct worker *worker)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
bool ret = false;
- if (gcwq->flags & GCWQ_MANAGING_WORKERS)
+ if (pool->flags & POOL_MANAGING_WORKERS)
return ret;
- gcwq->flags &= ~GCWQ_MANAGE_WORKERS;
- gcwq->flags |= GCWQ_MANAGING_WORKERS;
+ pool->flags &= ~POOL_MANAGE_WORKERS;
+ pool->flags |= POOL_MANAGING_WORKERS;
/*
* Destroy and then create so that may_start_working() is true
* on return.
*/
- ret |= maybe_destroy_workers(gcwq);
- ret |= maybe_create_worker(gcwq);
+ ret |= maybe_destroy_workers(pool);
+ ret |= maybe_create_worker(pool);
- gcwq->flags &= ~GCWQ_MANAGING_WORKERS;
+ pool->flags &= ~POOL_MANAGING_WORKERS;
/*
* The trustee might be waiting to take over the manager
@@ -1720,10 +1727,9 @@
{
struct work_struct *work = list_first_entry(&cwq->delayed_works,
struct work_struct, entry);
- struct list_head *pos = gcwq_determine_ins_pos(cwq->gcwq, cwq);
trace_workqueue_activate_work(work);
- move_linked_works(work, pos, NULL);
+ move_linked_works(work, &cwq->pool->worklist, NULL);
__clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work));
cwq->nr_active++;
}
@@ -1796,7 +1802,8 @@
__acquires(&gcwq->lock)
{
struct cpu_workqueue_struct *cwq = get_work_cwq(work);
- struct global_cwq *gcwq = cwq->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
struct hlist_head *bwh = busy_worker_head(gcwq, work);
bool cpu_intensive = cwq->wq->flags & WQ_CPU_INTENSIVE;
work_func_t f = work->func;
@@ -1836,27 +1843,19 @@
list_del_init(&work->entry);
/*
- * If HIGHPRI_PENDING, check the next work, and, if HIGHPRI,
- * wake up another worker; otherwise, clear HIGHPRI_PENDING.
- */
- if (unlikely(gcwq->flags & GCWQ_HIGHPRI_PENDING)) {
- struct work_struct *nwork = list_first_entry(&gcwq->worklist,
- struct work_struct, entry);
-
- if (!list_empty(&gcwq->worklist) &&
- get_work_cwq(nwork)->wq->flags & WQ_HIGHPRI)
- wake_up_worker(gcwq);
- else
- gcwq->flags &= ~GCWQ_HIGHPRI_PENDING;
- }
-
- /*
* CPU intensive works don't participate in concurrency
* management. They're the scheduler's responsibility.
*/
if (unlikely(cpu_intensive))
worker_set_flags(worker, WORKER_CPU_INTENSIVE, true);
+ /*
+ * Unbound gcwq isn't concurrency managed and work items should be
+ * executed ASAP. Wake up another worker if necessary.
+ */
+ if ((worker->flags & WORKER_UNBOUND) && need_more_worker(pool))
+ wake_up_worker(pool);
+
spin_unlock_irq(&gcwq->lock);
work_clear_pending(work);
@@ -1929,7 +1928,8 @@
static int worker_thread(void *__worker)
{
struct worker *worker = __worker;
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
/* tell the scheduler that this is a workqueue worker */
worker->task->flags |= PF_WQ_WORKER;
@@ -1946,11 +1946,11 @@
worker_leave_idle(worker);
recheck:
/* no more worker necessary? */
- if (!need_more_worker(gcwq))
+ if (!need_more_worker(pool))
goto sleep;
/* do we need to manage? */
- if (unlikely(!may_start_working(gcwq)) && manage_workers(worker))
+ if (unlikely(!may_start_working(pool)) && manage_workers(worker))
goto recheck;
/*
@@ -1969,7 +1969,7 @@
do {
struct work_struct *work =
- list_first_entry(&gcwq->worklist,
+ list_first_entry(&pool->worklist,
struct work_struct, entry);
if (likely(!(*work_data_bits(work) & WORK_STRUCT_LINKED))) {
@@ -1981,11 +1981,11 @@
move_linked_works(work, &worker->scheduled, NULL);
process_scheduled_works(worker);
}
- } while (keep_working(gcwq));
+ } while (keep_working(pool));
worker_set_flags(worker, WORKER_PREP, false);
sleep:
- if (unlikely(need_to_manage_workers(gcwq)) && manage_workers(worker))
+ if (unlikely(need_to_manage_workers(pool)) && manage_workers(worker))
goto recheck;
/*
@@ -2043,14 +2043,15 @@
for_each_mayday_cpu(cpu, wq->mayday_mask) {
unsigned int tcpu = is_unbound ? WORK_CPU_UNBOUND : cpu;
struct cpu_workqueue_struct *cwq = get_cwq(tcpu, wq);
- struct global_cwq *gcwq = cwq->gcwq;
+ struct worker_pool *pool = cwq->pool;
+ struct global_cwq *gcwq = pool->gcwq;
struct work_struct *work, *n;
__set_current_state(TASK_RUNNING);
mayday_clear_cpu(cpu, wq->mayday_mask);
/* migrate to the target cpu if possible */
- rescuer->gcwq = gcwq;
+ rescuer->pool = pool;
worker_maybe_bind_and_lock(rescuer);
/*
@@ -2058,7 +2059,7 @@
* process'em.
*/
BUG_ON(!list_empty(&rescuer->scheduled));
- list_for_each_entry_safe(work, n, &gcwq->worklist, entry)
+ list_for_each_entry_safe(work, n, &pool->worklist, entry)
if (get_work_cwq(work) == cwq)
move_linked_works(work, scheduled, &n);
@@ -2069,8 +2070,8 @@
* regular worker; otherwise, we end up with 0 concurrency
* and stalling the execution.
*/
- if (keep_working(gcwq))
- wake_up_worker(gcwq);
+ if (keep_working(pool))
+ wake_up_worker(pool);
spin_unlock_irq(&gcwq->lock);
}
@@ -2195,7 +2196,7 @@
for_each_cwq_cpu(cpu, wq) {
struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
- struct global_cwq *gcwq = cwq->gcwq;
+ struct global_cwq *gcwq = cwq->pool->gcwq;
spin_lock_irq(&gcwq->lock);
@@ -2411,9 +2412,9 @@
struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
bool drained;
- spin_lock_irq(&cwq->gcwq->lock);
+ spin_lock_irq(&cwq->pool->gcwq->lock);
drained = !cwq->nr_active && list_empty(&cwq->delayed_works);
- spin_unlock_irq(&cwq->gcwq->lock);
+ spin_unlock_irq(&cwq->pool->gcwq->lock);
if (drained)
continue;
@@ -2453,7 +2454,7 @@
*/
smp_rmb();
cwq = get_work_cwq(work);
- if (unlikely(!cwq || gcwq != cwq->gcwq))
+ if (unlikely(!cwq || gcwq != cwq->pool->gcwq))
goto already_gone;
} else if (wait_executing) {
worker = find_worker_executing_work(gcwq, work);
@@ -2971,13 +2972,6 @@
if (flags & WQ_MEM_RECLAIM)
flags |= WQ_RESCUER;
- /*
- * Unbound workqueues aren't concurrency managed and should be
- * dispatched to workers immediately.
- */
- if (flags & WQ_UNBOUND)
- flags |= WQ_HIGHPRI;
-
max_active = max_active ?: WQ_DFL_ACTIVE;
max_active = wq_clamp_max_active(max_active, flags, wq->name);
@@ -2998,9 +2992,10 @@
for_each_cwq_cpu(cpu, wq) {
struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
struct global_cwq *gcwq = get_gcwq(cpu);
+ int pool_idx = (bool)(flags & WQ_HIGHPRI);
BUG_ON((unsigned long)cwq & WORK_STRUCT_FLAG_MASK);
- cwq->gcwq = gcwq;
+ cwq->pool = &gcwq->pools[pool_idx];
cwq->wq = wq;
cwq->flush_color = -1;
cwq->max_active = max_active;
@@ -3304,9 +3299,30 @@
__ret1 < 0 ? -1 : 0; \
})
+static bool gcwq_is_managing_workers(struct global_cwq *gcwq)
+{
+ struct worker_pool *pool;
+
+ for_each_worker_pool(pool, gcwq)
+ if (pool->flags & POOL_MANAGING_WORKERS)
+ return true;
+ return false;
+}
+
+static bool gcwq_has_idle_workers(struct global_cwq *gcwq)
+{
+ struct worker_pool *pool;
+
+ for_each_worker_pool(pool, gcwq)
+ if (!list_empty(&pool->idle_list))
+ return true;
+ return false;
+}
+
static int __cpuinit trustee_thread(void *__gcwq)
{
struct global_cwq *gcwq = __gcwq;
+ struct worker_pool *pool;
struct worker *worker;
struct work_struct *work;
struct hlist_node *pos;
@@ -3322,13 +3338,15 @@
* cancelled.
*/
BUG_ON(gcwq->cpu != smp_processor_id());
- rc = trustee_wait_event(!(gcwq->flags & GCWQ_MANAGING_WORKERS));
+ rc = trustee_wait_event(!gcwq_is_managing_workers(gcwq));
BUG_ON(rc < 0);
- gcwq->flags |= GCWQ_MANAGING_WORKERS;
+ for_each_worker_pool(pool, gcwq) {
+ pool->flags |= POOL_MANAGING_WORKERS;
- list_for_each_entry(worker, &gcwq->idle_list, entry)
- worker->flags |= WORKER_ROGUE;
+ list_for_each_entry(worker, &pool->idle_list, entry)
+ worker->flags |= WORKER_ROGUE;
+ }
for_each_busy_worker(worker, i, pos, gcwq)
worker->flags |= WORKER_ROGUE;
@@ -3349,10 +3367,12 @@
* keep_working() are always true as long as the worklist is
* not empty.
*/
- atomic_set(get_gcwq_nr_running(gcwq->cpu), 0);
+ for_each_worker_pool(pool, gcwq)
+ atomic_set(get_pool_nr_running(pool), 0);
spin_unlock_irq(&gcwq->lock);
- del_timer_sync(&gcwq->idle_timer);
+ for_each_worker_pool(pool, gcwq)
+ del_timer_sync(&pool->idle_timer);
spin_lock_irq(&gcwq->lock);
/*
@@ -3374,29 +3394,38 @@
* may be frozen works in freezable cwqs. Don't declare
* completion while frozen.
*/
- while (gcwq->nr_workers != gcwq->nr_idle ||
- gcwq->flags & GCWQ_FREEZING ||
- gcwq->trustee_state == TRUSTEE_IN_CHARGE) {
- int nr_works = 0;
+ while (true) {
+ bool busy = false;
- list_for_each_entry(work, &gcwq->worklist, entry) {
- send_mayday(work);
- nr_works++;
- }
+ for_each_worker_pool(pool, gcwq)
+ busy |= pool->nr_workers != pool->nr_idle;
- list_for_each_entry(worker, &gcwq->idle_list, entry) {
- if (!nr_works--)
- break;
- wake_up_process(worker->task);
- }
+ if (!busy && !(gcwq->flags & GCWQ_FREEZING) &&
+ gcwq->trustee_state != TRUSTEE_IN_CHARGE)
+ break;
- if (need_to_create_worker(gcwq)) {
- spin_unlock_irq(&gcwq->lock);
- worker = create_worker(gcwq, false);
- spin_lock_irq(&gcwq->lock);
- if (worker) {
- worker->flags |= WORKER_ROGUE;
- start_worker(worker);
+ for_each_worker_pool(pool, gcwq) {
+ int nr_works = 0;
+
+ list_for_each_entry(work, &pool->worklist, entry) {
+ send_mayday(work);
+ nr_works++;
+ }
+
+ list_for_each_entry(worker, &pool->idle_list, entry) {
+ if (!nr_works--)
+ break;
+ wake_up_process(worker->task);
+ }
+
+ if (need_to_create_worker(pool)) {
+ spin_unlock_irq(&gcwq->lock);
+ worker = create_worker(pool, false);
+ spin_lock_irq(&gcwq->lock);
+ if (worker) {
+ worker->flags |= WORKER_ROGUE;
+ start_worker(worker);
+ }
}
}
@@ -3411,11 +3440,18 @@
* all workers till we're canceled.
*/
do {
- rc = trustee_wait_event(!list_empty(&gcwq->idle_list));
- while (!list_empty(&gcwq->idle_list))
- destroy_worker(list_first_entry(&gcwq->idle_list,
- struct worker, entry));
- } while (gcwq->nr_workers && rc >= 0);
+ rc = trustee_wait_event(gcwq_has_idle_workers(gcwq));
+
+ i = 0;
+ for_each_worker_pool(pool, gcwq) {
+ while (!list_empty(&pool->idle_list)) {
+ worker = list_first_entry(&pool->idle_list,
+ struct worker, entry);
+ destroy_worker(worker);
+ }
+ i |= pool->nr_workers;
+ }
+ } while (i && rc >= 0);
/*
* At this point, either draining has completed and no worker
@@ -3424,7 +3460,8 @@
* Tell the remaining busy ones to rebind once it finishes the
* currently scheduled works by scheduling the rebind_work.
*/
- WARN_ON(!list_empty(&gcwq->idle_list));
+ for_each_worker_pool(pool, gcwq)
+ WARN_ON(!list_empty(&pool->idle_list));
for_each_busy_worker(worker, i, pos, gcwq) {
struct work_struct *rebind_work = &worker->rebind_work;
@@ -3449,7 +3486,8 @@
}
/* relinquish manager role */
- gcwq->flags &= ~GCWQ_MANAGING_WORKERS;
+ for_each_worker_pool(pool, gcwq)
+ pool->flags &= ~POOL_MANAGING_WORKERS;
/* notify completion */
gcwq->trustee = NULL;
@@ -3491,8 +3529,10 @@
unsigned int cpu = (unsigned long)hcpu;
struct global_cwq *gcwq = get_gcwq(cpu);
struct task_struct *new_trustee = NULL;
- struct worker *uninitialized_var(new_worker);
+ struct worker *new_workers[NR_WORKER_POOLS] = { };
+ struct worker_pool *pool;
unsigned long flags;
+ int i;
action &= ~CPU_TASKS_FROZEN;
@@ -3505,12 +3545,12 @@
kthread_bind(new_trustee, cpu);
/* fall through */
case CPU_UP_PREPARE:
- BUG_ON(gcwq->first_idle);
- new_worker = create_worker(gcwq, false);
- if (!new_worker) {
- if (new_trustee)
- kthread_stop(new_trustee);
- return NOTIFY_BAD;
+ i = 0;
+ for_each_worker_pool(pool, gcwq) {
+ BUG_ON(pool->first_idle);
+ new_workers[i] = create_worker(pool, false);
+ if (!new_workers[i++])
+ goto err_destroy;
}
}
@@ -3527,8 +3567,11 @@
wait_trustee_state(gcwq, TRUSTEE_IN_CHARGE);
/* fall through */
case CPU_UP_PREPARE:
- BUG_ON(gcwq->first_idle);
- gcwq->first_idle = new_worker;
+ i = 0;
+ for_each_worker_pool(pool, gcwq) {
+ BUG_ON(pool->first_idle);
+ pool->first_idle = new_workers[i++];
+ }
break;
case CPU_DYING:
@@ -3545,8 +3588,10 @@
gcwq->trustee_state = TRUSTEE_BUTCHER;
/* fall through */
case CPU_UP_CANCELED:
- destroy_worker(gcwq->first_idle);
- gcwq->first_idle = NULL;
+ for_each_worker_pool(pool, gcwq) {
+ destroy_worker(pool->first_idle);
+ pool->first_idle = NULL;
+ }
break;
case CPU_DOWN_FAILED:
@@ -3563,18 +3608,32 @@
* Put the first_idle in and request a real manager to
* take a look.
*/
- spin_unlock_irq(&gcwq->lock);
- kthread_bind(gcwq->first_idle->task, cpu);
- spin_lock_irq(&gcwq->lock);
- gcwq->flags |= GCWQ_MANAGE_WORKERS;
- start_worker(gcwq->first_idle);
- gcwq->first_idle = NULL;
+ for_each_worker_pool(pool, gcwq) {
+ spin_unlock_irq(&gcwq->lock);
+ kthread_bind(pool->first_idle->task, cpu);
+ spin_lock_irq(&gcwq->lock);
+ pool->flags |= POOL_MANAGE_WORKERS;
+ start_worker(pool->first_idle);
+ pool->first_idle = NULL;
+ }
break;
}
spin_unlock_irqrestore(&gcwq->lock, flags);
return notifier_from_errno(0);
+
+err_destroy:
+ if (new_trustee)
+ kthread_stop(new_trustee);
+
+ spin_lock_irqsave(&gcwq->lock, flags);
+ for (i = 0; i < NR_WORKER_POOLS; i++)
+ if (new_workers[i])
+ destroy_worker(new_workers[i]);
+ spin_unlock_irqrestore(&gcwq->lock, flags);
+
+ return NOTIFY_BAD;
}
#ifdef CONFIG_SMP
@@ -3733,6 +3792,7 @@
for_each_gcwq_cpu(cpu) {
struct global_cwq *gcwq = get_gcwq(cpu);
+ struct worker_pool *pool;
struct workqueue_struct *wq;
spin_lock_irq(&gcwq->lock);
@@ -3754,7 +3814,8 @@
cwq_activate_first_delayed(cwq);
}
- wake_up_worker(gcwq);
+ for_each_worker_pool(pool, gcwq)
+ wake_up_worker(pool);
spin_unlock_irq(&gcwq->lock);
}
@@ -3775,24 +3836,29 @@
/* initialize gcwqs */
for_each_gcwq_cpu(cpu) {
struct global_cwq *gcwq = get_gcwq(cpu);
+ struct worker_pool *pool;
spin_lock_init(&gcwq->lock);
- INIT_LIST_HEAD(&gcwq->worklist);
gcwq->cpu = cpu;
gcwq->flags |= GCWQ_DISASSOCIATED;
- INIT_LIST_HEAD(&gcwq->idle_list);
for (i = 0; i < BUSY_WORKER_HASH_SIZE; i++)
INIT_HLIST_HEAD(&gcwq->busy_hash[i]);
- init_timer_deferrable(&gcwq->idle_timer);
- gcwq->idle_timer.function = idle_worker_timeout;
- gcwq->idle_timer.data = (unsigned long)gcwq;
+ for_each_worker_pool(pool, gcwq) {
+ pool->gcwq = gcwq;
+ INIT_LIST_HEAD(&pool->worklist);
+ INIT_LIST_HEAD(&pool->idle_list);
- setup_timer(&gcwq->mayday_timer, gcwq_mayday_timeout,
- (unsigned long)gcwq);
+ init_timer_deferrable(&pool->idle_timer);
+ pool->idle_timer.function = idle_worker_timeout;
+ pool->idle_timer.data = (unsigned long)pool;
- ida_init(&gcwq->worker_ida);
+ setup_timer(&pool->mayday_timer, gcwq_mayday_timeout,
+ (unsigned long)pool);
+
+ ida_init(&pool->worker_ida);
+ }
gcwq->trustee_state = TRUSTEE_DONE;
init_waitqueue_head(&gcwq->trustee_wait);
@@ -3801,15 +3867,20 @@
/* create the initial worker */
for_each_online_gcwq_cpu(cpu) {
struct global_cwq *gcwq = get_gcwq(cpu);
- struct worker *worker;
+ struct worker_pool *pool;
if (cpu != WORK_CPU_UNBOUND)
gcwq->flags &= ~GCWQ_DISASSOCIATED;
- worker = create_worker(gcwq, true);
- BUG_ON(!worker);
- spin_lock_irq(&gcwq->lock);
- start_worker(worker);
- spin_unlock_irq(&gcwq->lock);
+
+ for_each_worker_pool(pool, gcwq) {
+ struct worker *worker;
+
+ worker = create_worker(pool, true);
+ BUG_ON(!worker);
+ spin_lock_irq(&gcwq->lock);
+ start_worker(worker);
+ spin_unlock_irq(&gcwq->lock);
+ }
}
system_wq = alloc_workqueue("events", 0, 0);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 69b9521..798c750 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -785,6 +785,10 @@
set_pageblock_migratetype(page, MIGRATE_CMA);
__free_pages(page, pageblock_order);
totalram_pages += pageblock_nr_pages;
+#ifdef CONFIG_HIGHMEM
+ if (PageHighMem(page))
+ totalhigh_pages += pageblock_nr_pages;
+#endif
}
#endif
@@ -5199,10 +5203,6 @@
zone->watermark[WMARK_LOW] = min_wmark_pages(zone) + (tmp >> 2);
zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + (tmp >> 1);
- zone->watermark[WMARK_MIN] += cma_wmark_pages(zone);
- zone->watermark[WMARK_LOW] += cma_wmark_pages(zone);
- zone->watermark[WMARK_HIGH] += cma_wmark_pages(zone);
-
setup_zone_migrate_reserve(zone);
spin_unlock_irqrestore(&zone->lock, flags);
}
@@ -5820,54 +5820,6 @@
return ret > 0 ? 0 : ret;
}
-/*
- * Update zone's cma pages counter used for watermark level calculation.
- */
-static inline void __update_cma_watermarks(struct zone *zone, int count)
-{
- unsigned long flags;
- spin_lock_irqsave(&zone->lock, flags);
- zone->min_cma_pages += count;
- spin_unlock_irqrestore(&zone->lock, flags);
- setup_per_zone_wmarks();
-}
-
-/*
- * Trigger memory pressure bump to reclaim some pages in order to be able to
- * allocate 'count' pages in single page units. Does similar work as
- *__alloc_pages_slowpath() function.
- */
-static int __reclaim_pages(struct zone *zone, gfp_t gfp_mask, int count)
-{
- enum zone_type high_zoneidx = gfp_zone(gfp_mask);
- struct zonelist *zonelist = node_zonelist(0, gfp_mask);
- int did_some_progress = 0;
- int order = 1;
-
- /*
- * Increase level of watermarks to force kswapd do his job
- * to stabilise at new watermark level.
- */
- __update_cma_watermarks(zone, count);
-
- /* Obey watermarks as if the page was being allocated */
- while (!zone_watermark_ok(zone, 0, low_wmark_pages(zone), 0, 0)) {
- wake_all_kswapd(order, zonelist, high_zoneidx, zone_idx(zone));
-
- did_some_progress = __perform_reclaim(gfp_mask, order, zonelist,
- NULL);
- if (!did_some_progress) {
- /* Exhausted what can be done so it's blamo time */
- out_of_memory(zonelist, gfp_mask, order, NULL, false);
- }
- }
-
- /* Restore original watermark levels. */
- __update_cma_watermarks(zone, -count);
-
- return count;
-}
-
/**
* alloc_contig_range() -- tries to allocate given range of pages
* @start: start PFN to allocate
@@ -5968,11 +5920,6 @@
goto done;
}
- /*
- * Reclaim enough pages to make sure that contiguous allocation
- * will not starve the system.
- */
- __reclaim_pages(zone, GFP_HIGHUSER_MOVABLE, end-start);
/* Grab isolated pages from freelists. */
outer_end = isolate_freepages_range(outer_start, end);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index d243646..2dba071 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2426,6 +2426,21 @@
}
}
+static inline void hci_hardware_error_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_ev_hardware_error *ev = (void *) skb->data;
+
+ BT_ERR("hdev=%p, hw_err_code = %u", hdev, ev->hw_err_code);
+
+ if (hdev && hdev->dev_type == HCI_BREDR) {
+ hci_dev_lock_bh(hdev);
+ mgmt_powered(hdev->id, 1);
+ hci_dev_unlock_bh(hdev);
+ }
+
+}
+
static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_role_change *ev = (void *) skb->data;
@@ -3555,6 +3570,10 @@
hci_cmd_status_evt(hdev, skb);
break;
+ case HCI_EV_HARDWARE_ERROR:
+ hci_hardware_error_evt(hdev, skb);
+ break;
+
case HCI_EV_ROLE_CHANGE:
hci_role_change_evt(hdev, skb);
break;
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 59debb7..2356791 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -137,6 +137,8 @@
static DEFINE_RWLOCK(nl_table_lock);
static atomic_t nl_table_users = ATOMIC_INIT(0);
+#define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock));
+
static ATOMIC_NOTIFIER_HEAD(netlink_chain);
static inline u32 netlink_group_mask(u32 group)
@@ -330,6 +332,11 @@
struct hlist_node *node;
unsigned long mask;
unsigned int i;
+ struct listeners *listeners;
+
+ listeners = nl_deref_protected(tbl->listeners);
+ if (!listeners)
+ return;
for (i = 0; i < NLGRPLONGS(tbl->groups); i++) {
mask = 0;
@@ -337,7 +344,7 @@
if (i < NLGRPLONGS(nlk_sk(sk)->ngroups))
mask |= nlk_sk(sk)->groups[i];
}
- tbl->listeners->masks[i] = mask;
+ listeners->masks[i] = mask;
}
/* this function is only called with the netlink table "grabbed", which
* makes sure updates are visible before bind or setsockopt return. */
@@ -518,7 +525,11 @@
if (netlink_is_kernel(sk)) {
BUG_ON(nl_table[sk->sk_protocol].registered == 0);
if (--nl_table[sk->sk_protocol].registered == 0) {
- kfree(nl_table[sk->sk_protocol].listeners);
+ struct listeners *old;
+
+ old = nl_deref_protected(nl_table[sk->sk_protocol].listeners);
+ RCU_INIT_POINTER(nl_table[sk->sk_protocol].listeners, NULL);
+ kfree_rcu(old, rcu);
nl_table[sk->sk_protocol].module = NULL;
nl_table[sk->sk_protocol].registered = 0;
}
@@ -948,7 +959,7 @@
rcu_read_lock();
listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners);
- if (group - 1 < nl_table[sk->sk_protocol].groups)
+ if (listeners && group - 1 < nl_table[sk->sk_protocol].groups)
res = test_bit(group - 1, listeners->masks);
rcu_read_unlock();
@@ -1579,7 +1590,7 @@
new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC);
if (!new)
return -ENOMEM;
- old = rcu_dereference_protected(tbl->listeners, 1);
+ old = nl_deref_protected(tbl->listeners);
memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups));
rcu_assign_pointer(tbl->listeners, new);
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index c8647fb1..e1a904f 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -34,6 +34,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
+#include <mach/qdsp6v2/apr.h>
#include "msm8x10-wcd.h"
#include "wcd9xxx-resmgr.h"
#include "msm8x10_wcd_registers.h"
@@ -52,7 +53,7 @@
#define MAX_MSM8X10_WCD_DEVICE 4
#define CODEC_DT_MAX_PROP_SIZE 40
-#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "1-000d"
+#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "5-000d"
enum {
MSM8X10_WCD_I2C_TOP_LEVEL = 0,
@@ -82,6 +83,12 @@
static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[];
static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
+#define MSM8X10_WCD_ACQUIRE_LOCK(x) do { \
+ mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); \
+} while (0)
+#define MSM8X10_WCD_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
+
+
/* Codec supports 2 IIR filters */
enum {
IIR1 = 0,
@@ -99,6 +106,12 @@
BAND_MAX,
};
+enum msm8x10_wcd_bandgap_type {
+ MSM8X10_WCD_BANDGAP_OFF = 0,
+ MSM8X10_WCD_BANDGAP_AUDIO_MODE,
+ MSM8X10_WCD_BANDGAP_MBHC_MODE,
+};
+
struct hpf_work {
struct msm8x10_wcd_priv *msm8x10_wcd;
u32 decimator;
@@ -113,11 +126,14 @@
u32 adc_count;
u32 rx_bias_count;
s32 dmic_1_2_clk_cnt;
-
+ enum msm8x10_wcd_bandgap_type bandgap_type;
+ bool mclk_enabled;
+ bool clock_active;
+ bool config_mode_active;
+ bool mbhc_polling_active;
+ struct mutex codec_resource_lock;
/* resmgr module */
struct wcd9xxx_resmgr resmgr;
- /* mbhc module */
- struct wcd9xxx_mbhc mbhc;
};
static unsigned short rx_digital_gain_reg[] = {
@@ -139,8 +155,8 @@
};
static char *msm8x10_wcd_supplies[] = {
- "cdc-vdd-mic-bias", "cdc-vdda-h", "cdc-vdd-1p2", "cdc-vdd-px",
- "cdc-vdda-cp",
+ "cdc-vdda-cp", "cdc-vdda-h", "cdc-vdd-px", "cdc-vdd-1p2v",
+ "cdc-vdd-mic-bias",
};
static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
@@ -158,7 +174,6 @@
{
int rtn = 0;
int value = ((reg & 0x0f00) >> 8) & 0x000f;
- pr_debug("%s: reg(0x%x) value(%d)\n", __func__, reg, value);
switch (value) {
case 0:
case 1:
@@ -171,7 +186,7 @@
return rtn;
}
-static int msm8x10_wcd_abh_write_device(u16 reg, unsigned int *value, u32 bytes)
+static int msm8x10_wcd_abh_write_device(u16 reg, u8 *value, u32 bytes)
{
u32 temp = ((u32)(*value)) & 0x000000FF;
u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
@@ -179,11 +194,13 @@
return 0;
}
-static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, unsigned int *value)
+static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, u8 *value)
{
+ u32 temp;
u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
- *value = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
+ temp = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
offset, 4));
+ *value = (u8)temp;
return 0;
}
@@ -274,7 +291,7 @@
}
}
}
- pr_debug("%s: Reg 0x%x = 0x%x\n", __func__, reg, *dest);
+ pr_debug("%s: reg 0x%x = 0x%x\n", __func__, reg, *dest);
return 0;
}
@@ -292,20 +309,22 @@
u16 reg, unsigned int *val)
{
int ret = -EINVAL;
+ u8 temp;
/* check if use I2C interface for Helicon or AHB for Dino */
mutex_lock(&msm8x10_wcd->io_lock);
if (MSM8X10_WCD_IS_HELICON_REG(reg))
- ret = msm8x10_wcd_i2c_read(reg, 1, val);
+ ret = msm8x10_wcd_i2c_read(reg, 1, &temp);
else if (MSM8X10_WCD_IS_DINO_REG(reg))
- ret = msm8x10_wcd_abh_read_device(reg, 1, val);
+ ret = msm8x10_wcd_abh_read_device(reg, 1, &temp);
mutex_unlock(&msm8x10_wcd->io_lock);
+ *val = temp;
return ret;
}
static int msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd, u16 reg,
- unsigned int val)
+ u8 val)
{
int ret = -EINVAL;
@@ -393,7 +412,7 @@
reg, ret);
}
- return msm8x10_wcd_reg_write(codec->control_data, reg, value);
+ return msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
}
static unsigned int msm8x10_wcd_read(struct snd_soc_codec *codec,
@@ -438,10 +457,14 @@
regnode = of_parse_phandle(dev->of_node, prop_name, 0);
if (!regnode) {
- dev_err(dev, "Looking up %s property in node %s failed",
+ dev_err(dev, "Looking up %s property in node %s failed\n",
prop_name, dev->of_node->full_name);
return -ENODEV;
}
+
+ dev_dbg(dev, "Looking up %s property in node %s\n",
+ prop_name, dev->of_node->full_name);
+
vreg->name = vreg_name;
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
@@ -481,17 +504,7 @@
u32 prop_val;
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,cdc-micbias-ldoh-v");
- ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
- if (ret) {
- dev_err(dev, "Looking up %s property in node %s failed",
- prop_name, dev->of_node->full_name);
- return -ENODEV;
- }
- micbias->ldoh_v = (u8)prop_val;
-
- snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,cdc-micbias-cfilt1-mv");
+ "qcom,cdc-micbias-cfilt-mv");
ret = of_property_read_u32(dev->of_node, prop_name,
&micbias->cfilt1_mv);
if (ret) {
@@ -501,7 +514,7 @@
}
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,cdc-micbias1-cfilt-sel");
+ "qcom,cdc-micbias-cfilt-sel");
ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
if (ret) {
dev_err(dev, "Looking up %s property in node %s failed",
@@ -559,23 +572,14 @@
if (ret)
goto err;
}
-
ret = msm8x10_wcd_dt_parse_micbias_info(dev, &pdata->micbias);
if (ret)
goto err;
-
- pdata->reset_gpio = of_get_named_gpio(dev->of_node,
- "qcom,cdc-reset-gpio", 0);
- if (pdata->reset_gpio < 0) {
- dev_err(dev, "Looking up %s property in node %s failed %d\n",
- "qcom, cdc-reset-gpio", dev->of_node->full_name,
- pdata->reset_gpio);
- goto err;
- }
- dev_dbg(dev, "%s: reset gpio %d", __func__, pdata->reset_gpio);
return pdata;
err:
devm_kfree(dev, pdata);
+ dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
+ __func__, ret);
return NULL;
}
@@ -611,6 +615,9 @@
MSM8X10_WCD_A_CDC_CLK_OTHR_CTL, 0x01,
0x00);
snd_soc_update_bits(codec,
+ MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec,
MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
break;
}
@@ -846,7 +853,7 @@
SOC_ENUM_EXT("EAR PA Gain", msm8x10_wcd_ear_pa_gain_enum[0],
msm8x10_wcd_pa_gain_get, msm8x10_wcd_pa_gain_put),
- SOC_SINGLE_TLV("LINEOUT1 Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
+ SOC_SINGLE_TLV("LINEOUT Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
0, 12, 1, line_gain),
SOC_SINGLE_TLV("HPHL Volume", MSM8X10_WCD_A_RX_HPH_L_GAIN,
@@ -1102,9 +1109,6 @@
switch (decimator) {
case 1:
case 2:
- if (dec_mux == 1)
- adc_dmic_sel = 0x1;
- else
adc_dmic_sel = 0x0;
break;
default:
@@ -1148,68 +1152,6 @@
SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
};
-/* virtual port entries */
-static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-
- ucontrol->value.integer.value[0] = widget->value;
- return 0;
-}
-
-static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return 0;
-}
-
-static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-
- ucontrol->value.enumerated.item[0] = widget->value;
- return 0;
-}
-
-static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return 0;
-}
-
-
-static const char *const slim_rx_mux_text[] = {
- "ZERO", "AIF1_PB"
-};
-
-static const struct soc_enum slim_rx_mux_enum =
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
-
-static const struct snd_kcontrol_new slim_rx_mux[MSM8X10_WCD_RX_MAX] = {
- SOC_DAPM_ENUM_EXT("I2S RX1 Mux", slim_rx_mux_enum,
- slim_rx_mux_get, slim_rx_mux_put),
- SOC_DAPM_ENUM_EXT("I2S RX2 Mux", slim_rx_mux_enum,
- slim_rx_mux_get, slim_rx_mux_put),
- SOC_DAPM_ENUM_EXT("I2S RX3 Mux", slim_rx_mux_enum,
- slim_rx_mux_get, slim_rx_mux_put),
-};
-
-static const struct snd_kcontrol_new aif_cap_mixer[] = {
- SOC_SINGLE_EXT("I2S TX1", SND_SOC_NOPM, MSM8X10_WCD_TX1, 1, 0,
- slim_tx_mixer_get, slim_tx_mixer_put),
- SOC_SINGLE_EXT("I2S TX2", SND_SOC_NOPM, MSM8X10_WCD_TX2, 1, 0,
- slim_tx_mixer_get, slim_tx_mixer_put),
- SOC_SINGLE_EXT("I2S TX3", SND_SOC_NOPM, MSM8X10_WCD_TX3, 1, 0,
- slim_tx_mixer_get, slim_tx_mixer_put),
- SOC_SINGLE_EXT("I2S TX4", SND_SOC_NOPM, MSM8X10_WCD_TX4, 1, 0,
- slim_tx_mixer_get, slim_tx_mixer_put),
-};
-
-
static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
int enable)
{
@@ -1243,7 +1185,7 @@
if (w->reg == MSM8X10_WCD_A_TX_1_EN)
init_bit_shift = 7;
- else if (adc_reg == MSM8X10_WCD_A_TX_2_EN)
+ else if (w->reg == MSM8X10_WCD_A_TX_2_EN)
init_bit_shift = 6;
else {
dev_err(codec->dev, "%s: Error, invalid adc register\n",
@@ -1365,54 +1307,36 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
u16 micb_int_reg;
- u8 cfilt_sel_val = 0;
char *internal1_text = "Internal1";
char *internal2_text = "Internal2";
char *internal3_text = "Internal3";
- enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
dev_dbg(codec->dev, "%s %d\n", __func__, event);
switch (w->reg) {
case MSM8X10_WCD_A_MICB_1_CTL:
micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
- cfilt_sel_val =
- msm8x10_wcd->resmgr.pdata->micbias.bias1_cfilt_sel;
- e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
- e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
- e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
break;
default:
dev_err(codec->dev,
- "%s: Error, invalid micbias register\n", __func__);
+ "%s: Error, invalid micbias register 0x%x\n",
+ __func__, w->reg);
return -EINVAL;
}
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- /* Let MBHC module know so micbias switch to be off */
- wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
-
- /* Get cfilt */
- wcd9xxx_resmgr_cfilt_get(&msm8x10_wcd->resmgr, cfilt_sel_val);
-
if (strnstr(w->name, internal1_text, 30))
- snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
+ snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
else if (strnstr(w->name, internal2_text, 30))
- snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
+ snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
else if (strnstr(w->name, internal3_text, 30))
- snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
+ snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
break;
case SND_SOC_DAPM_POST_PMU:
usleep_range(20000, 20100);
- /* Let MBHC module know so micbias is on */
- wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
break;
case SND_SOC_DAPM_POST_PMD:
- /* Let MBHC module know so micbias switch to be off */
- wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
-
if (strnstr(w->name, internal1_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
else if (strnstr(w->name, internal2_text, 30))
@@ -1420,14 +1344,36 @@
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
- /* Put cfilt */
- wcd9xxx_resmgr_cfilt_put(&msm8x10_wcd->resmgr, cfilt_sel_val);
break;
}
-
return 0;
}
+static void tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+ struct delayed_work *hpf_delayed_work;
+ struct hpf_work *hpf_work;
+ struct msm8x10_wcd_priv *msm8x10_wcd;
+ struct snd_soc_codec *codec;
+ u16 tx_mux_ctl_reg;
+ u8 hpf_cut_of_freq;
+
+ hpf_delayed_work = to_delayed_work(work);
+ hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+ msm8x10_wcd = hpf_work->msm8x10_wcd;
+ codec = hpf_work->msm8x10_wcd->codec;
+ hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
+
+ tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
+ (hpf_work->decimator - 1) * 32;
+
+ dev_info(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
+ __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
+
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
+}
+
+
#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
#define CF_MIN_3DB_4HZ 0x0
#define CF_MIN_3DB_75HZ 0x1
@@ -1582,6 +1528,7 @@
{
struct snd_soc_codec *codec = w->codec;
struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+ msm8x10_wcd->resmgr.codec = codec;
dev_dbg(codec->dev, "%s %d\n", __func__, event);
@@ -1697,21 +1644,12 @@
{"I2S TX1", NULL, "TX_I2S_CLK"},
{"I2S TX2", NULL, "TX_I2S_CLK"},
- {"I2S TX3", NULL, "TX_I2S_CLK"},
- {"I2S TX4", NULL, "TX_I2S_CLK"},
- {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+ {"DEC1 MUX", NULL, "TX CLK"},
+ {"DEC2 MUX", NULL, "TX CLK"},
- {"AIF1_CAP Mixer", "I2S TX1", "I2S TX1 MUX"},
- {"AIF1_CAP Mixer", "I2S TX2", "I2S TX2 MUX"},
- {"AIF1_CAP Mixer", "I2S TX3", "I2S TX3 MUX"},
- {"AIF1_CAP Mixer", "I2S TX4", "I2S TX4 MUX"},
-
- {"I2S TX1 MUX", NULL, "DEC1 MUX"},
- {"I2S TX2 MUX", NULL, "DEC2 MUX"},
- {"I2S TX3 MUX", NULL, "RX1 MIX1"},
- {"I2S TX4 MUX", "RMIX2", "RX1 MIX2"},
- {"I2S TX4 MUX", "RMIX3", "RX1 MIX3"},
+ {"I2S TX1", NULL, "DEC1 MUX"},
+ {"I2S TX2", NULL, "DEC2 MUX"},
/* Earpiece (RX MIX1) */
{"EAR", NULL, "EAR PA"},
@@ -1725,33 +1663,32 @@
{"HPHL", NULL, "HPHL DAC"},
{"HPHR", NULL, "HPHR DAC"},
- {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
{"HPHL DAC", NULL, "CP"},
{"HPHR DAC", NULL, "CP"},
+ {"SPK DAC", NULL, "CP"},
{"DAC1", "Switch", "RX1 CHAIN"},
{"HPHL DAC", "Switch", "RX1 CHAIN"},
{"HPHR DAC", NULL, "RX2 CHAIN"},
- {"LINEOUT1", NULL, "LINEOUT1 PA"},
+ {"LINEOUT", NULL, "LINEOUT PA"},
{"SPK_OUT", NULL, "SPK PA"},
- {"LINEOUT1 PA", NULL, "CP"},
- {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
+ {"LINEOUT PA", NULL, "CP"},
+ {"LINEOUT PA", NULL, "LINEOUT DAC"},
- {"LINEOUT1 DAC", "RX2 INPUT", "RX2 MIX1"},
- {"LINEOUT1 DAC", "RX3 INPUT", "RX3 MIX1"},
-
+ {"CP", NULL, "RX_BIAS"},
{"SPK PA", NULL, "SPK DAC"},
- {"SPK DAC", NULL, "RX7 MIX2"},
+ {"SPK DAC", NULL, "RX3 CHAIN"},
+ {"RX1 CHAIN", NULL, "RX1 CLK"},
+ {"RX2 CHAIN", NULL, "RX2 CLK"},
+ {"RX3 CHAIN", NULL, "RX3 CLK"},
{"RX1 CHAIN", NULL, "RX1 MIX2"},
{"RX2 CHAIN", NULL, "RX2 MIX2"},
-
- {"LINEOUT1 DAC", NULL, "RX_BIAS"},
- {"SPK DAC", NULL, "RX_BIAS"},
+ {"RX3 CHAIN", NULL, "RX3 MIX1"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
@@ -1761,19 +1698,7 @@
{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
{"RX1 MIX2", NULL, "RX1 MIX1"},
- {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
- {"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
{"RX2 MIX2", NULL, "RX2 MIX1"},
- {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
- {"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
-
- {"I2S RX1 MUX", "AIF1_PB", "AIF1 PB"},
- {"I2S RX2 MUX", "AIF1_PB", "AIF1 PB"},
- {"I2S RX3 MUX", "AIF1_PB", "AIF1 PB"},
-
- {"I2S RX1", NULL, "I2S RX1 MUX"},
- {"I2S RX2", NULL, "I2S RX2 MUX"},
- {"I2S RX3", NULL, "I2S RX3 MUX"},
{"RX1 MIX1 INP1", "RX1", "I2S RX1"},
{"RX1 MIX1 INP1", "RX2", "I2S RX2"},
@@ -1825,41 +1750,109 @@
{"IIR1", NULL, "IIR1 INP1 MUX"},
{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
-
- /* There is no LDO_H in Helicon */
- {"MIC BIAS1 Internal1", NULL, "LDO_H"},
- {"MIC BIAS1 Internal2", NULL, "LDO_H"},
- {"MIC BIAS1 External", NULL, "LDO_H"},
+ {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
+ {"MIC BIAS External", NULL, "INT_LDO_H"},
};
static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct msm8x10_wcd *msm8x10_wcd_core =
- dev_get_drvdata(dai->codec->dev);
dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
__func__,
substream->name, substream->stream);
- if ((msm8x10_wcd_core != NULL) &&
- (msm8x10_wcd_core->dev != NULL))
- pm_runtime_get_sync(msm8x10_wcd_core->dev);
-
return 0;
}
static void msm8x10_wcd_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct msm8x10_wcd *msm8x10_wcd_core =
- dev_get_drvdata(dai->codec->dev);
dev_dbg(dai->codec->dev,
"%s(): substream = %s stream = %d\n" , __func__,
substream->name, substream->stream);
- if ((msm8x10_wcd_core != NULL) &&
- (msm8x10_wcd_core->dev != NULL)) {
- pm_runtime_mark_last_busy(msm8x10_wcd_core->dev);
- pm_runtime_put(msm8x10_wcd_core->dev);
+}
+
+static int msm8x10_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
+ int enable)
+{
+ if (enable) {
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
+ 0x03, 0x03);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+ 0x0f, 0x0d);
+ } else {
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+ 0x0f, 0x00);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+ 0x03, 0x00);
}
+ return 0;
+}
+
+static void msm8x10_wcd_codec_enable_audio_mode_bandgap(struct snd_soc_codec
+ *codec)
+{
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x80);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x04,
+ 0x04);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x01,
+ 0x01);
+ usleep_range(1000, 1000);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x00);
+}
+
+static void msm8x10_wcd_codec_enable_bandgap(struct snd_soc_codec *codec,
+ enum msm8x10_wcd_bandgap_type choice)
+{
+ struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+
+ /* TODO lock resources accessed by audio streams and threaded
+ * interrupt handlers
+ */
+
+ dev_dbg(codec->dev, "%s, choice is %d, current is %d\n",
+ __func__, choice,
+ msm8x10_wcd->bandgap_type);
+
+ if (msm8x10_wcd->bandgap_type == choice)
+ return;
+
+ if ((msm8x10_wcd->bandgap_type == MSM8X10_WCD_BANDGAP_OFF) &&
+ (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
+ msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
+ } else if (choice == MSM8X10_WCD_BANDGAP_MBHC_MODE) {
+ /* bandgap mode becomes fast,
+ * mclk should be off or clk buff source souldn't be VBG
+ * Let's turn off mclk always */
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x2, 0x2);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x80, 0x80);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x4, 0x4);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x01, 0x01);
+ usleep_range(1000, 1000);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x80, 0x00);
+ } else if ((msm8x10_wcd->bandgap_type ==
+ MSM8X10_WCD_BANDGAP_MBHC_MODE) &&
+ (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
+ snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
+ usleep_range(100, 100);
+ msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
+ } else if (choice == MSM8X10_WCD_BANDGAP_OFF) {
+ snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
+ } else {
+ dev_err(codec->dev,
+ "%s: Error, Invalid bandgap settings\n", __func__);
+ }
+ msm8x10_wcd->bandgap_type = choice;
}
int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
@@ -1867,24 +1860,30 @@
{
struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
- dev_dbg(codec->dev,
- "%s: mclk_enable = %u, dapm = %d\n", __func__,
- mclk_enable, dapm);
- WCD9XXX_BCL_LOCK(&msm8x10_wcd->resmgr);
+ dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
+ __func__, mclk_enable, dapm);
+ if (dapm)
+ MSM8X10_WCD_ACQUIRE_LOCK(msm8x10_wcd->codec_resource_lock);
if (mclk_enable) {
- wcd9xxx_resmgr_get_bandgap(&msm8x10_wcd->resmgr,
- WCD9XXX_BANDGAP_AUDIO_MODE);
- wcd9xxx_resmgr_get_clk_block(&msm8x10_wcd->resmgr,
- WCD9XXX_CLK_MCLK);
+ msm8x10_wcd->mclk_enabled = true;
+ msm8x10_wcd_codec_enable_bandgap(codec,
+ MSM8X10_WCD_BANDGAP_AUDIO_MODE);
+ msm8x10_wcd_codec_enable_clock_block(codec, 1);
} else {
- /* Put clock and BG */
- wcd9xxx_resmgr_put_clk_block(&msm8x10_wcd->resmgr,
- WCD9XXX_CLK_MCLK);
- wcd9xxx_resmgr_put_bandgap(&msm8x10_wcd->resmgr,
- WCD9XXX_BANDGAP_AUDIO_MODE);
+ if (!msm8x10_wcd->mclk_enabled) {
+ if (dapm)
+ MSM8X10_WCD_RELEASE_LOCK(
+ msm8x10_wcd->codec_resource_lock);
+ dev_err(codec->dev, "Error, MCLK already diabled\n");
+ return -EINVAL;
+ }
+ msm8x10_wcd->mclk_enabled = false;
+ msm8x10_wcd_codec_enable_clock_block(codec, 0);
+ msm8x10_wcd_codec_enable_bandgap(codec,
+ MSM8X10_WCD_BANDGAP_OFF);
}
- WCD9XXX_BCL_UNLOCK(&msm8x10_wcd->resmgr);
-
+ if (dapm)
+ MSM8X10_WCD_RELEASE_LOCK(msm8x10_wcd->codec_resource_lock);
return 0;
}
@@ -2027,7 +2026,7 @@
.rate_max = 192000,
.rate_min = 8000,
.channels_min = 1,
- .channels_max = 4,
+ .channels_max = 3,
},
.ops = &msm8x10_wcd_dai_ops,
},
@@ -2077,23 +2076,16 @@
SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
ARRAY_SIZE(dac1_switch)),
- SND_SOC_DAPM_AIF_IN("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
- AIF1_PB, 0),
+ SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_MUX("I2S RX1 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX1, 0,
- &slim_rx_mux[MSM8X10_WCD_RX1]),
- SND_SOC_DAPM_MUX("I2S RX2 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX2, 0,
- &slim_rx_mux[MSM8X10_WCD_RX2]),
- SND_SOC_DAPM_MUX("I2S RX3 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX3, 0,
- &slim_rx_mux[MSM8X10_WCD_RX3]),
+ SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_MIXER("I2S RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("I2S RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("I2S RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("I2S RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("I2S RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
- /* Headphone */
+ SND_SOC_DAPM_SUPPLY("TX CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+ 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
+
SND_SOC_DAPM_OUTPUT("HEADPHONE"),
SND_SOC_DAPM_PGA_E("HPHL", MSM8X10_WCD_A_RX_HPH_CNP_EN,
5, 0, NULL, 0,
@@ -2114,10 +2106,10 @@
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/* Speaker */
- SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT"),
SND_SOC_DAPM_OUTPUT("SPK_OUT"),
- SND_SOC_DAPM_PGA_E("LINEOUT1 PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
+ SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
0, 0, NULL, 0, msm8x10_wcd_codec_enable_lineout,
SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -2127,7 +2119,7 @@
SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL,
+ SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
MSM8X10_WCD_A_RX_LINE_1_DAC_CTL, 7, 0,
msm8x10_wcd_lineout_dac_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
@@ -2152,10 +2144,18 @@
0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+ 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+ 2, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RX1 CHAIN", MSM8X10_WCD_A_CDC_RX1_B6_CTL,
5, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RX2 CHAIN", MSM8X10_WCD_A_CDC_RX2_B6_CTL,
5, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX3 CHAIN", MSM8X10_WCD_A_CDC_RX3_B6_CTL,
+ 5, 0, NULL, 0),
SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
&rx_mix1_inp1_mux),
@@ -2191,26 +2191,28 @@
SND_SOC_DAPM_INPUT("AMIC1"),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External",
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1",
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2",
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS("MIC BIAS External", MSM8X10_WCD_A_MICB_1_CTL,
+ 7, 0),
+
SND_SOC_DAPM_INPUT("AMIC3"),
SND_SOC_DAPM_MUX_E("DEC1 MUX",
@@ -2226,11 +2228,13 @@
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_INPUT("AMIC2"),
- SND_SOC_DAPM_AIF_OUT("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
- AIF1_CAP, 0),
- SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
- aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+ SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM,
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM,
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM,
+ 0, 0),
/* Digital Mic Inputs */
SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
@@ -2254,7 +2258,7 @@
static const struct msm8x10_wcd_reg_mask_val msm8x10_wcd_reg_defaults[] = {
/* set MCLk to 9.6 */
- MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x0A),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x00),
/* EAR PA deafults */
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_CMBUFF, 0x05),
@@ -2280,7 +2284,12 @@
/* Disable TX7 internal biasing path which can cause leakage */
- MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_1, 0xBF),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
};
static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
@@ -2338,12 +2347,36 @@
static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
{
+ struct msm8x10_wcd_priv *msm8x10_wcd;
+ int i;
dev_dbg(codec->dev, "%s()\n", __func__);
+ msm8x10_wcd = kzalloc(sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
+ if (!msm8x10_wcd) {
+ dev_err(codec->dev, "Failed to allocate private data\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0 ; i < NUM_DECIMATORS; i++) {
+ tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd;
+ tx_hpf_work[i].decimator = i + 1;
+ INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
+ tx_hpf_corner_freq_callback);
+ }
+
codec->control_data = dev_get_drvdata(codec->dev);
+ snd_soc_codec_set_drvdata(codec, msm8x10_wcd);
+ msm8x10_wcd->codec = codec;
msm8x10_wcd_codec_init_reg(codec);
msm8x10_wcd_update_reg_defaults(codec);
+ msm8x10_wcd->mclk_enabled = false;
+ msm8x10_wcd->bandgap_type = MSM8X10_WCD_BANDGAP_OFF;
+ msm8x10_wcd->clock_active = false;
+ msm8x10_wcd->config_mode_active = false;
+ msm8x10_wcd->mbhc_polling_active = false;
+ mutex_init(&msm8x10_wcd->codec_resource_lock);
+ msm8x10_wcd->codec = codec;
return 0;
}
@@ -2353,18 +2386,6 @@
return 0;
}
-static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
-{
-
- mutex_init(&msm8x10->io_lock);
- mutex_init(&msm8x10->xfer_lock);
- mutex_init(&msm8x10->pm_lock);
- msm8x10->wlock_holders = 0;
-
- return 0;
-}
-
-
static struct snd_soc_codec_driver soc_codec_dev_msm8x10_wcd = {
.probe = msm8x10_wcd_codec_probe,
.remove = msm8x10_wcd_codec_remove,
@@ -2387,6 +2408,124 @@
.num_dapm_routes = ARRAY_SIZE(audio_map),
};
+static int msm8x10_wcd_enable_supplies(struct msm8x10_wcd *msm8x10,
+ struct msm8x10_wcd_pdata *pdata)
+{
+ int ret;
+ int i;
+ msm8x10->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
+ ARRAY_SIZE(pdata->regulator),
+ GFP_KERNEL);
+ if (!msm8x10->supplies) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ msm8x10->num_of_supplies = 0;
+
+ if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
+ dev_err(msm8x10->dev, "%s: Array Size out of bound\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+ if (pdata->regulator[i].name) {
+ msm8x10->supplies[i].supply = pdata->regulator[i].name;
+ msm8x10->num_of_supplies++;
+ }
+ }
+
+ ret = regulator_bulk_get(msm8x10->dev, msm8x10->num_of_supplies,
+ msm8x10->supplies);
+ if (ret != 0) {
+ dev_err(msm8x10->dev, "Failed to get supplies: err = %d\n",
+ ret);
+ goto err_supplies;
+ }
+
+ for (i = 0; i < msm8x10->num_of_supplies; i++) {
+ ret = regulator_set_voltage(msm8x10->supplies[i].consumer,
+ pdata->regulator[i].min_uV, pdata->regulator[i].max_uV);
+ if (ret) {
+ dev_err(msm8x10->dev, "%s: Setting regulator voltage failed for regulator %s err = %d\n",
+ __func__, msm8x10->supplies[i].supply, ret);
+ goto err_get;
+ }
+
+ ret = regulator_set_optimum_mode(msm8x10->supplies[i].consumer,
+ pdata->regulator[i].optimum_uA);
+ if (ret < 0) {
+ dev_err(msm8x10->dev, "%s: Setting regulator optimum mode failed for regulator %s err = %d\n",
+ __func__, msm8x10->supplies[i].supply, ret);
+ goto err_get;
+ }
+ }
+
+ ret = regulator_bulk_enable(msm8x10->num_of_supplies,
+ msm8x10->supplies);
+ if (ret != 0) {
+ dev_err(msm8x10->dev, "Failed to enable supplies: err = %d\n",
+ ret);
+ goto err_configure;
+ }
+ return ret;
+
+err_configure:
+ for (i = 0; i < msm8x10->num_of_supplies; i++) {
+ regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
+ pdata->regulator[i].max_uV);
+ regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
+ }
+err_get:
+ regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
+err_supplies:
+ kfree(msm8x10->supplies);
+err:
+ return ret;
+}
+
+static void msm8x10_wcd_disable_supplies(struct msm8x10_wcd *msm8x10,
+ struct msm8x10_wcd_pdata *pdata)
+{
+ int i;
+
+ regulator_bulk_disable(msm8x10->num_of_supplies,
+ msm8x10->supplies);
+ for (i = 0; i < msm8x10->num_of_supplies; i++) {
+ regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
+ pdata->regulator[i].max_uV);
+ regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
+ }
+ regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
+ kfree(msm8x10->supplies);
+}
+
+static int msm8x10_wcd_bringup(struct msm8x10_wcd *msm8x10)
+{
+ msm8x10->read_dev = msm8x10_wcd_reg_read;
+ msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CDC_RST_CTL, 0x02);
+ msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CHIP_CTL, 0x00);
+ usleep_range(5000, 5000);
+ msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CDC_RST_CTL, 0x03);
+ return 0;
+}
+
+static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
+{
+ mutex_init(&msm8x10->io_lock);
+ mutex_init(&msm8x10->xfer_lock);
+ mutex_init(&msm8x10->pm_lock);
+ msm8x10->wlock_holders = 0;
+
+ iowrite32(0x03C00000, ioremap(0xFD512050, 4));
+ usleep_range(5000, 5000);
+
+ msm8x10_wcd_bringup(msm8x10);
+ return 0;
+}
+
static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -2401,7 +2540,7 @@
if (device_id > 0) {
msm8x10_wcd_modules[device_id++].client = client;
- return ret;
+ goto rtn;
}
dev = &client->dev;
@@ -2421,19 +2560,25 @@
dev_err(&client->dev,
"%s: error, allocation failed\n", __func__);
ret = -ENOMEM;
- goto fail;
+ goto rtn;
}
msm8x10->dev = &client->dev;
msm8x10_wcd_modules[device_id++].client = client;
msm8x10->read_dev = msm8x10_wcd_reg_read;
msm8x10->write_dev = msm8x10_wcd_reg_write;
+ ret = msm8x10_wcd_enable_supplies(msm8x10, pdata);
+ if (ret) {
+ dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
+ __func__);
+ goto err_codec;
+ }
ret = msm8x10_wcd_device_init(msm8x10);
if (ret) {
dev_err(&client->dev,
"%s:msm8x10_wcd_device_init failed with error %d\n",
__func__, ret);
- goto fail;
+ goto err_supplies;
}
dev_set_drvdata(&client->dev, msm8x10);
ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
@@ -2443,7 +2588,14 @@
dev_err(&client->dev,
"%s:snd_soc_register_codec failed with error %d\n",
__func__, ret);
-fail:
+ else
+ goto rtn;
+
+err_supplies:
+ msm8x10_wcd_disable_supplies(msm8x10, pdata);
+err_codec:
+ kfree(msm8x10);
+rtn:
return ret;
}
diff --git a/sound/soc/codecs/msm8x10-wcd.h b/sound/soc/codecs/msm8x10-wcd.h
index 44e8a6d..d250e0a 100644
--- a/sound/soc/codecs/msm8x10-wcd.h
+++ b/sound/soc/codecs/msm8x10-wcd.h
@@ -199,7 +199,7 @@
int (*read_dev)(struct msm8x10_wcd *msm8x10,
unsigned short reg, unsigned int *val);
int (*write_dev)(struct msm8x10_wcd *msm8x10,
- unsigned short reg, unsigned int val);
+ unsigned short reg, u8 val);
u32 num_of_supplies;
struct regulator_bulk_data *supplies;
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 67674f3..b71dd65 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -461,8 +461,8 @@
kcontrol->private_value)->shift;
ucontrol->value.integer.value[0] =
- snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
- (1 << band_idx);
+ (snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
+ (1 << band_idx)) != 0;
dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
iir_idx, band_idx,
@@ -485,23 +485,54 @@
snd_soc_update_bits(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx),
(1 << band_idx), (value << band_idx));
- dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
- iir_idx, band_idx, value);
+ pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+ iir_idx, band_idx,
+ ((snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
+ (1 << band_idx)) != 0));
return 0;
}
static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
int iir_idx, int band_idx,
int coeff_idx)
{
+ uint32_t value = 0;
+
/* Address does not automatically update if reading */
snd_soc_write(codec,
(TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
- (band_idx * BAND_MAX + coeff_idx) & 0x1F);
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t)) & 0x7F);
+
+ value |= snd_soc_read(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx));
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 1) & 0x7F);
+
+ value |= (snd_soc_read(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 8);
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 2) & 0x7F);
+
+ value |= (snd_soc_read(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 16);
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 3) & 0x7F);
/* Mask bits top 2 bits since they are reserved */
- return ((snd_soc_read(codec,
- (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24)) &
- 0x3FFFFFFF;
+ value |= ((snd_soc_read(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) & 0x3F) << 24);
+
+ return value;
+
}
static int tapan_get_iir_band_audio_mixer(
@@ -545,13 +576,19 @@
static void set_iir_band_coeff(struct snd_soc_codec *codec,
int iir_idx, int band_idx,
- int coeff_idx, uint32_t value)
+ uint32_t value)
{
- /* Mask top 3 bits, 6-8 are reserved */
- /* Update address manually each time */
snd_soc_write(codec,
- (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
- (band_idx * BAND_MAX + coeff_idx) & 0x1F);
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+ (value & 0xFF));
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+ (value >> 8) & 0xFF);
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+ (value >> 16) & 0xFF);
/* Mask top 2 bits, 7-8 are reserved */
snd_soc_write(codec,
@@ -570,15 +607,21 @@
int band_idx = ((struct soc_multi_mixer_control *)
kcontrol->private_value)->shift;
- set_iir_band_coeff(codec, iir_idx, band_idx, 0,
+ /* Mask top bit it is reserved */
+ /* Updates addr automatically for each B2 write */
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
+
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[0]);
- set_iir_band_coeff(codec, iir_idx, band_idx, 1,
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[1]);
- set_iir_band_coeff(codec, iir_idx, band_idx, 2,
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[2]);
- set_iir_band_coeff(codec, iir_idx, band_idx, 3,
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[3]);
- set_iir_band_coeff(codec, iir_idx, band_idx, 4,
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[4]);
dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 43a1042..5d4f9e6 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -110,6 +110,15 @@
AANC_FF_GAIN_ADAPTIVE,
AANC_FFGAIN_ADAPTIVE_EN,
AANC_GAIN_CONTROL,
+ SPKR_CLIP_PIPE_BANK_SEL,
+ SPKR_CLIPDET_VAL0,
+ SPKR_CLIPDET_VAL1,
+ SPKR_CLIPDET_VAL2,
+ SPKR_CLIPDET_VAL3,
+ SPKR_CLIPDET_VAL4,
+ SPKR_CLIPDET_VAL5,
+ SPKR_CLIPDET_VAL6,
+ SPKR_CLIPDET_VAL7,
MAX_CFG_REGISTERS,
};
@@ -182,6 +191,74 @@
(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_ANC1_GAIN_CTL),
AANC_GAIN_CONTROL, 0xFF, 8, 0
},
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_DESTN3),
+ MAD_CLIP_INT_DEST_SELECT_REG, 0x8, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_MASK3),
+ MAD_CLIP_INT_MASK_REG, 0x8, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_STATUS3),
+ MAD_CLIP_INT_STATUS_REG, 0x8, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_CLEAR3),
+ MAD_CLIP_INT_CLEAR_REG, 0x8, 8, 0
+ },
+};
+
+static struct afe_param_cdc_reg_cfg clip_reg_cfg[] = {
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_B1_CTL),
+ SPKR_CLIP_PIPE_BANK_SEL, 0x3, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL0),
+ SPKR_CLIPDET_VAL0, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL1),
+ SPKR_CLIPDET_VAL1, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL2),
+ SPKR_CLIPDET_VAL2, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL3),
+ SPKR_CLIPDET_VAL3, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL4),
+ SPKR_CLIPDET_VAL4, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL5),
+ SPKR_CLIPDET_VAL5, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL6),
+ SPKR_CLIPDET_VAL6, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL7),
+ SPKR_CLIPDET_VAL7, 0xff, 8, 0
+ },
};
static struct afe_param_cdc_reg_cfg_data taiko_audio_reg_cfg = {
@@ -189,11 +266,22 @@
.reg_data = audio_reg_cfg,
};
+static struct afe_param_cdc_reg_cfg_data taiko_clip_reg_cfg = {
+ .num_registers = ARRAY_SIZE(clip_reg_cfg),
+ .reg_data = clip_reg_cfg,
+};
+
static struct afe_param_id_cdc_aanc_version taiko_cdc_aanc_version = {
.cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION,
.aanc_hw_version = AANC_HW_BLOCK_VERSION_2,
};
+static struct afe_param_id_clip_bank_sel clip_bank_sel = {
+ .minor_version = AFE_API_VERSION_CLIP_BANK_SEL_CFG,
+ .num_banks = AFE_CLIP_MAX_BANKS,
+ .bank_map = {0, 1, 2, 3},
+};
+
module_param_cb(spkr_drv_wrnd, &spkr_drv_wrnd_param_ops, &spkr_drv_wrnd, 0644);
MODULE_PARM_DESC(spkr_drv_wrnd,
"Run software workaround to avoid leakage on the speaker drive");
@@ -400,6 +488,8 @@
bool spkr_pa_widget_on;
struct regulator *spkdrv_reg;
+ bool mbhc_started;
+
struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
/* resmgr module */
@@ -2560,7 +2650,9 @@
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
- if (micb_ctl_reg == TAIKO_A_MICB_2_CTL)
+ if (taiko->mbhc_started &&
+ taiko->resmgr.pdata->micbias.bias2_is_headset_only &&
+ micb_ctl_reg == TAIKO_A_MICB_2_CTL)
wcd9xxx_resmgr_add_cond_update_bits(&taiko->resmgr,
WCD9XXX_COND_HPH_MIC,
micb_ctl_reg, w->shift,
@@ -2575,7 +2667,9 @@
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_on);
break;
case SND_SOC_DAPM_POST_PMD:
- if (micb_ctl_reg == TAIKO_A_MICB_2_CTL)
+ if (taiko->mbhc_started &&
+ taiko->resmgr.pdata->micbias.bias2_is_headset_only &&
+ micb_ctl_reg == TAIKO_A_MICB_2_CTL)
wcd9xxx_resmgr_rm_cond_update_bits(&taiko->resmgr,
WCD9XXX_COND_HPH_MIC,
micb_ctl_reg, 7, false);
@@ -4620,9 +4714,6 @@
dai = &taiko_p->dai[w->shift];
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- /*Enable Clip Detection*/
- snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_CLIP_DET,
- 0x8, 0x8);
/*Enable V&I sensing*/
snd_soc_update_bits(codec, TAIKO_A_SPKR_PROT_EN,
0x88, 0x88);
@@ -4635,6 +4726,7 @@
/*Enable Current Decimator*/
snd_soc_update_bits(codec,
TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x1F, 0x13);
+ (void) taiko_codec_enable_slim_chmask(dai, true);
ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
dai->rate, dai->bit_width,
&dai->grph);
@@ -4657,9 +4749,6 @@
/*Disable V&I sensing*/
snd_soc_update_bits(codec, TAIKO_A_SPKR_PROT_EN,
0x88, 0x00);
- /*Disable clip detection*/
- snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_CLIP_DET,
- 0x8, 0x0);
break;
}
out_vi:
@@ -5877,8 +5966,12 @@
int taiko_hs_detect(struct snd_soc_codec *codec,
struct wcd9xxx_mbhc_config *mbhc_cfg)
{
+ int rc;
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
- return wcd9xxx_mbhc_start(&taiko->mbhc, mbhc_cfg);
+ rc = wcd9xxx_mbhc_start(&taiko->mbhc, mbhc_cfg);
+ if (!rc)
+ taiko->mbhc_started = true;
+ return rc;
}
EXPORT_SYMBOL_GPL(taiko_hs_detect);
@@ -5934,13 +6027,20 @@
taiko_init_slim_slave_cfg(codec);
taiko_slim_interface_init_reg(codec);
- wcd9xxx_mbhc_deinit(&taiko->mbhc);
- ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
- WCD9XXX_MBHC_VERSION_TAIKO);
- if (ret)
- pr_err("%s: mbhc init failed %d\n", __func__, ret);
- else
- wcd9xxx_mbhc_start(&taiko->mbhc, taiko->mbhc.mbhc_cfg);
+ if (taiko->mbhc_started) {
+ wcd9xxx_mbhc_deinit(&taiko->mbhc);
+ taiko->mbhc_started = false;
+ ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
+ WCD9XXX_MBHC_VERSION_TAIKO);
+ if (ret) {
+ pr_err("%s: mbhc init failed %d\n", __func__, ret);
+ } else {
+ ret = wcd9xxx_mbhc_start(&taiko->mbhc,
+ taiko->mbhc.mbhc_cfg);
+ if (!ret)
+ taiko->mbhc_started = true;
+ }
+ }
mutex_unlock(&codec->mutex);
return ret;
}
@@ -5949,6 +6049,7 @@
enum afe_config_type config_type)
{
struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx *taiko_core = dev_get_drvdata(codec->dev->parent);
switch (config_type) {
case AFE_SLIMBUS_SLAVE_CONFIG:
@@ -5959,6 +6060,16 @@
return &taiko_slimbus_slave_port_cfg;
case AFE_AANC_VERSION:
return &taiko_cdc_aanc_version;
+ case AFE_CLIP_BANK_SEL:
+ if (!TAIKO_IS_1_0(taiko_core->version))
+ return &clip_bank_sel;
+ else
+ return NULL;
+ case AFE_CDC_CLIP_REGISTERS_CONFIG:
+ if (!TAIKO_IS_1_0(taiko_core->version))
+ return &taiko_clip_reg_cfg;
+ else
+ return NULL;
default:
pr_err("%s: Unknown config_type 0x%x\n", __func__, config_type);
return NULL;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index daba6d5..a37b4eb 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -2786,6 +2786,7 @@
wcd9xxx_turn_onoff_rel_detection(codec, true);
pr_debug("%s: leave\n", __func__);
+ return;
gen_err:
pr_err("%s: Error returned, ret: %d\n", __func__, ret);
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index ebde90b..7ab4811 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -55,8 +55,7 @@
# for MSM 8960 sound card driver
obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
-
-snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
+snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-loopback.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o msm-pcm-dtmf.o msm-pcm-host-voice.o
snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index b140b5b..c3967dc 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -2336,6 +2336,9 @@
{
int ret;
+ /* Set GPIO headset detection by default */
+ hs_detect_use_gpio = true;
+
if (!cpu_is_msm9615()) {
pr_err("%s: Not the right machine type\n", __func__);
return -ENODEV ;
@@ -2413,8 +2416,6 @@
sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
secpcm_portslc_virt_addr = ioremap(SEC_PCM_PORT_SLC_ADDR, 4);
- hs_detect_use_gpio = true;
-
return ret;
}
module_init(mdm9615_audio_init);
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 8db13f6..1b51595 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -236,6 +236,17 @@
.rate_min = 8000,
.rate_max = 192000,
},
+ .capture = {
+ .stream_name = "MultiMedia6 Capture",
+ .aif_name = "MM_UL6",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia6",
},
@@ -549,6 +560,34 @@
.name = "SEC_I2S_RX_HOSTLESS",
},
{
+ .capture = {
+ .stream_name = "Primary MI2S_TX Hostless Capture",
+ .aif_name = "PRI_MI2S_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_MI2S_TX_HOSTLESS",
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary MI2S_RX Hostless Playback",
+ .aif_name = "SEC_MI2S_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_MI2S_RX_HOSTLESS",
+ },
+ {
.playback = {
.stream_name = "Voice2 Playback",
.aif_name = "VOICE2_DL",
diff --git a/sound/soc/msm/msm-pcm-loopback.c b/sound/soc/msm/msm-pcm-loopback.c
new file mode 100644
index 0000000..84ea9c6
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-loopback.c
@@ -0,0 +1,362 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*/
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/apr_audio.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/q6asm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm-routing.h"
+
+struct msm_pcm_loopback {
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+
+ int instance;
+
+ struct mutex lock;
+
+ uint32_t samp_rate;
+ uint32_t channel_mode;
+
+ int playback_start;
+ int capture_start;
+ int session_id;
+ struct audio_client *audio_client;
+};
+
+static void stop_pcm(struct msm_pcm_loopback *pcm);
+
+static const struct snd_pcm_hardware dummy_pcm_hardware = {
+ .formats = 0xffffffff,
+ .channels_min = 1,
+ .channels_max = UINT_MAX,
+
+ /* Random values to keep userspace happy when checking constraints */
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ .buffer_bytes_max = 128*1024,
+ .period_bytes_min = 1024,
+ .period_bytes_max = 1024*2,
+ .periods_min = 2,
+ .periods_max = 128,
+};
+
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+ void *priv_data)
+{
+ struct msm_pcm_loopback *pcm = priv_data;
+
+ BUG_ON(!pcm);
+
+ pr_debug("%s: event %x\n", __func__, event);
+
+ switch (event) {
+ case MSM_PCM_RT_EVT_DEVSWITCH:
+ q6asm_cmd(pcm->audio_client, CMD_PAUSE);
+ q6asm_cmd(pcm->audio_client, CMD_FLUSH);
+ q6asm_run(pcm->audio_client, 0, 0, 0);
+ default:
+ break;
+ }
+}
+
+static void msm_pcm_loopback_event_handler(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv)
+{
+ pr_debug("%s\n", __func__);
+ switch (opcode) {
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ pr_err("Not Supported Event opcode[0x%x]\n", opcode);
+ break;
+ }
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct msm_pcm_loopback *pcm;
+ int ret = 0;
+ struct msm_pcm_routing_evt event;
+
+ pcm = dev_get_drvdata(rtd->platform->dev);
+ mutex_lock(&pcm->lock);
+
+ snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_substream = substream;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_substream = substream;
+
+ pcm->instance++;
+ dev_dbg(rtd->platform->dev, "%s: pcm out open: %d,%d\n", __func__,
+ pcm->instance, substream->stream);
+ if (pcm->instance == 2) {
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+ if (pcm->audio_client != NULL)
+ stop_pcm(pcm);
+
+ pcm->audio_client = q6asm_audio_client_alloc(
+ (app_cb)msm_pcm_loopback_event_handler, pcm);
+ if (!pcm->audio_client) {
+ dev_err(rtd->platform->dev,
+ "%s: Could not allocate memory\n", __func__);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ pcm->session_id = pcm->audio_client->session;
+ pcm->audio_client->perf_mode = false;
+ ret = q6asm_open_loopack(pcm->audio_client);
+ if (ret < 0) {
+ dev_err(rtd->platform->dev,
+ "%s: pcm out open failed\n", __func__);
+ q6asm_audio_client_free(pcm->audio_client);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ event.event_func = msm_pcm_route_event_handler;
+ event.priv_data = (void *) pcm;
+ msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->capture_substream->stream);
+ msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->playback_substream->stream,
+ event);
+ }
+ dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
+ __func__ , pcm->instance, substream->pcm->id);
+ runtime->private_data = pcm;
+
+ mutex_unlock(&pcm->lock);
+
+ return 0;
+}
+
+static void stop_pcm(struct msm_pcm_loopback *pcm)
+{
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+
+ if (pcm->audio_client == NULL)
+ return;
+ q6asm_cmd(pcm->audio_client, CMD_CLOSE);
+
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ q6asm_audio_client_free(pcm->audio_client);
+ pcm->audio_client = NULL;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ int ret = 0;
+
+ mutex_lock(&pcm->lock);
+
+ dev_dbg(rtd->platform->dev, "%s: end pcm call:%d\n",
+ __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_start = 0;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_start = 0;
+
+ pcm->instance--;
+ if (!pcm->playback_start || !pcm->capture_start) {
+ dev_dbg(rtd->platform->dev, "%s: end pcm call\n", __func__);
+ stop_pcm(pcm);
+ }
+
+ mutex_unlock(&pcm->lock);
+ return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ mutex_lock(&pcm->lock);
+
+ dev_dbg(rtd->platform->dev, "%s: ASM loopback stream:%d\n",
+ __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (!pcm->playback_start)
+ pcm->playback_start = 1;
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (!pcm->capture_start)
+ pcm->capture_start = 1;
+ }
+ mutex_unlock(&pcm->lock);
+
+ return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ dev_dbg(rtd->platform->dev,
+ "%s: playback_start:%d,capture_start:%d\n", __func__,
+ pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ dev_dbg(rtd->platform->dev,
+ "%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
+ __func__, pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ dev_dbg(rtd->platform->dev, "%s: ASM loopback\n", __func__);
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+}
+
+static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .hw_params = msm_pcm_hw_params,
+ .hw_free = msm_pcm_hw_free,
+ .close = msm_pcm_close,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+};
+
+
+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);
+ return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+ struct msm_pcm_loopback *pcm;
+
+ dev_dbg(&pdev->dev, "%s: dev name %s\n",
+ __func__, dev_name(&pdev->dev));
+
+ pcm = kzalloc(sizeof(struct msm_pcm_loopback), GFP_KERNEL);
+ if (!pcm) {
+ dev_err(&pdev->dev, "%s Failed to allocate memory for pcm\n",
+ __func__);
+ return -ENOMEM;
+ } else {
+ mutex_init(&pcm->lock);
+ dev_set_drvdata(&pdev->dev, pcm);
+ }
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ struct msm_pcm_loopback *pcm;
+
+ pcm = dev_get_drvdata(&pdev->dev);
+ mutex_destroy(&pcm->lock);
+
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-pcm-loopback",
+ .owner = THIS_MODULE,
+ },
+ .probe = msm_pcm_probe,
+ .remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM loopback platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index e74a0dd..2c3c6df 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -658,6 +658,11 @@
msm_bedais[reg].sample_rate, channels,
DEFAULT_COPP_TOPOLOGY);
+ if (session_type == SESSION_TYPE_RX &&
+ fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_DEVSWITCH,
+ fdai->event_info.priv_data);
msm_pcm_routing_build_matrix(val,
fdai->strm_id, path_type);
@@ -976,10 +981,8 @@
static int msm_routing_set_fm_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- afe_loopback_gain(INT_FM_TX , ucontrol->value.integer.value[0]);
-
+ afe_loopback_gain(INT_FM_TX, ucontrol->value.integer.value[0]);
msm_route_fm_vol_control = ucontrol->value.integer.value[0];
-
return 0;
}
@@ -1660,6 +1663,9 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1696,6 +1702,9 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1714,6 +1723,9 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -1810,6 +1822,12 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -2715,6 +2733,7 @@
SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@@ -2828,6 +2847,8 @@
mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -3008,6 +3029,7 @@
{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
@@ -3026,6 +3048,7 @@
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3040,12 +3063,14 @@
{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -3054,12 +3079,14 @@
{"MM_UL2", NULL, "MultiMedia2 Mixer"},
{"MM_UL4", NULL, "MultiMedia4 Mixer"},
{"MM_UL5", NULL, "MultiMedia5 Mixer"},
+ {"MM_UL6", NULL, "MultiMedia6 Mixer"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index c42e155..e25a44a 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -117,6 +117,7 @@
enum msm_pcm_routing_event {
MSM_PCM_RT_EVT_BUF_RECFG,
+ MSM_PCM_RT_EVT_DEVSWITCH,
MSM_PCM_RT_EVT_MAX,
};
/* dai_id: front-end ID,
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 737317c..dd92e34 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -1143,6 +1143,22 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
},
+ {
+ .name = "MSM8960 FM",
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
/* Backend DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 7acb294..945840d 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -75,6 +75,11 @@
#define EXT_CLASS_D_DIS_DELAY 3000
#define EXT_CLASS_D_DELAY_DELTA 2000
+/* It takes about 13ms for Class-AB PAs to ramp-up */
+#define EXT_CLASS_AB_EN_DELAY 10000
+#define EXT_CLASS_AB_DIS_DELAY 1000
+#define EXT_CLASS_AB_DELAY_DELTA 1000
+
#define NUM_OF_AUXPCM_GPIOS 4
static inline int param_is_mask(int p)
@@ -184,6 +189,8 @@
static struct platform_device *spdev;
static struct regulator *ext_spk_amp_regulator;
static int ext_spk_amp_gpio = -1;
+static int ext_ult_spk_amp_gpio = -1;
+static int ext_ult_lo_amp_gpio = -1;
static int msm8974_spk_control = 1;
static int msm8974_ext_spk_pamp;
static int msm_slim_0_rx_ch = 1;
@@ -231,9 +238,43 @@
}
}
+ ext_ult_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,ext-ult-spk-amp-gpio", 0);
+
+ if (ext_ult_spk_amp_gpio >= 0) {
+ ret = gpio_request(ext_ult_spk_amp_gpio,
+ "ext_ult_spk_amp_gpio");
+ if (ret) {
+ pr_err("%s: gpio_request failed for ext-ult_spk-amp-gpio.\n",
+ __func__);
+ return -EINVAL;
+ }
+ gpio_direction_output(ext_ult_spk_amp_gpio, 0);
+ }
+
return 0;
}
+static void msm8974_liquid_ext_ult_spk_power_amp_enable(u32 on)
+{
+ if (on) {
+ regulator_enable(ext_spk_amp_regulator);
+ gpio_direction_output(ext_ult_spk_amp_gpio, 1);
+ /* time takes enable the external power class AB amplifier */
+ usleep_range(EXT_CLASS_AB_EN_DELAY,
+ EXT_CLASS_AB_EN_DELAY + EXT_CLASS_AB_DELAY_DELTA);
+ } else {
+ gpio_direction_output(ext_ult_spk_amp_gpio, 0);
+ regulator_disable(ext_spk_amp_regulator);
+ /* time takes disable the external power class AB amplifier */
+ usleep_range(EXT_CLASS_AB_DIS_DELAY,
+ EXT_CLASS_AB_DIS_DELAY + EXT_CLASS_AB_DELAY_DELTA);
+ }
+
+ pr_debug("%s: %s external ultrasound SPKR_DRV PAs.\n", __func__,
+ on ? "Enable" : "Disable");
+}
+
static void msm8974_liquid_ext_spk_power_amp_enable(u32 on)
{
if (on) {
@@ -287,7 +328,6 @@
}
-
static irqreturn_t msm8974_liquid_docking_irq_handler(int irq, void *dev)
{
struct msm8974_liquid_dock_dev *dock_dev = dev;
@@ -351,41 +391,82 @@
return 0;
}
-
-
-
-static void msm8974_ext_spk_power_amp_on(u32 spk)
+static int msm8974_liquid_ext_spk_power_amp_on(u32 spk)
{
- if (spk & (LO_1_SPK_AMP |
- LO_3_SPK_AMP |
- LO_2_SPK_AMP |
- LO_4_SPK_AMP)) {
+ int rc;
- pr_debug("%s() External Left/Right Speakers already turned on. spk = 0x%08x\n",
- __func__, spk);
+ if (spk & (LO_1_SPK_AMP | LO_3_SPK_AMP | LO_2_SPK_AMP | LO_4_SPK_AMP)) {
+ pr_debug("%s: External speakers are already on. spk = 0x%x\n",
+ __func__, spk);
msm8974_ext_spk_pamp |= spk;
-
if ((msm8974_ext_spk_pamp & LO_1_SPK_AMP) &&
- (msm8974_ext_spk_pamp & LO_3_SPK_AMP) &&
- (msm8974_ext_spk_pamp & LO_2_SPK_AMP) &&
- (msm8974_ext_spk_pamp & LO_4_SPK_AMP)) {
-
+ (msm8974_ext_spk_pamp & LO_3_SPK_AMP) &&
+ (msm8974_ext_spk_pamp & LO_2_SPK_AMP) &&
+ (msm8974_ext_spk_pamp & LO_4_SPK_AMP))
if (ext_spk_amp_gpio >= 0 &&
- msm8974_liquid_dock_dev != NULL &&
- msm8974_liquid_dock_dev->dock_plug_det == 0)
+ msm8974_liquid_dock_dev &&
+ msm8974_liquid_dock_dev->dock_plug_det == 0)
msm8974_liquid_ext_spk_power_amp_enable(1);
- }
+ rc = 0;
} else {
+ pr_err("%s: Invalid external speaker ampl. spk = 0x%x\n",
+ __func__, spk);
+ rc = -EINVAL;
+ }
- pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+ return rc;
+}
+
+static void msm8974_fluid_ext_us_amp_on(u32 spk)
+{
+ if (!gpio_is_valid(ext_ult_lo_amp_gpio)) {
+ pr_err("%s: ext_ult_lo_amp_gpio isn't configured\n", __func__);
+ } else if (spk & (LO_1_SPK_AMP | LO_3_SPK_AMP)) {
+ pr_debug("%s: External US amp is already on. spk = 0x%x\n",
+ __func__, spk);
+ msm8974_ext_spk_pamp |= spk;
+ if ((msm8974_ext_spk_pamp & LO_1_SPK_AMP) &&
+ (msm8974_ext_spk_pamp & LO_3_SPK_AMP))
+ pr_debug("%s: Turn on US amp. spk = 0x%x\n",
+ __func__, spk);
+ gpio_direction_output(ext_ult_lo_amp_gpio, 1);
+
+ } else {
+ pr_err("%s: Invalid external speaker ampl. spk = 0x%x\n",
__func__, spk);
- return;
}
}
-static void msm8974_ext_spk_power_amp_off(u32 spk)
+static void msm8974_fluid_ext_us_amp_off(u32 spk)
{
+ if (!gpio_is_valid(ext_ult_lo_amp_gpio)) {
+ pr_err("%s: ext_ult_lo_amp_gpio isn't configured\n", __func__);
+ } else if (spk & (LO_1_SPK_AMP | LO_3_SPK_AMP)) {
+ pr_debug("%s LO1 and LO3. spk = 0x%x", __func__, spk);
+ if (!msm8974_ext_spk_pamp) {
+ pr_debug("%s: Turn off US amp. spk = 0x%x\n",
+ __func__, spk);
+ gpio_direction_output(ext_ult_lo_amp_gpio, 0);
+ msm8974_ext_spk_pamp = 0;
+ }
+ } else {
+ pr_err("%s: Invalid external speaker ampl. spk = 0x%x\n",
+ __func__, spk);
+ }
+}
+
+static void msm8974_ext_spk_power_amp_on(u32 spk)
+{
+ if (gpio_is_valid(ext_spk_amp_gpio))
+ msm8974_liquid_ext_spk_power_amp_on(spk);
+ else if (gpio_is_valid(ext_ult_lo_amp_gpio))
+ msm8974_fluid_ext_us_amp_on(spk);
+}
+
+static void msm8974_liquid_ext_spk_power_amp_off(u32 spk)
+{
+
if (spk & (LO_1_SPK_AMP |
LO_3_SPK_AMP |
LO_2_SPK_AMP |
@@ -410,6 +491,14 @@
}
}
+static void msm8974_ext_spk_power_amp_off(u32 spk)
+{
+ if (gpio_is_valid(ext_spk_amp_gpio))
+ msm8974_liquid_ext_spk_power_amp_off(spk);
+ else if (gpio_is_valid(ext_ult_lo_amp_gpio))
+ msm8974_fluid_ext_us_amp_off(spk);
+}
+
static void msm8974_ext_control(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
@@ -495,6 +584,33 @@
}
+static int msm_ext_spkramp_ultrasound_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+
+ pr_debug("%s()\n", __func__);
+
+ if (!strncmp(w->name, "SPK_ultrasound amp", 19)) {
+ if (!gpio_is_valid(ext_ult_spk_amp_gpio)) {
+ pr_err("%s: ext_ult_spk_amp_gpio isn't configured\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ msm8974_liquid_ext_ult_spk_power_amp_enable(1);
+ else
+ msm8974_liquid_ext_ult_spk_power_amp_enable(0);
+
+ } else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm)
{
@@ -567,6 +683,8 @@
SND_SOC_DAPM_SPK("Lineout_2 amp", msm_ext_spkramp_event),
SND_SOC_DAPM_SPK("Lineout_4 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("SPK_ultrasound amp",
+ msm_ext_spkramp_ultrasound_event),
SND_SOC_DAPM_MIC("Handset Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -1142,6 +1260,22 @@
return 0;
}
+static int msm_slim_4_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ return 0;
+}
+
static int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1306,7 +1440,26 @@
__func__, err);
goto out;
}
-
+ config_data = taiko_get_afe_config(codec,
+ AFE_CDC_CLIP_REGISTERS_CONFIG);
+ if (config_data) {
+ err = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+ config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set clip registers %d\n",
+ __func__, err);
+ return err;
+ }
+ }
+ config_data = taiko_get_afe_config(codec, AFE_CLIP_BANK_SEL);
+ if (config_data) {
+ err = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set AFE bank selection %d\n",
+ __func__, err);
+ return err;
+ }
+ }
/* start mbhc */
mbhc_cfg.calibration = def_taiko_mbhc_cal();
if (mbhc_cfg.calibration) {
@@ -2058,7 +2211,7 @@
.codec_name = "taiko_codec",
.codec_dai_name = "taiko_vifeedback",
.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
- .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .be_hw_params_fixup = msm_slim_4_tx_be_hw_params_fixup,
.ops = &msm8974_be_ops,
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
@@ -2251,7 +2404,7 @@
{
struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
int ret;
- if (pdata->us_euro_gpio) {
+ if (pdata->us_euro_gpio >= 0) {
dev_dbg(card->dev, "%s : us_euro gpio request %d", __func__,
pdata->us_euro_gpio);
ret = gpio_request(pdata->us_euro_gpio, "TAIKO_CODEC_US_EURO");
@@ -2272,6 +2425,7 @@
struct msm8974_asoc_mach_data *pdata;
int ret;
const char *auxpcm_pri_gpio_set = NULL;
+ const char *prop_name_ult_lo_gpio = "qcom,ext-ult-lo-amp-gpio";
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "No platform supplied from device tree\n");
@@ -2343,9 +2497,26 @@
goto err;
}
+ ext_ult_lo_amp_gpio = of_get_named_gpio(pdev->dev.of_node,
+ prop_name_ult_lo_gpio, 0);
+ if (!gpio_is_valid(ext_ult_lo_amp_gpio)) {
+ dev_dbg(&pdev->dev,
+ "Couldn't find %s property in node %s, %d\n",
+ prop_name_ult_lo_gpio, pdev->dev.of_node->full_name,
+ ext_ult_lo_amp_gpio);
+ } else {
+ ret = gpio_request(ext_ult_lo_amp_gpio, "US_AMP_GPIO");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: Failed to request US amp gpio %d\n",
+ __func__, ext_ult_lo_amp_gpio);
+ goto err;
+ }
+ }
+
ret = msm8974_prepare_codec_mclk(card);
if (ret)
- goto err;
+ goto err1;
if (of_property_read_bool(pdev->dev.of_node, "qcom,hdmi-audio-rx")) {
dev_info(&pdev->dev, "%s(): hdmi audio support present\n",
@@ -2369,7 +2540,7 @@
pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
"qcom,us-euro-gpios", 0);
if (pdata->us_euro_gpio < 0) {
- dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+ dev_info(&pdev->dev, "property %s not detected in node %s",
"qcom,us-euro-gpios",
pdev->dev.of_node->full_name);
} else {
@@ -2394,7 +2565,7 @@
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
ret);
- goto err;
+ goto err1;
}
ret = of_property_read_string(pdev->dev.of_node,
@@ -2403,7 +2574,7 @@
dev_err(&pdev->dev, "Looking up %s property in node %s failed",
"qcom,prim-auxpcm-gpio-set",
pdev->dev.of_node->full_name);
- goto err;
+ goto err1;
}
if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-prim")) {
lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
@@ -2413,20 +2584,24 @@
dev_err(&pdev->dev, "Invalid value %s for AUXPCM GPIO set\n",
auxpcm_pri_gpio_set);
ret = -EINVAL;
- goto err;
+ goto err1;
}
if (lpaif_pri_muxsel_virt_addr == NULL) {
pr_err("%s Pri muxsel virt addr is null\n", __func__);
ret = -EINVAL;
- goto err;
+ goto err1;
}
lpaif_sec_muxsel_virt_addr = ioremap(LPAIF_SEC_MODE_MUXSEL, 4);
if (lpaif_sec_muxsel_virt_addr == NULL) {
pr_err("%s Sec muxsel virt addr is null\n", __func__);
ret = -EINVAL;
- goto err;
+ goto err1;
}
return 0;
+
+err1:
+ gpio_free(ext_ult_lo_amp_gpio);
+ ext_ult_lo_amp_gpio = -1;
err:
if (pdata->mclk_gpio > 0) {
dev_dbg(&pdev->dev, "%s free gpio %d\n",
@@ -2452,9 +2627,15 @@
if (ext_spk_amp_regulator)
regulator_put(ext_spk_amp_regulator);
+ if (gpio_is_valid(ext_ult_spk_amp_gpio))
+ gpio_free(ext_ult_spk_amp_gpio);
+
+ if (gpio_is_valid(ext_ult_lo_amp_gpio))
+ gpio_free(ext_ult_lo_amp_gpio);
+
gpio_free(pdata->mclk_gpio);
gpio_free(pdata->us_euro_gpio);
- if (ext_spk_amp_gpio >= 0)
+ if (gpio_is_valid(ext_spk_amp_gpio))
gpio_free(ext_spk_amp_gpio);
if (msm8974_liquid_dock_dev != NULL) {
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 4dd85fc..4db3ea5 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/qpnp/clkdiv.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -26,8 +27,196 @@
#include <asm/mach-types.h>
#include <mach/socinfo.h>
#include <qdsp6v2/msm-pcm-routing-v2.h>
+#include <sound/q6afe-v2.h>
#include <linux/module.h>
+#include "../codecs/msm8x10-wcd.h"
#define DRV_NAME "msm8x10-asoc-wcd"
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_btsco_ch = 1;
+
+static int msm_proxy_rx_ch = 2;
+
+#define MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL 0xFE03B004
+#define MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR 0xFE02C000
+#define MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR 0xFE02C004
+#define MSM8X10_DINO_LPASS_DIGCODEC_M 0xFE02C008
+#define MSM8X10_DINO_LPASS_DIGCODEC_N 0xFE02C00C
+#define MSM8X10_DINO_LPASS_DIGCODEC_D 0xFE02C010
+#define MSM8X10_DINO_LPASS_DIGCODEC_CBCR 0xFE02C014
+#define MSM8X10_DINO_LPASS_DIGCODEC_AHB_CBCR 0xFE02C018
+
+/*
+ * There is limitation for the clock root selection from
+ * either MI2S or DIG_CODEC.
+ * If DIG_CODEC root can only provide 9.6MHz clock
+ * to codec while MI2S only can provide
+ * 12.288MHz.
+ */
+enum {
+ DIG_CDC_CLK_SEL_DIG_CODEC,
+ DIG_CDC_CLK_SEL_PRI_MI2S,
+ DIG_CDC_CLK_SEL_SEC_MI2S,
+};
+
+static struct afe_clk_cfg mi2s_rx_clk = {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_OSR_CLK_12_P288_MHZ,
+ Q6AFE_LPASS_CLK_SRC_INTERNAL,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ Q6AFE_LPASS_MODE_BOTH_VALID,
+ 0,
+};
+
+static struct afe_clk_cfg mi2s_tx_clk = {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_OSR_CLK_12_P288_MHZ,
+ Q6AFE_LPASS_CLK_SRC_INTERNAL,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ Q6AFE_LPASS_MODE_BOTH_VALID,
+ 0,
+};
+
+static struct afe_digital_clk_cfg digital_cdc_clk = {
+ AFE_API_VERSION_I2S_CONFIG,
+ 9600000,
+ 5, /* Digital Codec root */
+ 0,
+};
+
+static atomic_t aud_init_rsc_ref;
+
+static int msm8x10_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+
+static const struct snd_soc_dapm_route msm8x10_common_audio_map[] = {
+ {"RX_BIAS", NULL, "MCLK"},
+ {"INT_LDO_H", NULL, "MCLK"},
+ {"MIC BIAS External", NULL, "Handset Mic"},
+ {"MIC BIAS Internal2", NULL, "Headset Mic"},
+ {"AMIC1", NULL, "MIC BIAS External"},
+ {"AMIC2", NULL, "MIC BIAS Internal2"},
+
+};
+
+static const struct snd_soc_dapm_widget msm8x10_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
+ msm8x10_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+
+};
+
+/*
+ * This function will be replaced by
+ * afe_set_lpass_internal_digital_codec_clock(port_id, cfg)
+ * in the future after LPASS API fix
+ */
+static int msm_enable_lpass_mclk(void)
+{
+ /* Select the codec root */
+ iowrite32(DIG_CDC_CLK_SEL_DIG_CODEC,
+ ioremap(MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL,
+ 4));
+ /* Div-2 */
+ iowrite32(0x3, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4));
+ /* Digital codec clock enable */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+ /* AHB clock enable */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_AHB_CBCR, 4));
+ /* Set the update bit to make the settings go through */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4));
+
+ return 0;
+}
+
+static int msm_enable_mclk_root(u16 port_id, struct afe_digital_clk_cfg *cfg)
+{
+ int ret = 0;
+ /*
+ * msm_enable_lpass_mclk() function call will be replaced by
+ * ret = afe_set_lpass_internal_digital_codec_clock(port_id, cfg)
+ * in the future. Currentlt there is a bug in LPASS plan which
+ * doesn't consider the digital codec clock. It will be fixed soon
+ * in new Q6 image
+ */
+ msm_enable_lpass_mclk();
+ pr_debug("%s(): return = %d\n", __func__, ret);
+ return ret;
+}
+
+static int msm_config_mclk(u16 port_id, struct afe_digital_clk_cfg *cfg)
+{
+ /* Select the codec root */
+ iowrite32(DIG_CDC_CLK_SEL_DIG_CODEC,
+ ioremap(MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL,
+ 4));
+ /* Div-2 */
+ iowrite32(0x3, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4));
+ /* Digital codec clock enable */
+ if (cfg->clk_val == 0) {
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+ pr_debug("%s(line %d)\n", __func__, __LINE__);
+ } else {
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+ pr_debug("%s(line %d)\n", __func__, __LINE__);
+ }
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+ /* AHB clock enable */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_AHB_CBCR, 4));
+ /* Set the update bit to make the settings go through */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4));
+
+ return 0;
+
+}
+
+static int msm_config_mi2s_clk(int enable)
+{
+ int ret = 0;
+ pr_debug("%s(line %d):enable = %x\n", __func__, __LINE__, enable);
+ if (enable) {
+ digital_cdc_clk.clk_val = 9600000;
+ mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+ mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &mi2s_rx_clk);
+ mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+ mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &mi2s_tx_clk);
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+ } else {
+ digital_cdc_clk.clk_val = 0;
+ mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &mi2s_rx_clk);
+ mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &mi2s_tx_clk);
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+ }
+ ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX, &digital_cdc_clk);
+ return ret;
+}
+
static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
@@ -41,13 +230,22 @@
return 0;
}
-static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
{
- pr_info("%s(), dev_name%s\n", __func__, dev_name(rtd->cpu_dai->dev));
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = msm_btsco_rate;
+ channels->min = channels->max = msm_btsco_ch;
+
return 0;
}
-static int msm_snd_hw_params(struct snd_pcm_substream *substream,
+static int msm_mi2s_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
@@ -55,34 +253,184 @@
return 0;
}
-static int msm_snd_startup(struct snd_pcm_substream *substream)
+static int mi2s_clk_ctl(struct snd_pcm_substream *substream, bool enable)
{
+ int ret = 0;
+ if (enable) {
+ digital_cdc_clk.clk_val = 9600000;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+ mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &mi2s_rx_clk);
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+ mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &mi2s_tx_clk);
+ } else
+ pr_err("%s:Not valid substream.\n", __func__);
+
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+ } else {
+ digital_cdc_clk.clk_val = 0;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &mi2s_rx_clk);
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &mi2s_tx_clk);
+ } else
+ pr_err("%s:Not valid substream.\n", __func__);
+
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+ }
+ ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX, &digital_cdc_clk);
+ return ret;
+}
+
+static int msm8x10_enable_codec_ext_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm)
+{
+ int ret = 0;
+
+ pr_debug("%s: enable = %d codec name %s enable %x\n",
+ __func__, enable, codec->name, enable);
+ if (enable) {
+ digital_cdc_clk.clk_val = 9600000;
+ msm_config_mi2s_clk(1);
+ ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &digital_cdc_clk);
+ msm8x10_wcd_mclk_enable(codec, 1, dapm);
+ } else {
+ msm8x10_wcd_mclk_enable(codec, 0, dapm);
+ ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &digital_cdc_clk);
+ msm_config_mi2s_clk(0);
+ }
+ return ret;
+}
+
+static int msm8x10_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ pr_debug("%s: event = %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm8x10_enable_codec_ext_clk(w->codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm8x10_enable_codec_ext_clk(w->codec, 0, true);
+ default:
+ return -EINVAL;
+ }
+}
+
+static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret;
+
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
+ ret = mi2s_clk_ctl(substream, false);
+ if (ret < 0)
+ pr_err("%s:clock disable failed\n", __func__);
+}
+
+static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ ret = mi2s_clk_ctl(substream, true);
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt cpu dai failed\n");
+
+ return ret;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+
+ pr_debug("%s(),dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+ pr_debug("%s(): aud_init_rsc_ref counter = %d\n",
+ __func__, atomic_read(&aud_init_rsc_ref));
+ if (atomic_inc_return(&aud_init_rsc_ref) != 1)
+ goto exit;
+
+ snd_soc_dapm_new_controls(dapm, msm8x10_dapm_widgets,
+ ARRAY_SIZE(msm8x10_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, msm8x10_common_audio_map,
+ ARRAY_SIZE(msm8x10_common_audio_map));
+
+ snd_soc_dapm_sync(dapm);
+ ret = msm_enable_mclk_root(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &digital_cdc_clk);
+exit:
+ return ret;
+}
+
+static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s: msm_proxy_rx_ch =%d\n", __func__, msm_proxy_rx_ch);
+
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
+ channels->min = channels->max = msm_proxy_rx_ch;
+ rate->min = rate->max = 48000;
return 0;
}
-
-static void msm_snd_shutdown(struct snd_pcm_substream *substream)
+static int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
{
- pr_debug("%s(): substream = %s stream = %d\n", __func__,
- substream->name, substream->stream);
-}
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
-static struct snd_soc_ops msm8x10_be_ops = {
- .startup = msm_snd_startup,
- .hw_params = msm_snd_hw_params,
- .shutdown = msm_snd_shutdown,
+ rate->min = rate->max = 48000;
+ return 0;
+}
+static struct snd_soc_ops msm8x10_mi2s_be_ops = {
+ .startup = msm_mi2s_snd_startup,
+ .hw_params = msm_mi2s_snd_hw_params,
+ .shutdown = msm_mi2s_snd_shutdown,
};
/* Digital audio interface glue - connects codec <---> CPU */
static struct snd_soc_dai_link msm8x10_dai[] = {
/* FrontEnd DAI Links */
- {
+ {/* hw:x,0 */
.name = "MSM8X10 Media1",
.stream_name = "MultiMedia1",
.cpu_dai_name = "MultiMedia1",
- .platform_name = "msm-pcm-dsp",
+ .platform_name = "msm-pcm-dsp.0",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
@@ -93,11 +441,11 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
},
- {
+ {/* hw:x,1 */
.name = "MSM8X10 Media2",
.stream_name = "MultiMedia2",
.cpu_dai_name = "MultiMedia2",
- .platform_name = "msm-pcm-dsp",
+ .platform_name = "msm-pcm-dsp.0",
.dynamic = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
@@ -108,31 +456,308 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
},
+ {/* hw:x,2 */
+ .name = "Circuit-Switch Voice",
+ .stream_name = "CS-Voice",
+ .cpu_dai_name = "CS-VOICE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_CS_VOICE,
+ },
+ {/* hw:x,3 */
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {/* hw:x,4 */
+ .name = "MSM8X10 LPA",
+ .stream_name = "LPA",
+ .cpu_dai_name = "MultiMedia3",
+ .platform_name = "msm-pcm-lpa",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ /* Hostless PCM purpose */
+ {/* hw:x,5 */
+ .name = "Secondary MI2S RX Hostless",
+ .stream_name = "Secondary MI2S_RX Hostless Playback",
+ .cpu_dai_name = "SEC_MI2S_RX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,6 */
+ .name = "INT_FM Hostless",
+ .stream_name = "INT_FM Hostless",
+ .cpu_dai_name = "INT_FM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,7 */
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6-dev.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {/* hw:x,8 */
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6-dev.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {/* hw:x,9 */
+ .name = "MSM8X10 Compr",
+ .stream_name = "COMPR",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ {/* hw:x,10 */
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,11 */
+ .name = "Primary MI2S TX Hostless",
+ .stream_name = "Primary MI2S_TX Hostless Capture",
+ .cpu_dai_name = "PRI_MI2S_TX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,12 */
+ .name = "MSM8x10 LowLatency",
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
/* Backend I2S DAI Links */
{
- .name = LPASS_BE_MI2S_RX,
- .stream_name = "Primary MI2S Playback",
- .cpu_dai_name = "msm-dai-q6-mi2s.0",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm8x10-wcd-i2c-core.1-000d",
- .codec_dai_name = "msm8x10_wcd_i2s_rx1",
- .no_pcm = 1,
- .be_id = MSM_BACKEND_DAI_MI2S_RX,
- .init = &msm_audrx_init,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
- .ops = &msm8x10_be_ops,
- },
- {
- .name = LPASS_BE_SEC_MI2S_TX,
- .stream_name = "Secondary MI2S Capture",
+ .name = LPASS_BE_SEC_MI2S_RX,
+ .stream_name = "Secondary MI2S Playback",
.cpu_dai_name = "msm-dai-q6-mi2s.1",
.platform_name = "msm-pcm-routing",
- .codec_name = "msm8x10-wcd-i2c-core.1-000d",
+ .codec_name = "msm8x10-wcd-i2c-core.5-000d",
+ .codec_dai_name = "msm8x10_wcd_i2s_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm8x10_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_MI2S_TX,
+ .stream_name = "Primary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm8x10-wcd-i2c-core.5-000d",
.codec_dai_name = "msm8x10_wcd_i2s_tx1",
.no_pcm = 1,
- .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ .be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
+ .init = &msm_audrx_init,
.be_hw_params_fixup = msm_be_hw_params_fixup,
- .ops = &msm8x10_be_ops,
+ .ops = &msm8x10_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_BT_SCO_RX,
+ .stream_name = "Internal BT-SCO Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.12288",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_BT_SCO_TX,
+ .stream_name = "Internal BT-SCO Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.12289",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_FM_RX,
+ .stream_name = "Internal FM Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.12292",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_FM_TX,
+ .stream_name = "Internal FM Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.12293",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = msm_proxy_rx_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ .be_hw_params_fixup = msm_proxy_tx_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
},
};
@@ -165,6 +790,8 @@
goto err;
}
+ atomic_set(&aud_init_rsc_ref, 0);
+
return 0;
err:
return ret;
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index f15f4d1..659d5a2 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -912,6 +912,7 @@
case ASM_STREAM_CMD_OPEN_WRITE:
case ASM_STREAM_CMD_OPEN_WRITE_V2_1:
case ASM_STREAM_CMD_OPEN_READWRITE:
+ case ASM_STREAM_CMD_OPEN_LOOPBACK:
case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
@@ -1852,6 +1853,45 @@
return -EINVAL;
}
+int q6asm_open_loopack(struct audio_client *ac)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_loopback open;
+
+ if ((ac == NULL) || (ac->apr == NULL)) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK;
+
+ open.mode_flags = 0;
+ open.src_endpointype = 0;
+ open.sink_endpointype = 0;
+ /* source endpoint : matrix */
+ open.postprocopo_id = get_asm_topology();
+ if (open.postprocopo_id == 0)
+ open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("open failed op[0x%x]rc[%d]\n", \
+ open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout. waited for OPEN_WRITE rc[%d]\n", rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
int q6asm_run(struct audio_client *ac, uint32_t flags,
uint32_t msw_ts, uint32_t lsw_ts)
{
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 9359ed7..ec5359c 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -29,6 +29,7 @@
#include <sound/pcm_params.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
+#include <linux/msm_audio_ion.h>
#include <sound/timer.h>
@@ -39,7 +40,10 @@
#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))
-#define COMPRE_CAPTURE_MAX_FRAME_SIZE (6144)
+/* 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)
@@ -226,7 +230,7 @@
prtd->pcm_irq_pos);
memcpy(prtd->audio_client->port[OUT].buf->data +
- prtd->pcm_irq_pos, (ptrmem + 2),
+ prtd->pcm_irq_pos, (ptrmem + READDONE_IDX_SIZE),
COMPRE_CAPTURE_HEADER_SIZE);
pr_debug("buf = %p, updated data = 0x%X, *data = %p\n",
prtd->audio_client->port[OUT].buf,
@@ -235,9 +239,10 @@
prtd->audio_client->port[OUT].buf->data);
if (!atomic_read(&prtd->start))
break;
- pr_debug("frame size=%d, buffer = 0x%X\n", ptrmem[2],
- ptrmem[1]);
- if (ptrmem[2] > COMPRE_CAPTURE_MAX_FRAME_SIZE) {
+ 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;
}
@@ -546,7 +551,7 @@
{
pr_debug("%s\n", __func__);
/* MP3 Block */
- compr->info.compr_cap.num_codecs = 4;
+ 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;
@@ -555,6 +560,7 @@
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 */
}
@@ -723,25 +729,14 @@
static int msm_compr_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
- int result = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
-
- pr_debug("%s\n", __func__);
+ 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 = &(apd[IN].buf[0]);
prtd->mmap_flag = 1;
- runtime->render_flag = SNDRV_NON_DMA_MODE;
- if (runtime->dma_addr && runtime->dma_bytes) {
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- result = remap_pfn_range(vma, vma->vm_start,
- runtime->dma_addr >> PAGE_SHIFT,
- runtime->dma_bytes,
- vma->vm_page_prot);
- } else {
- pr_err("Physical address or size of buf is NULL");
- return -EINVAL;
- }
- return result;
+
+ return msm_audio_ion_mmap(ab, vma);
}
static int msm_compr_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 8bb3eaf..04a0a84 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -190,8 +190,8 @@
if (dai->id == AFE_PORT_ID_PRIMARY_PCM_RX
|| dai->id == AFE_PORT_ID_PRIMARY_PCM_TX) {
- rx_port = PCM_RX;
- tx_port = PCM_TX;
+ rx_port = AFE_PORT_ID_PRIMARY_PCM_RX;
+ tx_port = AFE_PORT_ID_PRIMARY_PCM_TX;
} else if (dai->id == AFE_PORT_ID_SECONDARY_PCM_RX
|| dai->id == AFE_PORT_ID_SECONDARY_PCM_TX) {
rx_port = AFE_PORT_ID_SECONDARY_PCM_RX;
@@ -295,8 +295,8 @@
if (dai->id == AFE_PORT_ID_PRIMARY_PCM_RX ||
dai->id == AFE_PORT_ID_PRIMARY_PCM_TX) {
- rx_port = PCM_RX;
- tx_port = PCM_TX;
+ rx_port = AFE_PORT_ID_PRIMARY_PCM_RX;
+ tx_port = AFE_PORT_ID_PRIMARY_PCM_TX;
} else if (dai->id == AFE_PORT_ID_SECONDARY_PCM_RX ||
dai->id == AFE_PORT_ID_SECONDARY_PCM_TX) {
rx_port = AFE_PORT_ID_SECONDARY_PCM_RX;
@@ -420,8 +420,8 @@
if (dai->id == AFE_PORT_ID_PRIMARY_PCM_RX ||
dai->id == AFE_PORT_ID_PRIMARY_PCM_TX) {
- rx_port = PCM_RX;
- tx_port = PCM_TX;
+ rx_port = AFE_PORT_ID_PRIMARY_PCM_RX;
+ tx_port = AFE_PORT_ID_PRIMARY_PCM_TX;
} else if (dai->id == AFE_PORT_ID_SECONDARY_PCM_RX ||
dai->id == AFE_PORT_ID_SECONDARY_PCM_TX) {
rx_port = AFE_PORT_ID_SECONDARY_PCM_RX;
@@ -1358,16 +1358,25 @@
SOC_ENUM_EXT("PRI MI2S RX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
- SOC_ENUM_EXT("SEC RX Format", mi2s_config_enum[0],
+ SOC_ENUM_EXT("SEC MI2S RX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("TERT MI2S RX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("QUAT MI2S RX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
SOC_ENUM_EXT("PRI MI2S TX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
- SOC_ENUM_EXT("SEC MI2S RX Format", mi2s_config_enum[0],
+ SOC_ENUM_EXT("SEC MI2S TX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
- SOC_ENUM_EXT("SEC MI2S TX Format", mi2s_config_enum[0],
+ SOC_ENUM_EXT("TERT MI2S TX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("QUAT MI2S TX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
};
@@ -1384,6 +1393,10 @@
if (!strncmp(dai->name, "msm-dai-q6-mi2s.0", 17))
ctrl = &mi2s_config_controls[0];
if (!strncmp(dai->name, "msm-dai-q6-mi2s.1", 17))
+ ctrl = &mi2s_config_controls[1];
+ if (!strncmp(dai->name, "msm-dai-q6-mi2s.2", 17))
+ ctrl = &mi2s_config_controls[2];
+ if (!strncmp(dai->name, "msm-dai-q6-mi2s.3", 17))
ctrl = &mi2s_config_controls[3];
}
@@ -1402,9 +1415,13 @@
ctrl = NULL;
if (mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.i2s.channel_mode) {
if (!strncmp(dai->name, "msm-dai-q6-mi2s.0", 17))
- ctrl = &mi2s_config_controls[2];
- if (!strncmp(dai->name, "msm-dai-q6-mi2s.1", 17))
ctrl = &mi2s_config_controls[4];
+ if (!strncmp(dai->name, "msm-dai-q6-mi2s.1", 17))
+ ctrl = &mi2s_config_controls[5];
+ if (!strncmp(dai->name, "msm-dai-q6-mi2s.2", 17))
+ ctrl = &mi2s_config_controls[6];
+ if (!strncmp(dai->name, "msm-dai-q6-mi2s.3", 17))
+ ctrl = &mi2s_config_controls[7];
}
if (ctrl) {
@@ -1482,7 +1499,7 @@
case SNDRV_PCM_STREAM_PLAYBACK:
switch (mi2s_id) {
case MSM_PRIM_MI2S:
- *port_id = MI2S_RX;
+ *port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
break;
case MSM_SEC_MI2S:
*port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
@@ -1502,7 +1519,7 @@
case SNDRV_PCM_STREAM_CAPTURE:
switch (mi2s_id) {
case MSM_PRIM_MI2S:
- *port_id = MI2S_TX;
+ *port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
break;
case MSM_SEC_MI2S:
*port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index f77ec0f..e6934f6 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -437,7 +437,8 @@
if (device == DEVICE_OUT_ALL) {
port_id = PRIMARY_I2S_RX | SLIMBUS_0_RX | HDMI_RX |
INT_BT_SCO_RX | INT_FM_RX |
- RT_PROXY_PORT_001_RX | PCM_RX |
+ RT_PROXY_PORT_001_RX |
+ AFE_PORT_ID_PRIMARY_PCM_RX |
MI2S_RX | SECONDARY_I2S_RX |
SLIMBUS_1_RX | SLIMBUS_4_RX | SLIMBUS_3_RX |
AFE_PORT_ID_SECONDARY_MI2S_RX;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 27b3f56..7055c57 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -29,6 +29,8 @@
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
+#include <linux/msm_audio_ion.h>
+
#include <sound/compress_params.h>
#include <sound/compress_offload.h>
#include <sound/compress_driver.h>
@@ -421,24 +423,14 @@
static int msm_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
- int result = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_audio *prtd = runtime->private_data;
-
- pr_debug("%s\n", __func__);
+ struct audio_client *ac = prtd->audio_client;
+ struct audio_port_data *apd = ac->port;
+ struct audio_buffer *ab = &(apd[IN].buf[0]);
prtd->mmap_flag = 1;
- if (runtime->dma_addr && runtime->dma_bytes) {
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- result = remap_pfn_range(vma, vma->vm_start,
- runtime->dma_addr >> PAGE_SHIFT,
- runtime->dma_bytes,
- vma->vm_page_prot);
- } else {
- pr_err("Physical address or size of buf is NULL");
- return -EINVAL;
- }
- return result;
+ return msm_audio_ion_mmap(ab, vma);
}
static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 717e63b..f4ca5b8 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -27,6 +27,7 @@
#include <sound/control.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
+#include <linux/msm_audio_ion.h>
#include <linux/of_device.h>
#include <sound/pcm_params.h>
@@ -420,6 +421,12 @@
}
data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size, &idx);
+ if (size < fbytes) {
+ pr_err("%s: size mismatch error size %d fbytes %d\n",
+ __func__ , size , fbytes);
+ ret = -EFAULT;
+ goto fail;
+ }
bufptr = data;
if (bufptr) {
pr_debug("%s:fbytes =%d: xfer=%d size=%d\n",
@@ -622,25 +629,14 @@
static int msm_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
- int result = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_audio *prtd = runtime->private_data;
-
- pr_debug("%s\n", __func__);
+ struct audio_client *ac = prtd->audio_client;
+ struct audio_port_data *apd = ac->port;
+ struct audio_buffer *ab = &(apd[IN].buf[0]);
prtd->mmap_flag = 1;
- if (runtime->dma_addr && runtime->dma_bytes) {
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- result = remap_pfn_range(vma, vma->vm_start,
- runtime->dma_addr >> PAGE_SHIFT,
- runtime->dma_bytes,
- vma->vm_page_prot);
- } else {
- pr_err("Physical address or size of buf is NULL");
- return -EINVAL;
- }
-
- return result;
+ return msm_audio_ion_mmap(ab, vma);
}
static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index c651ec7..643f280 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -44,7 +44,7 @@
unsigned int sample_rate;
unsigned int channel;
unsigned int format;
- bool perf_mode;
+ unsigned long perf_mode;
};
#define INVALID_SESSION -1
@@ -213,8 +213,8 @@
{ INT_FM_TX, 0, 0, 0, 0, 0},
{ RT_PROXY_PORT_001_RX, 0, 0, 0, 0, 0},
{ RT_PROXY_PORT_001_TX, 0, 0, 0, 0, 0},
- { PCM_RX, 0, 0, 0, 0, 0},
- { PCM_TX, 0, 0, 0, 0, 0},
+ { AFE_PORT_ID_PRIMARY_PCM_RX, 0, 0, 0, 0, 0},
+ { AFE_PORT_ID_PRIMARY_PCM_TX, 0, 0, 0, 0, 0},
{ VOICE_PLAYBACK_TX, 0, 0, 0, 0, 0},
{ VOICE_RECORD_RX, 0, 0, 0, 0, 0},
{ VOICE_RECORD_TX, 0, 0, 0, 0, 0},
@@ -270,7 +270,7 @@
}
static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
- int path_type)
+ int path_type, bool perf_mode)
{
int i, port_type;
struct route_payload payload;
@@ -290,7 +290,7 @@
if (payload.num_copps)
adm_matrix_map(dspst_id, path_type,
- payload.num_copps, payload.copp_ids, 0);
+ payload.num_copps, payload.copp_ids, 0, perf_mode);
}
void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
@@ -365,8 +365,8 @@
msm_send_eq_values(fedai_id);
topology = get_topology(path_type);
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
- if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
- msm_bedais[i].perf_mode = perf_mode;
+ if (test_bit(fedai_id, &msm_bedais[i].fe_sessions) && perf_mode)
+ set_bit(fedai_id, &msm_bedais[i].perf_mode);
if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
@@ -385,7 +385,8 @@
path_type,
msm_bedais[i].sample_rate,
msm_bedais[i].channel,
- topology, msm_bedais[i].perf_mode,
+ topology,
+ test_bit(fedai_id, &msm_bedais[i].perf_mode),
bits_per_sample);
else
adm_open(msm_bedais[i].port_id,
@@ -408,7 +409,7 @@
}
if (payload.num_copps)
adm_matrix_map(dspst_id, path_type,
- payload.num_copps, payload.copp_ids, 0);
+ payload.num_copps, payload.copp_ids, 0, perf_mode);
mutex_unlock(&routing_lock);
}
@@ -440,7 +441,8 @@
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
(test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
- adm_close(msm_bedais[i].port_id);
+ adm_close(msm_bedais[i].port_id,
+ test_bit(fedai_id, &msm_bedais[i].perf_mode));
if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
dolby_dap_deinit(msm_bedais[i].port_id);
}
@@ -473,6 +475,7 @@
int session_type, path_type, port_id, topology;
u32 channels;
uint16_t bits_per_sample = 16;
+ bool perf_mode = false;
pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
@@ -507,12 +510,14 @@
if ((session_type == SESSION_TYPE_RX) &&
(channels > 0)) {
+ perf_mode = test_bit(val,
+ &msm_bedais[reg].perf_mode);
adm_multi_ch_copp_open(msm_bedais[reg].port_id,
path_type,
msm_bedais[reg].sample_rate,
channels,
topology,
- msm_bedais[reg].perf_mode,
+ perf_mode,
bits_per_sample);
} else
adm_open(msm_bedais[reg].port_id,
@@ -521,7 +526,8 @@
topology, false, bits_per_sample);
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type);
+ fe_dai_map[val][session_type], path_type,
+ perf_mode);
port_id = srs_port_id = msm_bedais[reg].port_id;
srs_send_params(srs_port_id, 1, 0);
if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
@@ -536,11 +542,13 @@
clear_bit(val, &msm_bedais[reg].fe_sessions);
if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
INVALID_SESSION) {
- adm_close(msm_bedais[reg].port_id);
+ perf_mode = test_bit(val, &msm_bedais[reg].perf_mode);
+ adm_close(msm_bedais[reg].port_id, perf_mode);
if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
dolby_dap_deinit(msm_bedais[reg].port_id);
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type);
+ fe_dai_map[val][session_type], path_type,
+ perf_mode);
}
}
if ((msm_bedais[reg].port_id == VOICE_RECORD_RX)
@@ -1406,6 +1414,24 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERTIARY_MI2S_RX ,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = {
@@ -1421,6 +1447,18 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mi2s_hl_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
@@ -1436,6 +1474,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
@@ -1571,9 +1612,15 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -1646,6 +1693,9 @@
SOC_SINGLE_EXT("SEC_AUX_PCM_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
@@ -1684,6 +1734,24 @@
msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new sec_mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -1865,6 +1933,9 @@
SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voice", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_Voice", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_voice2_mixer_controls[] = {
@@ -1934,6 +2005,9 @@
SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voip", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_Voip", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
@@ -2426,15 +2500,21 @@
__func__, e->shift_l , e->values[item]);
if (e->shift_l < MSM_BACKEND_DAI_MAX &&
e->values[item] < MSM_BACKEND_DAI_MAX)
+ /* Enable feedback TX path */
ret = afe_spk_prot_feed_back_cfg(
msm_bedais[e->values[item]].port_id,
- msm_bedais[e->shift_l].port_id, 1, 0);
+ msm_bedais[e->shift_l].port_id, 1, 0, 1);
else {
- pr_err("%s values are out of range\n", __func__);
- ret = -EINVAL;
+ pr_debug("%s values are out of range item %d\n",
+ __func__, e->values[item]);
+ /* Disable feedback TX path */
+ if (e->values[item] == MSM_BACKEND_DAI_MAX)
+ ret = afe_spk_prot_feed_back_cfg(0, 0, 0, 0, 0);
+ else
+ ret = -EINVAL;
}
} else {
- pr_err("%s item value is out of range\n", __func__);
+ pr_err("%s item value is out of range item\n", __func__);
ret = -EINVAL;
}
mutex_unlock(&routing_lock);
@@ -2449,11 +2529,11 @@
}
static const char * const slim0_rx_vi_fb_tx_lch_mux_text[] = {
- "SLIM4_TX",
+ "ZERO", "SLIM4_TX"
};
static const int const slim0_rx_vi_fb_tx_lch_value[] = {
- MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_SLIMBUS_4_TX
};
static const struct soc_enum slim0_rx_vi_fb_lch_mux_enum =
SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_SLIMBUS_0_RX, 0, 0,
@@ -2510,12 +2590,19 @@
SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SEC_I2S_DL_HL", "SEC_I2S_RX_HOSTLESS Playback",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_MI2S_DL_HL",
+ "Secondary MI2S_RX Hostless Playback",
+ 0, 0, 0, 0),
+
SND_SOC_DAPM_AIF_IN("AUXPCM_DL_HL", "AUXPCM_HOSTLESS Playback",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("AUXPCM_UL_HL", "AUXPCM_HOSTLESS Capture",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MI2S_UL_HL", "MI2S_TX_HOSTLESS Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_MI2S_UL_HL",
+ "Primary MI2S_TX Hostless Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MI2S_DL_HL", "MI2S_RX_HOSTLESS Playback",
0, 0, 0, 0),
@@ -2535,6 +2622,8 @@
SND_SOC_DAPM_AIF_OUT("MI2S_RX", "MI2S Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_MI2S_RX", "Tertiary MI2S Playback",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("SEC_MI2S_RX", "Secondary MI2S Playback",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("PRI_MI2S_RX", "Primary MI2S Playback",
@@ -2543,6 +2632,10 @@
SND_SOC_DAPM_AIF_IN("MI2S_TX", "MI2S Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("QUAT_MI2S_TX", "Quaternary MI2S Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_MI2S_TX", "Primary MI2S Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_MI2S_TX", "Tertiary MI2S Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SEC_MI2S_TX", "Secondary MI2S Capture",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
@@ -2618,9 +2711,15 @@
SND_SOC_DAPM_MIXER("QUAT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
quaternary_mi2s_rx_mixer_controls,
ARRAY_SIZE(quaternary_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tertiary_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(tertiary_mi2s_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
secondary_mi2s_rx_mixer_controls,
ARRAY_SIZE(secondary_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+ mi2s_hl_mixer_controls,
+ ARRAY_SIZE(mi2s_hl_mixer_controls)),
SND_SOC_DAPM_MIXER("PRI_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
primary_mi2s_rx_mixer_controls,
ARRAY_SIZE(primary_mi2s_rx_mixer_controls)),
@@ -2651,6 +2750,10 @@
SND_SOC_NOPM, 0, 0,
sec_i2s_rx_voice_mixer_controls,
ARRAY_SIZE(sec_i2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ sec_mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(sec_mi2s_rx_voice_mixer_controls)),
SND_SOC_DAPM_MIXER("SLIM_0_RX_Voice Mixer",
SND_SOC_NOPM, 0, 0,
slimbus_rx_voice_mixer_controls,
@@ -2799,25 +2902,38 @@
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX Audio Mixer"},
{"SEC_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"SEC_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"SEC_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SEC_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Audio Mixer"},
+ {"SEC_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"SEC_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+
{"PRI_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"PRI_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"PRI_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"PRI_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Audio Mixer"},
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
{"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia5 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"MultiMedia1 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"MultiMedia5 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
@@ -2825,6 +2941,7 @@
{"MultiMedia5 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -2895,6 +3012,13 @@
{"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
+ {"SEC_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SEC_MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX_Voice Mixer"},
+
{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SLIM_0_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
@@ -2945,6 +3069,7 @@
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
+ {"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"},
{"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
{"Voice_Tx Mixer", "SLIM_0_TX_Voice", "SLIMBUS_0_TX"},
{"Voice_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice", "INT_BT_SCO_TX"},
@@ -2976,6 +3101,7 @@
{"Voip_Tx Mixer", "AFE_PCM_TX_Voip", "PCM_TX"},
{"Voip_Tx Mixer", "AUX_PCM_TX_Voip", "AUX_PCM_TX"},
{"Voip_Tx Mixer", "SEC_AUX_PCM_TX_Voip", "SEC_AUX_PCM_TX"},
+ {"Voip_Tx Mixer", "PRI_MI2S_TX_Voip", "PRI_MI2S_TX"},
{"VOIP_UL", NULL, "Voip_Tx Mixer"},
{"SLIMBUS_DL_HL", "Switch", "SLIM0_DL_HL"},
@@ -3006,8 +3132,11 @@
{"MI2S_UL_HL", NULL, "MI2S_TX"},
{"PCM_RX_DL_HL", "Switch", "SLIM0_DL_HL"},
{"PCM_RX", NULL, "PCM_RX_DL_HL"},
- {"MI2S_UL_HL", NULL, "MI2S_TX"},
+ {"MI2S_UL_HL", NULL, "TERT_MI2S_TX"},
{"SEC_I2S_RX", NULL, "SEC_I2S_DL_HL"},
+ {"PRI_MI2S_UL_HL", NULL, "PRI_MI2S_TX"},
+ {"SEC_MI2S_RX", NULL, "SEC_MI2S_DL_HL"},
+
{"SLIMBUS_0_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"SLIMBUS_0_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"SLIMBUS_0_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
@@ -3073,6 +3202,7 @@
{"BE_OUT", NULL, "HDMI"},
{"BE_OUT", NULL, "MI2S_RX"},
{"BE_OUT", NULL, "QUAT_MI2S_RX"},
+ {"BE_OUT", NULL, "TERT_MI2S_RX"},
{"BE_OUT", NULL, "SEC_MI2S_RX"},
{"BE_OUT", NULL, "PRI_MI2S_RX"},
{"BE_OUT", NULL, "INT_BT_SCO_RX"},
@@ -3081,30 +3211,32 @@
{"BE_OUT", NULL, "SLIMBUS_3_RX"},
{"BE_OUT", NULL, "AUX_PCM_RX"},
{"BE_OUT", NULL, "SEC_AUX_PCM_RX"},
+ {"BE_OUT", NULL, "INT_BT_SCO_RX"},
+ {"BE_OUT", NULL, "INT_FM_RX"},
+ {"BE_OUT", NULL, "PCM_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_3_RX"},
+ {"BE_OUT", NULL, "AUX_PCM_RX"},
+ {"BE_OUT", NULL, "SEC_AUX_PCM_RX"},
+ {"BE_OUT", NULL, "VOICE_PLAYBACK_TX"},
{"PRI_I2S_TX", NULL, "BE_IN"},
{"MI2S_TX", NULL, "BE_IN"},
{"QUAT_MI2S_TX", NULL, "BE_IN"},
+ {"PRI_MI2S_TX", NULL, "BE_IN"},
+ {"TERT_MI2S_TX", NULL, "BE_IN"},
{"SEC_MI2S_TX", NULL, "BE_IN"},
{"SLIMBUS_0_TX", NULL, "BE_IN" },
{"SLIMBUS_1_TX", NULL, "BE_IN" },
{"SLIMBUS_3_TX", NULL, "BE_IN" },
{"SLIMBUS_4_TX", NULL, "BE_IN" },
{"SLIMBUS_5_TX", NULL, "BE_IN" },
- {"BE_OUT", NULL, "INT_BT_SCO_RX"},
{"INT_BT_SCO_TX", NULL, "BE_IN"},
- {"BE_OUT", NULL, "INT_FM_RX"},
{"INT_FM_TX", NULL, "BE_IN"},
- {"BE_OUT", NULL, "PCM_RX"},
{"PCM_TX", NULL, "BE_IN"},
- {"BE_OUT", NULL, "SLIMBUS_3_RX"},
- {"BE_OUT", NULL, "AUX_PCM_RX"},
{"AUX_PCM_TX", NULL, "BE_IN"},
- {"BE_OUT", NULL, "SEC_AUX_PCM_RX"},
{"SEC_AUX_PCM_TX", NULL, "BE_IN"},
{"INCALL_RECORD_TX", NULL, "BE_IN"},
{"INCALL_RECORD_RX", NULL, "BE_IN"},
- {"BE_OUT", NULL, "VOICE_PLAYBACK_TX"},
{"SLIM0_RX_VI_FB_LCH_MUX", "SLIM4_TX", "SLIMBUS_4_TX"},
{"SLIMBUS_0_RX", NULL, "SLIM0_RX_VI_FB_LCH_MUX"},
};
@@ -3152,8 +3284,10 @@
topology = get_topology(path_type);
for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
if (fe_dai_map[i][session_type] != INVALID_SESSION) {
- adm_close(bedai->port_id);
+ adm_close(bedai->port_id,
+ test_bit(i, &(bedai->perf_mode)));
srs_port_id = -1;
+ clear_bit(i, &(bedai->perf_mode));
if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
dolby_dap_deinit(bedai->port_id);
}
@@ -3162,7 +3296,6 @@
bedai->active = 0;
bedai->sample_rate = 0;
bedai->channel = 0;
- bedai->perf_mode = false;
mutex_unlock(&routing_lock);
return 0;
@@ -3177,6 +3310,7 @@
u32 channels;
bool playback, capture;
uint16_t bits_per_sample = 16;
+ bool perf_mode = false;
if (be_id >= MSM_BACKEND_DAI_MAX) {
pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -3215,11 +3349,13 @@
bits_per_sample = 24;
if ((playback) && (channels > 0)) {
+ perf_mode = test_bit(i, &(bedai->perf_mode));
adm_multi_ch_copp_open(bedai->port_id,
path_type,
bedai->sample_rate,
channels,
- topology, bedai->perf_mode,
+ topology,
+ perf_mode,
bits_per_sample);
} else if (capture) {
adm_open(bedai->port_id,
@@ -3231,7 +3367,8 @@
}
msm_pcm_routing_build_matrix(i,
- fe_dai_map[i][session_type], path_type);
+ fe_dai_map[i][session_type], path_type,
+ perf_mode);
port_id = srs_port_id = bedai->port_id;
srs_send_params(srs_port_id, 1, 0);
if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 1bd3eac..29c06cb 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -39,6 +39,9 @@
void *apr;
atomic_t copp_id[AFE_MAX_PORTS];
atomic_t copp_cnt[AFE_MAX_PORTS];
+ atomic_t copp_low_latency_id[AFE_MAX_PORTS];
+ atomic_t copp_low_latency_cnt[AFE_MAX_PORTS];
+ atomic_t copp_perf_mode[AFE_MAX_PORTS];
atomic_t copp_stat[AFE_MAX_PORTS];
wait_queue_head_t wait[AFE_MAX_PORTS];
@@ -445,7 +448,12 @@
for (i = 0; i < AFE_MAX_PORTS; i++) {
atomic_set(&this_adm.copp_id[i],
RESET_COPP_ID);
+ atomic_set(&this_adm.copp_low_latency_id[i],
+ RESET_COPP_ID);
atomic_set(&this_adm.copp_cnt[i], 0);
+ atomic_set(&this_adm.copp_low_latency_cnt[i],
+ 0);
+ atomic_set(&this_adm.copp_perf_mode[i], 0);
atomic_set(&this_adm.copp_stat[i], 0);
}
this_adm.apr = NULL;
@@ -545,7 +553,13 @@
wake_up(&this_adm.wait[index]);
break;
}
- atomic_set(&this_adm.copp_id[index], open->copp_id);
+ if (atomic_read(&this_adm.copp_perf_mode[index])) {
+ atomic_set(&this_adm.copp_low_latency_id[index],
+ open->copp_id);
+ } else {
+ atomic_set(&this_adm.copp_id[index],
+ open->copp_id);
+ }
atomic_set(&this_adm.copp_stat[index], 1);
pr_debug("%s: coppid rxed=%d\n", __func__,
open->copp_id);
@@ -892,8 +906,8 @@
int index;
int tmp_port = q6audio_get_port_id(port_id);
- pr_debug("%s: port %#x path:%d rate:%d mode:%d\n", __func__,
- port_id, path, rate, channel_mode);
+ pr_debug("%s: port %#x path:%d rate:%d mode:%d perf_mode:%d\n",
+ __func__, port_id, path, rate, channel_mode, perf_mode);
port_id = q6audio_convert_virtual_to_portid(port_id);
@@ -916,11 +930,19 @@
rtac_set_adm_handle(this_adm.apr);
}
- send_adm_custom_topology(port_id);
+ if (!perf_mode) {
+ atomic_set(&this_adm.copp_perf_mode[index], 0);
+ send_adm_custom_topology(port_id);
+ } else {
+ atomic_set(&this_adm.copp_perf_mode[index], 1);
+ }
/* Create a COPP if port id are not enabled */
- if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
-
+ if ((!perf_mode && (atomic_read(&this_adm.copp_cnt[index]) == 0)) ||
+ (perf_mode &&
+ (atomic_read(&this_adm.copp_low_latency_cnt[index]) == 0))) {
+ pr_debug("%s:opening ADM: perf_mode: %d\n", __func__,
+ perf_mode);
open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
open.hdr.pkt_size = sizeof(open);
@@ -950,6 +972,9 @@
(open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
rate = 16000;
+ if (perf_mode)
+ open.topology_id = NULL_COPP_TOPOLOGY;
+
open.dev_num_channel = channel_mode & 0x00FF;
open.bit_width = bits_per_sample;
open.sample_rate = rate;
@@ -1026,7 +1051,15 @@
goto fail_cmd;
}
}
- atomic_inc(&this_adm.copp_cnt[index]);
+ if (perf_mode) {
+ atomic_inc(&this_adm.copp_low_latency_cnt[index]);
+ pr_debug("%s: index: %d coppid: %d", __func__, index,
+ atomic_read(&this_adm.copp_low_latency_id[index]));
+ } else {
+ atomic_inc(&this_adm.copp_cnt[index]);
+ pr_debug("%s: index: %d coppid: %d", __func__, index,
+ atomic_read(&this_adm.copp_id[index]));
+ }
return 0;
fail_cmd:
@@ -1046,7 +1079,7 @@
}
int adm_matrix_map(int session_id, int path, int num_copps,
- unsigned int *port_id, int copp_id)
+ unsigned int *port_id, int copp_id, bool perf_mode)
{
struct adm_cmd_matrix_map_routings_v5 *route;
struct adm_session_map_node_v5 *node;
@@ -1085,7 +1118,12 @@
route->hdr.src_port = copp_id;
route->hdr.dest_svc = APR_SVC_ADM;
route->hdr.dest_domain = APR_DOMAIN_ADSP;
- route->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ if (perf_mode) {
+ route->hdr.dest_port =
+ atomic_read(&this_adm.copp_low_latency_id[index]);
+ } else {
+ route->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ }
route->hdr.token = copp_id;
route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
route->num_sessions = 1;
@@ -1117,9 +1155,14 @@
tmp = q6audio_get_port_index(port_id[i]);
- if (tmp >= 0 && tmp < AFE_MAX_PORTS)
- copps_list[i] =
+ if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+ if (perf_mode)
+ copps_list[i] =
+ atomic_read(&this_adm.copp_low_latency_id[tmp]);
+ else
+ copps_list[i] =
atomic_read(&this_adm.copp_id[tmp]);
+ }
else
continue;
pr_debug("%s: port_id[%#x]: %d, index: %d act coppid[0x%x]\n",
@@ -1144,21 +1187,42 @@
ret = -EINVAL;
goto fail_cmd;
}
- for (i = 0; i < num_copps; i++)
- send_adm_cal(port_id[i], path);
+ if (perf_mode) {
+ for (i = 0; i < num_copps; i++) {
+ int tmp;
- for (i = 0; i < num_copps; i++) {
- int tmp;
- tmp = afe_get_port_index(port_id[i]);
- if (tmp >= 0 && tmp < AFE_MAX_PORTS)
- rtac_add_adm_device(port_id[i],
- atomic_read(&this_adm.copp_id[tmp]),
- path, session_id);
- else
- pr_debug("%s: Invalid port index %d",
- __func__, tmp);
+ tmp = afe_get_port_index(port_id[i]);
+ if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+ rtac_add_adm_device(port_id[i], atomic_read(
+ &this_adm.copp_low_latency_id[tmp]),
+ path, session_id);
+ pr_debug("%s, copp_id: %d\n", __func__,
+ atomic_read(
+ &this_adm.copp_low_latency_id[tmp]));
+ } else {
+ pr_debug("%s: Invalid port index %d",
+ __func__, tmp);
+ }
+ }
+ } else {
+ for (i = 0; i < num_copps; i++)
+ send_adm_cal(port_id[i], path);
+
+ for (i = 0; i < num_copps; i++) {
+ int tmp;
+ tmp = afe_get_port_index(port_id[i]);
+ if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+ rtac_add_adm_device(port_id[i],
+ atomic_read(&this_adm.copp_id[tmp]),
+ path, session_id);
+ pr_debug("%s, copp_id: %d\n", __func__,
+ atomic_read(&this_adm.copp_id[tmp]));
+ } else {
+ pr_debug("%s: Invalid port index %d",
+ __func__, tmp);
+ }
+ }
}
-
fail_cmd:
kfree(matrix_map);
return ret;
@@ -1319,7 +1383,7 @@
return atomic_read(&this_adm.copp_id[port_index]);
}
-int adm_close(int port_id)
+int adm_close(int port_id, bool perf_mode)
{
struct apr_hdr close;
@@ -1332,16 +1396,30 @@
if (q6audio_validate_port(port_id) < 0)
return -EINVAL;
- pr_debug("%s port_id=%#x index %d\n", __func__, port_id, index);
+ pr_debug("%s port_id=%#x index %d perf_mode: %d\n", __func__, port_id,
+ index, perf_mode);
- if (!(atomic_read(&this_adm.copp_cnt[index]))) {
- pr_err("%s: copp count for port[%#x]is 0\n", __func__, port_id);
-
- goto fail_cmd;
+ if (perf_mode) {
+ if (!(atomic_read(&this_adm.copp_low_latency_cnt[index]))) {
+ pr_err("%s: copp count for port[%#x]is 0\n", __func__,
+ port_id);
+ goto fail_cmd;
+ }
+ atomic_dec(&this_adm.copp_low_latency_cnt[index]);
+ } else {
+ if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+ pr_err("%s: copp count for port[%#x]is 0\n", __func__,
+ port_id);
+ goto fail_cmd;
+ }
+ atomic_dec(&this_adm.copp_cnt[index]);
}
- atomic_dec(&this_adm.copp_cnt[index]);
- if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+ if ((!perf_mode && !(atomic_read(&this_adm.copp_cnt[index]))) ||
+ (perf_mode &&
+ !(atomic_read(&this_adm.copp_low_latency_cnt[index])))) {
+ pr_debug("%s:Closing ADM: perf_mode: %d\n", __func__,
+ perf_mode);
close.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
close.pkt_size = sizeof(close);
@@ -1350,19 +1428,33 @@
close.src_port = port_id;
close.dest_svc = APR_SVC_ADM;
close.dest_domain = APR_DOMAIN_ADSP;
- close.dest_port = atomic_read(&this_adm.copp_id[index]);
+ if (perf_mode)
+ close.dest_port =
+ atomic_read(&this_adm.copp_low_latency_id[index]);
+ else
+ close.dest_port = atomic_read(&this_adm.copp_id[index]);
close.token = port_id;
close.opcode = ADM_CMD_DEVICE_CLOSE_V5;
- atomic_set(&this_adm.copp_id[index], RESET_COPP_ID);
atomic_set(&this_adm.copp_stat[index], 0);
-
- pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
+ if (perf_mode) {
+ pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
+ __func__,
+ atomic_read(&this_adm.copp_low_latency_id[index]),
+ port_id, index,
+ atomic_read(&this_adm.copp_low_latency_cnt[index]));
+ atomic_set(&this_adm.copp_low_latency_id[index],
+ RESET_COPP_ID);
+ } else {
+ pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
__func__,
atomic_read(&this_adm.copp_id[index]),
port_id, index,
atomic_read(&this_adm.copp_cnt[index]));
+ atomic_set(&this_adm.copp_id[index],
+ RESET_COPP_ID);
+ }
ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close);
if (ret < 0) {
@@ -1380,7 +1472,10 @@
ret = -EINVAL;
goto fail_cmd;
}
-
+ }
+ if (!atomic_read(&this_adm.copp_cnt[index]) &&
+ !atomic_read(&this_adm.copp_low_latency_cnt[index])) {
+ pr_debug("%s: remove adm device from rtac\n", __func__);
rtac_remove_adm_device(port_id);
}
@@ -1396,8 +1491,11 @@
for (i = 0; i < AFE_MAX_PORTS; i++) {
atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
+ atomic_set(&this_adm.copp_low_latency_id[i], RESET_COPP_ID);
atomic_set(&this_adm.copp_cnt[i], 0);
+ atomic_set(&this_adm.copp_low_latency_cnt[i], 0);
atomic_set(&this_adm.copp_stat[i], 0);
+ atomic_set(&this_adm.copp_perf_mode[i], 0);
init_waitqueue_head(&this_adm.wait[i]);
}
return 0;
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 2b0d155..ce5e816 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -217,7 +217,7 @@
switch (port_id) {
case PRIMARY_I2S_RX:
- case PCM_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
case SECONDARY_I2S_RX:
case MI2S_RX:
case HDMI_RX:
@@ -241,7 +241,7 @@
break;
case PRIMARY_I2S_TX:
- case PCM_TX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
case SECONDARY_I2S_TX:
case MI2S_TX:
case DIGI_MIC_TX:
@@ -307,8 +307,8 @@
case RT_PROXY_PORT_001_TX:
ret_size = SIZEOF_CFG_CMD(afe_param_id_rt_proxy_port_cfg);
break;
- case PCM_RX:
- case PCM_TX:
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
case AFE_PORT_ID_SECONDARY_PCM_RX:
case AFE_PORT_ID_SECONDARY_PCM_TX:
default:
@@ -899,6 +899,44 @@
return ret;
}
+static int afe_send_bank_selection_clip(
+ struct afe_param_id_clip_bank_sel *param)
+{
+ int ret;
+ struct afe_svc_cmd_set_clip_bank_selection config;
+ if (!param) {
+ pr_err("%s: Invalid params", __func__);
+ return -EINVAL;
+ }
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ config.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+ sizeof(struct afe_param_id_clip_bank_sel);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+
+ config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.pdata.param_id = AFE_PARAM_ID_CLIP_BANK_SEL_CFG;
+ config.pdata.param_size =
+ sizeof(struct afe_param_id_clip_bank_sel);
+ config.bank_sel = *param;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_CLIP_BANK_SEL_CFG failed %d\n",
+ __func__, ret);
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EAGAIN;
+ }
+ return ret;
+}
int afe_send_aanc_version(
struct afe_param_id_cdc_aanc_version *version_cfg)
{
@@ -991,6 +1029,12 @@
case AFE_AANC_VERSION:
ret = afe_send_aanc_version(config_data);
break;
+ case AFE_CLIP_BANK_SEL:
+ ret = afe_send_bank_selection_clip(config_data);
+ break;
+ case AFE_CDC_CLIP_REGISTERS_CONFIG:
+ ret = afe_send_codec_reg_config(config_data);
+ break;
default:
pr_err("%s: unknown configuration type", __func__);
ret = -EINVAL;
@@ -1149,21 +1193,20 @@
config.hdr.token = index;
switch (port_id) {
- case PRIMARY_I2S_RX:
- case PRIMARY_I2S_TX:
- cfg_type = AFE_PARAM_ID_PCM_CONFIG;
- break;
- case PCM_RX:
- case PCM_TX:
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
case AFE_PORT_ID_SECONDARY_PCM_RX:
case AFE_PORT_ID_SECONDARY_PCM_TX:
cfg_type = AFE_PARAM_ID_PCM_CONFIG;
break;
+ case PRIMARY_I2S_RX:
+ case PRIMARY_I2S_TX:
case SECONDARY_I2S_RX:
case SECONDARY_I2S_TX:
case MI2S_RX:
case MI2S_TX:
case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
case AFE_PORT_ID_SECONDARY_MI2S_RX:
case AFE_PORT_ID_SECONDARY_MI2S_TX:
case AFE_PORT_ID_TERTIARY_MI2S_RX:
@@ -1250,8 +1293,10 @@
switch (port_id) {
case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
- case PCM_RX: return IDX_PCM_RX;
- case PCM_TX: return IDX_PCM_TX;
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ return IDX_AFE_PORT_ID_PRIMARY_PCM_RX;
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_PCM_TX;
case AFE_PORT_ID_SECONDARY_PCM_RX:
return IDX_AFE_PORT_ID_SECONDARY_PCM_RX;
case AFE_PORT_ID_SECONDARY_PCM_TX:
@@ -1286,6 +1331,8 @@
case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
case AFE_PORT_ID_PRIMARY_MI2S_RX:
return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_MI2S_TX;
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
@@ -1294,6 +1341,10 @@
return IDX_AFE_PORT_ID_SECONDARY_MI2S_RX;
case AFE_PORT_ID_SECONDARY_MI2S_TX:
return IDX_AFE_PORT_ID_SECONDARY_MI2S_TX;
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_TERTIARY_MI2S_RX;
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_TERTIARY_MI2S_TX;
default: return -EINVAL;
}
@@ -1349,8 +1400,8 @@
case PRIMARY_I2S_TX:
cfg_type = AFE_PARAM_ID_I2S_CONFIG;
break;
- case PCM_RX:
- case PCM_TX:
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
case AFE_PORT_ID_SECONDARY_PCM_RX:
case AFE_PORT_ID_SECONDARY_PCM_TX:
cfg_type = AFE_PARAM_ID_PCM_CONFIG;
@@ -2538,8 +2589,8 @@
switch (port_id) {
case PRIMARY_I2S_RX:
case PRIMARY_I2S_TX:
- case PCM_RX:
- case PCM_TX:
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
case AFE_PORT_ID_SECONDARY_PCM_RX:
case AFE_PORT_ID_SECONDARY_PCM_TX:
case SECONDARY_I2S_RX:
@@ -2965,12 +3016,18 @@
}
int afe_spk_prot_feed_back_cfg(int src_port, int dst_port,
- int l_ch, int r_ch)
+ int l_ch, int r_ch, u32 enable)
{
int ret = -EINVAL;
union afe_spkr_prot_config prot_config;
int index = 0;
+ if (!enable) {
+ pr_debug("%s Disable Feedback tx path", __func__);
+ this_afe.vi_tx_port = -1;
+ return 0;
+ }
+
if ((q6audio_validate_port(src_port) < 0) ||
(q6audio_validate_port(dst_port) < 0)) {
pr_err("%s invalid ports src %d dst %d",
@@ -3011,6 +3068,7 @@
this_afe.apr = NULL;
this_afe.dtmf_gen_rx_portid = -1;
this_afe.mmap_handle = 0;
+ this_afe.vi_tx_port = -1;
for (i = 0; i < AFE_MAX_PORTS; i++)
init_waitqueue_head(&this_afe.wait[i]);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 59d4de2..c2fd2d7 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -45,17 +45,6 @@
#define TRUE 0x01
#define FALSE 0x00
-#define READDONE_IDX_STATUS 0
-#define READDONE_IDX_BUFADD_LSW 1
-#define READDONE_IDX_BUFADD_MSW 2
-#define READDONE_IDX_MEMMAP_HDL 3
-#define READDONE_IDX_SIZE 4
-#define READDONE_IDX_OFFSET 5
-#define READDONE_IDX_LSW_TS 6
-#define READDONE_IDX_MSW_TS 7
-#define READDONE_IDX_FLAGS 8
-#define READDONE_IDX_NUMFRAMES 9
-#define READDONE_IDX_SEQ_ID 10
/* TODO, combine them together */
static DEFINE_MUTEX(session_lock);
@@ -342,6 +331,7 @@
mutex_unlock(&session_lock);
ac->session = 0;
ac->perf_mode = 0;
+ ac->fptr_cache_ops = NULL;
return;
}
@@ -621,6 +611,7 @@
ac->priv = priv;
ac->io_mode = SYNC_IO_MODE;
ac->perf_mode = false;
+ ac->fptr_cache_ops = NULL;
ac->apr = apr_register("ADSP", "ASM", \
(apr_fn)q6asm_callback,\
((ac->session) << 8 | 0x0001),\
@@ -3371,6 +3362,7 @@
struct list_head *ptr, *next;
u32 lbuf_addr_lsw;
u32 liomode;
+ u32 io_compressed;
if (!ac || ac->apr == NULL) {
pr_err("%s: APR handle NULL\n", __func__);
@@ -3387,12 +3379,15 @@
read.buf_size = param->len;
read.seq_id = param->uid;
liomode = (NT_MODE | ASYNC_IO_MODE);
+ io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
if (ac->io_mode == liomode)
lbuf_addr_lsw = (read.buf_addr_lsw - 32);
+ else if (ac->io_mode == io_compressed)
+ lbuf_addr_lsw = (read.buf_addr_lsw - 64);
else
lbuf_addr_lsw = read.buf_addr_lsw;
- list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
+ list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
buf_node = list_entry(ptr, struct asm_buffer_node, list);
if (buf_node->buf_addr_lsw == lbuf_addr_lsw) {
read.mem_map_handle = buf_node->mmap_hdl;
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index faf5f35..bc7ad4d 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -24,8 +24,10 @@
switch (port_id) {
case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
- case PCM_RX: return IDX_PCM_RX;
- case PCM_TX: return IDX_PCM_TX;
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ return IDX_AFE_PORT_ID_PRIMARY_PCM_RX;
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_PCM_TX;
case AFE_PORT_ID_SECONDARY_PCM_RX:
return IDX_AFE_PORT_ID_SECONDARY_PCM_RX;
case AFE_PORT_ID_SECONDARY_PCM_TX:
@@ -58,6 +60,8 @@
case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
case AFE_PORT_ID_PRIMARY_MI2S_RX:
return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_MI2S_TX;
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
@@ -66,6 +70,10 @@
return IDX_AFE_PORT_ID_SECONDARY_MI2S_RX;
case AFE_PORT_ID_SECONDARY_MI2S_TX:
return IDX_AFE_PORT_ID_SECONDARY_MI2S_TX;
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_TERTIARY_MI2S_RX;
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_TERTIARY_MI2S_TX;
default: return -EINVAL;
}
@@ -74,10 +82,12 @@
int q6audio_get_port_id(u16 port_id)
{
switch (port_id) {
- case PRIMARY_I2S_RX: return AFE_PORT_ID_PRIMARY_MI2S_RX;
- case PRIMARY_I2S_TX: return AFE_PORT_ID_PRIMARY_MI2S_TX;
- case PCM_RX: return AFE_PORT_ID_PRIMARY_PCM_RX;
- case PCM_TX: return AFE_PORT_ID_PRIMARY_PCM_TX;
+ case PRIMARY_I2S_RX: return PRIMARY_I2S_RX;
+ case PRIMARY_I2S_TX: return PRIMARY_I2S_TX;
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ return AFE_PORT_ID_PRIMARY_PCM_RX;
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
+ return AFE_PORT_ID_PRIMARY_PCM_TX;
case AFE_PORT_ID_SECONDARY_PCM_RX:
return AFE_PORT_ID_SECONDARY_PCM_RX;
case AFE_PORT_ID_SECONDARY_PCM_TX:
@@ -110,6 +120,8 @@
case RT_PROXY_PORT_001_TX: return AFE_PORT_ID_RT_PROXY_PORT_001_TX;
case AFE_PORT_ID_PRIMARY_MI2S_RX:
return AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ return AFE_PORT_ID_PRIMARY_MI2S_TX;
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
return AFE_PORT_ID_QUATERNARY_MI2S_RX;
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
@@ -118,7 +130,10 @@
return AFE_PORT_ID_SECONDARY_MI2S_RX;
case AFE_PORT_ID_SECONDARY_MI2S_TX:
return AFE_PORT_ID_SECONDARY_MI2S_TX;
-
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ return AFE_PORT_ID_TERTIARY_MI2S_RX;
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ return AFE_PORT_ID_TERTIARY_MI2S_TX;
default:
pr_warn("%s: Invalid port_id %d\n", __func__, port_id);
return -EINVAL;
@@ -152,8 +167,8 @@
switch (port_id) {
case PRIMARY_I2S_RX:
case PRIMARY_I2S_TX:
- case PCM_RX:
- case PCM_TX:
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
case AFE_PORT_ID_SECONDARY_PCM_RX:
case AFE_PORT_ID_SECONDARY_PCM_TX:
case SECONDARY_I2S_RX:
@@ -164,6 +179,10 @@
case AFE_PORT_ID_TERTIARY_MI2S_RX:
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_MI2S_TX:
break;
default:
ret = -EINVAL;
@@ -179,8 +198,8 @@
switch (port_id) {
case PRIMARY_I2S_RX:
case PRIMARY_I2S_TX:
- case PCM_RX:
- case PCM_TX:
+ case AFE_PORT_ID_PRIMARY_PCM_RX:
+ case AFE_PORT_ID_PRIMARY_PCM_TX:
case AFE_PORT_ID_SECONDARY_PCM_RX:
case AFE_PORT_ID_SECONDARY_PCM_TX:
case SECONDARY_I2S_RX:
@@ -210,6 +229,7 @@
case RT_PROXY_PORT_001_RX:
case RT_PROXY_PORT_001_TX:
case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
case AFE_PORT_ID_SECONDARY_MI2S_RX: