Merge "arm: Make the WFE macro unconditional" into msm-3.4
diff --git a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
new file mode 100644
index 0000000..068e256
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
@@ -0,0 +1,42 @@
+* Memory reservations for MSM targets
+
+Large contiguous allocations (generally sizes greater than 64KB) must be
+allocated from a carved out memory pool. The size of the carved out pools
+is based on the sizes drivers need. To properly size the pools, devices
+must specify the size and type of the memory needed. Any driver wanting to
+allocate contiguous memory should indicate this via device tree bindings:
+
+Required parameters:
+- qcom,memory-reservation-type: type of memory to be reserved. This is a
+string defined in arch/arm/mach-msm/memory.c
+- qcom,memory-reservation-size: size of memory to be reserved
+
+Example:
+
+ qcom,a-driver {
+ compatible = "qcom,a-driver";
+ qcom,memory-reservation-type = "EBI1" /* reserve EBI memory */
+ qcom,memory-reservation-size = <0x400000>; /* size 4MB */
+ };
+
+Under some circumstances, it may be necessary to remove a chunk of memory
+from the kernel completely using memblock remove. Note this is different
+than adjusting the memory tags passed in via the bootloader as the virtual
+range is not affected. Any driver needing to remove a block of memory should
+add the appropriate binding:
+
+Required parameters:
+- qcom,memblock-remove: base and size of block to be removed
+
+ qcom,a-driver {
+ compatible = "qcom,a-driver";
+ /* Remove 4MB at 0x200000*/
+ qcom,memblock-remove = <0x200000 0x400000>;
+ };
+
+In order to ensure memory is only reserved when a driver is actually enabled,
+drivers are required to add EXPORT_COMPAT(<name of compatible string>) some
+where in the driver. For the examples above, the driver must add
+EXPORT_COMPAT("qcom,a-driver") to the driver, similar to EXPORT_SYMBOL.
+The EXPORT_COMPAT is to ensure that memory is only carved out if the
+driver is actually enabled, otherwise the memory will not be used.
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_rtb.txt b/Documentation/devicetree/bindings/arm/msm/msm_rtb.txt
new file mode 100644
index 0000000..7b8642b
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm_rtb.txt
@@ -0,0 +1,21 @@
+Register Trace Buffer (RTB)
+
+The RTB is used to log discrete events in the system in an uncached buffer that
+can be post processed from RAM dumps. The RTB must reserve memory using
+the msm specific memory reservation bindings (see
+Documentation/devicetree/bindings/arm/msm/memory-reserve.txt).
+
+Required properties
+
+- compatible: "qcom,msm-rtb"
+- qcom,memory-reservation-size: size of reserved memory for the RTB buffer
+- qcom,memory-reservation-type: type of memory to be reserved
+(see memory-reserve.txt for information about memory reservations)
+
+Example:
+
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt b/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
index 82935ed..93b5144 100644
--- a/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
+++ b/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
@@ -140,12 +140,25 @@
corner values supported on MSM8974 for PMIC
PM8841 SMPS 2 (VDD_Dig); nominal voltages for
these corners are also shown:
- 0 = Retention (0.5000 V)
- 1 = SVS Krait (0.7250 V)
- 2 = SVS SOC (0.8125 V)
- 3 = Normal (0.9000 V)
- 4 = Turbo (0.9875 V)
- 5 = Super Turbo (1.0500 V)
+ 0 = None (don't care)
+ 1 = Retention (0.5000 V)
+ 2 = SVS Krait (0.7250 V)
+ 3 = SVS SOC (0.8125 V)
+ 4 = Normal (0.9000 V)
+ 5 = Turbo (0.9875 V)
+ 6 = Super Turbo (1.0500 V)
+- qcom,init-disallow-bypass: Specify that bypass mode should not be used for a
+ given LDO regulator. When in bypass mode, an
+ LDO performs no regulation and acts as a simple
+ switch. The RPM can utilize this mode for an
+ LDO that is subregulated from an SMPS when it is
+ possible to reduce the SMPS voltage to the
+ desired LDO output level. Bypass mode may be
+ disallowed if lower LDO output noise is
+ required. Supported values are:
+ 0 = Allow RPM to utilize LDO bypass mode
+ if possible
+ 1 = Disallow LDO bypass mode
All properties specified within the core regulator framework can also be used in
second level nodes. These bindings can be found in:
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
new file mode 100644
index 0000000..c50a6c3
--- /dev/null
+++ b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
@@ -0,0 +1,18 @@
+* QCEDEV (Qualcomm Crypto Engine Device)
+
+Required properties:
+ - compatible : should be "qcom,qcedev"
+ - reg : should contain crypto, BAM register map.
+ - interrupts : should contain crypto BAM interrupt.
+ - qcom,bam-pipe-pair : should contain crypto BAM pipe pair index.
+
+Example:
+
+ qcom,qcedev@fd440000 {
+ compatible = "qcom,qcedev";
+ reg = <0xfd440000 0x20000>,
+ <0xfd444000 0x8000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 235 0>;
+ qcom,bam-pipe-pair = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
new file mode 100644
index 0000000..1b0f703
--- /dev/null
+++ b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
@@ -0,0 +1,18 @@
+* QCRYPTO (Qualcomm Crypto)
+
+Required properties:
+ - compatible : should be "qcom,qcrypto"
+ - reg : should contain crypto, BAM register map.
+ - interrupts : should contain crypto BAM interrupt.
+ - qcom,bam-pipe-pair : should contain crypto BAM pipe pair.
+
+Example:
+
+ qcom,qcrypto@fd444000 {
+ compatible = "qcom,qcrypto";
+ reg = <0xfd440000 0x20000>,
+ <0xfd444000 0x8000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 235 0>;
+ qcom,bam-pipe-pair = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu.txt b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
index 67933e7..c198fe9 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
@@ -13,12 +13,15 @@
- qcom,iommu-ctx-sids : List of stream identifiers associated with this
translation context.
- qcom,iommu-ctx-name : Name of the context bank
+ - qcom,iommu-smt-size : Number of SMR entries in the SMT of this HW block
+ - vdd-supply : vdd-supply: phandle to GDSC regulator controlling this IOMMU.
Example:
qcom,iommu@fda64000 {
compatible = "qcom,msm-smmu-v2";
reg = <0xfda64000 0x10000>;
+ vdd-supply = <&gdsc_iommu>;
qcom,iommu-ctx@fda6c000 {
reg = <0xfda6c000 0x1000>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index 11af7a9..dbbe46d 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -5,11 +5,20 @@
- "qcom,msm-vidc"
- reg : offset and length of the register set for the device.
- interrupts : should contain the vidc interrupt.
+- vidc-cp-map : start and size of device virtual address range for secure buffers.
+ Video hardware uses this address range to identify if the buffers are secure
+ or non-secure.
+- vidc-ns-map : start and size of device virtual address range for non-secure buffers.
+ Video hardware uses this address range to identify if the buffers are secure
+ or non-secure.
Example:
+
qcom,vidc@fdc00000 {
compatible = "qcom,msm-vidc";
reg = <0xfdc00000 0xff000>;
interrupts = <0 44 0>;
+ vidc-cp-map = <0x1000000 0x40000000>;
+ vidc-ns-map = <0x40000000 0x40000000>;
};
diff --git a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
index 35ac0ec..a8de90f 100644
--- a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
+++ b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
@@ -35,6 +35,15 @@
- qcom,sdcc-<supply>-current_level - specifies load levels for supply in lpm or
high power mode (hpm). Should be specified in pairs (lpm, hpm), units uA.
+ - gpios - specifies gpios assigned for sdcc slot.
+ - qcom,sdcc-gpio-names - a list of strings that map in order to the list of gpios
+ A slot has either gpios or dedicated tlmm pins as represented below.
+ - qcom,sdcc-pad-pull-on - Active pull configuration for sdc tlmm pins
+ - qcom,sdcc-pad-pull-off - Suspend pull configuration for sdc tlmm pins.
+ - qcom,sdcc-pad-drv-on - Active drive strength configuration for sdc tlmm pins.
+ - qcom,sdcc-pad-drv-off - Suspend drive strength configuration for sdc tlmm pins.
+ Tlmm pins are specified as <clk cmd data>
+
Example:
qcom,sdcc@f9600000 {
diff --git a/Documentation/devicetree/bindings/ocmem/msm-ocmem.txt b/Documentation/devicetree/bindings/ocmem/msm-ocmem.txt
new file mode 100644
index 0000000..1549f10
--- /dev/null
+++ b/Documentation/devicetree/bindings/ocmem/msm-ocmem.txt
@@ -0,0 +1,70 @@
+Qualcomm MSM On-Chip Memory Driver
+
+msm-ocmem is a driver for managing On-Chip Memory (OCMEM) in MSM SoCs.
+It is responsible for allowing various clients to allocate memory from
+OCMEM based on performance, latency and power requirements.
+
+Required Properties:
+- compatible: Must be "qcom,msm-ocmem"
+- reg: Four pairs of physical base addresses and region sizes
+ of memory mapped registers.
+- reg-names : Register region name(s) referenced in reg above
+ "ocmem_ctrl_physical" corresponds to OCMEM control registers.
+ "dm_ctrl_physical" corresponds to DM control registers.
+ "br_ctrl_physical" corresponds to BR control registers.
+ "ocmem_physical" corresponds to address range of OCMEM memory.
+- interrupts: OCMEM core interrupt(s).
+- interrupt-names: OCMEM core interrupt name(s) reference in interrupts above
+ "ocmem_irq" corresponds to OCMEM Error Interrupt.
+ "dm_irq" corresponds to DM Interrupt.
+- qcom,ocmem-num-regions: The number of OCMEM hardware memory regions.
+
+In addition to the information on the OCMEM core, the
+device tree contains additional information describing partitions
+of the OCMEM address space. This is used to establish regions
+of OCMEM that are used for each potential client. The partitions
+can overlap and the OCMEM driver ensures that there is no possibility
+of concurrent access from more than one client to the same address range.
+This allows the OCMEM driver to maximize the usage of OCMEM at all times.
+
+Each partition is represented as a sub-node of the OCMEM device.
+
+OCMEM partitions
+
+Required Properties:
+ - reg : The partition's offset and size within OCMEM.
+ - qcom,ocmem-part-name : The name for this partition.
+ - qcom,ocmem-part-min: The minimum amount of memory reserved exclusively for
+ this client.
+Optional Properties:
+ - qcom,ocmem-part-tail : This parameter, if present, indicates that successive
+ allocations from this partition must be allocated at
+ lower offsetis.
+Example:
+
+ qcom,ocmem@fdd00000 {
+ reg = <0xfdd00000 0x2000>,
+ <0xfdd02000 0x2000>,
+ <0xfe039000 0x400>,
+ <0xfec00000 0x180000>;
+ 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 = <0x3>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0xfec00000 0x180000>;
+
+ partition@0 {
+ reg = <0x0 0x100000>;
+ qcom,ocmem-part-name = "graphics";
+ qcom,ocmem-part-min = <0x80000>;
+ };
+
+ partition@100000 {
+ reg = <0x100000 0x80000>;
+ qcom,ocmem-part-name = "video";
+ qcom,ocmem-part-min = <0x55000>;
+ };
+
+ };
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
new file mode 100644
index 0000000..2e7f9c3
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -0,0 +1,39 @@
+Qualcomm QPNP power-on
+
+The qpnp-power-on is a driver which supports the power-on(PON)
+peripheral on Qualcomm PMICs. The supported functionality includes
+power on/off reason, power-key press/release detection and other PON
+features. This peripheral is connected to the host processor via the SPMI
+interface.
+
+Required properties:
+- compatible: Must be "qcom,qpnp-power-on"
+- reg: Specifies the SPMI address and size for this PON (power-on) peripheral
+- interrupts: Specifies the interrupt associated with the power-key.
+
+Optional properties:
+- qcom,pon-key-enable: Enable power-key detection. It enables monitoring
+ of the KPDPWR_N line (connected to the power-key).
+- qcom,pon-key-dbc-delay: The debouce delay for the power-key interrupt
+ specifed in us. The value ranges from 2 seconds
+ to 1/64 of a second. Possible values are -
+ - 2, 1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64
+ - Intermediate value is rounded down to the
+ nearest valid value.
+- qcom,pon-key-pull-up: The intial state of the KPDPWR_N pin
+ (connected to the power-key)
+ 0 = No pull-up
+ 1 = pull-up enabled
+
+If any of the above optional property is not defined, the driver will continue
+with the default hardware state.
+
+Example:
+ qcom,power-on@800 {
+ compatible = "qcom,qpnp-power-on";
+ reg = <0x800 0x100>;
+ interrupts = <0x0 0x8 0x1>;
+ qcom,pon-key-enable= <true>;
+ qcom,pon-key-pull-up = <true>;
+ qcom,pon-key-dbc-delay = <15625>;
+ }
diff --git a/Documentation/devicetree/bindings/rtc/qpnp-rtc.txt b/Documentation/devicetree/bindings/rtc/qpnp-rtc.txt
new file mode 100644
index 0000000..156141f
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/qpnp-rtc.txt
@@ -0,0 +1,64 @@
+* msm-qpnp-rtc
+
+msm-qpnp-rtc is a RTC driver that supports 32 bit RTC housed inside PMIC.
+Driver utilizes MSM SPMI interface to communicate with the RTC module.
+RTC device is divided into two sub-peripherals one which controls basic RTC
+and other for controlling alarm.
+
+[PMIC RTC Device Declarations]
+
+-Root Node-
+
+Required properties :
+ - compatible: Must be "qcom,qpnp-rtc"
+ - #address-cells: The number of cells dedicated to represent an address
+ This must be set to '1'.
+ - #size-cells: The number of cells dedicated to represent address
+ space range of a peripheral. This must be set to '1'.
+ - spmi-dev-container: This specifies that all the device nodes specified
+ within this node should have their resources
+ coalesced into a single spmi_device.
+
+Optional properties:
+ - qcom,qpnp-rtc-write: This property enables/disables rtc write
+ operation. If not mentioned rtc driver keeps
+ rtc writes disabled.
+ 0 = Disable rtc writes.
+ 1 = Enable rtc writes.
+ - qcom,qpnp-rtc-alarm-pwrup: This property enables/disables feature of
+ powering up phone (from power down state)
+ through alarm interrupt.
+ If not mentioned rtc driver will disable
+ feature of powring-up phone through alarm.
+ 0 = Disable powering up of phone through
+ alarm interrupt.
+ 1 = Enable powering up of phone through
+ alarm interrupt.
+
+-Child Nodes-
+
+Required properties :
+ - reg : Specify the spmi offset and size for device.
+ - interrupts: Specifies alarm interrupt, only for rtc_alarm
+ sub-peripheral.
+
+Example:
+ qcom,pm8941_rtc {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-rtc";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,qpnp-rtc-write = <0>;
+ qcom,qpnp-rtc-alarm-pwrup = <0>;
+
+ qcom,pm8941_rtc_rw@6000 {
+ reg = <0x6000 0x100>;
+ };
+
+ qcom,pm8941_rtc_alarm@6100 {
+ reg = <0x6100 0x100>;
+ interrupts = <0x0 0x61 0x1>;
+ };
+ };
+
+
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
new file mode 100644
index 0000000..c683f58
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -0,0 +1,42 @@
+Qualcomm's TSENS driver
+
+The TSENS driver supports reading temperature from sensors across
+the MSM. The driver defaults to support a 10 bit ADC.
+
+The driver uses the Thermal sysfs framework to provide thermal
+clients the ability to enable/disable the sensors, read trip zones,
+read cool/warm temperature thresholds, set temperature thresholds
+for cool/warm notification and receive notification on temperature
+threshold events.
+
+TSENS node
+
+Required properties:
+- compatible : should be "qcom,msm-tsens" for MSM8974 TSENS driver.
+- reg : offset and length of the TSENS registers.
+- reg : offset and length of the QFPROM registers used for storing
+ the calibration data for the individual sensors.
+- reg-names : resource names used for the physical address of the TSENS
+ registers and the QFPROM efuse calibration address.
+ Should be "tsens_physical" for physical address of the TSENS
+ and "tsens_eeprom_physical" for physical address where calibration
+ data is stored.
+- interrupts : TSENS interrupt for cool/warm temperature threshold.
+- qcom,sensors : Total number of available Temperature sensors for TSENS.
+- qcom,slope : One point calibration characterized slope data for each
+ sensor used to compute the offset. Slope is represented
+ as ADC code/DegC and the value is multipled by a factor
+ of 1000.
+
+Example:
+
+tsens@fc4a8000 {
+ compatible = "qcom,msm-tsens";
+ reg = <0xfc4a8000 0x2000>,
+ <0xfc4b80d0 0x5>;
+ reg-names = "tsens_physical", "tsens_eeprom_physical";
+ interrupts = <0 184 0>;
+ qcom,sensors = <11>;
+ qcom,slope = <1134 1122 1142 1123 1176 1176 1176 1186 1176
+ 1176>;
+};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 87864fd..6737e89 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -22,6 +22,16 @@
#address-cells = <1>;
#size-cells = <1>;
+ qcom,power-on@800 {
+ compatible = "qcom,qpnp-power-on";
+ reg = <0x800 0x100>;
+ interrupts = <0x0 0x8 0x0>;
+ interrupt-names = "power-key";
+ qcom,pon-key-enable = <1>;
+ qcom,pon-key-dbc-delay = <15625>;
+ qcom,pon-key-pull-up = <1>;
+ };
+
pm8941_gpios {
spmi-dev-container;
compatible = "qcom,qpnp-pin";
@@ -305,6 +315,23 @@
status = "disabled";
};
};
+
+ qcom,pm8941_rtc {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-rtc";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,qpnp-rtc-write = <0>;
+ qcom,qpnp-rtc-alarm-pwrup = <0>;
+
+ qcom,pm8941_rtc_rw@6000 {
+ reg = <0x6000 0x100>;
+ };
+ qcom,pm8941_rtc_alarm@6100 {
+ reg = <0x6100 0x100>;
+ interrupts = <0x0 0x61 0x1>;
+ };
+ };
};
qcom,pm8941@1 {
diff --git a/arch/arm/boot/dts/msm8974-iommu.dtsi b/arch/arm/boot/dts/msm8974-iommu.dtsi
index e1a0a9b..a115fd8 100755
--- a/arch/arm/boot/dts/msm8974-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-iommu.dtsi
@@ -18,6 +18,7 @@
ranges;
reg = <0xfda64000 0x10000>;
vdd-supply = <&gdsc_jpeg>;
+ qcom,iommu-smt-size = <16>;
qcom,iommu-ctx@fda6c000 {
reg = <0xfda6c000 0x1000>;
@@ -46,6 +47,7 @@
ranges;
reg = <0xfd928000 0x10000>;
vdd-supply = <&gdsc_mdss>;
+ qcom,iommu-smt-size = <16>;
qcom,iommu-ctx@fd930000 {
reg = <0xfd930000 0x1000>;
@@ -68,6 +70,7 @@
ranges;
reg = <0xfdc84000 0x10000>;
vdd-supply = <&gdsc_venus>;
+ qcom,iommu-smt-size = <16>;
qcom,iommu-ctx@fdc8c000 {
reg = <0xfdc8c000 0x1000>;
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index f0c635e..91894de 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -109,7 +109,7 @@
regulator-name = "8841_s2_corner";
qcom,set = <3>;
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <6>;
+ regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
compatible = "qcom,rpm-regulator-smd";
qcom,consumer-supplies = "vdd_dig", "";
@@ -118,7 +118,7 @@
regulator-name = "8841_s2_corner_ao";
qcom,set = <1>;
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <6>;
+ regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
compatible = "qcom,rpm-regulator-smd";
};
diff --git a/arch/arm/boot/dts/msm8974-rumi.dts b/arch/arm/boot/dts/msm8974-rumi.dts
index b179d94..2cf68b8 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dts
+++ b/arch/arm/boot/dts/msm8974-rumi.dts
@@ -103,4 +103,8 @@
qcom,pronto@fb21b000 {
status = "disable";
};
+
+ qcom,mss@fc880000 {
+ status = "disable";
+ };
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 54f6863..efb42cc 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -46,6 +46,8 @@
compatible = "qcom,msm-vidc";
reg = <0xfdc00000 0xff000>;
interrupts = <0 44 0>;
+ vidc-cp-map = <0x1000000 0x40000000>;
+ vidc-ns-map = <0x40000000 0x40000000>;
};
serial@f991f000 {
@@ -74,7 +76,7 @@
};
qcom,sdcc@f9824000 {
- cell-index = <1>;
+ cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
reg = <0xf9824000 0x1000>;
interrupts = <0 123 0>;
@@ -88,6 +90,11 @@
qcom,sdcc-vdd-io-voltage_level = <1800000 1800000>;
qcom,sdcc-vdd-io-current_level = <250 154000>;
+ qcom,sdcc-pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,sdcc-pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,sdcc-pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,sdcc-pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
qcom,sdcc-sup-voltages = <2950 2950>;
qcom,sdcc-bus-width = <8>;
@@ -96,7 +103,7 @@
};
qcom,sdcc@f98a4000 {
- cell-index = <2>;
+ cell-index = <2>; /* SDC2 SD card slot */
compatible = "qcom,msm-sdcc";
reg = <0xf98a4000 0x1000>;
interrupts = <0 125 0>;
@@ -111,6 +118,11 @@
qcom,sdcc-vdd-io-voltage_level = <1800000 2950000>;
qcom,sdcc-vdd-io-current_level = <6 22000>;
+ qcom,sdcc-pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,sdcc-pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,sdcc-pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,sdcc-pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
qcom,sdcc-sup-voltages = <2950 2950>;
qcom,sdcc-bus-width = <4>;
@@ -120,11 +132,19 @@
};
qcom,sdcc@f9864000 {
- cell-index = <3>;
+ cell-index = <3>; /* SDC3 SDIO slot */
compatible = "qcom,msm-sdcc";
reg = <0xf9864000 0x1000>;
interrupts = <0 127 0>;
+ gpios = <&msmgpio 40 0>, /* CLK */
+ <&msmgpio 39 0>, /* CMD */
+ <&msmgpio 38 0>, /* DATA0 */
+ <&msmgpio 37 0>, /* DATA1 */
+ <&msmgpio 36 0>, /* DATA2 */
+ <&msmgpio 35 0>; /* DATA3 */
+ qcom,sdcc-gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+
qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
qcom,sdcc-sup-voltages = <1800 1800>;
qcom,sdcc-bus-width = <4>;
@@ -133,11 +153,19 @@
};
qcom,sdcc@f98e4000 {
- cell-index = <4>;
+ cell-index = <4>; /* SDC4 SDIO slot */
compatible = "qcom,msm-sdcc";
reg = <0xf98e4000 0x1000>;
interrupts = <0 129 0>;
+ gpios = <&msmgpio 93 0>, /* CLK */
+ <&msmgpio 91 0>, /* CMD */
+ <&msmgpio 96 0>, /* DATA0 */
+ <&msmgpio 95 0>, /* DATA1 */
+ <&msmgpio 94 0>, /* DATA2 */
+ <&msmgpio 92 0>; /* DATA3 */
+ qcom,sdcc-gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+
qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
qcom,sdcc-sup-voltages = <1800 1800>;
qcom,sdcc-bus-width = <4>;
@@ -420,7 +448,48 @@
};
qcom,ocmem@fdd00000 {
- compatible = "qcom,msm_ocmem";
+ compatible = "qcom,msm-ocmem";
+ reg = <0xfdd00000 0x2000>,
+ <0xfdd02000 0x2000>,
+ <0xfe039000 0x400>,
+ <0xfec00000 0x180000>;
+ 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 = <0x3>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0xfec00000 0x180000>;
+
+ partition@0 {
+ reg = <0x0 0x100000>;
+ qcom,ocmem-part-name = "graphics";
+ qcom,ocmem-part-min = <0x80000>;
+ };
+
+ partition@80000 {
+ reg = <0x80000 0xA0000>;
+ qcom,ocmem-part-name = "lp_audio";
+ qcom,ocmem-part-min = <0xA0000>;
+ };
+
+ partition@E0000 {
+ reg = <0x120000 0x20000>;
+ qcom,ocmem-part-name = "blast";
+ qcom,ocmem-part-min = <0x20000>;
+ };
+
+ partition@100000 {
+ reg = <0x100000 0x80000>;
+ qcom,ocmem-part-name = "video";
+ qcom,ocmem-part-min = <0x55000>;
+ };
+
+ partition@140000 {
+ reg = <0x140000 0x40000>;
+ qcom,ocmem-part-name = "sensors";
+ qcom,ocmem-part-min = <0x40000>;
+ };
};
rpm_bus: qcom,rpm-smd {
@@ -477,6 +546,17 @@
qcom,firmware-min-paddr = <0xF500000>;
qcom,firmware-max-paddr = <0xFA00000>;
};
+
+ tsens@fc4a8000 {
+ compatible = "qcom,msm-tsens";
+ reg = <0xfc4a8000 0x2000>,
+ <0xfc4b80d0 0x5>;
+ reg-names = "tsens_physical", "tsens_eeprom_physical";
+ interrupts = <0 184 0>;
+ qcom,sensors = <11>;
+ qcom,slope = <1134 1122 1142 1123 1176 1176 1176 1186 1176
+ 1176 1176>;
+ };
};
/include/ "msm-pm8x41-rpm-regulator.dtsi"
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 913e084..a8abb30 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -17,7 +17,6 @@
CONFIG_KALLSYMS_ALL=y
CONFIG_ASHMEM=y
CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
@@ -313,6 +312,7 @@
CONFIG_LEDS_GPIO=y
CONFIG_LEDS_MSM_PDM=y
CONFIG_LEDS_PMIC_MPP=y
+CONFIG_LEDS_MSM_TRICOLOR=y
CONFIG_SWITCH=y
CONFIG_SWITCH_GPIO=y
CONFIG_RTC_CLASS=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 8cd091c..314f91b 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -17,7 +17,6 @@
CONFIG_KALLSYMS_ALL=y
CONFIG_ASHMEM=y
CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
@@ -313,6 +312,7 @@
CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y
CONFIG_LEDS_MSM_PDM=y
CONFIG_LEDS_PMIC_MPP=y
+CONFIG_LEDS_MSM_TRICOLOR=y
CONFIG_SWITCH=y
CONFIG_SWITCH_GPIO=y
CONFIG_RTC_CLASS=y
@@ -340,8 +340,6 @@
CONFIG_LOCKUP_DETECTOR=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
-CONFIG_DEBUG_SLAB=y
-CONFIG_DEBUG_SLAB_LEAK=y
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_ATOMIC_SLEEP=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 6c213c3..0197f78 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -345,6 +345,7 @@
CONFIG_MSM_CAMERA_FLASH_SC628A=y
CONFIG_MSM_CAMERA_FLASH_TPS61310=y
CONFIG_OV2720=y
+CONFIG_MSM_CSI20_HEADER=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
CONFIG_MSM_EEPROM=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 9eea6f6..d2aaeb0 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -341,6 +341,7 @@
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_USB_VIDEO_CLASS=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_MSM_CAMERA_V4L2=y
CONFIG_IMX074=y
@@ -348,6 +349,7 @@
CONFIG_IMX074_ACT=y
CONFIG_MSM_CAMERA_FLASH_SC628A=y
CONFIG_OV2720=y
+CONFIG_MSM_CSI20_HEADER=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
CONFIG_MSM_EEPROM=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 9bd967b..622d165 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -168,7 +168,6 @@
# CONFIG_LCD_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
# CONFIG_BACKLIGHT_GENERIC is not set
-# CONFIG_HID_SUPPORT is not set
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_STORAGE=y
@@ -251,3 +250,7 @@
CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_QSEECOM=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index c9bc610..5acfd24 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -79,6 +79,9 @@
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_IP_MROUTE=y
CONFIG_IP_MULTIPLE_TABLES=y
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 702667b..59e285b 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -23,10 +23,12 @@
endif
obj-y += acpuclock.o
+obj-$(CONFIG_ARCH_MSM_KRAIT) += acpuclock-krait.o
obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7627.o clock-pll.o
obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o
obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o perf_event_msm_krait_l2.o
+obj-$(CONFIG_ARCH_MSM_KRAIT) += krait-scm.o
obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o
ifndef CONFIG_MSM_SMP
@@ -268,6 +270,7 @@
obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o
obj-$(CONFIG_ARCH_MSM8960) += devices-8960.o
obj-$(CONFIG_ARCH_APQ8064) += devices-8960.o devices-8064.o
+obj-$(CONFIG_ARCH_APQ8064) += acpuclock-8064.o
board-8960-all-objs += board-8960.o board-8960-camera.o board-8960-display.o board-8960-pmic.o board-8960-storage.o board-8960-gpiomux.o
board-8930-all-objs += board-8930.o board-8930-camera.o board-8930-display.o board-8930-pmic.o board-8930-storage.o board-8930-gpiomux.o devices-8930.o board-8930-gpu.o
board-8064-all-objs += board-8064.o board-8064-pmic.o board-8064-storage.o board-8064-gpiomux.o board-8064-camera.o board-8064-display.o board-8064-gpu.o
@@ -290,10 +293,11 @@
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_MSM8974) += board-8974.o board-dt.o board-8974-regulator.o board-8974-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8974) += acpuclock-krait.o acpuclock-8974.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
obj-$(CONFIG_ARCH_MSM8974) += gdsc.o
obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
+obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
new file mode 100644
index 0000000..d46d268
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This 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/platform_device.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+
+#include "acpuclock.h"
+#include "acpuclock-krait.h"
+
+static struct hfpll_data hfpll_data __initdata = {
+ .mode_offset = 0x00,
+ .l_offset = 0x08,
+ .m_offset = 0x0C,
+ .n_offset = 0x10,
+ .config_offset = 0x04,
+ .config_val = 0x7845C665,
+ .has_droop_ctl = true,
+ .droop_offset = 0x14,
+ .droop_val = 0x0108C000,
+ .low_vdd_l_max = 40,
+ .vdd[HFPLL_VDD_NONE] = 0,
+ .vdd[HFPLL_VDD_LOW] = 945000,
+ .vdd[HFPLL_VDD_NOM] = 1050000,
+};
+
+static struct scalable scalable[] __initdata = {
+ [CPU0] = {
+ .hfpll_phys_base = 0x00903200,
+ .aux_clk_sel_phys = 0x02088014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x4501,
+ .vreg[VREG_CORE] = { "krait0", 1300000, 1740000 },
+ .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait0_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 },
+ },
+ [CPU1] = {
+ .hfpll_phys_base = 0x00903240,
+ .aux_clk_sel_phys = 0x02098014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x5501,
+ .vreg[VREG_CORE] = { "krait1", 1300000, 1740000 },
+ .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait1_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 },
+ },
+ [CPU2] = {
+ .hfpll_phys_base = 0x00903280,
+ .aux_clk_sel_phys = 0x020A8014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x6501,
+ .vreg[VREG_CORE] = { "krait2", 1300000, 1740000 },
+ .vreg[VREG_MEM] = { "krait2_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait2_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait2_hfpll", 1800000 },
+ },
+ [CPU3] = {
+ .hfpll_phys_base = 0x009032C0,
+ .aux_clk_sel_phys = 0x020B8014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x7501,
+ .vreg[VREG_CORE] = { "krait3", 1300000, 1740000 },
+ .vreg[VREG_MEM] = { "krait3_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait3_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait3_hfpll", 1800000 },
+ },
+ [L2] = {
+ .hfpll_phys_base = 0x00903300,
+ .aux_clk_sel_phys = 0x02011028,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x0500,
+ .vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
+ },
+};
+
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
+ [0] = BW_MBPS(640), /* At least 80 MHz on bus. */
+ [1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
+ [2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
+ [3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
+ [4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
+ [5] = BW_MBPS(4264), /* At least 533 MHz on bus. */
+};
+
+static struct msm_bus_scale_pdata bus_scale_data __initdata = {
+ .usecase = bw_level_tbl,
+ .num_usecases = ARRAY_SIZE(bw_level_tbl),
+ .active_only = 1,
+ .name = "acpuclk-8064",
+};
+
+static struct l2_level l2_freq_tbl[] __initdata __initdata = {
+ [0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, 1050000, 1050000, 0 },
+ [1] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
+ [2] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
+ [3] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
+ [4] = { { 540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
+ [5] = { { 594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
+ [6] = { { 648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 4 },
+ [7] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
+ [8] = { { 756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 4 },
+ [9] = { { 810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 4 },
+ [10] = { { 864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
+ [11] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 5 },
+ [12] = { { 972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 5 },
+ [13] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 5 },
+ [14] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 5 },
+ [15] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 5 },
+};
+
+static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
+ { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 975000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 975000 },
+ { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 1000000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 1000000 },
+ { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 1025000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 1025000 },
+ { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 1075000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 1075000 },
+ { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1100000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1100000 },
+ { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1125000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1125000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1200000 },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1225000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1225000 },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1237500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1237500 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1250000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
+ { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 925000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 925000 },
+ { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 950000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 950000 },
+ { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 975000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 975000 },
+ { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 1025000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 1025000 },
+ { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1050000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1050000 },
+ { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1075000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1075000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1125000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1125000 },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1150000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1150000 },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1175000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1175000 },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1187500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1187500 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 850000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 850000 },
+ { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 875000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 875000 },
+ { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 900000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 900000 },
+ { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 925000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 925000 },
+ { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 975000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 975000 },
+ { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1000000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1000000 },
+ { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1025000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1025000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1075000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1075000 },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1100000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1100000 },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1125000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1125000 },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1137500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1137500 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1150000 },
+ { 0, { 0 } }
+};
+
+static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
+ [PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow) },
+ [PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom) },
+ [PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast) },
+ /* TODO: update the faster table when data is available */
+ [PVS_FASTER] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast) },
+};
+
+static struct acpuclk_krait_params acpuclk_8064_params __initdata = {
+ .scalable = scalable,
+ .scalable_size = sizeof(scalable),
+ .hfpll_data = &hfpll_data,
+ .pvs_tables = pvs_tables,
+ .l2_freq_tbl = l2_freq_tbl,
+ .l2_freq_tbl_size = sizeof(l2_freq_tbl),
+ .bus_scale = &bus_scale_data,
+ .qfprom_phys_base = 0x00700000,
+};
+
+static int __init acpuclk_8064_probe(struct platform_device *pdev)
+{
+ return acpuclk_krait_init(&pdev->dev, &acpuclk_8064_params);
+}
+
+static struct platform_driver acpuclk_8064_driver = {
+ .driver = {
+ .name = "acpuclk-8064",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init acpuclk_8064_init(void)
+{
+ return platform_driver_probe(&acpuclk_8064_driver,
+ acpuclk_8064_probe);
+}
+device_initcall(acpuclk_8064_init);
diff --git a/arch/arm/mach-msm/acpuclock-8627.c b/arch/arm/mach-msm/acpuclock-8627.c
new file mode 100644
index 0000000..8060803
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-8627.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This 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/platform_device.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+
+#include "acpuclock.h"
+#include "acpuclock-krait.h"
+
+/* Corner type vreg VDD values */
+#define LVL_NONE RPM_VREG_CORNER_NONE
+#define LVL_LOW RPM_VREG_CORNER_LOW
+#define LVL_NOM RPM_VREG_CORNER_NOMINAL
+#define LVL_HIGH RPM_VREG_CORNER_HIGH
+
+static struct hfpll_data hfpll_data __initdata = {
+ .mode_offset = 0x00,
+ .l_offset = 0x08,
+ .m_offset = 0x0C,
+ .n_offset = 0x10,
+ .config_offset = 0x04,
+ .config_val = 0x7845C665,
+ .has_droop_ctl = true,
+ .droop_offset = 0x14,
+ .droop_val = 0x0108C000,
+ .low_vdd_l_max = 40,
+ .vdd[HFPLL_VDD_NONE] = LVL_NONE,
+ .vdd[HFPLL_VDD_LOW] = LVL_LOW,
+ .vdd[HFPLL_VDD_NOM] = LVL_NOM,
+};
+
+static struct scalable scalable[] __initdata = {
+ [CPU0] = {
+ .hfpll_phys_base = 0x00903200,
+ .aux_clk_sel_phys = 0x02088014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x4501,
+ .vreg[VREG_CORE] = { "krait0", 1300000, 1740000 },
+ .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait0_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 },
+ },
+ [CPU1] = {
+ .hfpll_phys_base = 0x00903300,
+ .aux_clk_sel_phys = 0x02098014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x5501,
+ .vreg[VREG_CORE] = { "krait1", 1300000, 1740000 },
+ .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait1_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 },
+ },
+ [L2] = {
+ .hfpll_phys_base = 0x00903400,
+ .aux_clk_sel_phys = 0x02011028,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x0500,
+ .vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
+ },
+};
+
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
+ [0] = BW_MBPS(640), /* At least 80 MHz on bus. */
+ [1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
+ [2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
+ [3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
+ [4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
+};
+
+static struct msm_bus_scale_pdata bus_scale_data __initdata = {
+ .usecase = bw_level_tbl,
+ .num_usecases = ARRAY_SIZE(bw_level_tbl),
+ .active_only = 1,
+ .name = "acpuclk-8627",
+};
+
+/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
+static struct l2_level l2_freq_tbl[] __initdata = {
+ [0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, LVL_NOM, 1050000, 0 },
+ [1] = { { 384000, PLL_8, 0, 2, 0x00 }, LVL_NOM, 1050000, 1 },
+ [2] = { { 432000, HFPLL, 2, 0, 0x20 }, LVL_NOM, 1050000, 1 },
+ [3] = { { 486000, HFPLL, 2, 0, 0x24 }, LVL_NOM, 1050000, 1 },
+ [4] = { { 540000, HFPLL, 2, 0, 0x28 }, LVL_NOM, 1050000, 2 },
+ [5] = { { 594000, HFPLL, 1, 0, 0x16 }, LVL_NOM, 1050000, 2 },
+ [6] = { { 648000, HFPLL, 1, 0, 0x18 }, LVL_NOM, 1050000, 2 },
+ [7] = { { 702000, HFPLL, 1, 0, 0x1A }, LVL_NOM, 1050000, 3 },
+ [8] = { { 756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 3 },
+ [9] = { { 810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 3 },
+ [10] = { { 864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
+ [11] = { { 918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 4 },
+ [12] = { { 972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 4 },
+};
+
+/* TODO: Update core voltages when data is available. */
+static struct acpu_level acpu_freq_tbl[] __initdata = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
+ { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(5), 925000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(5), 925000 },
+ { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(5), 937500 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(5), 962500 },
+ { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(9), 987500 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(9), 1000000 },
+ { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(9), 1025000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(9), 1062500 },
+ { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(12), 1062500 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(12), 1087500 },
+ { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(12), 1100000 },
+ { 0, { 0 } }
+};
+
+static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
+ [PVS_SLOW] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+ [PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+ [PVS_FAST] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+};
+
+static struct acpuclk_krait_params acpuclk_8627_params __initdata = {
+ .scalable = scalable,
+ .scalable_size = sizeof(scalable),
+ .hfpll_data = &hfpll_data,
+ .pvs_tables = pvs_tables,
+ .l2_freq_tbl = l2_freq_tbl,
+ .l2_freq_tbl_size = sizeof(l2_freq_tbl),
+ .bus_scale = &bus_scale_data,
+ .qfprom_phys_base = 0x00700000,
+};
+
+static int __init acpuclk_8627_probe(struct platform_device *pdev)
+{
+ return acpuclk_krait_init(&pdev->dev, &acpuclk_8627_params);
+}
+
+static struct platform_driver acpuclk_8627_driver = {
+ .driver = {
+ .name = "acpuclk-8627",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init acpuclk_8627_init(void)
+{
+ return platform_driver_probe(&acpuclk_8627_driver,
+ acpuclk_8627_probe);
+}
+device_initcall(acpuclk_8627_init);
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
new file mode 100644
index 0000000..d04ce03
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-8930.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This 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/platform_device.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+
+#include "acpuclock.h"
+#include "acpuclock-krait.h"
+
+/* Corner type vreg VDD values */
+#define LVL_NONE RPM_VREG_CORNER_NONE
+#define LVL_LOW RPM_VREG_CORNER_LOW
+#define LVL_NOM RPM_VREG_CORNER_NOMINAL
+#define LVL_HIGH RPM_VREG_CORNER_HIGH
+
+static struct hfpll_data hfpll_data __initdata = {
+ .mode_offset = 0x00,
+ .l_offset = 0x08,
+ .m_offset = 0x0C,
+ .n_offset = 0x10,
+ .config_offset = 0x04,
+ .config_val = 0x7845C665,
+ .has_droop_ctl = true,
+ .droop_offset = 0x14,
+ .droop_val = 0x0108C000,
+ .low_vdd_l_max = 40,
+ .vdd[HFPLL_VDD_NONE] = LVL_NONE,
+ .vdd[HFPLL_VDD_LOW] = LVL_LOW,
+ .vdd[HFPLL_VDD_NOM] = LVL_NOM,
+};
+
+static struct scalable scalable[] __initdata = {
+ [CPU0] = {
+ .hfpll_phys_base = 0x00903200,
+ .aux_clk_sel_phys = 0x02088014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x4501,
+ .vreg[VREG_CORE] = { "krait0", 1300000, 1740000 },
+ .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait0_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 },
+ },
+ [CPU1] = {
+ .hfpll_phys_base = 0x00903300,
+ .aux_clk_sel_phys = 0x02098014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x5501,
+ .vreg[VREG_CORE] = { "krait1", 1300000, 1740000 },
+ .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait1_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 },
+ },
+ [L2] = {
+ .hfpll_phys_base = 0x00903400,
+ .aux_clk_sel_phys = 0x02011028,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x0500,
+ .vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
+ },
+};
+
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
+ [0] = BW_MBPS(640), /* At least 80 MHz on bus. */
+ [1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
+ [2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
+ [3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
+ [4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
+ [5] = BW_MBPS(3600), /* At least 450 MHz on bus. */
+ [6] = BW_MBPS(3936), /* At least 492 MHz on bus. */
+ [7] = BW_MBPS(4264), /* At least 533 MHz on bus. */
+};
+
+static struct msm_bus_scale_pdata bus_scale_data __initdata = {
+ .usecase = bw_level_tbl,
+ .num_usecases = ARRAY_SIZE(bw_level_tbl),
+ .active_only = 1,
+ .name = "acpuclk-8930",
+};
+
+/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
+static struct l2_level l2_freq_tbl[] __initdata = {
+ [0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, LVL_NOM, 1050000, 0 },
+ [1] = { { 384000, PLL_8, 0, 2, 0x00 }, LVL_NOM, 1050000, 1 },
+ [2] = { { 432000, HFPLL, 2, 0, 0x20 }, LVL_NOM, 1050000, 2 },
+ [3] = { { 486000, HFPLL, 2, 0, 0x24 }, LVL_NOM, 1050000, 2 },
+ [4] = { { 540000, HFPLL, 2, 0, 0x28 }, LVL_NOM, 1050000, 2 },
+ [5] = { { 594000, HFPLL, 1, 0, 0x16 }, LVL_NOM, 1050000, 2 },
+ [6] = { { 648000, HFPLL, 1, 0, 0x18 }, LVL_NOM, 1050000, 4 },
+ [7] = { { 702000, HFPLL, 1, 0, 0x1A }, LVL_NOM, 1050000, 4 },
+ [8] = { { 756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 4 },
+ [9] = { { 810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 4 },
+ [10] = { { 864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
+ [11] = { { 918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 7 },
+ [12] = { { 972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 7 },
+ [13] = { { 1026000, HFPLL, 1, 0, 0x26 }, LVL_HIGH, 1150000, 7 },
+ [14] = { { 1080000, HFPLL, 1, 0, 0x28 }, LVL_HIGH, 1150000, 7 },
+ [15] = { { 1134000, HFPLL, 1, 0, 0x2A }, LVL_HIGH, 1150000, 7 },
+ [16] = { { 1188000, HFPLL, 1, 0, 0x2C }, LVL_HIGH, 1150000, 7 },
+};
+
+static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
+ { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 975000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 975000 },
+ { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 1000000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 1000000 },
+ { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 1025000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1025000 },
+ { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1075000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1075000 },
+ { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1100000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1100000 },
+ { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(11), 1125000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(11), 1125000 },
+ { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1175000 },
+ { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 925000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 925000 },
+ { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 950000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 950000 },
+ { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 975000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 975000 },
+ { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 1000000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1000000 },
+ { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1050000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1050000 },
+ { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1075000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1075000 },
+ { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(11), 1100000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(11), 1100000 },
+ { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1150000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1150000 },
+ { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1175000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
+ { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 900000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 900000 },
+ { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 925000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 925000 },
+ { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 950000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 950000 },
+ { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1000000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1000000 },
+ { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1025000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1025000 },
+ { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(11), 1050000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(11), 1050000 },
+ { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1100000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1100000 },
+ { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1125000 },
+ { 0, { 0 } }
+};
+
+static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
+ [PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow) },
+ [PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom) },
+ [PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast) },
+};
+
+static struct acpuclk_krait_params acpuclk_8930_params __initdata = {
+ .scalable = scalable,
+ .scalable_size = sizeof(scalable),
+ .hfpll_data = &hfpll_data,
+ .pvs_tables = pvs_tables,
+ .l2_freq_tbl = l2_freq_tbl,
+ .l2_freq_tbl_size = sizeof(l2_freq_tbl),
+ .bus_scale = &bus_scale_data,
+ .qfprom_phys_base = 0x00700000,
+};
+
+static int __init acpuclk_8930_probe(struct platform_device *pdev)
+{
+ return acpuclk_krait_init(&pdev->dev, &acpuclk_8930_params);
+}
+
+static struct platform_driver acpuclk_8930_driver = {
+ .driver = {
+ .name = "acpuclk-8930",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init acpuclk_8930_init(void)
+{
+ return platform_driver_probe(&acpuclk_8930_driver,
+ acpuclk_8930_probe);
+}
+device_initcall(acpuclk_8930_init);
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 7f198d2..8623c2b 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/*
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This 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,413 +11,66 @@
* GNU General Public License for more details.
*/
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/cpufreq.h>
-#include <linux/cpu.h>
-#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
-
-#include <asm/mach-types.h>
-#include <asm/cpu.h>
-
-#include <mach/board.h>
-#include <mach/msm_iomap.h>
#include <mach/rpm-regulator.h>
-#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
-#include <mach/socinfo.h>
-#include <mach/msm-krait-l2-accessors.h>
-#include <mach/rpm-regulator.h>
+#include <mach/msm_bus.h>
#include "acpuclock.h"
-#include "pm.h"
+#include "acpuclock-krait.h"
-/*
- * Source IDs.
- * These must be negative to not overlap with the source IDs
- * used by the 8x60 local clock driver.
- */
-#define PLL_8 0
-#define HFPLL -1
-#define QSB -2
-
-/* Mux source selects. */
-#define PRI_SRC_SEL_SEC_SRC 0
-#define PRI_SRC_SEL_HFPLL 1
-#define PRI_SRC_SEL_HFPLL_DIV2 2
-#define SEC_SRC_SEL_QSB 0
-#define SEC_SRC_SEL_AUX 2
-
-/* HFPLL registers offsets. */
-#define HFPLL_MODE 0x00
-#define HFPLL_CONFIG_CTL 0x04
-#define HFPLL_L_VAL 0x08
-#define HFPLL_M_VAL 0x0C
-#define HFPLL_N_VAL 0x10
-#define HFPLL_DROOP_CTL 0x14
-
-/* CP15 L2 indirect addresses. */
-#define L2CPMR_IADDR 0x500
-#define L2CPUCPMR_IADDR 0x501
-
-#define STBY_KHZ 1
-
-#define HFPLL_LOW_VDD_PLL_L_MAX 0x28
-
-#define SECCLKAGD BIT(4)
-
-/* PTE EFUSE register. */
-#define QFPROM_PTE_EFUSE_ADDR (MSM_QFPROM_BASE + 0x00C0)
-
-/* Corner type vreg VDD values */
-#define LVL_NONE RPM_VREG_CORNER_NONE
-#define LVL_LOW RPM_VREG_CORNER_LOW
-#define LVL_NOM RPM_VREG_CORNER_NOMINAL
-#define LVL_HIGH RPM_VREG_CORNER_HIGH
-
-enum scalables {
- CPU0 = 0,
- CPU1,
- CPU2,
- CPU3,
- L2,
- NUM_SCALABLES
+static struct hfpll_data hfpll_data __initdata = {
+ .mode_offset = 0x00,
+ .l_offset = 0x08,
+ .m_offset = 0x0C,
+ .n_offset = 0x10,
+ .config_offset = 0x04,
+ .config_val = 0x7845C665,
+ .has_droop_ctl = true,
+ .droop_offset = 0x14,
+ .droop_val = 0x0108C000,
+ .low_vdd_l_max = 40,
+ .vdd[HFPLL_VDD_NONE] = 0,
+ .vdd[HFPLL_VDD_LOW] = 850000,
+ .vdd[HFPLL_VDD_NOM] = 1050000,
};
-enum vregs {
- VREG_CORE,
- VREG_MEM,
- VREG_DIG,
- VREG_HFPLL_A,
- VREG_HFPLL_B,
- NUM_VREG
-};
-
-enum hfpll_vdd_levels {
- HFPLL_VDD_NONE,
- HFPLL_VDD_LOW,
- HFPLL_VDD_NOM
-};
-
-enum pvs {
- PVS_SLOW,
- PVS_NOM,
- PVS_FAST,
- PVS_FASTER,
- NUM_PVS
-};
-
-struct vreg {
- const char name[15];
- const unsigned int max_vdd;
- const int rpm_vreg_voter;
- const int rpm_vreg_id;
- struct regulator *reg;
- unsigned int cur_vdd;
-};
-
-struct core_speed {
- unsigned int khz;
- int src;
- unsigned int pri_src_sel;
- unsigned int sec_src_sel;
- unsigned int pll_l_val;
-};
-
-struct l2_level {
- struct core_speed speed;
- unsigned int vdd_dig;
- unsigned int vdd_mem;
- unsigned int bw_level;
-};
-
-struct acpu_level {
- unsigned int use_for_scaling;
- struct core_speed speed;
- struct l2_level *l2_level;
- unsigned int vdd_core;
-};
-
-struct scalable {
- void * __iomem const hfpll_base;
- void * __iomem const aux_clk_sel;
- const uint32_t l2cpmr_iaddr;
- struct core_speed *current_speed;
- struct l2_level *l2_vote;
- struct vreg vreg[NUM_VREG];
- unsigned int *hfpll_vdd_tbl;
- bool regulators_initialized;
- bool clocks_initialized;
-};
-
-static unsigned int hfpll_vdd_tbl_8960[] = {
- [HFPLL_VDD_NONE] = 0,
- [HFPLL_VDD_LOW] = 850000,
- [HFPLL_VDD_NOM] = 1050000
-};
-
-static unsigned int hfpll_vdd_tbl_8064[] = {
- [HFPLL_VDD_NONE] = 0,
- [HFPLL_VDD_LOW] = 945000,
- [HFPLL_VDD_NOM] = 1050000
-};
-
-static unsigned int hfpll_vdd_dig_tbl_8930[] = {
- [HFPLL_VDD_NONE] = LVL_NONE,
- [HFPLL_VDD_LOW] = LVL_LOW,
- [HFPLL_VDD_NOM] = LVL_NOM
-};
-
-static struct scalable scalable_8960[] = {
+static struct scalable scalable[] __initdata = {
[CPU0] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x200,
- .aux_clk_sel = MSM_ACC0_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_L24 },
- .vreg[VREG_DIG] = { "krait0_dig", 1150000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_A] = { "hfpll0_s8", 2100000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_S8 },
- .vreg[VREG_HFPLL_B] = { "hfpll0_l23", 1800000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_L23 },
- },
+ .hfpll_phys_base = 0x00903200,
+ .aux_clk_sel_phys = 0x02088014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x4501,
+ .vreg[VREG_CORE] = { "krait0", 1300000, 3200000 },
+ .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait0_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait0_s8", 2050000 },
+ .vreg[VREG_HFPLL_B] = { "krait0_l23", 1800000 },
+ },
[CPU1] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x300,
- .aux_clk_sel = MSM_ACC1_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_L24 },
- .vreg[VREG_DIG] = { "krait1_dig", 1150000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_A] = { "hfpll1_s8", 2100000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_S8 },
- .vreg[VREG_HFPLL_B] = { "hfpll1_l23", 1800000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_L23 },
- },
+ .hfpll_phys_base = 0x00903300,
+ .aux_clk_sel_phys = 0x02098014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x5501,
+ .vreg[VREG_CORE] = { "krait1", 1300000, 3200000 },
+ .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait1_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait1_s8", 2050000 },
+ .vreg[VREG_HFPLL_B] = { "krait1_l23", 1800000 },
+ },
[L2] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x400,
- .hfpll_vdd_tbl = hfpll_vdd_tbl_8960,
- .aux_clk_sel = MSM_APCS_GCC_BASE + 0x028,
- .l2cpmr_iaddr = L2CPMR_IADDR,
- .vreg[VREG_HFPLL_A] = { "hfpll_l2_s8", 2100000,
- RPM_VREG_VOTER6,
- RPM_VREG_ID_PM8921_S8 },
- .vreg[VREG_HFPLL_B] = { "hfpll_l2_l23", 1800000,
- RPM_VREG_VOTER6,
- RPM_VREG_ID_PM8921_L23 },
- },
+ .hfpll_phys_base = 0x00903400,
+ .aux_clk_sel_phys = 0x02011028,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x0500,
+ .vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
+ .vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
+ },
};
-static DEFINE_MUTEX(driver_lock);
-static DEFINE_SPINLOCK(l2_lock);
-
-static struct scalable scalable_8064[] = {
- [CPU0] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x200,
- .aux_clk_sel = MSM_ACC0_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_L24 },
- .vreg[VREG_DIG] = { "krait0_dig", 1150000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_B] = { "hfpll0", 1800000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_LVS7 },
- },
- [CPU1] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x240,
- .aux_clk_sel = MSM_ACC1_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_L24 },
- .vreg[VREG_DIG] = { "krait1_dig", 1150000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_B] = { "hfpll1", 1800000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_LVS7 },
- },
- [CPU2] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x280,
- .aux_clk_sel = MSM_ACC2_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait2", 1300000 },
- .vreg[VREG_MEM] = { "krait2_mem", 1150000,
- RPM_VREG_VOTER4,
- RPM_VREG_ID_PM8921_L24 },
- .vreg[VREG_DIG] = { "krait2_dig", 1150000,
- RPM_VREG_VOTER4,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_B] = { "hfpll2", 1800000,
- RPM_VREG_VOTER4,
- RPM_VREG_ID_PM8921_LVS7 },
- },
- [CPU3] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x2C0,
- .aux_clk_sel = MSM_ACC3_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait3", 1300000 },
- .vreg[VREG_MEM] = { "krait3_mem", 1150000,
- RPM_VREG_VOTER5,
- RPM_VREG_ID_PM8921_L24 },
- .vreg[VREG_DIG] = { "krait3_dig", 1150000,
- RPM_VREG_VOTER5,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_B] = { "hfpll3", 1800000,
- RPM_VREG_VOTER5,
- RPM_VREG_ID_PM8921_LVS7 },
- },
- [L2] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x300,
- .hfpll_vdd_tbl = hfpll_vdd_tbl_8064,
- .aux_clk_sel = MSM_APCS_GCC_BASE + 0x028,
- .l2cpmr_iaddr = L2CPMR_IADDR,
- .vreg[VREG_HFPLL_B] = { "hfpll_l2", 1800000,
- RPM_VREG_VOTER6,
- RPM_VREG_ID_PM8921_LVS7 },
- },
-};
-
-static struct scalable scalable_8930[] = {
- [CPU0] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x200,
- .aux_clk_sel = MSM_ACC0_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8038_L24 },
- .vreg[VREG_DIG] = { "krait0_dig", LVL_HIGH,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8038_VDD_DIG_CORNER
- },
- .vreg[VREG_HFPLL_B] = { "hfpll0", 1800000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8038_L23 },
- },
- [CPU1] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x300,
- .aux_clk_sel = MSM_ACC1_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8038_L24 },
- .vreg[VREG_DIG] = { "krait1_dig", LVL_HIGH,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8038_VDD_DIG_CORNER
- },
- .vreg[VREG_HFPLL_B] = { "hfpll1", 1800000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8038_L23 },
- },
- [L2] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x400,
- .hfpll_vdd_tbl = hfpll_vdd_dig_tbl_8930,
- .aux_clk_sel = MSM_APCS_GCC_BASE + 0x028,
- .l2cpmr_iaddr = L2CPMR_IADDR,
- .vreg[VREG_HFPLL_B] = { "hfpll_l2", 1800000,
- RPM_VREG_VOTER6,
- RPM_VREG_ID_PM8038_L23 },
- },
-};
-
-/*TODO: Update the rpm vreg id when the rpm driver is ready */
-static struct scalable scalable_8627[] = {
- [CPU0] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x200,
- .aux_clk_sel = MSM_ACC0_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8038_L24 },
- .vreg[VREG_DIG] = { "krait0_dig", LVL_HIGH,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8038_VDD_DIG_CORNER
- },
- .vreg[VREG_HFPLL_B] = { "hfpll0", 1800000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8038_L23 },
- },
- [CPU1] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x300,
- .aux_clk_sel = MSM_ACC1_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8038_L24 },
- .vreg[VREG_DIG] = { "krait1_dig", LVL_HIGH,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8038_VDD_DIG_CORNER
- },
- .vreg[VREG_HFPLL_B] = { "hfpll1", 1800000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8038_L23 },
- },
- [L2] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x400,
- .hfpll_vdd_tbl = hfpll_vdd_dig_tbl_8930,
- .aux_clk_sel = MSM_APCS_GCC_BASE + 0x028,
- .l2cpmr_iaddr = L2CPMR_IADDR,
- .vreg[VREG_HFPLL_B] = { "hfpll_l2", 1800000,
- RPM_VREG_VOTER6,
- RPM_VREG_ID_PM8038_L23 },
- },
-};
-
-static struct l2_level *l2_freq_tbl;
-static struct acpu_level *acpu_freq_tbl;
-static int l2_freq_tbl_size;
-static struct scalable *scalable;
-#define SCALABLE_TO_CPU(sc) ((sc) - scalable)
-
-/* Instantaneous bandwidth requests in MB/s. */
-#define BW_MBPS(_bw) \
- { \
- .vectors = (struct msm_bus_vectors[]){ \
- {\
- .src = MSM_BUS_MASTER_AMPSS_M0, \
- .dst = MSM_BUS_SLAVE_EBI_CH0, \
- .ib = (_bw) * 1000000UL, \
- .ab = (_bw) * 100000UL, \
- }, \
- { \
- .src = MSM_BUS_MASTER_AMPSS_M1, \
- .dst = MSM_BUS_SLAVE_EBI_CH0, \
- .ib = (_bw) * 1000000UL, \
- .ab = (_bw) * 100000UL, \
- }, \
- }, \
- .num_paths = 2, \
- }
-static struct msm_bus_paths bw_level_tbl[] = {
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
[0] = BW_MBPS(640), /* At least 80 MHz on bus. */
[1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
[2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
@@ -424,70 +78,16 @@
[4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
[5] = BW_MBPS(3600), /* At least 450 MHz on bus. */
[6] = BW_MBPS(3936), /* At least 492 MHz on bus. */
- [7] = BW_MBPS(4264), /* At least 533 MHz on bus. */
};
-static struct msm_bus_scale_pdata bus_client_pdata = {
+static struct msm_bus_scale_pdata bus_scale_data __initdata = {
.usecase = bw_level_tbl,
.num_usecases = ARRAY_SIZE(bw_level_tbl),
.active_only = 1,
- .name = "acpuclock",
+ .name = "acpuclk-8960",
};
-static uint32_t bus_perf_client;
-
-/* TODO: Update vdd_dig and vdd_mem when voltage data is available. */
-#define L2(x) (&l2_freq_tbl_8960_kraitv1[(x)])
-static struct l2_level l2_freq_tbl_8960_kraitv1[] = {
- [0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, 1050000, 1050000, 0 },
- [1] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
- [2] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 1 },
- [3] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 1 },
- [4] = { { 540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 1 },
- [5] = { { 594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
- [6] = { { 648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 2 },
- [7] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 2 },
- [8] = { { 756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 2 },
- [9] = { { 810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 3 },
- [10] = { { 864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 3 },
- [11] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 3 },
-};
-
-static struct acpu_level acpu_freq_tbl_8960_kraitv1_slow[] = {
- { 0, {STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 925000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 925000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 937500 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 962500 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 987500 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1000000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1025000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1062500 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1062500 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1087500 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_8960_kraitv1_nom_fast[] = {
- { 0, {STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 862500 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 862500 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 862500 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 887500 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 900000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 925000 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 925000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 937500 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 962500 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1012500 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1025000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1025000 },
- { 0, { 0 } }
-};
-
-#undef L2
-#define L2(x) (&l2_freq_tbl_8960_kraitv2[(x)])
-static struct l2_level l2_freq_tbl_8960_kraitv2[] = {
+static struct l2_level l2_freq_tbl[] __initdata = {
[0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, 1050000, 1050000, 0 },
[1] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
[2] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
@@ -510,7 +110,7 @@
[19] = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 6 },
};
-static struct acpu_level acpu_freq_tbl_8960_kraitv2_slow[] = {
+static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
{ 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
{ 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
{ 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 975000 },
@@ -537,7 +137,7 @@
{ 0, { 0 } }
};
-static struct acpu_level acpu_freq_tbl_8960_kraitv2_nom[] = {
+static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
{ 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
{ 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
{ 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 925000 },
@@ -564,7 +164,7 @@
{ 0, { 0 } }
};
-static struct acpu_level acpu_freq_tbl_8960_kraitv2_fast[] = {
+static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
{ 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 850000 },
{ 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 850000 },
{ 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 875000 },
@@ -591,1076 +191,26 @@
{ 0, { 0 } }
};
-/* TODO: Update vdd_dig and vdd_mem when voltage data is available. */
-#undef L2
-#define L2(x) (&l2_freq_tbl_8064[(x)])
-static struct l2_level l2_freq_tbl_8064[] = {
- [0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, 1050000, 1050000, 0 },
- [1] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
- [2] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
- [3] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
- [4] = { { 540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
- [5] = { { 594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
- [6] = { { 648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 4 },
- [7] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
- [8] = { { 756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 4 },
- [9] = { { 810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 4 },
- [10] = { { 864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
- [11] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 7 },
- [12] = { { 972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 7 },
- [13] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 7 },
- [14] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 7 },
- [15] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 7 },
+static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
+ [PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow) },
+ [PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom) },
+ [PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast) },
};
-/* TODO: Update core voltages when data is available. */
-static struct acpu_level acpu_freq_tbl_8064_slow[] = {
- { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
- { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 975000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 975000 },
- { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 1000000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 1000000 },
- { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 1025000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 1025000 },
- { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 1075000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 1075000 },
- { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1100000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1100000 },
- { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1125000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1125000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1200000 },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1225000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1225000 },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1237500 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1250000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_8064_nom[] = {
- { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
- { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 925000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 925000 },
- { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 950000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 950000 },
- { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 975000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 975000 },
- { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 1025000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 1025000 },
- { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1050000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1050000 },
- { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1075000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1075000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1125000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1125000 },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1150000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1150000 },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1175000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1175000 },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1187500 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1187500 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1200000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_8064_fast[] = {
- { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 850000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 850000 },
- { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 875000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 875000 },
- { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 900000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 900000 },
- { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 925000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 925000 },
- { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 975000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 975000 },
- { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1000000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1000000 },
- { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1025000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1025000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1075000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1075000 },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1100000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1100000 },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1125000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1125000 },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1137500 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1137500 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1150000 },
- { 0, { 0 } }
-};
-
-/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
-#undef L2
-#define L2(x) (&l2_freq_tbl_8930[(x)])
-static struct l2_level l2_freq_tbl_8930[] = {
- [0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, LVL_NOM, 1050000, 0 },
- [1] = { { 384000, PLL_8, 0, 2, 0x00 }, LVL_NOM, 1050000, 1 },
- [2] = { { 432000, HFPLL, 2, 0, 0x20 }, LVL_NOM, 1050000, 2 },
- [3] = { { 486000, HFPLL, 2, 0, 0x24 }, LVL_NOM, 1050000, 2 },
- [4] = { { 540000, HFPLL, 2, 0, 0x28 }, LVL_NOM, 1050000, 2 },
- [5] = { { 594000, HFPLL, 1, 0, 0x16 }, LVL_NOM, 1050000, 2 },
- [6] = { { 648000, HFPLL, 1, 0, 0x18 }, LVL_NOM, 1050000, 4 },
- [7] = { { 702000, HFPLL, 1, 0, 0x1A }, LVL_NOM, 1050000, 4 },
- [8] = { { 756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 4 },
- [9] = { { 810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 4 },
- [10] = { { 864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
- [11] = { { 918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 7 },
- [12] = { { 972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 7 },
- [13] = { { 1026000, HFPLL, 1, 0, 0x26 }, LVL_HIGH, 1150000, 7 },
- [14] = { { 1080000, HFPLL, 1, 0, 0x28 }, LVL_HIGH, 1150000, 7 },
- [15] = { { 1134000, HFPLL, 1, 0, 0x2A }, LVL_HIGH, 1150000, 7 },
- [16] = { { 1188000, HFPLL, 1, 0, 0x2C }, LVL_HIGH, 1150000, 7 },
-};
-
-/* TODO: Update core voltages when data is available. */
-static struct acpu_level acpu_freq_tbl_8930_slow[] = {
- { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 975000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 975000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 1000000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 1000000 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 1025000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1025000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1075000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1075000 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1100000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1100000 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(11), 1125000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(11), 1125000 },
- { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1175000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1175000 },
- { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1200000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_8930_nom[] = {
- { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 925000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 925000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 950000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 950000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 975000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 975000 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 1000000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1000000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1050000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1050000 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1075000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1075000 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(11), 1100000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(11), 1100000 },
- { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1150000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1150000 },
- { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1175000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_8930_fast[] = {
- { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 900000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 900000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 925000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 925000 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 950000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 950000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1000000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1000000 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1025000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1025000 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(11), 1050000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(11), 1050000 },
- { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1100000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1100000 },
- { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1125000 },
- { 0, { 0 } }
-};
-/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
-#undef L2
-#define L2(x) (&l2_freq_tbl_8627[(x)])
-static struct l2_level l2_freq_tbl_8627[] = {
- [0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, LVL_NOM, 1050000, 0 },
- [1] = { { 384000, PLL_8, 0, 2, 0x00 }, LVL_NOM, 1050000, 1 },
- [2] = { { 432000, HFPLL, 2, 0, 0x20 }, LVL_NOM, 1050000, 1 },
- [3] = { { 486000, HFPLL, 2, 0, 0x24 }, LVL_NOM, 1050000, 1 },
- [4] = { { 540000, HFPLL, 2, 0, 0x28 }, LVL_NOM, 1050000, 2 },
- [5] = { { 594000, HFPLL, 1, 0, 0x16 }, LVL_NOM, 1050000, 2 },
- [6] = { { 648000, HFPLL, 1, 0, 0x18 }, LVL_NOM, 1050000, 2 },
- [7] = { { 702000, HFPLL, 1, 0, 0x1A }, LVL_NOM, 1050000, 3 },
- [8] = { { 756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 3 },
- [9] = { { 810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 3 },
- [10] = { { 864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
- [11] = { { 918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 4 },
- [12] = { { 972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 4 },
-};
-
-/* TODO: Update core voltages when data is available. */
-static struct acpu_level acpu_freq_tbl_8627[] = {
- { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(5), 925000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(5), 925000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(5), 937500 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(5), 962500 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(9), 987500 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(9), 1000000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(9), 1025000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(9), 1062500 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(12), 1062500 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(12), 1087500 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(12), 1100000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level *acpu_freq_tbl_8960_v1[NUM_PVS] __initdata = {
- [PVS_SLOW] = acpu_freq_tbl_8960_kraitv1_slow,
- [PVS_NOM] = acpu_freq_tbl_8960_kraitv1_nom_fast,
- [PVS_FAST] = acpu_freq_tbl_8960_kraitv1_nom_fast,
-};
-
-static struct acpu_level *acpu_freq_tbl_8960_v2[NUM_PVS] __initdata = {
- [PVS_SLOW] = acpu_freq_tbl_8960_kraitv2_slow,
- [PVS_NOM] = acpu_freq_tbl_8960_kraitv2_nom,
- [PVS_FAST] = acpu_freq_tbl_8960_kraitv2_fast,
-};
-
-/* TODO: update the faster table when data is available */
-static struct acpu_level *acpu_freq_tbl_8064[NUM_PVS] __initdata = {
- [PVS_SLOW] = acpu_freq_tbl_8064_slow,
- [PVS_NOM] = acpu_freq_tbl_8064_nom,
- [PVS_FAST] = acpu_freq_tbl_8064_fast,
- [PVS_FASTER] = acpu_freq_tbl_8064_fast,
-};
-
-static struct acpu_level *acpu_freq_tbl_8930_pvs[NUM_PVS] __initdata = {
- [PVS_SLOW] = acpu_freq_tbl_8930_slow,
- [PVS_NOM] = acpu_freq_tbl_8930_nom,
- [PVS_FAST] = acpu_freq_tbl_8930_fast,
-};
-
-static struct acpu_level *max_acpu_level;
-
-static unsigned long acpuclk_8960_get_rate(int cpu)
-{
- return scalable[cpu].current_speed->khz;
-}
-
-/* Get the selected source on primary MUX. */
-static int get_pri_clk_src(struct scalable *sc)
-{
- uint32_t regval;
-
- regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
- return regval & 0x3;
-}
-
-/* Set the selected source on primary MUX. */
-static void set_pri_clk_src(struct scalable *sc, uint32_t pri_src_sel)
-{
- uint32_t regval;
-
- regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
- regval &= ~0x3;
- regval |= (pri_src_sel & 0x3);
- set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
- /* Wait for switch to complete. */
- mb();
- udelay(1);
-}
-
-/* Get the selected source on secondary MUX. */
-static int get_sec_clk_src(struct scalable *sc)
-{
- uint32_t regval;
-
- regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
- return (regval >> 2) & 0x3;
-}
-
-/* Set the selected source on secondary MUX. */
-static void set_sec_clk_src(struct scalable *sc, uint32_t sec_src_sel)
-{
- uint32_t regval;
-
- /* Disable secondary source clock gating during switch. */
- regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
- regval |= SECCLKAGD;
- set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
-
- /* Program the MUX. */
- regval &= ~(0x3 << 2);
- regval |= ((sec_src_sel & 0x3) << 2);
- set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
-
- /* Wait for switch to complete. */
- mb();
- udelay(1);
-
- /* Re-enable secondary source clock gating. */
- regval &= ~SECCLKAGD;
- set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
-}
-
-/* Enable an already-configured HFPLL. */
-static void hfpll_enable(struct scalable *sc, bool skip_regulators)
-{
- int rc;
-
- if (!skip_regulators) {
- if (cpu_is_msm8960()) {
- rc = rpm_vreg_set_voltage(
- sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
- 2050000,
- sc->vreg[VREG_HFPLL_A].max_vdd, 0);
- if (rc)
- pr_err("%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_A].name, rc);
- }
- rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_B].rpm_vreg_voter, 1800000,
- sc->vreg[VREG_HFPLL_B].max_vdd, 0);
- if (rc)
- pr_err("%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_B].name, rc);
- }
- /* Disable PLL bypass mode. */
- writel_relaxed(0x2, sc->hfpll_base + HFPLL_MODE);
-
- /*
- * H/W requires a 5us delay between disabling the bypass and
- * de-asserting the reset. Delay 10us just to be safe.
- */
- mb();
- udelay(10);
-
- /* De-assert active-low PLL reset. */
- writel_relaxed(0x6, sc->hfpll_base + HFPLL_MODE);
-
- /* Wait for PLL to lock. */
- mb();
- udelay(60);
-
- /* Enable PLL output. */
- writel_relaxed(0x7, sc->hfpll_base + HFPLL_MODE);
-}
-
-/* Disable a HFPLL for power-savings or while its being reprogrammed. */
-static void hfpll_disable(struct scalable *sc, bool skip_regulators)
-{
- int rc;
-
- /*
- * Disable the PLL output, disable test mode, enable
- * the bypass mode, and assert the reset.
- */
- writel_relaxed(0, sc->hfpll_base + HFPLL_MODE);
-
- if (!skip_regulators) {
- rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_B].rpm_vreg_voter, 0,
- 0, 0);
- if (rc)
- pr_err("%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_B].name, rc);
-
- if (cpu_is_msm8960()) {
- rc = rpm_vreg_set_voltage(
- sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
- 0, 0, 0);
- if (rc)
- pr_err("%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_A].name, rc);
- }
- }
-}
-
-/* Program the HFPLL rate. Assumes HFPLL is already disabled. */
-static void hfpll_set_rate(struct scalable *sc, struct core_speed *tgt_s)
-{
- writel_relaxed(tgt_s->pll_l_val, sc->hfpll_base + HFPLL_L_VAL);
-}
-
-/* Return the L2 speed that should be applied. */
-static struct l2_level *compute_l2_level(struct scalable *sc,
- struct l2_level *vote_l)
-{
- struct l2_level *new_l;
- int cpu;
-
- /* Bounds check. */
- BUG_ON(vote_l >= (l2_freq_tbl + l2_freq_tbl_size));
-
- /* Find max L2 speed vote. */
- sc->l2_vote = vote_l;
- new_l = l2_freq_tbl;
- for_each_present_cpu(cpu)
- new_l = max(new_l, scalable[cpu].l2_vote);
-
- return new_l;
-}
-
-/* Update the bus bandwidth request. */
-static void set_bus_bw(unsigned int bw)
-{
- int ret;
-
- /* Bounds check. */
- if (bw >= ARRAY_SIZE(bw_level_tbl)) {
- pr_err("invalid bandwidth request (%d)\n", bw);
- return;
- }
-
- /* Update bandwidth if request has changed. This may sleep. */
- ret = msm_bus_scale_client_update_request(bus_perf_client, bw);
- if (ret)
- pr_err("bandwidth request failed (%d)\n", ret);
-}
-
-/* Set the CPU or L2 clock speed. */
-static void set_speed(struct scalable *sc, struct core_speed *tgt_s,
- enum setrate_reason reason)
-{
- struct core_speed *strt_s = sc->current_speed;
-
- if (tgt_s == strt_s)
- return;
-
- if (strt_s->src == HFPLL && tgt_s->src == HFPLL) {
- /*
- * Move to an always-on source running at a frequency that does
- * not require an elevated CPU voltage. PLL8 is used here.
- */
- set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
- set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
-
- /* Program CPU HFPLL. */
- hfpll_disable(sc, 1);
- hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, 1);
-
- /* Move CPU to HFPLL source. */
- set_pri_clk_src(sc, tgt_s->pri_src_sel);
- } else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
- /*
- * If responding to CPU_DEAD we must be running on another CPU.
- * Therefore, we can't access the downed CPU's clock MUX CP15
- * registers from here and can't change clock sources. If the
- * CPU is collapsed, however, it is still safe to turn off the
- * PLL without switching the MUX away from it.
- */
- if (reason != SETRATE_HOTPLUG || sc == &scalable[L2]) {
- set_sec_clk_src(sc, tgt_s->sec_src_sel);
- set_pri_clk_src(sc, tgt_s->pri_src_sel);
- hfpll_disable(sc, 0);
- } else if (reason == SETRATE_HOTPLUG
- && msm_pm_verify_cpu_pc(SCALABLE_TO_CPU(sc))) {
- hfpll_disable(sc, 0);
- }
- } else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
- /*
- * If responding to CPU_UP_PREPARE, we can't change CP15
- * registers for the CPU that's coming up since we're not
- * running on that CPU. That's okay though, since the MUX
- * source was not changed on the way down, either.
- */
- if (reason != SETRATE_HOTPLUG || sc == &scalable[L2]) {
- hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, 0);
- set_pri_clk_src(sc, tgt_s->pri_src_sel);
- } else if (reason == SETRATE_HOTPLUG
- && msm_pm_verify_cpu_pc(SCALABLE_TO_CPU(sc))) {
- /* PLL was disabled during hot-unplug. Re-enable it. */
- hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, 0);
- }
- } else {
- if (reason != SETRATE_HOTPLUG || sc == &scalable[L2])
- set_sec_clk_src(sc, tgt_s->sec_src_sel);
- }
-
- sc->current_speed = tgt_s;
-}
-
-/* Apply any per-cpu voltage increases. */
-static int increase_vdd(int cpu, unsigned int vdd_core, unsigned int vdd_mem,
- unsigned int vdd_dig, enum setrate_reason reason)
-{
- struct scalable *sc = &scalable[cpu];
- int rc = 0;
-
- /*
- * Increase vdd_mem active-set before vdd_dig.
- * vdd_mem should be >= vdd_dig.
- */
- if (vdd_mem > sc->vreg[VREG_MEM].cur_vdd) {
- rc = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
- sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
- sc->vreg[VREG_MEM].max_vdd, 0);
- if (rc) {
- pr_err("%s increase failed (%d)\n",
- sc->vreg[VREG_MEM].name, rc);
- return rc;
- }
- sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
- }
-
- /* Increase vdd_dig active-set vote. */
- if (vdd_dig > sc->vreg[VREG_DIG].cur_vdd) {
- rc = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
- sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
- sc->vreg[VREG_DIG].max_vdd, 0);
- if (rc) {
- pr_err("%s increase failed (%d)\n",
- sc->vreg[VREG_DIG].name, rc);
- return rc;
- }
- sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
- }
-
- /*
- * Update per-CPU core voltage. Don't do this for the hotplug path for
- * which it should already be correct. Attempting to set it is bad
- * because we don't know what CPU we are running on at this point, but
- * the CPU regulator API requires we call it from the affected CPU.
- */
- if (vdd_core > sc->vreg[VREG_CORE].cur_vdd
- && reason != SETRATE_HOTPLUG) {
- rc = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
- sc->vreg[VREG_CORE].max_vdd);
- if (rc) {
- pr_err("%s increase failed (%d)\n",
- sc->vreg[VREG_CORE].name, rc);
- return rc;
- }
- sc->vreg[VREG_CORE].cur_vdd = vdd_core;
- }
-
- return rc;
-}
-
-/* Apply any per-cpu voltage decreases. */
-static void decrease_vdd(int cpu, unsigned int vdd_core, unsigned int vdd_mem,
- unsigned int vdd_dig, enum setrate_reason reason)
-{
- struct scalable *sc = &scalable[cpu];
- int ret;
-
- /*
- * Update per-CPU core voltage. This must be called on the CPU
- * that's being affected. Don't do this in the hotplug remove path,
- * where the rail is off and we're executing on the other CPU.
- */
- if (vdd_core < sc->vreg[VREG_CORE].cur_vdd
- && reason != SETRATE_HOTPLUG) {
- ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
- sc->vreg[VREG_CORE].max_vdd);
- if (ret) {
- pr_err("%s decrease failed (%d)\n",
- sc->vreg[VREG_CORE].name, ret);
- return;
- }
- sc->vreg[VREG_CORE].cur_vdd = vdd_core;
- }
-
- /* Decrease vdd_dig active-set vote. */
- if (vdd_dig < sc->vreg[VREG_DIG].cur_vdd) {
- ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
- sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
- sc->vreg[VREG_DIG].max_vdd, 0);
- if (ret) {
- pr_err("%s decrease failed (%d)\n",
- sc->vreg[VREG_DIG].name, ret);
- return;
- }
- sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
- }
-
- /*
- * Decrease vdd_mem active-set after vdd_dig.
- * vdd_mem should be >= vdd_dig.
- */
- if (vdd_mem < sc->vreg[VREG_MEM].cur_vdd) {
- ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
- sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
- sc->vreg[VREG_MEM].max_vdd, 0);
- if (ret) {
- pr_err("%s decrease failed (%d)\n",
- sc->vreg[VREG_MEM].name, ret);
- return;
- }
- sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
- }
-}
-
-static unsigned int calculate_vdd_mem(struct acpu_level *tgt)
-{
- return tgt->l2_level->vdd_mem;
-}
-
-static unsigned int calculate_vdd_dig(struct acpu_level *tgt)
-{
- unsigned int pll_vdd_dig;
-
- if (tgt->l2_level->speed.src != HFPLL)
- pll_vdd_dig = scalable[L2].hfpll_vdd_tbl[HFPLL_VDD_NONE];
- else if (tgt->l2_level->speed.pll_l_val > HFPLL_LOW_VDD_PLL_L_MAX)
- pll_vdd_dig = scalable[L2].hfpll_vdd_tbl[HFPLL_VDD_NOM];
- else
- pll_vdd_dig = scalable[L2].hfpll_vdd_tbl[HFPLL_VDD_LOW];
-
- return max(tgt->l2_level->vdd_dig, pll_vdd_dig);
-}
-
-static unsigned int calculate_vdd_core(struct acpu_level *tgt)
-{
- return tgt->vdd_core;
-}
-
-/* Set the CPU's clock rate and adjust the L2 rate, if appropriate. */
-static int acpuclk_8960_set_rate(int cpu, unsigned long rate,
- enum setrate_reason reason)
-{
- struct core_speed *strt_acpu_s, *tgt_acpu_s;
- struct l2_level *tgt_l2_l;
- struct acpu_level *tgt;
- unsigned int vdd_mem, vdd_dig, vdd_core;
- unsigned long flags;
- int rc = 0;
-
- if (cpu > num_possible_cpus())
- return -EINVAL;
-
- if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
- mutex_lock(&driver_lock);
-
- strt_acpu_s = scalable[cpu].current_speed;
-
- /* Return early if rate didn't change. */
- if (rate == strt_acpu_s->khz)
- goto out;
-
- /* Find target frequency. */
- for (tgt = acpu_freq_tbl; tgt->speed.khz != 0; tgt++) {
- if (tgt->speed.khz == rate) {
- tgt_acpu_s = &tgt->speed;
- break;
- }
- }
- if (tgt->speed.khz == 0) {
- rc = -EINVAL;
- goto out;
- }
-
- /* Calculate voltage requirements for the current CPU. */
- vdd_mem = calculate_vdd_mem(tgt);
- vdd_dig = calculate_vdd_dig(tgt);
- vdd_core = calculate_vdd_core(tgt);
-
- /* Increase VDD levels if needed. */
- if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG) {
- rc = increase_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
- if (rc)
- goto out;
- }
-
- pr_debug("Switching from ACPU%d rate %u KHz -> %u KHz\n",
- cpu, strt_acpu_s->khz, tgt_acpu_s->khz);
-
- /* Set the CPU speed. */
- set_speed(&scalable[cpu], tgt_acpu_s, reason);
-
- /*
- * Update the L2 vote and apply the rate change. A spinlock is
- * necessary to ensure L2 rate is calulated and set atomically,
- * even if acpuclk_8960_set_rate() is called from an atomic context
- * and the driver_lock mutex is not acquired.
- */
- spin_lock_irqsave(&l2_lock, flags);
- tgt_l2_l = compute_l2_level(&scalable[cpu], tgt->l2_level);
- set_speed(&scalable[L2], &tgt_l2_l->speed, reason);
- spin_unlock_irqrestore(&l2_lock, flags);
-
- /* Nothing else to do for power collapse or SWFI. */
- if (reason == SETRATE_PC || reason == SETRATE_SWFI)
- goto out;
-
- /* Update bus bandwith request. */
- set_bus_bw(tgt_l2_l->bw_level);
-
- /* Drop VDD levels if we can. */
- decrease_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
-
- pr_debug("ACPU%d speed change complete\n", cpu);
-
-out:
- if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
- mutex_unlock(&driver_lock);
- return rc;
-}
-
-/* Initialize a HFPLL at a given rate and enable it. */
-static void __cpuinit hfpll_init(struct scalable *sc, struct core_speed *tgt_s)
-{
- pr_debug("Initializing HFPLL%d\n", sc - scalable);
-
- /* Disable the PLL for re-programming. */
- hfpll_disable(sc, 1);
-
- /* Configure PLL parameters for integer mode. */
- writel_relaxed(0x7845C665, sc->hfpll_base + HFPLL_CONFIG_CTL);
- writel_relaxed(0, sc->hfpll_base + HFPLL_M_VAL);
- writel_relaxed(1, sc->hfpll_base + HFPLL_N_VAL);
-
- /* Program droop controller. */
- writel_relaxed(0x0108C000, sc->hfpll_base + HFPLL_DROOP_CTL);
-
- /* Set an initial rate and enable the PLL. */
- hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, 0);
-}
-
-/* Voltage regulator initialization. */
-static void __cpuinit regulator_init(int cpu, struct acpu_level *lvl)
-{
- int ret;
- struct scalable *sc = &scalable[cpu];
- unsigned int vdd_mem, vdd_dig, vdd_core;
-
- vdd_mem = calculate_vdd_mem(lvl);
- vdd_dig = calculate_vdd_dig(lvl);
-
- /* Set initial vdd_mem vote. */
- ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
- sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
- sc->vreg[VREG_MEM].max_vdd, 0);
- if (ret) {
- pr_err("%s initialization failed (%d)\n",
- sc->vreg[VREG_MEM].name, ret);
- BUG();
- }
- sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
-
- /* Set initial vdd_dig vote. */
- ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
- sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
- sc->vreg[VREG_DIG].max_vdd, 0);
- if (ret) {
- pr_err("%s initialization failed (%d)\n",
- sc->vreg[VREG_DIG].name, ret);
- BUG();
- }
- sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
-
- /* Setup Krait CPU regulators and initial core voltage. */
- sc->vreg[VREG_CORE].reg = regulator_get(NULL,
- sc->vreg[VREG_CORE].name);
- if (IS_ERR(sc->vreg[VREG_CORE].reg)) {
- pr_err("regulator_get(%s) failed (%ld)\n",
- sc->vreg[VREG_CORE].name,
- PTR_ERR(sc->vreg[VREG_CORE].reg));
- BUG();
- }
- vdd_core = calculate_vdd_core(lvl);
- ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
- sc->vreg[VREG_CORE].max_vdd);
- if (ret) {
- pr_err("%s initialization failed (%d)\n",
- sc->vreg[VREG_CORE].name, ret);
- BUG();
- }
- sc->vreg[VREG_CORE].cur_vdd = vdd_core;
- ret = regulator_enable(sc->vreg[VREG_CORE].reg);
- if (ret) {
- pr_err("regulator_enable(%s) failed (%d)\n",
- sc->vreg[VREG_CORE].name, ret);
- BUG();
- }
- sc->regulators_initialized = true;
-}
-
-/* Set initial rate for a given core. */
-static void __cpuinit init_clock_sources(struct scalable *sc,
- struct core_speed *tgt_s)
-{
- uint32_t regval;
-
- /* Select PLL8 as AUX source input to the secondary MUX. */
- writel_relaxed(0x3, sc->aux_clk_sel);
-
- /* Switch away from the HFPLL while it's re-initialized. */
- set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
- set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
- hfpll_init(sc, tgt_s);
-
- /* Set PRI_SRC_SEL_HFPLL_DIV2 divider to div-2. */
- regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
- regval &= ~(0x3 << 6);
- set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
-
- /* Switch to the target clock source. */
- set_sec_clk_src(sc, tgt_s->sec_src_sel);
- set_pri_clk_src(sc, tgt_s->pri_src_sel);
- sc->current_speed = tgt_s;
-}
-
-static void __cpuinit per_cpu_init(void *data)
-{
- int cpu = smp_processor_id();
-
- init_clock_sources(&scalable[cpu], &max_acpu_level->speed);
- scalable[cpu].l2_vote = max_acpu_level->l2_level;
- scalable[cpu].clocks_initialized = true;
-}
-
-/* Register with bus driver. */
-static void __init bus_init(unsigned int init_bw)
-{
- int ret;
-
- bus_perf_client = msm_bus_scale_register_client(&bus_client_pdata);
- if (!bus_perf_client) {
- pr_err("unable to register bus client\n");
- BUG();
- }
-
- ret = msm_bus_scale_client_update_request(bus_perf_client, init_bw);
- if (ret)
- pr_err("initial bandwidth request failed (%d)\n", ret);
-}
-
-#ifdef CONFIG_CPU_FREQ_MSM
-static struct cpufreq_frequency_table freq_table[NR_CPUS][30];
-
-static void __init cpufreq_table_init(void)
-{
- int cpu;
-
- for_each_possible_cpu(cpu) {
- int i, freq_cnt = 0;
- /* Construct the freq_table tables from acpu_freq_tbl. */
- for (i = 0; acpu_freq_tbl[i].speed.khz != 0
- && freq_cnt < ARRAY_SIZE(*freq_table); i++) {
- if (acpu_freq_tbl[i].use_for_scaling) {
- freq_table[cpu][freq_cnt].index = freq_cnt;
- freq_table[cpu][freq_cnt].frequency
- = acpu_freq_tbl[i].speed.khz;
- freq_cnt++;
- }
- }
- /* freq_table not big enough to store all usable freqs. */
- BUG_ON(acpu_freq_tbl[i].speed.khz != 0);
-
- freq_table[cpu][freq_cnt].index = freq_cnt;
- freq_table[cpu][freq_cnt].frequency = CPUFREQ_TABLE_END;
-
- pr_info("CPU%d: %d scaling frequencies supported.\n",
- cpu, freq_cnt);
-
- /* Register table with CPUFreq. */
- cpufreq_frequency_table_get_attr(freq_table[cpu], cpu);
- }
-}
-#else
-static void __init cpufreq_table_init(void) {}
-#endif
-
-#define HOT_UNPLUG_KHZ STBY_KHZ
-static int __cpuinit acpuclock_cpu_callback(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
-{
- static int prev_khz[NR_CPUS];
- static int prev_pri_src[NR_CPUS];
- static int prev_sec_src[NR_CPUS];
- int cpu = (int)hcpu;
-
- switch (action) {
- case CPU_DYING:
- case CPU_DYING_FROZEN:
- /*
- * On Krait v1 and 8064v1, the primary and secondary muxes must
- * be set to QSB before L2 power collapse and restored after.
- */
- if (cpu_is_krait_v1() || cpu_is_apq8064()) {
- prev_sec_src[cpu] = get_sec_clk_src(&scalable[cpu]);
- prev_pri_src[cpu] = get_pri_clk_src(&scalable[cpu]);
- set_sec_clk_src(&scalable[cpu], SEC_SRC_SEL_QSB);
- set_pri_clk_src(&scalable[cpu], PRI_SRC_SEL_SEC_SRC);
- }
- break;
- case CPU_DEAD:
- case CPU_DEAD_FROZEN:
- prev_khz[cpu] = acpuclk_8960_get_rate(cpu);
- /* Fall through. */
- case CPU_UP_CANCELED:
- case CPU_UP_CANCELED_FROZEN:
- if (scalable[cpu].clocks_initialized)
- acpuclk_8960_set_rate(cpu, HOT_UNPLUG_KHZ,
- SETRATE_HOTPLUG);
- break;
- case CPU_UP_PREPARE:
- case CPU_UP_PREPARE_FROZEN:
- if (scalable[cpu].clocks_initialized)
- acpuclk_8960_set_rate(cpu, prev_khz[cpu],
- SETRATE_HOTPLUG);
- if (!scalable[cpu].regulators_initialized)
- regulator_init(cpu, max_acpu_level);
- break;
- case CPU_STARTING:
- case CPU_STARTING_FROZEN:
- if (!scalable[cpu].clocks_initialized) {
- per_cpu_init(NULL);
- } else if (cpu_is_krait_v1() || cpu_is_apq8064()) {
- set_sec_clk_src(&scalable[cpu], prev_sec_src[cpu]);
- set_pri_clk_src(&scalable[cpu], prev_pri_src[cpu]);
- }
- break;
- default:
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata acpuclock_cpu_notifier = {
- .notifier_call = acpuclock_cpu_callback,
-};
-
-static const int krait_needs_vmin(void)
-{
- switch (read_cpuid_id()) {
- case 0x511F04D0:
- case 0x511F04D1:
- case 0x510F06F0:
- return 1;
- default:
- return 0;
- };
-}
-
-static void kraitv2_apply_vmin(struct acpu_level *tbl)
-{
- for (; tbl->speed.khz != 0; tbl++)
- if (tbl->vdd_core < 1150000)
- tbl->vdd_core = 1150000;
-}
-
-static enum pvs __init get_pvs(void)
-{
- uint32_t pte_efuse, pvs;
-
- pte_efuse = readl_relaxed(QFPROM_PTE_EFUSE_ADDR);
- pvs = (pte_efuse >> 10) & 0x7;
- if (pvs == 0x7)
- pvs = (pte_efuse >> 13) & 0x7;
-
- switch (pvs) {
- case 0x0:
- case 0x7:
- pr_info("ACPU PVS: Slow\n");
- return PVS_SLOW;
- case 0x1:
- pr_info("ACPU PVS: Nominal\n");
- return PVS_NOM;
- case 0x3:
- pr_info("ACPU PVS: Fast\n");
- return PVS_FAST;
- case 0x4:
- if (cpu_is_apq8064()) {
- pr_info("ACPU PVS: Faster\n");
- return PVS_FASTER;
- }
- default:
- pr_warn("ACPU PVS: Unknown. Defaulting to slow\n");
- return PVS_SLOW;
- }
-}
-
-static void __init select_freq_plan(void)
-{
- struct acpu_level *l;
-
- /* Select frequency tables. */
- if (cpu_is_msm8960()) {
- enum pvs pvs_id = get_pvs();
-
- scalable = scalable_8960;
- if (cpu_is_krait_v1()) {
- acpu_freq_tbl = acpu_freq_tbl_8960_v1[pvs_id];
- l2_freq_tbl = l2_freq_tbl_8960_kraitv1;
- l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv1);
- } else {
- acpu_freq_tbl = acpu_freq_tbl_8960_v2[pvs_id];
- l2_freq_tbl = l2_freq_tbl_8960_kraitv2;
- l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv2);
- }
- } else if (cpu_is_apq8064()) {
- enum pvs pvs_id = get_pvs();
-
- scalable = scalable_8064;
- acpu_freq_tbl = acpu_freq_tbl_8064[pvs_id];
- l2_freq_tbl = l2_freq_tbl_8064;
- l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8064);
- } else if (cpu_is_msm8627()) {
- scalable = scalable_8627;
- acpu_freq_tbl = acpu_freq_tbl_8627;
- l2_freq_tbl = l2_freq_tbl_8627;
- l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8627);
- } else if (cpu_is_msm8930() || cpu_is_msm8930aa()) {
- enum pvs pvs_id = get_pvs();
-
- scalable = scalable_8930;
- acpu_freq_tbl = acpu_freq_tbl_8930_pvs[pvs_id];
- l2_freq_tbl = l2_freq_tbl_8930;
- l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8930);
- } else {
- BUG();
- }
- BUG_ON(!acpu_freq_tbl);
- if (krait_needs_vmin())
- kraitv2_apply_vmin(acpu_freq_tbl);
-
- /* Find the max supported scaling frequency. */
- for (l = acpu_freq_tbl; l->speed.khz != 0; l++)
- if (l->use_for_scaling)
- max_acpu_level = l;
- BUG_ON(!max_acpu_level);
- pr_info("Max ACPU freq: %u KHz\n", max_acpu_level->speed.khz);
-}
-
-static struct acpuclk_data acpuclk_8960_data = {
- .set_rate = acpuclk_8960_set_rate,
- .get_rate = acpuclk_8960_get_rate,
- .power_collapse_khz = STBY_KHZ,
- .wait_for_irq_khz = STBY_KHZ,
+static struct acpuclk_krait_params acpuclk_8960_params __initdata = {
+ .scalable = scalable,
+ .scalable_size = sizeof(scalable),
+ .hfpll_data = &hfpll_data,
+ .pvs_tables = pvs_tables,
+ .l2_freq_tbl = l2_freq_tbl,
+ .l2_freq_tbl_size = sizeof(l2_freq_tbl),
+ .bus_scale = &bus_scale_data,
+ .qfprom_phys_base = 0x00700000,
};
static int __init acpuclk_8960_probe(struct platform_device *pdev)
{
- int cpu;
-
- select_freq_plan();
-
- for_each_online_cpu(cpu)
- regulator_init(cpu, max_acpu_level);
- bus_init(max_acpu_level->l2_level->bw_level);
-
- init_clock_sources(&scalable[L2], &max_acpu_level->l2_level->speed);
- on_each_cpu(per_cpu_init, NULL, true);
-
- cpufreq_table_init();
-
- acpuclk_register(&acpuclk_8960_data);
- register_hotcpu_notifier(&acpuclock_cpu_notifier);
-
- return 0;
+ return acpuclk_krait_init(&pdev->dev, &acpuclk_8960_params);
}
static struct platform_driver acpuclk_8960_driver = {
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index c67109e..9ed038b 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -28,21 +28,7 @@
#define LVL_NOM RPM_REGULATOR_CORNER_NORMAL
#define LVL_HIGH RPM_REGULATOR_CORNER_SUPER_TURBO
-static struct hfpll_data hfpll_data_cpu = {
- .mode_offset = 0x00,
- .l_offset = 0x04,
- .m_offset = 0x08,
- .n_offset = 0x0C,
- .config_offset = 0x14,
- /* TODO: Verify magic number for 8974 when available. */
- .config_val = 0x7845C665,
- .low_vdd_l_max = 52,
- .vdd[HFPLL_VDD_NONE] = 0,
- .vdd[HFPLL_VDD_LOW] = 810000,
- .vdd[HFPLL_VDD_NOM] = 900000,
-};
-
-static struct hfpll_data hfpll_data_l2 = {
+static struct hfpll_data hfpll_data __initdata = {
.mode_offset = 0x00,
.l_offset = 0x04,
.m_offset = 0x08,
@@ -56,10 +42,9 @@
.vdd[HFPLL_VDD_NOM] = LVL_NOM,
};
-static struct scalable scalable[] = {
+static struct scalable scalable[] __initdata = {
[CPU0] = {
.hfpll_phys_base = 0xF908A000,
- .hfpll_data = &hfpll_data_cpu,
.l2cpmr_iaddr = 0x4501,
.vreg[VREG_CORE] = { "krait0", 1050000, 3200000 },
.vreg[VREG_MEM] = { "krait0_mem", 1050000 },
@@ -69,7 +54,6 @@
},
[CPU1] = {
.hfpll_phys_base = 0xF909A000,
- .hfpll_data = &hfpll_data_cpu,
.l2cpmr_iaddr = 0x5501,
.vreg[VREG_CORE] = { "krait1", 1050000, 3200000 },
.vreg[VREG_MEM] = { "krait1_mem", 1050000 },
@@ -79,7 +63,6 @@
},
[CPU2] = {
.hfpll_phys_base = 0xF90AA000,
- .hfpll_data = &hfpll_data_cpu,
.l2cpmr_iaddr = 0x6501,
.vreg[VREG_CORE] = { "krait2", 1050000, 3200000 },
.vreg[VREG_MEM] = { "krait2_mem", 1050000 },
@@ -89,7 +72,6 @@
},
[CPU3] = {
.hfpll_phys_base = 0xF90BA000,
- .hfpll_data = &hfpll_data_cpu,
.l2cpmr_iaddr = 0x7501,
.vreg[VREG_CORE] = { "krait3", 1050000, 3200000 },
.vreg[VREG_MEM] = { "krait3_mem", 1050000 },
@@ -99,14 +81,13 @@
},
[L2] = {
.hfpll_phys_base = 0xF9016000,
- .hfpll_data = &hfpll_data_l2,
.l2cpmr_iaddr = 0x0500,
.vreg[VREG_HFPLL_A] = { "l2_hfpll_a", 2150000 },
.vreg[VREG_HFPLL_B] = { "l2_hfpll_b", 1800000 },
},
};
-static struct msm_bus_paths bw_level_tbl[] = {
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
[0] = BW_MBPS(400), /* At least 50 MHz on bus. */
[1] = BW_MBPS(800), /* At least 100 MHz on bus. */
[2] = BW_MBPS(1334), /* At least 167 MHz on bus. */
@@ -114,17 +95,16 @@
[4] = BW_MBPS(3200), /* At least 333 MHz on bus. */
};
-static struct msm_bus_scale_pdata bus_scale_data = {
+static struct msm_bus_scale_pdata bus_scale_data __initdata = {
.usecase = bw_level_tbl,
.num_usecases = ARRAY_SIZE(bw_level_tbl),
.active_only = 1,
.name = "acpuclk-8974",
};
-#define L2(x) (&l2_freq_tbl[(x)])
-static struct l2_level l2_freq_tbl[] = {
- [0] = { {STBY_KHZ, QSB, 0, 0, 0 }, LVL_NOM, 1050000, 0 },
- [1] = { { 300000, PLL_0, 0, 2, 0 }, LVL_NOM, 1050000, 2 },
+static struct l2_level l2_freq_tbl[] __initdata = {
+ [0] = { {STBY_KHZ, QSB, 0, 0, 0 }, LVL_LOW, 1050000, 0 },
+ [1] = { { 300000, PLL_0, 0, 2, 0 }, LVL_LOW, 1050000, 2 },
[2] = { { 384000, HFPLL, 2, 0, 40 }, LVL_NOM, 1050000, 2 },
[3] = { { 460800, HFPLL, 2, 0, 48 }, LVL_NOM, 1050000, 2 },
[4] = { { 537600, HFPLL, 1, 0, 28 }, LVL_NOM, 1050000, 2 },
@@ -137,7 +117,7 @@
[11] = { { 1036800, HFPLL, 1, 0, 54 }, LVL_NOM, 1050000, 4 },
};
-static struct acpu_level acpu_freq_tbl[] = {
+static struct acpu_level acpu_freq_tbl[] __initdata = {
{ 0, {STBY_KHZ, QSB, 0, 0, 0 }, L2(0), 1050000 },
{ 1, { 300000, PLL_0, 0, 2, 0 }, L2(1), 1050000 },
{ 1, { 384000, HFPLL, 2, 0, 40 }, L2(2), 1050000 },
@@ -153,14 +133,20 @@
{ 0, { 0 } }
};
-static struct acpuclk_krait_params acpuclk_8974_params = {
+static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
+ [PVS_SLOW] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+ [PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+ [PVS_FAST] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+};
+
+static struct acpuclk_krait_params acpuclk_8974_params __initdata = {
.scalable = scalable,
- .pvs_acpu_freq_tbl[PVS_SLOW] = acpu_freq_tbl,
- .pvs_acpu_freq_tbl[PVS_NOMINAL] = acpu_freq_tbl,
- .pvs_acpu_freq_tbl[PVS_FAST] = acpu_freq_tbl,
+ .scalable_size = sizeof(scalable),
+ .hfpll_data = &hfpll_data,
+ .pvs_tables = pvs_tables,
.l2_freq_tbl = l2_freq_tbl,
- .l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl),
- .bus_scale_data = &bus_scale_data,
+ .l2_freq_tbl_size = sizeof(l2_freq_tbl),
+ .bus_scale = &bus_scale_data,
.qfprom_phys_base = 0xFC4A8000,
};
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index 8bd54e3..fd43f57 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -57,7 +57,9 @@
const struct acpu_level *max_acpu_lvl;
const struct l2_level *l2_freq_tbl;
struct scalable *scalable;
+ struct hfpll_data *hfpll_data;
u32 bus_perf_client;
+ struct msm_bus_scale_pdata *bus_scale;
struct device *dev;
} drv;
@@ -130,7 +132,7 @@
}
/* Disable PLL bypass mode. */
- writel_relaxed(0x2, sc->hfpll_base + sc->hfpll_data->mode_offset);
+ writel_relaxed(0x2, sc->hfpll_base + drv.hfpll_data->mode_offset);
/*
* H/W requires a 5us delay between disabling the bypass and
@@ -140,14 +142,14 @@
udelay(10);
/* De-assert active-low PLL reset. */
- writel_relaxed(0x6, sc->hfpll_base + sc->hfpll_data->mode_offset);
+ writel_relaxed(0x6, sc->hfpll_base + drv.hfpll_data->mode_offset);
/* Wait for PLL to lock. */
mb();
udelay(60);
/* Enable PLL output. */
- writel_relaxed(0x7, sc->hfpll_base + sc->hfpll_data->mode_offset);
+ writel_relaxed(0x7, sc->hfpll_base + drv.hfpll_data->mode_offset);
}
/* Disable a HFPLL for power-savings or while it's being reprogrammed. */
@@ -157,7 +159,7 @@
* Disable the PLL output, disable test mode, enable the bypass mode,
* and assert the reset.
*/
- writel_relaxed(0, sc->hfpll_base + sc->hfpll_data->mode_offset);
+ writel_relaxed(0, sc->hfpll_base + drv.hfpll_data->mode_offset);
if (!skip_regulators) {
/* Remove voltage votes required by the HFPLL. */
@@ -170,19 +172,17 @@
static void hfpll_set_rate(struct scalable *sc, const struct core_speed *tgt_s)
{
writel_relaxed(tgt_s->pll_l_val,
- sc->hfpll_base + sc->hfpll_data->l_offset);
+ sc->hfpll_base + drv.hfpll_data->l_offset);
}
/* Return the L2 speed that should be applied. */
-static const struct l2_level *compute_l2_level(struct scalable *sc,
- const struct l2_level *vote_l)
+static unsigned int compute_l2_level(struct scalable *sc, unsigned int vote_l)
{
- const struct l2_level *new_l;
+ unsigned int new_l = 0;
int cpu;
/* Find max L2 speed vote. */
sc->l2_vote = vote_l;
- new_l = drv.l2_freq_tbl;
for_each_present_cpu(cpu)
new_l = max(new_l, drv.scalable[cpu].l2_vote);
@@ -350,23 +350,23 @@
static int calculate_vdd_mem(const struct acpu_level *tgt)
{
- return tgt->l2_level->vdd_mem;
+ return drv.l2_freq_tbl[tgt->l2_level].vdd_mem;
}
static int calculate_vdd_dig(const struct acpu_level *tgt)
{
int pll_vdd_dig;
- const int *hfpll_vdd = drv.scalable[L2].hfpll_data->vdd;
- const u32 low_vdd_l_max = drv.scalable[L2].hfpll_data->low_vdd_l_max;
+ const int *hfpll_vdd = drv.hfpll_data->vdd;
+ const u32 low_vdd_l_max = drv.hfpll_data->low_vdd_l_max;
- if (tgt->l2_level->speed.src != HFPLL)
+ if (drv.l2_freq_tbl[tgt->l2_level].speed.src != HFPLL)
pll_vdd_dig = hfpll_vdd[HFPLL_VDD_NONE];
- else if (tgt->l2_level->speed.pll_l_val > low_vdd_l_max)
+ else if (drv.l2_freq_tbl[tgt->l2_level].speed.pll_l_val > low_vdd_l_max)
pll_vdd_dig = hfpll_vdd[HFPLL_VDD_NOM];
else
pll_vdd_dig = hfpll_vdd[HFPLL_VDD_LOW];
- return max(tgt->l2_level->vdd_dig, pll_vdd_dig);
+ return max(drv.l2_freq_tbl[tgt->l2_level].vdd_dig, pll_vdd_dig);
}
static int calculate_vdd_core(const struct acpu_level *tgt)
@@ -379,8 +379,8 @@
enum setrate_reason reason)
{
const struct core_speed *strt_acpu_s, *tgt_acpu_s;
- const struct l2_level *tgt_l2_l;
const struct acpu_level *tgt;
+ int tgt_l2_l;
int vdd_mem, vdd_dig, vdd_core;
unsigned long flags;
int rc = 0;
@@ -436,7 +436,7 @@
*/
spin_lock_irqsave(&l2_lock, flags);
tgt_l2_l = compute_l2_level(&drv.scalable[cpu], tgt->l2_level);
- set_speed(&drv.scalable[L2], &tgt_l2_l->speed);
+ set_speed(&drv.scalable[L2], &drv.l2_freq_tbl[tgt_l2_l].speed);
spin_unlock_irqrestore(&l2_lock, flags);
/* Nothing else to do for power collapse or SWFI. */
@@ -444,7 +444,7 @@
goto out;
/* Update bus bandwith request. */
- set_bus_bw(tgt_l2_l->bw_level);
+ set_bus_bw(drv.l2_freq_tbl[tgt_l2_l].bw_level);
/* Drop VDD levels if we can. */
decrease_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
@@ -467,15 +467,15 @@
hfpll_disable(sc, true);
/* Configure PLL parameters for integer mode. */
- writel_relaxed(sc->hfpll_data->config_val,
- sc->hfpll_base + sc->hfpll_data->config_offset);
- writel_relaxed(0, sc->hfpll_base + sc->hfpll_data->m_offset);
- writel_relaxed(1, sc->hfpll_base + sc->hfpll_data->n_offset);
+ writel_relaxed(drv.hfpll_data->config_val,
+ sc->hfpll_base + drv.hfpll_data->config_offset);
+ writel_relaxed(0, sc->hfpll_base + drv.hfpll_data->m_offset);
+ writel_relaxed(1, sc->hfpll_base + drv.hfpll_data->n_offset);
/* Program droop controller, if supported */
- if (sc->hfpll_data->has_droop_ctl)
- writel_relaxed(sc->hfpll_data->droop_val,
- sc->hfpll_base + sc->hfpll_data->droop_offset);
+ if (drv.hfpll_data->has_droop_ctl)
+ writel_relaxed(drv.hfpll_data->droop_val,
+ sc->hfpll_base + drv.hfpll_data->droop_offset);
/* Set an initial rate and enable the PLL. */
hfpll_set_rate(sc, tgt_s);
@@ -679,18 +679,18 @@
}
/* Register with bus driver. */
-static void __init bus_init(struct msm_bus_scale_pdata *bus_scale_data)
+static void __init bus_init(void)
{
int ret;
- drv.bus_perf_client = msm_bus_scale_register_client(bus_scale_data);
+ drv.bus_perf_client = msm_bus_scale_register_client(drv.bus_scale);
if (!drv.bus_perf_client) {
dev_err(drv.dev, "unable to register bus client\n");
BUG();
}
ret = msm_bus_scale_client_update_request(drv.bus_perf_client,
- drv.max_acpu_lvl->l2_level->bw_level);
+ drv.l2_freq_tbl[drv.max_acpu_lvl->l2_level].bw_level);
if (ret)
dev_err(drv.dev, "initial bandwidth req failed (%d)\n", ret);
}
@@ -792,13 +792,11 @@
tbl->vdd_core = 1150000;
}
-static void __init select_freq_plan(struct acpu_level *const *pvs_tbl,
- u32 qfprom_phys)
+static int __init select_freq_plan(u32 qfprom_phys)
{
- const struct acpu_level *l;
void __iomem *qfprom_base;
u32 pte_efuse, pvs, tbl_idx;
- char *pvs_names[] = { "Slow", "Nominal", "Fast", "Unknown" };
+ char *pvs_names[] = { "Slow", "Nominal", "Fast", "Faster", "Unknown" };
qfprom_base = ioremap(qfprom_phys, SZ_256);
/* Select frequency tables. */
@@ -820,6 +818,9 @@
case 0x3:
tbl_idx = PVS_FAST;
break;
+ case 0x4:
+ tbl_idx = PVS_FASTER;
+ break;
default:
tbl_idx = PVS_UNKNOWN;
break;
@@ -828,24 +829,29 @@
tbl_idx = PVS_UNKNOWN;
dev_err(drv.dev, "Unable to map QFPROM base\n");
}
- dev_info(drv.dev, "ACPU PVS: %s\n", pvs_names[tbl_idx]);
if (tbl_idx == PVS_UNKNOWN) {
tbl_idx = PVS_SLOW;
dev_warn(drv.dev, "ACPU PVS: Defaulting to %s\n",
pvs_names[tbl_idx]);
+ } else {
+ dev_info(drv.dev, "ACPU PVS: %s\n", pvs_names[tbl_idx]);
}
- drv.acpu_freq_tbl = pvs_tbl[tbl_idx];
- if (krait_needs_vmin())
- krait_apply_vmin(drv.acpu_freq_tbl);
+ return tbl_idx;
+}
- /* Find the max supported scaling frequency. */
- for (l = drv.acpu_freq_tbl; l->speed.khz != 0; l++)
+static const struct acpu_level __init *find_max_acpu_lvl(struct acpu_level *tbl)
+{
+ struct acpu_level *l, *max_lvl = NULL;
+
+ for (l = tbl; l->speed.khz != 0; l++)
if (l->use_for_scaling)
- drv.max_acpu_lvl = l;
- BUG_ON(!drv.max_acpu_lvl);
- dev_info(drv.dev, "Max ACPU freq: %lu KHz\n",
- drv.max_acpu_lvl->speed.khz);
+ max_lvl = l;
+
+ BUG_ON(!max_lvl);
+ dev_info(drv.dev, "Max CPU freq: %lu KHz\n", max_lvl->speed.khz);
+
+ return max_lvl;
}
static struct acpuclk_data acpuclk_krait_data = {
@@ -855,20 +861,51 @@
.wait_for_irq_khz = STBY_KHZ,
};
-int __init acpuclk_krait_init(struct device *dev,
- const struct acpuclk_krait_params *params)
+static void __init drv_data_init(struct device *dev,
+ const struct acpuclk_krait_params *params)
{
- struct scalable *l2;
+ int tbl_idx;
+
+ drv.dev = dev;
+ drv.scalable = kmemdup(params->scalable, params->scalable_size,
+ GFP_KERNEL);
+ BUG_ON(!drv.scalable);
+
+ drv.hfpll_data = kmemdup(params->hfpll_data, sizeof(*drv.hfpll_data),
+ GFP_KERNEL);
+ BUG_ON(!drv.hfpll_data);
+
+ drv.l2_freq_tbl = kmemdup(params->l2_freq_tbl, params->l2_freq_tbl_size,
+ GFP_KERNEL);
+ BUG_ON(!drv.l2_freq_tbl);
+
+ drv.bus_scale = kmemdup(params->bus_scale, sizeof(*drv.bus_scale),
+ GFP_KERNEL);
+ BUG_ON(!drv.bus_scale);
+ drv.bus_scale->usecase = kmemdup(drv.bus_scale->usecase,
+ drv.bus_scale->num_usecases * sizeof(*drv.bus_scale->usecase),
+ GFP_KERNEL);
+ BUG_ON(!drv.bus_scale->usecase);
+
+ tbl_idx = select_freq_plan(params->qfprom_phys_base);
+ drv.acpu_freq_tbl = kmemdup(params->pvs_tables[tbl_idx].table,
+ params->pvs_tables[tbl_idx].size,
+ GFP_KERNEL);
+ BUG_ON(!drv.acpu_freq_tbl);
+
+ drv.max_acpu_lvl = find_max_acpu_lvl(drv.acpu_freq_tbl);
+}
+
+static void __init hw_init(void)
+{
+ struct scalable *l2 = &drv.scalable[L2];
int cpu, rc;
- drv.scalable = params->scalable;
- drv.l2_freq_tbl = params->l2_freq_tbl;
- drv.dev = dev;
+ if (krait_needs_vmin())
+ krait_apply_vmin(drv.acpu_freq_tbl);
- select_freq_plan(params->pvs_acpu_freq_tbl, params->qfprom_phys_base);
- bus_init(params->bus_scale_data);
+ bus_init();
- l2 = &drv.scalable[L2];
l2->hfpll_base = ioremap(l2->hfpll_phys_base, SZ_32);
BUG_ON(!l2->hfpll_base);
@@ -878,17 +915,23 @@
rc = rpm_regulator_init(l2, VREG_HFPLL_B,
l2->vreg[VREG_HFPLL_B].max_vdd, false);
BUG_ON(rc);
-
- rc = init_clock_sources(l2, &drv.max_acpu_lvl->l2_level->speed);
+ rc = init_clock_sources(l2,
+ &drv.l2_freq_tbl[drv.max_acpu_lvl->l2_level].speed);
BUG_ON(rc);
for_each_online_cpu(cpu) {
rc = per_cpu_init(cpu);
BUG_ON(rc);
}
+}
+
+int __init acpuclk_krait_init(struct device *dev,
+ const struct acpuclk_krait_params *params)
+{
+ drv_data_init(dev, params);
+ hw_init();
cpufreq_table_init();
-
acpuclk_register(&acpuclk_krait_data);
register_hotcpu_notifier(&acpuclk_cpu_notifier);
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index f121548..f92aaf3 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -15,7 +15,7 @@
#define __ARCH_ARM_MACH_MSM_ACPUCLOCK_KRAIT_H
#define STBY_KHZ 1
-
+#define L2(x) (x)
#define BW_MBPS(_bw) \
{ \
.vectors = (struct msm_bus_vectors[]){ \
@@ -50,6 +50,7 @@
PVS_SLOW = 0,
PVS_NOMINAL,
PVS_FAST,
+ PVS_FASTER,
PVS_UNKNOWN,
NUM_PVS
};
@@ -146,7 +147,7 @@
struct acpu_level {
const int use_for_scaling;
const struct core_speed speed;
- const struct l2_level *l2_level;
+ const unsigned int l2_level;
int vdd_core;
};
@@ -162,7 +163,7 @@
* @droop_offset: Droop controller register offset from base address.
* @droop_val: Value to initialize the @config_offset register to.
* @low_vdd_l_max: Maximum "L" value supported at HFPLL_VDD_LOW.
- * @vdd: voltage requirements for each VDD level.
+ * @vdd: voltage requirements for each VDD level for the L2 PLL.
*/
struct hfpll_data {
const u32 mode_offset;
@@ -185,7 +186,6 @@
* @aux_clk_sel_phys: Physical address of auxiliary MUX.
* @aux_clk_sel: Auxiliary mux input to select at boot.
* @l2cpmr_iaddr: Indirect address of the CPMR MUX/divider CP15 register.
- * @hfpll_data: Descriptive data of HFPLL hardware.
* @cur_speed: Pointer to currently-set speed.
* @l2_vote: L2 performance level vote associate with the current CPU speed.
* @vreg: Array of voltage regulators needed by the scalable.
@@ -197,29 +197,42 @@
const phys_addr_t aux_clk_sel_phys;
const u32 aux_clk_sel;
const u32 l2cpmr_iaddr;
- const struct hfpll_data *hfpll_data;
const struct core_speed *cur_speed;
- const struct l2_level *l2_vote;
+ unsigned int l2_vote;
struct vreg vreg[NUM_VREG];
bool initialized;
};
/**
+ * struct pvs_table - CPU performance level table and size.
+ * @table: CPU performance level table
+ * @size: sizeof(@table)
+ */
+struct pvs_table {
+ struct acpu_level *table;
+ size_t size;
+};
+
+/**
* struct acpuclk_krait_params - SoC specific driver parameters.
* @scalable: Array of scalables.
- * @pvs_acpu_freq_tbl: Array of CPU frequency tables.
+ * @scalable_size: Size of @scalable.
+ * @hfpll_data: HFPLL configuration data.
+ * @pvs_tables: CPU frequency tables.
* @l2_freq_tbl: L2 frequency table.
- * @l2_freq_tbl_size: Number of rows in @l2_freq_tbl.
+ * @l2_freq_tbl_size: Size of @l2_freq_tbl.
* @qfprom_phys_base: Physical base address of QFPROM.
- * @bus_scale_data: MSM bus driver parameters.
+ * @bus_scale: MSM bus driver parameters.
*/
struct acpuclk_krait_params {
struct scalable *scalable;
- struct acpu_level *pvs_acpu_freq_tbl[NUM_PVS];
- const struct l2_level *l2_freq_tbl;
- const size_t l2_freq_tbl_size;
- const phys_addr_t qfprom_phys_base;
- struct msm_bus_scale_pdata *bus_scale_data;
+ size_t scalable_size;
+ struct hfpll_data *hfpll_data;
+ struct pvs_table *pvs_tables;
+ struct l2_level *l2_freq_tbl;
+ size_t l2_freq_tbl_size;
+ phys_addr_t qfprom_phys_base;
+ struct msm_bus_scale_pdata *bus_scale;
};
/**
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index a44ba7a..5aea0ed 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -434,30 +434,26 @@
mutex_lock(&bam_rx_pool_mutexlock);
list_add_tail(&info->list_node, &bam_rx_pool);
rx_len_cached = ++bam_rx_pool_len;
- mutex_unlock(&bam_rx_pool_mutexlock);
-
ret = sps_transfer_one(bam_rx_pipe, info->dma_address,
BUFFER_SIZE, info,
SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT);
-
if (ret) {
+ list_del(&info->list_node);
+ rx_len_cached = --bam_rx_pool_len;
+ mutex_unlock(&bam_rx_pool_mutexlock);
DMUX_LOG_KERR("%s: sps_transfer_one failed %d\n",
__func__, ret);
- goto fail_transfer;
+
+ dma_unmap_single(NULL, info->dma_address, BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+
+ goto fail_skb;
}
+ mutex_unlock(&bam_rx_pool_mutexlock);
+
}
return;
-fail_transfer:
- mutex_lock(&bam_rx_pool_mutexlock);
- list_del(&info->list_node);
- --bam_rx_pool_len;
- rx_len_cached = bam_rx_pool_len;
- mutex_unlock(&bam_rx_pool_mutexlock);
-
- dma_unmap_single(NULL, info->dma_address, BUFFER_SIZE,
- DMA_FROM_DEVICE);
-
fail_skb:
dev_kfree_skb_any(info->skb);
@@ -1078,18 +1074,29 @@
mutex_lock(&bam_rx_pool_mutexlock);
if (unlikely(list_empty(&bam_rx_pool))) {
+ DMUX_LOG_KERR("%s: have iovec %p but rx pool empty\n",
+ __func__, (void *)iov.addr);
mutex_unlock(&bam_rx_pool_mutexlock);
continue;
}
info = list_first_entry(&bam_rx_pool, struct rx_pkt_info,
list_node);
+ if (info->dma_address != iov.addr) {
+ DMUX_LOG_KERR("%s: iovec %p != dma %p\n",
+ __func__,
+ (void *)iov.addr,
+ (void *)info->dma_address);
+ list_for_each_entry(info, &bam_rx_pool, list_node) {
+ DMUX_LOG_KERR("%s: dma %p\n", __func__,
+ (void *)info->dma_address);
+ if (iov.addr == info->dma_address)
+ break;
+ }
+ }
+ BUG_ON(info->dma_address != iov.addr);
list_del(&info->list_node);
--bam_rx_pool_len;
mutex_unlock(&bam_rx_pool_mutexlock);
- if (info->dma_address != iov.addr)
- DMUX_LOG_KERR("%s: iovec %p != dma %p\n",
- __func__,
- (void *)info->dma_address, (void *)iov.addr);
handle_bam_mux_cmd(&info->work);
}
return;
@@ -1123,13 +1130,30 @@
inactive_cycles = 0;
mutex_lock(&bam_rx_pool_mutexlock);
if (unlikely(list_empty(&bam_rx_pool))) {
+ DMUX_LOG_KERR(
+ "%s: have iovec %p but rx pool empty\n",
+ __func__, (void *)iov.addr);
mutex_unlock(&bam_rx_pool_mutexlock);
continue;
}
info = list_first_entry(&bam_rx_pool,
struct rx_pkt_info, list_node);
- --bam_rx_pool_len;
+ if (info->dma_address != iov.addr) {
+ DMUX_LOG_KERR("%s: iovec %p != dma %p\n",
+ __func__,
+ (void *)iov.addr,
+ (void *)info->dma_address);
+ list_for_each_entry(info, &bam_rx_pool,
+ list_node) {
+ DMUX_LOG_KERR("%s: dma %p\n", __func__,
+ (void *)info->dma_address);
+ if (iov.addr == info->dma_address)
+ break;
+ }
+ }
+ BUG_ON(info->dma_address != iov.addr);
list_del(&info->list_node);
+ --bam_rx_pool_len;
mutex_unlock(&bam_rx_pool_mutexlock);
handle_bam_mux_cmd(&info->work);
}
@@ -1888,7 +1912,7 @@
ul_powerdown_finish();
a2_pc_disabled = 0;
a2_pc_disabled_wakelock_skipped = 0;
- disconnect_ack = 0;
+ disconnect_ack = 1;
/* Cleanup Channel States */
mutex_lock(&bam_pdev_mutexlock);
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index c37491d..40995bb 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -243,7 +243,7 @@
{
.src = MSM_BUS_MASTER_VFE,
.dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 140451840,
+ .ab = 274406400,
.ib = 561807360,
},
{
@@ -302,6 +302,27 @@
},
};
+static struct msm_bus_vectors cam_video_ls_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 348192000,
+ .ib = 617103360,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 206807040,
+ .ib = 488816640,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 540000000,
+ .ib = 1350000000,
+ },
+};
+
static struct msm_bus_paths cam_bus_client_config[] = {
{
ARRAY_SIZE(cam_init_vectors),
@@ -323,6 +344,10 @@
ARRAY_SIZE(cam_zsl_vectors),
cam_zsl_vectors,
},
+ {
+ ARRAY_SIZE(cam_video_ls_vectors),
+ cam_video_ls_vectors,
+ },
};
static struct msm_bus_scale_pdata cam_bus_client_pdata = {
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 177e1fd..330d7a8 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -1045,7 +1045,8 @@
}
}
-void __init apq8064_set_display_params(char *prim_panel, char *ext_panel)
+void __init apq8064_set_display_params(char *prim_panel, char *ext_panel,
+ unsigned char resolution)
{
/*
* For certain MPQ boards, HDMI should be set as primary display
@@ -1080,4 +1081,6 @@
pr_debug("msm_fb_pdata.ext_panel_name %s\n",
msm_fb_pdata.ext_panel_name);
}
+
+ msm_fb_pdata.ext_resolution = resolution;
}
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 0f9c939..eb36a81e 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -13,10 +13,11 @@
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
#include <mach/msm_bus_board.h>
#include <mach/board.h>
#include <mach/msm_dcvs.h>
+#include <mach/socinfo.h>
#include "devices.h"
#include "board-8064.h"
@@ -247,5 +248,13 @@
void __init apq8064_init_gpu(void)
{
+ unsigned int version = socinfo_get_version();
+
+ if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+ (SOCINFO_VERSION_MINOR(version) == 1))
+ kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 1);
+ else
+ kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 0);
+
platform_device_register(&device_kgsl_3d0);
}
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index f727852..a84cb39 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -179,11 +179,11 @@
};
VREG_CONSUMERS(S5) = {
REGULATOR_SUPPLY("8921_s5", NULL),
- REGULATOR_SUPPLY("krait0", NULL),
+ REGULATOR_SUPPLY("krait0", "acpuclk-8064"),
};
VREG_CONSUMERS(S6) = {
REGULATOR_SUPPLY("8921_s6", NULL),
- REGULATOR_SUPPLY("krait1", NULL),
+ REGULATOR_SUPPLY("krait1", "acpuclk-8064"),
};
VREG_CONSUMERS(S7) = {
REGULATOR_SUPPLY("8921_s7", NULL),
@@ -221,7 +221,6 @@
REGULATOR_SUPPLY("8921_lvs7", NULL),
REGULATOR_SUPPLY("pll_vdd", "pil_riva"),
REGULATOR_SUPPLY("lvds_vdda", "lvds.0"),
- REGULATOR_SUPPLY("hdmi_pll_fs", "mdp.0"),
REGULATOR_SUPPLY("dsi1_vddio", "mipi_dsi.1"),
REGULATOR_SUPPLY("hdmi_vdda", "hdmi_msm.0"),
};
@@ -238,11 +237,11 @@
};
VREG_CONSUMERS(8821_S0) = {
REGULATOR_SUPPLY("8821_s0", NULL),
- REGULATOR_SUPPLY("krait2", NULL),
+ REGULATOR_SUPPLY("krait2", "acpuclk-8064"),
};
VREG_CONSUMERS(8821_S1) = {
REGULATOR_SUPPLY("8821_s1", NULL),
- REGULATOR_SUPPLY("krait3", NULL),
+ REGULATOR_SUPPLY("krait3", "acpuclk-8064"),
};
VREG_CONSUMERS(EXT_5V) = {
REGULATOR_SUPPLY("ext_5v", NULL),
@@ -607,10 +606,37 @@
int msm8064_pm8921_regulator_pdata_len __devinitdata =
ARRAY_SIZE(msm8064_pm8921_regulator_pdata);
+#define RPM_REG_MAP(_id, _sleep_also, _voter, _supply, _dev_name) \
+ { \
+ .vreg_id = RPM_VREG_ID_PM8921_##_id, \
+ .sleep_also = _sleep_also, \
+ .voter = _voter, \
+ .supply = _supply, \
+ .dev_name = _dev_name, \
+ }
+static struct rpm_regulator_consumer_mapping
+ msm_rpm_regulator_consumer_mapping[] __devinitdata = {
+ RPM_REG_MAP(LVS7, 0, 1, "krait0_hfpll", "acpuclk-8064"),
+ RPM_REG_MAP(LVS7, 0, 2, "krait1_hfpll", "acpuclk-8064"),
+ RPM_REG_MAP(LVS7, 0, 4, "krait2_hfpll", "acpuclk-8064"),
+ RPM_REG_MAP(LVS7, 0, 5, "krait3_hfpll", "acpuclk-8064"),
+ RPM_REG_MAP(LVS7, 0, 6, "l2_hfpll", "acpuclk-8064"),
+ RPM_REG_MAP(L24, 0, 1, "krait0_mem", "acpuclk-8064"),
+ RPM_REG_MAP(L24, 0, 2, "krait1_mem", "acpuclk-8064"),
+ RPM_REG_MAP(L24, 0, 4, "krait2_mem", "acpuclk-8064"),
+ RPM_REG_MAP(L24, 0, 5, "krait3_mem", "acpuclk-8064"),
+ RPM_REG_MAP(S3, 0, 1, "krait0_dig", "acpuclk-8064"),
+ RPM_REG_MAP(S3, 0, 2, "krait1_dig", "acpuclk-8064"),
+ RPM_REG_MAP(S3, 0, 4, "krait2_dig", "acpuclk-8064"),
+ RPM_REG_MAP(S3, 0, 5, "krait3_dig", "acpuclk-8064"),
+};
+
struct rpm_regulator_platform_data apq8064_rpm_regulator_pdata __devinitdata = {
.init_data = apq8064_rpm_regulator_init_data,
.num_regulators = ARRAY_SIZE(apq8064_rpm_regulator_init_data),
.version = RPM_VREG_VERSION_8960,
.vreg_id_vdd_mem = RPM_VREG_ID_PM8921_L24,
.vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3,
+ .consumer_map = msm_rpm_regulator_consumer_mapping,
+ .consumer_map_len = ARRAY_SIZE(msm_rpm_regulator_consumer_mapping),
};
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 08c3408..3e07833 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -657,6 +657,9 @@
static char prim_panel_name[PANEL_NAME_MAX_LEN];
static char ext_panel_name[PANEL_NAME_MAX_LEN];
+
+static int ext_resolution;
+
static int __init prim_display_setup(char *param)
{
if (strnlen(param, PANEL_NAME_MAX_LEN))
@@ -673,9 +676,18 @@
}
early_param("ext_display", ext_display_setup);
+static int __init hdmi_resulution_setup(char *param)
+{
+ int ret;
+ ret = kstrtoint(param, 10, &ext_resolution);
+ return ret;
+}
+early_param("ext_resolution", hdmi_resulution_setup);
+
static void __init apq8064_reserve(void)
{
- apq8064_set_display_params(prim_panel_name, ext_panel_name);
+ apq8064_set_display_params(prim_panel_name, ext_panel_name,
+ ext_resolution);
msm_reserve();
if (apq8064_fmem_pdata.size) {
#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
@@ -2037,12 +2049,6 @@
},
};
-static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
- .base_addr = MSM_ACC0_BASE + 0x08,
- .cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
- .mask = 1UL << 13,
-};
-
static void __init apq8064_init_buses(void)
{
msm_bus_rpm_set_mt_mask();
@@ -2148,7 +2154,7 @@
};
static struct platform_device *common_devices[] __initdata = {
- &msm8960_device_acpuclk,
+ &apq8064_device_acpuclk,
&apq8064_device_dmov,
&apq8064_device_qup_spi_gsbi5,
&apq8064_device_ext_5v_vreg,
@@ -2953,7 +2959,6 @@
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
- msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
apq8064_epm_adc_init();
}
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index a241ab3..2258b8d 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -87,7 +87,8 @@
void apq8064_init_fb(void);
void apq8064_allocate_fb_region(void);
void apq8064_mdp_writeback(struct memtype_reserve *reserve_table);
-void __init apq8064_set_display_params(char *prim_panel, char *ext_panel);
+void __init apq8064_set_display_params(char *prim_panel, char *ext_panel,
+ unsigned char resolution);
void apq8064_init_gpu(void);
void apq8064_pm8xxx_gpio_mpp_init(void);
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index 6ee315c..d3e37cd 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -251,7 +251,7 @@
{
.src = MSM_BUS_MASTER_VFE,
.dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 140451840,
+ .ab = 274406400,
.ib = 561807360,
},
{
@@ -310,6 +310,27 @@
},
};
+static struct msm_bus_vectors cam_video_ls_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 348192000,
+ .ib = 617103360,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 206807040,
+ .ib = 488816640,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 540000000,
+ .ib = 1350000000,
+ },
+};
+
static struct msm_bus_paths cam_bus_client_config[] = {
{
ARRAY_SIZE(cam_init_vectors),
@@ -331,6 +352,10 @@
ARRAY_SIZE(cam_zsl_vectors),
cam_zsl_vectors,
},
+ {
+ ARRAY_SIZE(cam_video_ls_vectors),
+ cam_video_ls_vectors,
+ },
};
static struct msm_bus_scale_pdata cam_bus_client_pdata = {
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index 066c134..bd343c1 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -13,7 +13,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
#include <mach/msm_bus_board.h>
#include <mach/board.h>
#include <mach/socinfo.h>
@@ -160,8 +160,16 @@
void __init msm8930_init_gpu(void)
{
- if (cpu_is_msm8627())
- kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 400000000;
+ unsigned int version = socinfo_get_version();
+
+ if (cpu_is_msm8930aa())
+ kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 450000000;
+
+ if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+ (SOCINFO_VERSION_MINOR(version) == 2))
+ kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 0, 5, 2);
+ else
+ kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 0, 5, 0);
platform_device_register(&device_kgsl_3d0);
}
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index f06a1b7..af91089 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -172,11 +172,13 @@
};
VREG_CONSUMERS(S5) = {
REGULATOR_SUPPLY("8038_s5", NULL),
- REGULATOR_SUPPLY("krait0", NULL),
+ REGULATOR_SUPPLY("krait0", "acpuclk-8627"),
+ REGULATOR_SUPPLY("krait0", "acpuclk-8930"),
};
VREG_CONSUMERS(S6) = {
REGULATOR_SUPPLY("8038_s6", NULL),
- REGULATOR_SUPPLY("krait1", NULL),
+ REGULATOR_SUPPLY("krait1", "acpuclk-8627"),
+ REGULATOR_SUPPLY("krait1", "acpuclk-8930"),
};
VREG_CONSUMERS(LVS1) = {
REGULATOR_SUPPLY("8038_lvs1", NULL),
@@ -511,10 +513,39 @@
int msm8930_pm8038_regulator_pdata_len __devinitdata =
ARRAY_SIZE(msm8930_pm8038_regulator_pdata);
+#define RPM_REG_MAP(_id, _sleep_also, _voter, _supply, _dev_name) \
+ { \
+ .vreg_id = RPM_VREG_ID_PM8038_##_id, \
+ .sleep_also = _sleep_also, \
+ .voter = _voter, \
+ .supply = _supply, \
+ .dev_name = _dev_name, \
+ }
+static struct rpm_regulator_consumer_mapping
+ msm_rpm_regulator_consumer_mapping[] __devinitdata = {
+ RPM_REG_MAP(L23, 0, 1, "krait0_hfpll", "acpuclk-8930"),
+ RPM_REG_MAP(L23, 0, 2, "krait1_hfpll", "acpuclk-8930"),
+ RPM_REG_MAP(L23, 0, 6, "l2_hfpll", "acpuclk-8930"),
+ RPM_REG_MAP(L24, 0, 1, "krait0_mem", "acpuclk-8930"),
+ RPM_REG_MAP(L24, 0, 2, "krait1_mem", "acpuclk-8930"),
+ RPM_REG_MAP(VDD_DIG_CORNER, 0, 1, "krait0_dig", "acpuclk-8930"),
+ RPM_REG_MAP(VDD_DIG_CORNER, 0, 2, "krait1_dig", "acpuclk-8930"),
+
+ RPM_REG_MAP(L23, 0, 1, "krait0_hfpll", "acpuclk-8627"),
+ RPM_REG_MAP(L23, 0, 2, "krait1_hfpll", "acpuclk-8627"),
+ RPM_REG_MAP(L23, 0, 6, "l2_hfpll", "acpuclk-8627"),
+ RPM_REG_MAP(L24, 0, 1, "krait0_mem", "acpuclk-8627"),
+ RPM_REG_MAP(L24, 0, 2, "krait1_mem", "acpuclk-8627"),
+ RPM_REG_MAP(VDD_DIG_CORNER, 0, 1, "krait0_dig", "acpuclk-8627"),
+ RPM_REG_MAP(VDD_DIG_CORNER, 0, 2, "krait1_dig", "acpuclk-8627"),
+};
+
struct rpm_regulator_platform_data msm8930_rpm_regulator_pdata __devinitdata = {
.init_data = msm8930_rpm_regulator_init_data,
.num_regulators = ARRAY_SIZE(msm8930_rpm_regulator_init_data),
.version = RPM_VREG_VERSION_8930,
.vreg_id_vdd_mem = RPM_VREG_ID_PM8038_L24,
.vreg_id_vdd_dig = RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
+ .consumer_map = msm_rpm_regulator_consumer_mapping,
+ .consumer_map_len = ARRAY_SIZE(msm_rpm_regulator_consumer_mapping),
};
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index e695241..d7a077c 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -26,7 +26,6 @@
#include <linux/spi/spi.h>
#include <linux/slimbus/slimbus.h>
#include <linux/bootmem.h>
-#include <linux/msm_kgsl.h>
#ifdef CONFIG_ANDROID_PMEM
#include <linux/android_pmem.h>
#endif
@@ -80,6 +79,7 @@
#include <linux/fmem.h>
#include <mach/msm_cache_dump.h>
+#include <mach/kgsl.h>
#ifdef CONFIG_INPUT_MPU3050
#include <linux/input/mpu3050.h>
#endif
@@ -1460,6 +1460,9 @@
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &usb_bus_scale_pdata,
#endif
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+ .mhl_dev_name = "sii8334",
+#endif
};
#endif
@@ -2159,7 +2162,6 @@
};
static struct platform_device *common_devices[] __initdata = {
- &msm8960_device_acpuclk,
&msm8960_device_dmov,
&msm_device_smd,
&msm8960_device_uart_gsbi5,
@@ -2399,12 +2401,6 @@
.mode = MSM_PM_BOOT_CONFIG_TZ,
};
-static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
- .base_addr = MSM_ACC0_BASE + 0x08,
- .cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
- .mask = 1UL << 13,
-};
-
#ifdef CONFIG_I2C
#define I2C_SURF 1
#define I2C_FFA (1 << 1)
@@ -2573,6 +2569,10 @@
msm_spm_l2_init(msm_spm_l2_data);
msm8930_init_buses();
platform_add_devices(msm8930_footswitch, msm8930_num_footswitch);
+ if (cpu_is_msm8627())
+ platform_device_register(&msm8627_device_acpuclk);
+ else if (cpu_is_msm8930() || cpu_is_msm8930aa())
+ platform_device_register(&msm8930_device_acpuclk);
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
msm8930_add_vidc_device();
/*
@@ -2597,7 +2597,6 @@
ARRAY_SIZE(msm_slim_devices));
change_memory_power = &msm8930_change_memory_power;
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
- msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
if (PLATFORM_IS_CHARM25())
platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index b6c03a4..a21c4c3 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -272,7 +272,7 @@
{
.src = MSM_BUS_MASTER_VFE,
.dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 154275840,
+ .ab = 274406400,
.ib = 617103360,
},
{
@@ -367,6 +367,40 @@
},
};
+static struct msm_bus_vectors cam_video_ls_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 348192000,
+ .ib = 617103360,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 206807040,
+ .ib = 488816640,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 540000000,
+ .ib = 1350000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_MM_IMEM,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_MM_IMEM,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+
static struct msm_bus_paths cam_bus_client_config[] = {
{
ARRAY_SIZE(cam_init_vectors),
@@ -388,6 +422,10 @@
ARRAY_SIZE(cam_zsl_vectors),
cam_zsl_vectors,
},
+ {
+ ARRAY_SIZE(cam_video_ls_vectors),
+ cam_video_ls_vectors,
+ },
};
static struct msm_bus_scale_pdata cam_bus_client_pdata = {
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index 20e9d2b..88827ab 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -1005,6 +1005,9 @@
void __init msm8960_init_fb(void)
{
+ if (cpu_is_msm8960ab())
+ mdp_pdata.mdp_rev = MDP_REV_44;
+
platform_device_register(&msm_fb_device);
#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index fd326f1..5851990 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -76,6 +76,18 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting gsbi8_uartdm_active_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi8_uartdm_suspended_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting gsbi9_active_cfg = {
.func = GPIOMUX_FUNC_2,
.drv = GPIOMUX_DRV_8MA,
@@ -240,6 +252,12 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting usbsw_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting mdp_vsync_suspend_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -304,6 +322,37 @@
},
};
#endif
+/* GSBI8 UART GPIOs for Atheros Bluetooth */
+static struct msm_gpiomux_config msm8960_gsbi8_uartdm_configs[] = {
+ {
+ .gpio = 34,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi8_uartdm_suspended_cfg,
+ [GPIOMUX_ACTIVE] = &gsbi8_uartdm_active_cfg,
+ }
+ },
+ {
+ .gpio = 35,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi8_uartdm_suspended_cfg,
+ [GPIOMUX_ACTIVE] = &gsbi8_uartdm_active_cfg,
+ }
+ },
+ {
+ .gpio = 36,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi8_uartdm_suspended_cfg,
+ [GPIOMUX_ACTIVE] = &gsbi8_uartdm_active_cfg,
+ }
+ },
+ {
+ .gpio = 37,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi8_uartdm_suspended_cfg,
+ [GPIOMUX_ACTIVE] = &gsbi8_uartdm_active_cfg,
+ }
+ },
+};
static struct msm_gpiomux_config msm8960_fusion_gsbi_configs[] = {
{
@@ -760,6 +809,13 @@
[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
}
},
+ /* USB_SW */
+ {
+ .gpio = 25,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &usbsw_cfg,
+ }
+ }
};
static struct msm_gpiomux_config msm8960_mdp_vsync_configs[] __initdata = {
@@ -975,6 +1031,10 @@
msm_gpiomux_install(msm8960_mdp_vsync_configs,
ARRAY_SIZE(msm8960_mdp_vsync_configs));
+ if (socinfo_get_platform_subtype() != PLATFORM_SUBTYPE_SGLTE)
+ msm_gpiomux_install(msm8960_gsbi8_uartdm_configs,
+ ARRAY_SIZE(msm8960_gsbi8_uartdm_configs));
+
if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
msm_gpiomux_install(msm8960_gsbi8_uart_configs,
ARRAY_SIZE(msm8960_gsbi8_uart_configs));
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 2664d6b..6ad44d8 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -116,7 +116,6 @@
REGULATOR_SUPPLY("8921_l23", NULL),
REGULATOR_SUPPLY("dsi_vddio", "mipi_dsi.1"),
REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"),
- REGULATOR_SUPPLY("hdmi_pll_fs", "mdp.0"),
REGULATOR_SUPPLY("pll_vdd", "pil_riva"),
REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"),
REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"),
@@ -182,11 +181,11 @@
};
VREG_CONSUMERS(S5) = {
REGULATOR_SUPPLY("8921_s5", NULL),
- REGULATOR_SUPPLY("krait0", NULL),
+ REGULATOR_SUPPLY("krait0", "acpuclk-8960"),
};
VREG_CONSUMERS(S6) = {
REGULATOR_SUPPLY("8921_s6", NULL),
- REGULATOR_SUPPLY("krait1", NULL),
+ REGULATOR_SUPPLY("krait1", "acpuclk-8960"),
};
VREG_CONSUMERS(S7) = {
REGULATOR_SUPPLY("8921_s7", NULL),
@@ -562,10 +561,34 @@
int msm_pm8921_regulator_pdata_len __devinitdata =
ARRAY_SIZE(msm_pm8921_regulator_pdata);
+#define RPM_REG_MAP(_id, _sleep_also, _voter, _supply, _dev_name) \
+ { \
+ .vreg_id = RPM_VREG_ID_PM8921_##_id, \
+ .sleep_also = _sleep_also, \
+ .voter = _voter, \
+ .supply = _supply, \
+ .dev_name = _dev_name, \
+ }
+static struct rpm_regulator_consumer_mapping
+ msm_rpm_regulator_consumer_mapping[] __devinitdata = {
+ RPM_REG_MAP(L23, 0, 1, "krait0_l23", "acpuclk-8960"),
+ RPM_REG_MAP(L23, 0, 2, "krait1_l23", "acpuclk-8960"),
+ RPM_REG_MAP(L23, 0, 6, "l2_l23", "acpuclk-8960"),
+ RPM_REG_MAP(L24, 0, 1, "krait0_mem", "acpuclk-8960"),
+ RPM_REG_MAP(L24, 0, 2, "krait1_mem", "acpuclk-8960"),
+ RPM_REG_MAP(S3, 0, 1, "krait0_dig", "acpuclk-8960"),
+ RPM_REG_MAP(S3, 0, 2, "krait1_dig", "acpuclk-8960"),
+ RPM_REG_MAP(S8, 0, 1, "krait0_s8", "acpuclk-8960"),
+ RPM_REG_MAP(S8, 0, 2, "krait1_s8", "acpuclk-8960"),
+ RPM_REG_MAP(S8, 0, 6, "l2_s8", "acpuclk-8960"),
+};
+
struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata = {
.init_data = msm_rpm_regulator_init_data,
.num_regulators = ARRAY_SIZE(msm_rpm_regulator_init_data),
.version = RPM_VREG_VERSION_8960,
.vreg_id_vdd_mem = RPM_VREG_ID_PM8921_L24,
.vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3,
+ .consumer_map = msm_rpm_regulator_consumer_mapping,
+ .consumer_map_len = ARRAY_SIZE(msm_rpm_regulator_consumer_mapping),
};
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index a4e45c9..d56bdbd 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -26,7 +26,6 @@
#include <linux/spi/spi.h>
#include <linux/slimbus/slimbus.h>
#include <linux/bootmem.h>
-#include <linux/msm_kgsl.h>
#ifdef CONFIG_ANDROID_PMEM
#include <linux/android_pmem.h>
#endif
@@ -87,6 +86,7 @@
#include <mach/scm.h>
#include <mach/iommu_domains.h>
+#include <mach/kgsl.h>
#include <linux/fmem.h>
#include "timer.h"
@@ -1293,6 +1293,7 @@
.peripheral_platform_device = NULL,
.ramdump_timeout_ms = 600000,
.no_powerdown_after_ramdumps = 1,
+ .image_upgrade_supported = 1,
};
#define MSM_TSIF0_PHYS (0x18200000)
@@ -1488,6 +1489,9 @@
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &usb_bus_scale_pdata,
#endif
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+ .mhl_dev_name = "sii8334",
+#endif
};
#endif
@@ -1911,18 +1915,9 @@
.gest_set = CY_GEST_GRP1 | CY_GEST_GRP2 |
CY_GEST_GRP3 | CY_GEST_GRP4 |
CY_ACT_DIST,
- /* change act_intrvl to customize the Active power state
- * scanning/processing refresh interval for Operating mode
- */
- .act_intrvl = CY_ACT_INTRVL_DFLT,
- /* change tch_tmout to customize the touch timeout for the
- * Active power state for Operating mode
- */
- .tch_tmout = CY_TCH_TMOUT_DFLT,
- /* change lp_intrvl to customize the Low Power power state
- * scanning/processing refresh interval for Operating mode
- */
- .lp_intrvl = CY_LP_INTRVL_DFLT,
+ .act_intrvl = 10,
+ .tch_tmout = 200,
+ .lp_intrvl = 30,
.sleep_gpio = CYTTSP_TS_SLEEP_GPIO,
.resout_gpio = CYTTSP_TS_RESOUT_N_GPIO,
.irq_gpio = CYTTSP_TS_GPIO_IRQ,
@@ -2326,12 +2321,6 @@
.src_clk_rate = 24000000,
};
-static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
- .base_addr = MSM_ACC0_BASE + 0x08,
- .cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
- .mask = 1UL << 13,
-};
-
static struct ks8851_pdata spi_eth_pdata = {
.irq_gpio = KS8851_IRQ_GPIO,
.rst_gpio = KS8851_RST_GPIO,
@@ -2467,7 +2456,36 @@
static struct msm_serial_hs_platform_data msm_uart_dm9_pdata = {
.gpio_config = configure_uart_gpios,
};
+
+static int configure_gsbi8_uart_gpios(int on)
+{
+ int ret = 0, i;
+ int uart_gpios[] = {34, 35, 36, 37};
+
+ for (i = 0; i < ARRAY_SIZE(uart_gpios); i++) {
+ if (on) {
+ ret = gpio_request(uart_gpios[i], NULL);
+ if (ret) {
+ pr_err("%s: unable to request uart gpio[%d]\n",
+ __func__, uart_gpios[i]);
+ break;
+ }
+ } else {
+ gpio_free(uart_gpios[i]);
+ }
+ }
+
+ if (ret && on && i)
+ for (; i >= 0; i--)
+ gpio_free(uart_gpios[i]);
+ return ret;
+}
+
+static struct msm_serial_hs_platform_data msm_uart_dm8_pdata = {
+ .gpio_config = configure_gsbi8_uart_gpios,
+};
#else
+static struct msm_serial_hs_platform_data msm_uart_dm8_pdata;
static struct msm_serial_hs_platform_data msm_uart_dm9_pdata;
#endif
@@ -2476,7 +2494,6 @@
&msm8960_device_dmov,
&msm_device_smd,
&msm_device_uart_dm6,
- &msm_device_uart_dm9,
&msm_device_saw_core0,
&msm_device_saw_core1,
&msm8960_device_ext_5v_vreg,
@@ -2696,13 +2713,26 @@
static void __init msm8960_gfx_init(void)
{
+ struct kgsl_device_platform_data *kgsl_3d0_pdata =
+ msm_kgsl_3d0.dev.platform_data;
uint32_t soc_platform_version = socinfo_get_version();
+
if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
- struct kgsl_device_platform_data *kgsl_3d0_pdata =
- msm_kgsl_3d0.dev.platform_data;
kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000;
kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000;
}
+ if (cpu_is_msm8960ab()) {
+ kgsl_3d0_pdata->chipid = ADRENO_CHIPID(3, 2, 1, 0);
+ } else {
+
+ /* 8960v3 GPU registers returns 5 for patch release
+ * but it should be 6, so dummy up the chipid here
+ * based the platform type
+ */
+
+ if (SOCINFO_VERSION_MAJOR(soc_platform_version) >= 3)
+ kgsl_3d0_pdata->chipid = ADRENO_CHIPID(2, 2, 0, 6);
+ }
}
static struct msm_rpmrs_level msm_rpmrs_levels[] = {
@@ -3040,7 +3070,6 @@
slim_register_board_info(msm_slim_devices,
ARRAY_SIZE(msm_slim_devices));
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
- msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
}
static void __init msm8960_rumi3_init(void)
@@ -3070,7 +3099,6 @@
slim_register_board_info(msm_slim_devices,
ARRAY_SIZE(msm_slim_devices));
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
- msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
}
static void __init msm8960_cdp_init(void)
@@ -3133,8 +3161,14 @@
if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
msm_uart_dm9_pdata.wakeup_irq = gpio_to_irq(94); /* GSBI9(2) */
msm_device_uart_dm9.dev.platform_data = &msm_uart_dm9_pdata;
+ platform_device_register(&msm_device_uart_dm9);
}
+ /* For 8960 Standalone External Bluetooth Interface */
+ if (socinfo_get_platform_subtype() != PLATFORM_SUBTYPE_SGLTE) {
+ msm_device_uart_dm8.dev.platform_data = &msm_uart_dm8_pdata;
+ platform_device_register(&msm_device_uart_dm8);
+ }
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
msm8960_pm8921_gpio_mpp_init();
platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
@@ -3153,7 +3187,6 @@
msm8960_init_dsps();
change_memory_power = &msm8960_change_memory_power;
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
- msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
mdm_sglte_device.dev.platform_data = &sglte_platform_data;
platform_device_register(&mdm_sglte_device);
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 557331a..7562c83 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -208,12 +208,12 @@
static struct resource smd_resource[] = {
{
.name = "modem_smd_in",
- .start = 32 + 17, /* mss_sw_to_kpss_ipc_irq0 */
+ .start = 32 + 25, /* mss_sw_to_kpss_ipc_irq0 */
.flags = IORESOURCE_IRQ,
},
{
.name = "modem_smsm_in",
- .start = 32 + 18, /* mss_sw_to_kpss_ipc_irq1 */
+ .start = 32 + 26, /* mss_sw_to_kpss_ipc_irq1 */
.flags = IORESOURCE_IRQ,
},
{
@@ -640,6 +640,8 @@
OF_DEV_AUXDATA("qcom,qseecom", 0xFE806000, \
"qseecom", NULL),
OF_DEV_AUXDATA("qcom,mdss_mdp", 0xFD900000, "mdp.0", NULL),
+ OF_DEV_AUXDATA("qcom,msm-tsens", 0xFC4A8000, \
+ "msm-tsens", NULL),
{}
};
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index 9259161..3726941 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -1188,9 +1188,9 @@
}
/*Toggle Backlight GPIO*/
gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
- udelay(190);
+ udelay(100);
gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 0);
- udelay(286);
+ udelay(430);
gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
/* 1 wire mode starts from this low to high transition */
udelay(50);
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index 22095cd..47e8381 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -22,6 +22,7 @@
#include <linux/delay.h>
#include <linux/atmel_maxtouch.h>
#include <linux/input/ft5x06_ts.h>
+#include <linux/leds-msm-tricolor.h>
#include <asm/gpio.h>
#include <asm/mach-types.h>
#include <mach/rpc_server_handset.h>
@@ -162,32 +163,6 @@
};
#define LED_GPIO_PDM 96
-#define LED_RED_GPIO_8625 49
-#define LED_GREEN_GPIO_8625 34
-
-static struct gpio_led gpio_leds_config_8625[] = {
- {
- .name = "green",
- .gpio = LED_GREEN_GPIO_8625,
- },
- {
- .name = "red",
- .gpio = LED_RED_GPIO_8625,
- },
-};
-
-static struct gpio_led_platform_data gpio_leds_pdata_8625 = {
- .num_leds = ARRAY_SIZE(gpio_leds_config_8625),
- .leds = gpio_leds_config_8625,
-};
-
-static struct platform_device gpio_leds_8625 = {
- .name = "leds-gpio",
- .id = -1,
- .dev = {
- .platform_data = &gpio_leds_pdata_8625,
- },
-};
#define MXT_TS_IRQ_GPIO 48
#define MXT_TS_RESET_GPIO 26
@@ -772,6 +747,30 @@
},
};
+static struct led_info tricolor_led_info[] = {
+ [0] = {
+ .name = "red",
+ .flags = LED_COLOR_RED,
+ },
+ [1] = {
+ .name = "green",
+ .flags = LED_COLOR_GREEN,
+ },
+};
+
+static struct led_platform_data tricolor_led_pdata = {
+ .leds = tricolor_led_info,
+ .num_leds = ARRAY_SIZE(tricolor_led_info),
+};
+
+static struct platform_device tricolor_leds_pdev = {
+ .name = "msm-tricolor-leds",
+ .id = -1,
+ .dev = {
+ .platform_data = &tricolor_led_pdata,
+ },
+};
+
void __init msm7627a_add_io_devices(void)
{
/* touchscreen */
@@ -868,24 +867,9 @@
platform_device_register(&kp_pdev_sku3);
/* leds */
- if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
- rc = gpio_tlmm_config(GPIO_CFG(LED_RED_GPIO_8625, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_16MA), GPIO_CFG_ENABLE);
- if (rc) {
- pr_err("%s: gpio_tlmm_config for %d failed\n",
- __func__, LED_RED_GPIO_8625);
- }
-
- rc = gpio_tlmm_config(GPIO_CFG(LED_GREEN_GPIO_8625, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_16MA), GPIO_CFG_ENABLE);
- if (rc) {
- pr_err("%s: gpio_tlmm_config for %d failed\n",
- __func__, LED_GREEN_GPIO_8625);
- }
-
- platform_device_register(&gpio_leds_8625);
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
+ machine_is_msm8625_evt()) {
platform_device_register(&pmic_mpp_leds_pdev);
+ platform_device_register(&tricolor_leds_pdev);
}
}
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 7db4bda..ba4e098 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -48,7 +48,6 @@
#include <mach/msm_battery.h>
#include <linux/smsc911x.h>
#include <linux/atmel_maxtouch.h>
-#include <linux/fmem.h>
#include <linux/msm_adc.h>
#include <linux/ion.h>
#include "devices.h"
@@ -448,9 +447,6 @@
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
.cached = 1,
.memory_type = MEMTYPE_EBI1,
- .request_region = request_fmem_c_region,
- .release_region = release_fmem_c_region,
- .reusable = 1,
};
static struct platform_device android_pmem_adsp_device = {
@@ -778,14 +774,6 @@
static void msm7x27a_cfg_uart2dm_serial(void) { }
#endif
-static struct fmem_platform_data fmem_pdata;
-
-static struct platform_device fmem_device = {
- .name = "fmem",
- .id = 1,
- .dev = { .platform_data = &fmem_pdata },
-};
-
static struct platform_device *rumi_sim_devices[] __initdata = {
&msm_device_dmov,
&msm_device_smd,
@@ -823,7 +811,6 @@
&android_pmem_device,
&android_pmem_adsp_device,
&android_pmem_audio_device,
- &fmem_device,
&msm_device_nand,
&msm_device_snd,
&msm_device_adspdec,
@@ -966,32 +953,10 @@
{
#ifdef CONFIG_ANDROID_PMEM
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
- unsigned int i;
- unsigned int reusable_count = 0;
-
android_pmem_adsp_pdata.size = pmem_adsp_size;
android_pmem_pdata.size = pmem_mdp_size;
android_pmem_audio_pdata.size = pmem_audio_size;
- fmem_pdata.size = 0;
- fmem_pdata.align = PAGE_SIZE;
-
- /* Find pmem devices that should use FMEM (reusable) memory.
- */
- for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
- struct android_pmem_platform_data *pdata = pmem_pdata_array[i];
-
- if (!reusable_count && pdata->reusable)
- fmem_pdata.size += pdata->size;
-
- reusable_count += (pdata->reusable) ? 1 : 0;
-
- if (pdata->reusable && reusable_count > 1) {
- pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n",
- __func__, pdata->name);
- pdata->reusable = 0;
- }
- }
#endif
#endif
}
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 5b9ea36..a694557 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -31,7 +31,6 @@
#include <linux/memblock.h>
#include <linux/input/ft5x06_ts.h>
#include <linux/msm_adc.h>
-#include <linux/fmem.h>
#include <linux/regulator/msm-gpio-regulator.h>
#include <linux/ion.h>
#include <asm/mach/mmc.h>
@@ -144,6 +143,7 @@
static struct android_usb_platform_data android_usb_pdata = {
.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+ .cdrom = 1,
};
static struct platform_device android_usb_device = {
@@ -393,9 +393,6 @@
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
.cached = 1,
.memory_type = MEMTYPE_EBI1,
- .request_region = request_fmem_c_region,
- .release_region = release_fmem_c_region,
- .reusable = 1,
};
static struct platform_device android_pmem_adsp_device = {
@@ -592,9 +589,9 @@
static u32 msm_calculate_batt_capacity(u32 current_voltage);
static struct msm_psy_batt_pdata msm_psy_batt_data = {
- .voltage_min_design = 3200,
+ .voltage_min_design = 3500,
.voltage_max_design = 4200,
- .voltage_fail_safe = 3340,
+ .voltage_fail_safe = 3598,
.avail_chg_sources = AC_CHG | USB_CHG ,
.batt_technology = POWER_SUPPLY_TECHNOLOGY_LION,
.calculate_capacity = &msm_calculate_batt_capacity,
@@ -638,14 +635,6 @@
},
};
-static struct fmem_platform_data fmem_pdata;
-
-static struct platform_device fmem_device = {
- .name = "fmem",
- .id = 1,
- .dev = { .platform_data = &fmem_pdata },
-};
-
#define GPIO_VREG_INIT(_id, _reg_name, _gpio_label, _gpio, _active_low) \
[GPIO_VREG_ID_##_id] = { \
.init_data = { \
@@ -716,7 +705,6 @@
&asoc_msm_dai0,
&asoc_msm_dai1,
&msm_adc_device,
- &fmem_device,
#ifdef CONFIG_ION_MSM
&ion_dev,
#endif
@@ -857,32 +845,9 @@
{
#ifdef CONFIG_ANDROID_PMEM
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
- unsigned int i;
- unsigned int reusable_count = 0;
-
android_pmem_adsp_pdata.size = pmem_adsp_size;
android_pmem_pdata.size = pmem_mdp_size;
android_pmem_audio_pdata.size = pmem_audio_size;
-
- fmem_pdata.size = 0;
- fmem_pdata.align = PAGE_SIZE;
-
- /* Find pmem devices that should use FMEM (reusable) memory.
- */
- for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
- struct android_pmem_platform_data *pdata = pmem_pdata_array[i];
-
- if (!reusable_count && pdata->reusable)
- fmem_pdata.size += pdata->size;
-
- reusable_count += (pdata->reusable) ? 1 : 0;
-
- if (pdata->reusable && reusable_count > 1) {
- pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n",
- __func__, pdata->name);
- pdata->reusable = 0;
- }
- }
#endif
#endif
}
diff --git a/arch/arm/mach-msm/board-swordfish.c b/arch/arm/mach-msm/board-swordfish.c
index 45d5bb0..7262277 100644
--- a/arch/arm/mach-msm/board-swordfish.c
+++ b/arch/arm/mach-msm/board-swordfish.c
@@ -21,7 +21,7 @@
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/android_pmem.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index f99e5de8..56b774d 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -194,6 +194,7 @@
#define DSI2_ESC_CC_REG REG_MM(0x013C)
#define DSI_PIXEL_CC_REG REG_MM(0x0130)
#define DSI2_PIXEL_CC_REG REG_MM(0x0094)
+#define DSI2_PIXEL_CC2_REG REG_MM(0x0264)
#define DBG_BUS_VEC_A_REG REG_MM(0x01C8)
#define DBG_BUS_VEC_B_REG REG_MM(0x01CC)
#define DBG_BUS_VEC_C_REG REG_MM(0x01D0)
@@ -419,16 +420,16 @@
.fmax[VDD_DIG_##l2] = (f2), \
.fmax[VDD_DIG_##l3] = (f3)
-enum vdd_sr2_pll_levels {
- VDD_SR2_PLL_OFF,
- VDD_SR2_PLL_ON
+enum vdd_sr2_hdmi_pll_levels {
+ VDD_SR2_HDMI_PLL_OFF,
+ VDD_SR2_HDMI_PLL_ON
};
-static int set_vdd_sr2_pll_8960(struct clk_vdd_class *vdd_class, int level)
+static int set_vdd_sr2_hdmi_pll_8960(struct clk_vdd_class *vdd_class, int level)
{
int rc = 0;
- if (level == VDD_SR2_PLL_OFF) {
+ if (level == VDD_SR2_HDMI_PLL_OFF) {
rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
RPM_VREG_VOTER3, 0, 0, 1);
if (rc)
@@ -453,20 +454,20 @@
return rc;
}
-static DEFINE_VDD_CLASS(vdd_sr2_pll, set_vdd_sr2_pll_8960);
+static DEFINE_VDD_CLASS(vdd_sr2_hdmi_pll, set_vdd_sr2_hdmi_pll_8960);
static int sr2_lreg_uv[] = {
- [VDD_SR2_PLL_OFF] = 0,
- [VDD_SR2_PLL_ON] = 1800000,
+ [VDD_SR2_HDMI_PLL_OFF] = 0,
+ [VDD_SR2_HDMI_PLL_ON] = 1800000,
};
-static int set_vdd_sr2_pll_8064(struct clk_vdd_class *vdd_class, int level)
+static int set_vdd_sr2_hdmi_pll_8064(struct clk_vdd_class *vdd_class, int level)
{
return rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_LVS7, RPM_VREG_VOTER3,
sr2_lreg_uv[level], sr2_lreg_uv[level], 1);
}
-static int set_vdd_sr2_pll_8930(struct clk_vdd_class *vdd_class, int level)
+static int set_vdd_sr2_hdmi_pll_8930(struct clk_vdd_class *vdd_class, int level)
{
return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_L23, RPM_VREG_VOTER3,
sr2_lreg_uv[level], sr2_lreg_uv[level], 1);
@@ -498,8 +499,8 @@
.dbg_name = "pll3_clk",
.rate = 1200000000,
.ops = &clk_ops_local_pll,
- .vdd_class = &vdd_sr2_pll,
- .fmax[VDD_SR2_PLL_ON] = ULONG_MAX,
+ .vdd_class = &vdd_sr2_hdmi_pll,
+ .fmax[VDD_SR2_HDMI_PLL_ON] = ULONG_MAX,
CLK_INIT(pll3_clk.c),
.warned = true,
},
@@ -785,7 +786,7 @@
};
/* gfx3d_axi_clk is set as a dependency of gmem_axi_clk at runtime */
-static struct branch_clk gfx3d_axi_clk_8064 = {
+static struct branch_clk gfx3d_axi_clk = {
.b = {
.ctl_reg = MAXI_EN5_REG,
.en_mask = BIT(25),
@@ -799,7 +800,7 @@
.c = {
.dbg_name = "gfx3d_axi_clk",
.ops = &clk_ops_branch,
- CLK_INIT(gfx3d_axi_clk_8064.c),
+ CLK_INIT(gfx3d_axi_clk.c),
},
};
@@ -2688,6 +2689,7 @@
.ops = &clk_ops_rcg,
VDD_DIG_FMAX_MAP2(LOW, 86000000, NOMINAL, 178000000),
CLK_INIT(csi0_src_clk.c),
+ .warned = true,
},
};
@@ -2705,6 +2707,7 @@
.dbg_name = "csi0_clk",
.ops = &clk_ops_branch,
CLK_INIT(csi0_clk.c),
+ .warned = true,
},
};
@@ -2744,6 +2747,7 @@
.ops = &clk_ops_rcg,
VDD_DIG_FMAX_MAP2(LOW, 86000000, NOMINAL, 178000000),
CLK_INIT(csi1_src_clk.c),
+ .warned = true,
},
};
@@ -2761,6 +2765,7 @@
.dbg_name = "csi1_clk",
.ops = &clk_ops_branch,
CLK_INIT(csi1_clk.c),
+ .warned = true,
},
};
@@ -2800,6 +2805,7 @@
.ops = &clk_ops_rcg,
VDD_DIG_FMAX_MAP2(LOW, 86000000, NOMINAL, 178000000),
CLK_INIT(csi2_src_clk.c),
+ .warned = true,
},
};
@@ -2817,6 +2823,7 @@
.dbg_name = "csi2_clk",
.ops = &clk_ops_branch,
CLK_INIT(csi2_clk.c),
+ .warned = true,
},
};
@@ -3406,6 +3413,27 @@
.ctl_val = CC_BANKED(9, 6, n), \
}
+static struct clk_freq_tbl clk_tbl_gfx3d_8960ab[] = {
+ F_GFX3D( 0, gnd, 0, 0),
+ F_GFX3D( 27000000, pxo, 0, 0),
+ F_GFX3D( 48000000, pll8, 1, 8),
+ F_GFX3D( 54857000, pll8, 1, 7),
+ F_GFX3D( 64000000, pll8, 1, 6),
+ F_GFX3D( 76800000, pll8, 1, 5),
+ F_GFX3D( 96000000, pll8, 1, 4),
+ F_GFX3D(128000000, pll8, 1, 3),
+ F_GFX3D(145455000, pll2, 2, 11),
+ F_GFX3D(160000000, pll2, 1, 5),
+ F_GFX3D(177778000, pll2, 2, 9),
+ F_GFX3D(200000000, pll2, 1, 4),
+ F_GFX3D(228571000, pll2, 2, 7),
+ F_GFX3D(266667000, pll2, 1, 3),
+ F_GFX3D(320000000, pll2, 2, 5),
+ F_GFX3D(325000000, pll3, 1, 2),
+ F_GFX3D(400000000, pll2, 1, 2),
+ F_END
+};
+
static struct clk_freq_tbl clk_tbl_gfx3d_8960[] = {
F_GFX3D( 0, gnd, 0, 0),
F_GFX3D( 27000000, pxo, 0, 0),
@@ -3713,6 +3741,27 @@
.ns_val = NS_MND_BANKED8(22, 14, n, m, 3, 0, s##_to_mm_mux), \
.ctl_val = CC_BANKED(9, 6, n), \
}
+static struct clk_freq_tbl clk_tbl_mdp_8960ab[] = {
+ F_MDP( 0, gnd, 0, 0),
+ F_MDP( 9600000, pll8, 1, 40),
+ F_MDP( 13710000, pll8, 1, 28),
+ F_MDP( 27000000, pxo, 0, 0),
+ F_MDP( 29540000, pll8, 1, 13),
+ F_MDP( 34910000, pll8, 1, 11),
+ F_MDP( 38400000, pll8, 1, 10),
+ F_MDP( 59080000, pll8, 2, 13),
+ F_MDP( 76800000, pll8, 1, 5),
+ F_MDP( 85330000, pll8, 2, 9),
+ F_MDP( 96000000, pll8, 1, 4),
+ F_MDP(128000000, pll8, 1, 3),
+ F_MDP(160000000, pll2, 1, 5),
+ F_MDP(177780000, pll2, 2, 9),
+ F_MDP(200000000, pll2, 1, 4),
+ F_MDP(228571000, pll2, 2, 7),
+ F_MDP(266667000, pll2, 1, 3),
+ F_END
+};
+
static struct clk_freq_tbl clk_tbl_mdp[] = {
F_MDP( 0, gnd, 0, 0),
F_MDP( 9600000, pll8, 1, 40),
@@ -3912,11 +3961,6 @@
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
}
-static unsigned long hdmi_pll_clk_get_rate(struct clk *c)
-{
- return hdmi_pll_get_rate();
-}
-
static struct clk *hdmi_pll_clk_get_parent(struct clk *c)
{
return &pxo_clk.c;
@@ -3925,13 +3969,14 @@
static struct clk_ops clk_ops_hdmi_pll = {
.enable = hdmi_pll_clk_enable,
.disable = hdmi_pll_clk_disable,
- .get_rate = hdmi_pll_clk_get_rate,
.get_parent = hdmi_pll_clk_get_parent,
};
static struct clk hdmi_pll_clk = {
.dbg_name = "hdmi_pll_clk",
.ops = &clk_ops_hdmi_pll,
+ .vdd_class = &vdd_sr2_hdmi_pll,
+ .fmax[VDD_SR2_HDMI_PLL_ON] = ULONG_MAX,
CLK_INIT(hdmi_pll_clk),
};
@@ -3975,8 +4020,10 @@
void set_rate_tv(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
{
unsigned long pll_rate = (unsigned long)nf->extra_freq_data;
- if (pll_rate)
+ if (pll_rate) {
hdmi_pll_set_rate(pll_rate);
+ hdmi_pll_clk.rate = pll_rate;
+ }
set_rate_mnd(rcg, nf);
}
@@ -4338,7 +4385,23 @@
.md_val = MD8(8, m, 0, n), \
.ns_val = NS(31, 24, n, m, 5, 4, 3, d, 2, 0, s##_to_lpa_mux), \
}
-static struct clk_freq_tbl clk_tbl_aif_osr[] = {
+static struct clk_freq_tbl clk_tbl_aif_osr_492[] = {
+ F_AIF_OSR( 0, gnd, 1, 0, 0),
+ F_AIF_OSR( 512000, pll4, 4, 1, 240),
+ F_AIF_OSR( 768000, pll4, 4, 1, 160),
+ F_AIF_OSR( 1024000, pll4, 4, 1, 120),
+ F_AIF_OSR( 1536000, pll4, 4, 1, 80),
+ F_AIF_OSR( 2048000, pll4, 4, 1, 60),
+ F_AIF_OSR( 3072000, pll4, 4, 1, 40),
+ F_AIF_OSR( 4096000, pll4, 4, 1, 30),
+ F_AIF_OSR( 6144000, pll4, 4, 1, 20),
+ F_AIF_OSR( 8192000, pll4, 4, 1, 15),
+ F_AIF_OSR(12288000, pll4, 4, 1, 10),
+ F_AIF_OSR(24576000, pll4, 4, 1, 5),
+ F_END
+};
+
+static struct clk_freq_tbl clk_tbl_aif_osr_393[] = {
F_AIF_OSR( 0, gnd, 1, 0, 0),
F_AIF_OSR( 512000, pll4, 4, 1, 192),
F_AIF_OSR( 768000, pll4, 4, 1, 128),
@@ -4371,7 +4434,7 @@
.ns_mask = (BM(31, 24) | BM(6, 0)), \
.mnd_en_mask = BIT(8), \
.set_rate = set_rate_mnd, \
- .freq_tbl = clk_tbl_aif_osr, \
+ .freq_tbl = clk_tbl_aif_osr_393, \
.current_freq = &rcg_dummy_freq, \
.c = { \
.dbg_name = #i "_clk", \
@@ -4397,7 +4460,7 @@
.ns_mask = (BM(31, 24) | BM(6, 0)), \
.mnd_en_mask = BIT(8), \
.set_rate = set_rate_mnd, \
- .freq_tbl = clk_tbl_aif_osr, \
+ .freq_tbl = clk_tbl_aif_osr_393, \
.current_freq = &rcg_dummy_freq, \
.c = { \
.dbg_name = #i "_clk", \
@@ -4478,7 +4541,23 @@
.md_val = MD16(m, n), \
.ns_val = NS(31, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_lpa_mux), \
}
-static struct clk_freq_tbl clk_tbl_pcm[] = {
+static struct clk_freq_tbl clk_tbl_pcm_492[] = {
+ { .ns_val = BIT(10) /* external input */ },
+ F_PCM( 512000, pll4, 4, 1, 240),
+ F_PCM( 768000, pll4, 4, 1, 160),
+ F_PCM( 1024000, pll4, 4, 1, 120),
+ F_PCM( 1536000, pll4, 4, 1, 80),
+ F_PCM( 2048000, pll4, 4, 1, 60),
+ F_PCM( 3072000, pll4, 4, 1, 40),
+ F_PCM( 4096000, pll4, 4, 1, 30),
+ F_PCM( 6144000, pll4, 4, 1, 20),
+ F_PCM( 8192000, pll4, 4, 1, 15),
+ F_PCM(12288000, pll4, 4, 1, 10),
+ F_PCM(24576000, pll4, 4, 1, 5),
+ F_END
+};
+
+static struct clk_freq_tbl clk_tbl_pcm_393[] = {
{ .ns_val = BIT(10) /* external input */ },
F_PCM( 512000, pll4, 4, 1, 192),
F_PCM( 768000, pll4, 4, 1, 128),
@@ -4510,7 +4589,7 @@
.ns_mask = BM(31, 16) | BIT(10) | BM(6, 0),
.mnd_en_mask = BIT(8),
.set_rate = set_rate_mnd,
- .freq_tbl = clk_tbl_pcm,
+ .freq_tbl = clk_tbl_pcm_393,
.current_freq = &rcg_dummy_freq,
.c = {
.dbg_name = "pcm_clk",
@@ -4537,7 +4616,7 @@
.ns_mask = (BM(31, 24) | BM(6, 0)),
.mnd_en_mask = BIT(8),
.set_rate = set_rate_mnd,
- .freq_tbl = clk_tbl_aif_osr,
+ .freq_tbl = clk_tbl_aif_osr_393,
.current_freq = &rcg_dummy_freq,
.c = {
.dbg_name = "audio_slimbus_clk",
@@ -4823,7 +4902,7 @@
{ TEST_MM_HS(0x35), &vcap_axi_clk.c },
{ TEST_MM_HS(0x36), &rgb_tv_clk.c },
{ TEST_MM_HS(0x37), &npl_tv_clk.c },
- { TEST_MM_HS(0x38), &gfx3d_axi_clk_8064.c },
+ { TEST_MM_HS(0x38), &gfx3d_axi_clk.c },
{ TEST_LPA(0x0F), &mi2s_bit_clk.c },
{ TEST_LPA(0x10), &codec_i2s_mic_bit_clk.c },
@@ -5109,7 +5188,10 @@
CLK_LOOKUP("core_clk", sdc2_clk.c, "msm_sdcc.2"),
CLK_LOOKUP("core_clk", sdc3_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("core_clk", sdc4_clk.c, "msm_sdcc.4"),
- CLK_LOOKUP("ref_clk", tsif_ref_clk.c, ""),
+ CLK_LOOKUP("ref_clk", tsif_ref_clk.c, "msm_tsif.0"),
+ CLK_LOOKUP("iface_clk", tsif_p_clk.c, "msm_tsif.0"),
+ CLK_LOOKUP("ref_clk", tsif_ref_clk.c, "msm_tsif.1"),
+ CLK_LOOKUP("iface_clk", tsif_p_clk.c, "msm_tsif.1"),
CLK_LOOKUP("core_clk", tssc_clk.c, ""),
CLK_LOOKUP("alt_core_clk", usb_hs1_xcvr_clk.c, "msm_otg"),
CLK_LOOKUP("alt_core_clk", usb_hs3_xcvr_clk.c, "msm_ehci_host.0"),
@@ -5198,7 +5280,7 @@
CLK_LOOKUP("core_clk", gfx3d_clk.c, "kgsl-3d0.0"),
CLK_LOOKUP("core_clk", gfx3d_clk.c, "footswitch-8x60.2"),
CLK_LOOKUP("bus_clk",
- gfx3d_axi_clk_8064.c, "footswitch-8x60.2"),
+ gfx3d_axi_clk.c, "footswitch-8x60.2"),
CLK_LOOKUP("iface_clk", vcap_p_clk.c, ""),
CLK_LOOKUP("iface_clk", vcap_p_clk.c, "msm_vcap.0"),
CLK_LOOKUP("iface_clk", vcap_p_clk.c, "footswitch-8x60.10"),
@@ -5304,7 +5386,7 @@
CLK_LOOKUP("core_clk", vfe_axi_clk.c, ""),
CLK_LOOKUP("core_clk", vcodec_axi_a_clk.c, ""),
CLK_LOOKUP("core_clk", vcodec_axi_b_clk.c, ""),
- CLK_LOOKUP("core_clk", gfx3d_axi_clk_8064.c, ""),
+ CLK_LOOKUP("core_clk", gfx3d_axi_clk.c, ""),
CLK_LOOKUP("dfab_dsps_clk", dfab_dsps_clk.c, NULL),
CLK_LOOKUP("core_clk", dfab_usb_hs_clk.c, "msm_otg"),
@@ -5334,8 +5416,9 @@
CLK_LOOKUP("core_clk", vfe_axi_clk.c, "msm_iommu.6"),
CLK_LOOKUP("core_clk", vcodec_axi_a_clk.c, "msm_iommu.7"),
CLK_LOOKUP("core_clk", vcodec_axi_b_clk.c, "msm_iommu.8"),
- CLK_LOOKUP("core_clk", gfx3d_axi_clk_8064.c, "msm_iommu.9"),
- CLK_LOOKUP("core_clk", gfx3d_axi_clk_8064.c, "msm_iommu.10"),
+ CLK_LOOKUP("core_clk", gfx3d_axi_clk.c, "msm_iommu.9"),
+ CLK_LOOKUP("core_clk", gfx3d_axi_clk.c, "msm_iommu.10"),
+
CLK_LOOKUP("core_clk", vcap_axi_clk.c, "msm_iommu.11"),
CLK_LOOKUP("mdp_iommu_clk", mdp_axi_clk.c, "msm_vidc.0"),
@@ -5357,7 +5440,7 @@
CLK_LOOKUP("krait3_mclk", krait3_m_clk, ""),
};
-static struct clk_lookup msm_clocks_8960[] = {
+static struct clk_lookup msm_clocks_8960_common[] __initdata = {
CLK_LOOKUP("xo", cxo_a_clk.c, ""),
CLK_LOOKUP("xo", pxo_a_clk.c, ""),
CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
@@ -5425,7 +5508,10 @@
CLK_LOOKUP("core_clk", gsbi5_uart_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("core_clk", gsbi6_uart_clk.c, "msm_serial_hs.0"),
CLK_LOOKUP("core_clk", gsbi7_uart_clk.c, ""),
+ /* used on 8960 SGLTE for console */
CLK_LOOKUP("core_clk", gsbi8_uart_clk.c, "msm_serial_hsl.1"),
+ /* used on 8960 standalone with Atheros Bluetooth */
+ CLK_LOOKUP("core_clk", gsbi8_uart_clk.c, "msm_serial_hs.2"),
CLK_LOOKUP("core_clk", gsbi9_uart_clk.c, "msm_serial_hs.1"),
CLK_LOOKUP("core_clk", gsbi10_uart_clk.c, ""),
CLK_LOOKUP("core_clk", gsbi11_uart_clk.c, ""),
@@ -5477,7 +5563,10 @@
CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("iface_clk", gsbi6_p_clk.c, "msm_serial_hs.0"),
CLK_LOOKUP("iface_clk", gsbi7_p_clk.c, ""),
+ /* used on 8960 SGLTE for serial console */
CLK_LOOKUP("iface_clk", gsbi8_p_clk.c, "msm_serial_hsl.1"),
+ /* used on 8960 standalone with Atheros Bluetooth */
+ CLK_LOOKUP("iface_clk", gsbi8_p_clk.c, "msm_serial_hs.2"),
CLK_LOOKUP("iface_clk", gsbi9_p_clk.c, "msm_serial_hs.1"),
CLK_LOOKUP("iface_clk", gsbi10_p_clk.c, "qup_i2c.10"),
CLK_LOOKUP("iface_clk", gsbi11_p_clk.c, ""),
@@ -5536,10 +5625,6 @@
CLK_LOOKUP("byte_clk", dsi2_byte_clk.c, "mipi_dsi.2"),
CLK_LOOKUP("esc_clk", dsi1_esc_clk.c, "mipi_dsi.1"),
CLK_LOOKUP("esc_clk", dsi2_esc_clk.c, "mipi_dsi.2"),
- CLK_LOOKUP("core_clk", gfx2d0_clk.c, "kgsl-2d0.0"),
- CLK_LOOKUP("core_clk", gfx2d0_clk.c, "footswitch-8x60.0"),
- CLK_LOOKUP("core_clk", gfx2d1_clk.c, "kgsl-2d1.1"),
- CLK_LOOKUP("core_clk", gfx2d1_clk.c, "footswitch-8x60.1"),
CLK_LOOKUP("core_clk", gfx3d_clk.c, "kgsl-3d0.0"),
CLK_LOOKUP("core_clk", gfx3d_clk.c, "footswitch-8x60.2"),
CLK_LOOKUP("bus_clk", ijpeg_axi_clk.c, "footswitch-8x60.3"),
@@ -5559,8 +5644,6 @@
CLK_LOOKUP("src_clk", tv_src_clk.c, "dtv.0"),
CLK_LOOKUP("src_clk", tv_src_clk.c, "tvenc.0"),
CLK_LOOKUP("tv_src_clk", tv_src_clk.c, "footswitch-8x60.4"),
- CLK_LOOKUP("enc_clk", tv_enc_clk.c, "tvenc.0"),
- CLK_LOOKUP("dac_clk", tv_dac_clk.c, "tvenc.0"),
CLK_LOOKUP("core_clk", vcodec_clk.c, "msm_vidc.0"),
CLK_LOOKUP("core_clk", vcodec_clk.c, "footswitch-8x60.7"),
CLK_LOOKUP("mdp_clk", mdp_tv_clk.c, "dtv.0"),
@@ -5589,10 +5672,6 @@
CLK_LOOKUP("slave_iface_clk", dsi1_s_p_clk.c, "mipi_dsi.1"),
CLK_LOOKUP("master_iface_clk", dsi2_m_p_clk.c, "mipi_dsi.2"),
CLK_LOOKUP("slave_iface_clk", dsi2_s_p_clk.c, "mipi_dsi.2"),
- CLK_LOOKUP("iface_clk", gfx2d0_p_clk.c, "kgsl-2d0.0"),
- CLK_LOOKUP("iface_clk", gfx2d0_p_clk.c, "footswitch-8x60.0"),
- CLK_LOOKUP("iface_clk", gfx2d1_p_clk.c, "kgsl-2d1.1"),
- CLK_LOOKUP("iface_clk", gfx2d1_p_clk.c, "footswitch-8x60.1"),
CLK_LOOKUP("iface_clk", gfx3d_p_clk.c, "kgsl-3d0.0"),
CLK_LOOKUP("iface_clk", gfx3d_p_clk.c, "footswitch-8x60.2"),
CLK_LOOKUP("master_iface_clk", hdmi_m_p_clk.c, "hdmi_msm.1"),
@@ -5606,7 +5685,6 @@
CLK_LOOKUP("iface_clk", smmu_p_clk.c, "msm_iommu"),
CLK_LOOKUP("iface_clk", rot_p_clk.c, "msm_rotator.0"),
CLK_LOOKUP("iface_clk", rot_p_clk.c, "footswitch-8x60.6"),
- CLK_LOOKUP("iface_clk", tv_enc_p_clk.c, "tvenc.0"),
CLK_LOOKUP("iface_clk", vcodec_p_clk.c, "msm_vidc.0"),
CLK_LOOKUP("iface_clk", vcodec_p_clk.c, "footswitch-8x60.7"),
CLK_LOOKUP("vfe_pclk", vfe_p_clk.c, "msm_vfe.0"),
@@ -5647,8 +5725,6 @@
CLK_LOOKUP("core_clk", vcodec_axi_a_clk.c, "msm_iommu.7"),
CLK_LOOKUP("core_clk", vcodec_axi_b_clk.c, "msm_iommu.8"),
CLK_LOOKUP("core_clk", gfx3d_clk.c, "msm_iommu.9"),
- CLK_LOOKUP("core_clk", gfx2d0_clk.c, "msm_iommu.10"),
- CLK_LOOKUP("core_clk", gfx2d1_clk.c, "msm_iommu.11"),
CLK_LOOKUP("mdp_iommu_clk", mdp_axi_clk.c, "msm_vidc.0"),
CLK_LOOKUP("rot_iommu_clk", rot_axi_clk.c, "msm_vidc.0"),
@@ -5682,6 +5758,32 @@
CLK_LOOKUP("q6_func_clk", q6_func_clk, ""),
};
+static struct clk_lookup msm_clocks_8960_only[] __initdata = {
+ CLK_LOOKUP("enc_clk", tv_enc_clk.c, "tvenc.0"),
+ CLK_LOOKUP("dac_clk", tv_dac_clk.c, "tvenc.0"),
+ CLK_LOOKUP("iface_clk", tv_enc_p_clk.c, "tvenc.0"),
+
+ CLK_LOOKUP("core_clk", gfx2d0_clk.c, "kgsl-2d0.0"),
+ CLK_LOOKUP("core_clk", gfx2d0_clk.c, "footswitch-8x60.0"),
+ CLK_LOOKUP("core_clk", gfx2d1_clk.c, "kgsl-2d1.1"),
+ CLK_LOOKUP("core_clk", gfx2d1_clk.c, "footswitch-8x60.1"),
+ CLK_LOOKUP("iface_clk", gfx2d0_p_clk.c, "kgsl-2d0.0"),
+ CLK_LOOKUP("iface_clk", gfx2d0_p_clk.c, "footswitch-8x60.0"),
+ CLK_LOOKUP("iface_clk", gfx2d1_p_clk.c, "kgsl-2d1.1"),
+ CLK_LOOKUP("iface_clk", gfx2d1_p_clk.c, "footswitch-8x60.1"),
+ CLK_LOOKUP("core_clk", gfx2d0_clk.c, "msm_iommu.10"),
+ CLK_LOOKUP("core_clk", gfx2d1_clk.c, "msm_iommu.11"),
+};
+
+static struct clk_lookup msm_clocks_8960ab_only[] __initdata = {
+ CLK_LOOKUP("bus_clk", gfx3d_axi_clk.c, "footswitch-8x60.2"),
+ CLK_LOOKUP("div_clk", tv_src_div_clk.c, ""),
+};
+
+static struct clk_lookup msm_clocks_8960[ARRAY_SIZE(msm_clocks_8960_common)
+ + ARRAY_SIZE(msm_clocks_8960_only)
+ + ARRAY_SIZE(msm_clocks_8960ab_only)];
+
static struct clk_lookup msm_clocks_8930[] = {
CLK_LOOKUP("xo", cxo_clk.c, "msm_xo"),
CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
@@ -6001,7 +6103,7 @@
.mode_reg = LCC_PLL0_MODE_REG,
};
-static struct pll_config pll4_config __initdata = {
+static struct pll_config pll4_config_393 __initdata = {
.l = 0xE,
.m = 0x27A,
.n = 0x465,
@@ -6079,12 +6181,12 @@
*/
/*
* Initialize MM AHB registers: Enable the FPB clock and disable HW
- * gating on 8627 for all clocks. Also set VFE_AHB's
+ * gating on 8627 and 8960 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()) {
+ if (cpu_is_msm8627() || cpu_is_msm8960ab()) {
rmwreg(0x00000003, AHB_EN_REG, 0x6C000103);
writel_relaxed(0x000007F9, AHB_EN2_REG);
} else {
@@ -6102,7 +6204,7 @@
/* 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() &&
+ if (cpu_is_msm8960ab() || (cpu_is_msm8960() &&
SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 3) ||
cpu_is_msm8627()) {
rmwreg(0x000007F9, MAXI_EN_REG, 0x0803FFFF);
@@ -6119,8 +6221,13 @@
rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627())
rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
+ if (cpu_is_msm8960ab())
+ rmwreg(0x009FE000, MAXI_EN5_REG, 0x01FFE000);
+
if (cpu_is_msm8627())
rmwreg(0x000003C7, SAXI_EN_REG, 0x00003FFF);
+ else if (cpu_is_msm8960ab())
+ rmwreg(0x000001C6, SAXI_EN_REG, 0x00001DF6);
else
rmwreg(0x00003C38, SAXI_EN_REG, 0x00003FFF);
@@ -6148,14 +6255,19 @@
rmwreg(0x80FF0000, VFE_CC_REG, 0xE0FF4010);
rmwreg(0x800000FF, VFE_CC2_REG, 0xE00000FF);
rmwreg(0x80FF0000, VPE_CC_REG, 0xE0FF0010);
- if (cpu_is_msm8960() || cpu_is_apq8064()) {
+ if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_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())
- rmwreg(0x80FF0000, TV_CC_REG, 0xE1FFC010);
+ rmwreg(0x80FF0000, TV_CC_REG, 0xE1FFC010);
+ if (cpu_is_msm8960ab())
+ rmwreg(0x00000000, TV_CC_REG, 0x00004010);
if (cpu_is_msm8960()) {
rmwreg(0x80FF0000, GFX2D0_CC_REG, 0xE0FF0010);
@@ -6189,12 +6301,12 @@
writel_relaxed(BIT(15), PDM_CLK_NS_REG);
/* Source SLIMBus xo src from slimbus reference clock */
- if (cpu_is_msm8960())
+ 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 */
rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
- if (cpu_is_msm8960() || cpu_is_apq8064())
+ if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_apq8064())
rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
/* Source the dsi1_esc_clk from the DSI1 PHY PLLs */
@@ -6232,7 +6344,7 @@
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_pll(&pll4_config, &pll4_regs, 1);
+ configure_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);
@@ -6256,15 +6368,54 @@
}
}
+struct clock_init_data msm8960_clock_init_data __initdata;
static void __init msm8960_clock_pre_init(void)
{
+ /* Initialize clock registers. */
+ reg_init();
+
if (cpu_is_apq8064()) {
- vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8064;
+ vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
} else if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
vdd_dig.set_vdd = set_vdd_dig_8930;
- vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8930;
+ vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_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;
+ }
+
+ if (cpu_is_msm8960() || cpu_is_msm8960ab())
+ memcpy(msm_clocks_8960, msm_clocks_8960_common,
+ sizeof(msm_clocks_8960_common));
+ if (cpu_is_msm8960ab()) {
+ pll3_clk.c.rate = 650000000;
+ gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8960ab;
+ gfx3d_clk.c.fmax[VDD_DIG_LOW] = 192000000;
+ gfx3d_clk.c.fmax[VDD_DIG_NOMINAL] = 325000000;
+ gfx3d_clk.c.fmax[VDD_DIG_HIGH] = 400000000;
+ mdp_clk.freq_tbl = clk_tbl_mdp_8960ab;
+ mdp_clk.c.fmax[VDD_DIG_LOW] = 128000000;
+ mdp_clk.c.fmax[VDD_DIG_NOMINAL] = 266667000;
+
+ 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);
+ } else if (cpu_is_msm8960()) {
+ memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
+ msm_clocks_8960_only, 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 8960 and 8064.
@@ -6283,7 +6434,7 @@
memcpy(vfe_clk.c.fmax, fmax_vfe_8064,
sizeof(vfe_clk.c.fmax));
- gmem_axi_clk.c.depends = &gfx3d_axi_clk_8064.c;
+ gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
}
/*
@@ -6305,9 +6456,6 @@
vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
clk_ops_local_pll.enable = sr_pll_clk_enable;
-
- /* Initialize clock registers. */
- reg_init();
}
static void __init msm8960_clock_post_init(void)
@@ -6335,8 +6483,8 @@
clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
}
clk_set_rate(&usb_fs1_src_clk.c, 60000000);
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_msm8627())
+ if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_msm8930() ||
+ cpu_is_msm8930aa() || cpu_is_msm8627())
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);
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 6c9a566..5124bd5 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -593,10 +593,12 @@
#define RPM_MEM_CLK_TYPE 0x326b6c63
#define CXO_ID 0x0
+#define QDSS_ID 0x1
#define PNOC_ID 0x0
#define SNOC_ID 0x1
#define CNOC_ID 0x2
+#define MMSSNOC_AHB_ID 0x4
#define BIMC_ID 0x0
#define OCMEM_ID 0x1
@@ -604,6 +606,8 @@
DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
DEFINE_CLK_RPM_SMD(cnoc_clk, cnoc_a_clk, RPM_BUS_CLK_TYPE, CNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, RPM_BUS_CLK_TYPE,
+ MMSSNOC_AHB_ID, NULL);
DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
DEFINE_CLK_RPM_SMD(ocmemgx_clk, ocmemgx_a_clk, RPM_MEM_CLK_TYPE, OCMEM_ID,
@@ -611,10 +615,10 @@
DEFINE_CLK_RPM_SMD_BRANCH(cxo_clk_src, cxo_a_clk_src,
RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID);
static struct pll_vote_clk gpll0_clk_src = {
.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE_REG,
- .en_mask = BIT(0),
.status_reg = (void __iomem *)GPLL0_STATUS_REG,
.status_mask = BIT(17),
.parent = &cxo_clk_src.c,
@@ -2111,6 +2115,7 @@
static struct branch_clk gcc_usb30_master_clk = {
.cbcr_reg = USB30_MASTER_CBCR,
+ .bcr_reg = USB_30_BCR,
.parent = &usb30_master_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[GCC_BASE],
@@ -2145,6 +2150,7 @@
static struct branch_clk gcc_usb_hs_system_clk = {
.cbcr_reg = USB_HS_SYSTEM_CBCR,
+ .bcr_reg = USB_HS_BCR,
.parent = &usb_hs_system_clk_src.c,
.base = &virt_bases[GCC_BASE],
.c = {
@@ -2167,6 +2173,7 @@
static struct branch_clk gcc_usb_hsic_clk = {
.cbcr_reg = USB_HSIC_CBCR,
+ .bcr_reg = USB_HS_HSIC_BCR,
.parent = &usb_hsic_clk_src.c,
.base = &virt_bases[GCC_BASE],
.c = {
@@ -3963,6 +3970,20 @@
},
};
+struct rcg_clk audio_core_lpaif_pcmoe_clk_src = {
+ .cmd_rcgr_reg = LPAIF_PCMOE_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_audio_core_lpaif_clock,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "audio_core_lpaif_pcmoe_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP1(LOW, 12290000),
+ CLK_INIT(audio_core_lpaif_pcmoe_clk_src.c),
+ },
+};
+
static struct branch_clk audio_core_lpaif_codec_spkr_osr_clk = {
.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR,
.parent = &audio_core_lpaif_codec_spkr_clk_src.c,
@@ -4190,6 +4211,17 @@
},
};
+struct branch_clk audio_core_lpaif_pcmoe_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR,
+ .parent = &audio_core_lpaif_pcmoe_clk_src.c,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "audio_core_lpaif_pcmoe_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_pcmoe_clk.c),
+ },
+};
+
static struct branch_clk q6ss_ahb_lfabif_clk = {
.cbcr_reg = LPASS_Q6SS_AHB_LFABIF_CBCR,
.has_sibling = 1,
@@ -4386,6 +4418,7 @@
{&audio_core_lpaif_quad_clk_src.c, LPASS_BASE, 0x0014},
{&audio_core_lpaif_pcm0_clk_src.c, LPASS_BASE, 0x0013},
{&audio_core_lpaif_pcm1_clk_src.c, LPASS_BASE, 0x0012},
+ {&audio_core_lpaif_pcmoe_clk_src.c, LPASS_BASE, 0x000f},
{&audio_core_slimbus_core_clk.c, LPASS_BASE, 0x003d},
{&audio_core_slimbus_lfabif_clk.c, LPASS_BASE, 0x003e},
{&q6ss_xo_clk.c, LPASS_BASE, 0x002b},
@@ -4789,6 +4822,8 @@
CLK_LOOKUP("core_clk", audio_core_lpaif_pcm1_clk_src.c, ""),
CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
+ CLK_LOOKUP("core_clk_src", audio_core_lpaif_pcmoe_clk_src.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_pcmoe_clk.c, ""),
CLK_LOOKUP("core_clk", mss_xo_q6_clk.c, "pil-q6v5-mss"),
CLK_LOOKUP("bus_clk", mss_bus_q6_clk.c, "pil-q6v5-mss"),
@@ -4830,6 +4865,36 @@
CLK_LOOKUP("bus_a_clk", ocmemnoc_clk.c, "msm_ocmem_noc"),
CLK_LOOKUP("bus_clk", mmss_mmssnoc_axi_clk.c, "msm_mmss_noc"),
CLK_LOOKUP("bus_a_clk", mmss_mmssnoc_axi_clk.c, "msm_mmss_noc"),
+
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etr"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tpiu"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-replicator"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etf"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-merg"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in0"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in1"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-kpss"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-mmss"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-stm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm0"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm1"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm2"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm3"),
+
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etr"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tpiu"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-replicator"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etf"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-merg"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in0"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in1"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-kpss"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-mmss"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-stm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm0"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm1"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm2"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm3"),
};
static struct pll_config_regs gpll0_regs __initdata = {
@@ -4986,7 +5051,7 @@
.main_output_mask = BIT(0),
};
-#define PLL_AUX_OUTPUT BIT(1)
+#define PLL_AUX_OUTPUT_BIT 1
static void __init reg_init(void)
{
@@ -5007,7 +5072,7 @@
/* Active GPLL0's aux output. This is needed by acpuclock. */
regval = readl_relaxed(GCC_REG_BASE(GPLL0_USER_CTL_REG));
- regval |= BIT(PLL_AUX_OUTPUT);
+ regval |= BIT(PLL_AUX_OUTPUT_BIT);
writel_relaxed(regval, GCC_REG_BASE(GPLL0_USER_CTL_REG));
/* Vote for GPLL0 to turn on. Needed by acpuclock. */
@@ -5028,6 +5093,13 @@
clk_set_rate(&ocmemnoc_clk_src.c, 333330000);
/*
+ * Hold an active set vote at a rate of 40MHz for the MMSS NOC AHB
+ * source. Sleep set vote is 0.
+ */
+ clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
+ clk_prepare_enable(&mmssnoc_ahb_a_clk.c);
+
+ /*
* Hold an active set vote for CXO; this is because CXO is expected
* to remain on whenever CPUs aren't power collapsed.
*/
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 4493ddc..1769f07 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3522,6 +3522,7 @@
CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("smi_clk", smi_clk.c, "msm_bus"),
CLK_LOOKUP("smi_a_clk", smi_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("mmfpb_a_clk", mmfpb_a_clk.c, "clock-8x60"),
CLK_LOOKUP("core_clk", gp0_clk.c, ""),
CLK_LOOKUP("core_clk", gp1_clk.c, ""),
@@ -3873,7 +3874,7 @@
int rc;
/* Vote for MMFPB to be at least 64MHz when an Apps CPU is active. */
- struct clk *mmfpb_a_clk = clk_get(NULL, "mmfpb_a_clk");
+ struct clk *mmfpb_a_clk = clk_get_sys("clock-8x60", "mmfpb_a_clk");
if (WARN(IS_ERR(mmfpb_a_clk), "mmfpb_a_clk not found (%ld)\n",
PTR_ERR(mmfpb_a_clk)))
return PTR_ERR(mmfpb_a_clk);
diff --git a/arch/arm/mach-msm/clock-dss-8960.c b/arch/arm/mach-msm/clock-dss-8960.c
index 4e17b29..ca1a3e1 100644
--- a/arch/arm/mach-msm/clock-dss-8960.c
+++ b/arch/arm/mach-msm/clock-dss-8960.c
@@ -90,7 +90,6 @@
#define PLL_PWRDN_B BIT(3)
#define PD_PLL BIT(1)
-static unsigned current_rate;
static unsigned hdmi_pll_on;
int hdmi_pll_enable(void)
@@ -219,11 +218,6 @@
hdmi_pll_on = 0;
}
-unsigned hdmi_pll_get_rate(void)
-{
- return current_rate;
-}
-
int hdmi_pll_set_rate(unsigned rate)
{
unsigned int set_power_dwn = 0;
@@ -378,7 +372,6 @@
if (set_power_dwn)
hdmi_pll_enable();
- current_rate = rate;
if (!ahb_enabled)
writel_relaxed(ahb_en_reg & ~BIT(4), AHB_EN_REG);
diff --git a/arch/arm/mach-msm/clock-dss-8960.h b/arch/arm/mach-msm/clock-dss-8960.h
index 4734cde..72e70fc 100644
--- a/arch/arm/mach-msm/clock-dss-8960.h
+++ b/arch/arm/mach-msm/clock-dss-8960.h
@@ -15,7 +15,6 @@
int hdmi_pll_enable(void);
void hdmi_pll_disable(void);
-unsigned hdmi_pll_get_rate(void);
int hdmi_pll_set_rate(unsigned rate);
#endif
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index 8096c10..207dbef 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -54,15 +54,11 @@
return (rc < 0) ? rc : iv.value * r->factor;
}
-#define RPM_SMD_KEY_RATE 0x007A484B
-#define RPM_SMD_KEY_ENABLE 0x62616E45
-
static int clk_rpmrs_set_rate_smd(struct rpm_clk *r, uint32_t value,
uint32_t context, int noirq)
{
- u32 rpm_key = r->branch ? RPM_SMD_KEY_ENABLE : RPM_SMD_KEY_RATE;
struct msm_rpm_kvp kvp = {
- .key = rpm_key,
+ .key = r->rpm_key,
.data = (void *)&value,
.length = sizeof(value),
};
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index ce878ce..22691c5 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -17,6 +17,10 @@
#include <mach/rpm.h>
#include <mach/rpm-smd.h>
+#define RPM_SMD_KEY_RATE 0x007A484B
+#define RPM_SMD_KEY_ENABLE 0x62616E45
+#define RPM_SMD_KEY_STATE 0x54415453
+
struct clk_ops;
struct clk_rpmrs_data;
extern struct clk_ops clk_ops_rpm;
@@ -24,6 +28,7 @@
struct rpm_clk {
const int rpm_res_type;
+ const int rpm_key;
const int rpm_clk_id;
const int rpm_status_id;
const bool active_only;
@@ -47,12 +52,14 @@
extern struct clk_rpmrs_data clk_rpmrs_data;
extern struct clk_rpmrs_data clk_rpmrs_data_smd;
-#define __DEFINE_CLK_RPM(name, active, type, r_id, stat_id, dep, rpmrsdata) \
+#define __DEFINE_CLK_RPM(name, active, type, r_id, stat_id, dep, key, \
+ rpmrsdata) \
static struct rpm_clk active; \
static struct rpm_clk name = { \
.rpm_res_type = (type), \
.rpm_clk_id = (r_id), \
.rpm_status_id = (stat_id), \
+ .rpm_key = (key), \
.peer = &active, \
.factor = 1000, \
.rpmrs_data = (rpmrsdata),\
@@ -67,6 +74,7 @@
.rpm_res_type = (type), \
.rpm_clk_id = (r_id), \
.rpm_status_id = (stat_id), \
+ .rpm_key = (key), \
.peer = &name, \
.active_only = true, \
.factor = 1000, \
@@ -80,12 +88,13 @@
};
#define __DEFINE_CLK_RPM_BRANCH(name, active, type, r_id, stat_id, r, \
- rpmrsdata) \
+ key, rpmrsdata) \
static struct rpm_clk active; \
static struct rpm_clk name = { \
.rpm_res_type = (type), \
.rpm_clk_id = (r_id), \
.rpm_status_id = (stat_id), \
+ .rpm_key = (key), \
.peer = &active, \
.last_set_khz = ((r) / 1000), \
.last_set_sleep_khz = ((r) / 1000), \
@@ -104,6 +113,7 @@
.rpm_res_type = (type), \
.rpm_clk_id = (r_id), \
.rpm_status_id = (stat_id), \
+ .rpm_key = (key), \
.peer = &name, \
.last_set_khz = ((r) / 1000), \
.active_only = true, \
@@ -119,12 +129,14 @@
}, \
};
-#define __DEFINE_CLK_RPM_QDSS(name, active, type, r_id, stat_id, rpmrsdata) \
+#define __DEFINE_CLK_RPM_QDSS(name, active, type, r_id, stat_id, \
+ key, rpmrsdata) \
static struct rpm_clk active; \
static struct rpm_clk name = { \
.rpm_res_type = (type), \
.rpm_clk_id = (r_id), \
.rpm_status_id = (stat_id), \
+ .rpm_key = (key), \
.peer = &active, \
.factor = 1, \
.rpmrs_data = (rpmrsdata),\
@@ -139,6 +151,7 @@
.rpm_res_type = (type), \
.rpm_clk_id = (r_id), \
.rpm_status_id = (stat_id), \
+ .rpm_key = (key), \
.peer = &name, \
.active_only = true, \
.factor = 1, \
@@ -153,21 +166,26 @@
#define DEFINE_CLK_RPM(name, active, r_id, dep) \
__DEFINE_CLK_RPM(name, active, 0, MSM_RPM_ID_##r_id##_CLK, \
- MSM_RPM_STATUS_ID_##r_id##_CLK, dep, &clk_rpmrs_data)
+ MSM_RPM_STATUS_ID_##r_id##_CLK, dep, 0, &clk_rpmrs_data)
#define DEFINE_CLK_RPM_QDSS(name, active) \
__DEFINE_CLK_RPM_QDSS(name, active, 0, MSM_RPM_ID_QDSS_CLK, \
- MSM_RPM_STATUS_ID_QDSS_CLK, &clk_rpmrs_data)
+ MSM_RPM_STATUS_ID_QDSS_CLK, 0, &clk_rpmrs_data)
#define DEFINE_CLK_RPM_BRANCH(name, active, r_id, r) \
__DEFINE_CLK_RPM_BRANCH(name, active, 0, MSM_RPM_ID_##r_id##_CLK, \
- MSM_RPM_STATUS_ID_##r_id##_CLK, r, &clk_rpmrs_data)
+ MSM_RPM_STATUS_ID_##r_id##_CLK, r, 0, &clk_rpmrs_data)
#define DEFINE_CLK_RPM_SMD(name, active, type, r_id, dep) \
- __DEFINE_CLK_RPM(name, active, type, r_id, 0, dep, &clk_rpmrs_data_smd)
+ __DEFINE_CLK_RPM(name, active, type, r_id, 0, dep, \
+ RPM_SMD_KEY_RATE, &clk_rpmrs_data_smd)
-#define DEFINE_CLK_RPM_SMD_BRANCH(name, active, type, r_id, dep) \
- __DEFINE_CLK_RPM_BRANCH(name, active, type, r_id, 0, dep, \
- &clk_rpmrs_data_smd)
+#define DEFINE_CLK_RPM_SMD_BRANCH(name, active, type, r_id, r) \
+ __DEFINE_CLK_RPM_BRANCH(name, active, type, r_id, 0, r, \
+ RPM_SMD_KEY_ENABLE, &clk_rpmrs_data_smd)
+
+#define DEFINE_CLK_RPM_SMD_QDSS(name, active, type, r_id) \
+ __DEFINE_CLK_RPM_QDSS(name, active, type, r_id, \
+ 0, RPM_SMD_KEY_STATE, &clk_rpmrs_data_smd)
#endif
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 56d3c6f..df2aa4e 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -181,7 +181,7 @@
int clock_debug_add(struct clk *clock);
void clock_debug_print_enabled(void);
#else
-static inline int clock_debug_init(struct clk_init_data *data) { return 0; }
+static inline int clock_debug_init(struct clock_init_data *data) { return 0; }
static inline int clock_debug_add(struct clk *clock) { return 0; }
static inline void clock_debug_print_enabled(void) { return; }
#endif
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 8a41a7c..aa67690 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -852,6 +852,11 @@
},
};
+struct platform_device apq8064_device_acpuclk = {
+ .name = "acpuclk-8064",
+ .id = -1,
+};
+
#define SHARED_IMEM_TZ_BASE 0x2a03f720
static struct resource tzlog_resources[] = {
{
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index a36e7d7..1f954c8 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -355,6 +355,16 @@
.id = MSM_BUS_FAB_CPSS_FPB,
};
+struct platform_device msm8627_device_acpuclk = {
+ .name = "acpuclk-8627",
+ .id = -1,
+};
+
+struct platform_device msm8930_device_acpuclk = {
+ .name = "acpuclk-8930",
+ .id = -1,
+};
+
static struct fs_driver_data gfx3d_fs_data = {
.clks = (struct fs_clk_data[]){
{ .name = "core_clk", .reset_rate = 27000000 },
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 7d93fe7..9a0c2d7 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -19,7 +19,7 @@
#include <linux/gpio.h>
#include <linux/coresight.h>
#include <asm/clkdev.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
#include <linux/android_pmem.h>
#include <mach/irqs-8960.h>
#include <mach/dma.h>
@@ -292,6 +292,52 @@
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
+
+/* GSBI 8 used into UARTDM Mode */
+static struct resource msm_uart_dm8_resources[] = {
+ {
+ .start = MSM_UART8DM_PHYS,
+ .end = MSM_UART8DM_PHYS + PAGE_SIZE - 1,
+ .name = "uartdm_resource",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = GSBI8_UARTDM_IRQ,
+ .end = GSBI8_UARTDM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM_GSBI8_PHYS,
+ .end = MSM_GSBI8_PHYS + 4 - 1,
+ .name = "gsbi_resource",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = DMOV_HSUART_GSBI8_TX_CHAN,
+ .end = DMOV_HSUART_GSBI8_RX_CHAN,
+ .name = "uartdm_channels",
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .start = DMOV_HSUART_GSBI8_TX_CRCI,
+ .end = DMOV_HSUART_GSBI8_RX_CRCI,
+ .name = "uartdm_crci",
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static u64 msm_uart_dm8_dma_mask = DMA_BIT_MASK(32);
+struct platform_device msm_device_uart_dm8 = {
+ .name = "msm_serial_hs",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(msm_uart_dm8_resources),
+ .resource = msm_uart_dm8_resources,
+ .dev = {
+ .dma_mask = &msm_uart_dm8_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
/*
* GSBI 9 used into UARTDM Mode
* For 8960 Fusion 2.2 Primary IPC
@@ -3812,6 +3858,7 @@
#define AP2MDM_PMIC_PWR_EN 22
#define AP2MDM_KPDPWR_N 79
#define AP2MDM_SOFT_RESET 78
+#define USB_SW 25
static struct resource sglte_resources[] = {
{
@@ -3856,6 +3903,12 @@
.name = "AP2MDM_SOFT_RESET",
.flags = IORESOURCE_IO,
},
+ {
+ .start = USB_SW,
+ .end = USB_SW,
+ .name = "USB_SW",
+ .flags = IORESOURCE_IO,
+ },
};
struct platform_device mdm_sglte_device = {
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index 1432902..ae8a8fe 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -1011,7 +1011,7 @@
ARRAY_SIZE(msm_iommu_gfx2d_devs));
}
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
platform_add_devices(msm_iommu_jpegd_devs,
ARRAY_SIZE(msm_iommu_jpegd_devs));
platform_add_devices(msm_iommu_8064_devs,
@@ -1030,7 +1030,7 @@
ARRAY_SIZE(msm_iommu_gfx2d_ctx_devs));
}
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
platform_add_devices(msm_iommu_jpegd_ctx_devs,
ARRAY_SIZE(msm_iommu_jpegd_ctx_devs));
platform_add_devices(msm_iommu_8064_ctx_devs,
@@ -1069,7 +1069,7 @@
platform_device_unregister(msm_iommu_jpegd_devs[i]);
}
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
for (i = 0; i < ARRAY_SIZE(msm_iommu_8064_ctx_devs); i++)
platform_device_unregister(msm_iommu_8064_ctx_devs[i]);
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index 4619cca..69d7430 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -15,7 +15,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
#include <linux/regulator/machine.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index c159926..8912e96 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -13,7 +13,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
#include <linux/regulator/machine.h>
#include <linux/init.h>
#include <linux/irq.h>
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 4b02f7a..f04ef9d 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -17,7 +17,7 @@
#include <linux/platform_device.h>
#include <linux/msm_rotator.h>
#include <linux/dma-mapping.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
#include <linux/android_pmem.h>
#include <linux/regulator/machine.h>
#include <linux/init.h>
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 2ced412..3920abe 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -20,7 +20,7 @@
#include <mach/dma.h>
#include <asm/mach/mmc.h>
#include <asm/clkdev.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
#include <linux/msm_rotator.h>
#include <mach/msm_hsusb.h>
#include "footswitch.h"
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index 2ecc852..ec4a14f 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -15,7 +15,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
-#include <linux/msm_kgsl.h>
+#include <mach/kgsl.h>
#include <linux/dma-mapping.h>
#include <asm/clkdev.h>
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 045dfb9..daf70a8 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -53,6 +53,7 @@
extern struct platform_device msm_device_uart_dm12;
extern struct platform_device *msm_device_uart_gsbi9;
extern struct platform_device msm_device_uart_dm6;
+extern struct platform_device msm_device_uart_dm8;
extern struct platform_device msm_device_uart_dm9;
extern struct platform_device msm8960_device_uart_gsbi2;
@@ -419,8 +420,11 @@
extern struct platform_device msm7x27a_device_acpuclk;
extern struct platform_device msm7x27aa_device_acpuclk;
extern struct platform_device msm7x30_device_acpuclk;
+extern struct platform_device apq8064_device_acpuclk;
extern struct platform_device msm8625_device_acpuclk;
+extern struct platform_device msm8627_device_acpuclk;
extern struct platform_device msm8x50_device_acpuclk;
extern struct platform_device msm8x60_device_acpuclk;
+extern struct platform_device msm8930_device_acpuclk;
extern struct platform_device msm8960_device_acpuclk;
extern struct platform_device msm9615_device_acpuclk;
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index e5dca00..12f5aa9 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -356,7 +356,7 @@
}
if (!dmov_conf[adm].channel_active) {
dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
- schedule_delayed_work(&dmov_conf[adm].work, HZ);
+ schedule_delayed_work(&dmov_conf[adm].work, (HZ/10));
}
spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
error:
@@ -573,7 +573,7 @@
if (!dmov_conf[adm].channel_active && valid) {
disable_irq_nosync(dmov_conf[adm].irq);
dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
- schedule_delayed_work(&dmov_conf[adm].work, HZ);
+ schedule_delayed_work(&dmov_conf[adm].work, (HZ/10));
}
mutex_unlock(&dmov_conf[adm].lock);
diff --git a/arch/arm/mach-msm/gss-8064.c b/arch/arm/mach-msm/gss-8064.c
index b9b877a..e528650 100644
--- a/arch/arm/mach-msm/gss-8064.c
+++ b/arch/arm/mach-msm/gss-8064.c
@@ -43,6 +43,8 @@
static int crash_shutdown;
+static struct subsys_device *gss_8064_dev;
+
#define MAX_SSR_REASON_LEN 81U
static void log_gss_sfr(void)
@@ -72,7 +74,7 @@
static void restart_gss(void)
{
log_gss_sfr();
- subsystem_restart("gss");
+ subsystem_restart_dev(gss_8064_dev);
}
static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
@@ -91,7 +93,7 @@
#define Q6_FW_WDOG_ENABLE 0x08882024
#define Q6_SW_WDOG_ENABLE 0x08982024
-static int gss_shutdown(const struct subsys_data *subsys)
+static int gss_shutdown(const struct subsys_desc *desc)
{
pil_force_shutdown("gss");
disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
@@ -99,14 +101,14 @@
return 0;
}
-static int gss_powerup(const struct subsys_data *subsys)
+static int gss_powerup(const struct subsys_desc *desc)
{
pil_force_boot("gss");
enable_irq(GSS_A5_WDOG_EXPIRED);
return 0;
}
-void gss_crash_shutdown(const struct subsys_data *subsys)
+void gss_crash_shutdown(const struct subsys_desc *desc)
{
crash_shutdown = 1;
smsm_reset_modem(SMSM_RESET);
@@ -122,7 +124,7 @@
};
static int gss_ramdump(int enable,
- const struct subsys_data *crashed_subsys)
+ const struct subsys_desc *crashed_subsys)
{
int ret = 0;
@@ -157,7 +159,7 @@
return IRQ_HANDLED;
}
-static struct subsys_data gss_8064 = {
+static struct subsys_desc gss_8064 = {
.name = "gss",
.shutdown = gss_shutdown,
.powerup = gss_powerup,
@@ -167,7 +169,10 @@
static int gss_subsystem_restart_init(void)
{
- return ssr_register_subsystem(&gss_8064);
+ gss_8064_dev = subsys_register(&gss_8064);
+ if (IS_ERR(gss_8064_dev))
+ return PTR_ERR(gss_8064_dev);
+ return 0;
}
static int gss_open(struct inode *inode, struct file *filep)
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 8607177..f21d296 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -201,8 +201,8 @@
};
struct msm_camera_csi_lane_params {
- uint8_t csi_lane_assign;
- uint8_t csi_lane_mask;
+ uint16_t csi_lane_assign;
+ uint16_t csi_lane_mask;
};
struct msm_camera_gpio_conf {
@@ -475,6 +475,7 @@
struct msm_fb_platform_data {
int (*detect_client)(const char *name);
int mddi_prescan;
+ unsigned char ext_resolution;
int (*allow_set_offset)(void);
char prim_panel_name[PANEL_NAME_MAX_LEN];
char ext_panel_name[PANEL_NAME_MAX_LEN];
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 4d66d88..43d707e 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -135,14 +135,16 @@
struct msm_camera_csid_params {
uint8_t lane_cnt;
- uint8_t lane_assign;
+ uint16_t lane_assign;
+ uint8_t phy_sel;
struct msm_camera_csid_lut_params lut_params;
};
struct msm_camera_csiphy_params {
uint8_t lane_cnt;
uint8_t settle_cnt;
- uint8_t lane_mask;
+ uint16_t lane_mask;
+ uint8_t combo_mode;
};
struct msm_camera_csi2_params {
@@ -565,6 +567,7 @@
S_STEREO_VIDEO,
S_STEREO_CAPTURE,
S_DEFAULT,
+ S_LIVESHOT,
S_EXIT
};
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index ba621e6..6a389de 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -188,6 +188,12 @@
#define DMOV_HSUART_GSBI6_RX_CHAN 8
#define DMOV_HSUART_GSBI6_RX_CRCI 11
+#define DMOV_HSUART_GSBI8_TX_CHAN 7
+#define DMOV_HSUART_GSBI8_TX_CRCI 10
+
+#define DMOV_HSUART_GSBI8_RX_CHAN 8
+#define DMOV_HSUART_GSBI8_RX_CRCI 9
+
#define DMOV_HSUART_GSBI9_TX_CHAN 4
#define DMOV_HSUART_GSBI9_TX_CRCI 13
@@ -263,6 +269,9 @@
#define DMOV8064_CE_OUT_CHAN 1
#define DMOV8064_CE_OUT_CRCI 15
+#define DMOV8064_TSIF_CHAN 2
+#define DMOV8064_TSIF_CRCI 1
+
/* no client rate control ifc (eg, ram) */
#define DMOV_NONE_CRCI 0
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 4bfbe61..28c53db 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -35,6 +35,9 @@
*/
#define MAX_NUM_MIDS 32
+/* Maximum number of SMT entries allowed by the system */
+#define MAX_NUM_SMR 128
+
/**
* struct msm_iommu_dev - a single IOMMU hardware instance
* name Human-readable name given to this IOMMU HW instance
@@ -69,6 +72,9 @@
* @irq: Interrupt number
* @clk: The bus clock for this IOMMU hardware instance
* @pclk: The clock for the IOMMU bus interconnect
+ * @name: Human-readable name of this IOMMU device
+ * @gdsc: Regulator needed to power this HW block (v2 only)
+ * @nsmr: Size of the SMT on this HW block (v2 only)
*
* A msm_iommu_drvdata holds the global driver data about a single piece
* of an IOMMU hardware instance.
@@ -81,6 +87,7 @@
struct clk *pclk;
const char *name;
struct regulator *gdsc;
+ unsigned int nsmr;
};
/**
@@ -89,6 +96,10 @@
* @pdev: Platform device associated wit this HW instance
* @attached_elm: List element for domains to track which devices are
* attached to them
+ * @attached_domain Domain currently attached to this context (if any)
+ * @name Human-readable name of this context device
+ * @sids List of Stream IDs mapped to this context (v2 only)
+ * @nsid Number of Stream IDs mapped to this context (v2 only)
*
* A msm_iommu_ctx_drvdata holds the driver data for a single context bank
* within each IOMMU hardware instance
@@ -99,6 +110,8 @@
struct list_head attached_elm;
struct iommu_domain *attached_domain;
const char *name;
+ u32 sids[MAX_NUM_SMR];
+ unsigned int nsid;
};
/*
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v2.h b/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
index fac13b3..b01dbd8 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
@@ -16,8 +16,6 @@
#define CTX_SHIFT 12
#define CTX_OFFSET 0x8000
-#define MAX_NUM_SMR 128
-
#define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
#define GET_CTX_REG(reg, base, ctx) \
(readl_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
new file mode 100644
index 0000000..a51cc46
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/kgsl.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This 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_KGSL_H
+#define _ARCH_ARM_MACH_KGSL_H
+
+/* Clock flags to show which clocks should be controled by a given platform */
+#define KGSL_CLK_SRC 0x00000001
+#define KGSL_CLK_CORE 0x00000002
+#define KGSL_CLK_IFACE 0x00000004
+#define KGSL_CLK_MEM 0x00000008
+#define KGSL_CLK_MEM_IFACE 0x00000010
+#define KGSL_CLK_AXI 0x00000020
+
+#define KGSL_MAX_PWRLEVELS 5
+
+#define KGSL_CONVERT_TO_MBPS(val) \
+ (val*1000*1000U)
+
+#define KGSL_3D0_REG_MEMORY "kgsl_3d0_reg_memory"
+#define KGSL_3D0_IRQ "kgsl_3d0_irq"
+#define KGSL_2D0_REG_MEMORY "kgsl_2d0_reg_memory"
+#define KGSL_2D0_IRQ "kgsl_2d0_irq"
+#define KGSL_2D1_REG_MEMORY "kgsl_2d1_reg_memory"
+#define KGSL_2D1_IRQ "kgsl_2d1_irq"
+
+#define ADRENO_CHIPID(_co, _ma, _mi, _pa) \
+ ((((_co) & 0xFF) << 24) | \
+ (((_ma) & 0xFF) << 16) | \
+ (((_mi) & 0xFF) << 8) | \
+ ((_pa) & 0xFF))
+
+enum kgsl_iommu_context_id {
+ KGSL_IOMMU_CONTEXT_USER = 0,
+ KGSL_IOMMU_CONTEXT_PRIV = 1,
+};
+
+struct kgsl_iommu_ctx {
+ const char *iommu_ctx_name;
+ enum kgsl_iommu_context_id ctx_id;
+};
+
+struct kgsl_device_iommu_data {
+ const struct kgsl_iommu_ctx *iommu_ctxs;
+ int iommu_ctx_count;
+ unsigned int physstart;
+ unsigned int physend;
+};
+
+struct kgsl_pwrlevel {
+ unsigned int gpu_freq;
+ unsigned int bus_freq;
+ unsigned int io_fraction;
+};
+
+struct kgsl_device_platform_data {
+ struct kgsl_pwrlevel pwrlevel[KGSL_MAX_PWRLEVELS];
+ int init_level;
+ int num_levels;
+ int (*set_grp_async)(void);
+ unsigned int idle_timeout;
+ bool strtstp_sleepwake;
+ unsigned int nap_allowed;
+ unsigned int clk_map;
+ unsigned int idle_needed;
+ struct msm_bus_scale_pdata *bus_scale_table;
+ struct kgsl_device_iommu_data *iommu_data;
+ int iommu_count;
+ struct msm_dcvs_core_info *core_info;
+ unsigned int chipid;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index 637a3cc..c4877cc 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -31,6 +31,7 @@
struct mdm_vddmin_resource *vddmin_resource;
struct platform_device *peripheral_platform_device;
const unsigned int ramdump_timeout_ms;
+ int image_upgrade_supported;
};
#endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
index b0475ed..927624d 100644
--- a/arch/arm/mach-msm/include/mach/ocmem.h
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -24,6 +24,8 @@
#define OCMEM_MAX_CHUNKS 32
#define MIN_CHUNK_SIZE (SZ_1K/8)
+struct ocmem_notifier;
+
struct ocmem_buf {
unsigned long addr;
unsigned long len;
@@ -80,9 +82,11 @@
/* APIS */
/* Notification APIs */
-void *ocmem_notifier_register(int client_id, struct notifier_block *nb);
+struct ocmem_notifier *ocmem_notifier_register(int client_id,
+ struct notifier_block *nb);
-int ocmem_notifier_unregister(void *notif_hndl, struct notifier_block *nb);
+int ocmem_notifier_unregister(struct ocmem_notifier *notif_hndl,
+ struct notifier_block *nb);
/* Obtain the maximum quota for the client */
unsigned long get_max_quota(int client_id);
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index dd976ea..64c9ffe 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -61,6 +61,23 @@
SCHED_DUMP,
};
+struct ocmem_plat_data {
+ void __iomem *vbase;
+ unsigned long size;
+ unsigned long base;
+ struct ocmem_partition *parts;
+ int nr_parts;
+ void __iomem *reg_base;
+ void __iomem *br_base;
+ void __iomem *dm_base;
+ unsigned nr_regions;
+ unsigned nr_macros;
+ unsigned nr_ports;
+ int ocmem_irq;
+ int dm_irq;
+ bool interleaved;
+};
+
struct ocmem_req {
struct rw_semaphore rw_sem;
/* Chain in sched queue */
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h b/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h
index 319c2d8..a32e168 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h
@@ -29,7 +29,8 @@
* in this enum correspond to MSM8974 for PMIC PM8841 SMPS 2 (VDD_Dig).
*/
enum rpm_regulator_voltage_corner {
- RPM_REGULATOR_CORNER_RETENTION = 1,
+ RPM_REGULATOR_CORNER_NONE = 1,
+ RPM_REGULATOR_CORNER_RETENTION,
RPM_REGULATOR_CORNER_SVS_KRAIT,
RPM_REGULATOR_CORNER_SVS_SOC,
RPM_REGULATOR_CORNER_NORMAL,
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 9110632..2c3d395 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -94,7 +94,9 @@
int __init socinfo_init(void) __must_check;
const int read_msm_cpu_type(void);
const int get_core_count(void);
+const int cpu_is_krait(void);
const int cpu_is_krait_v1(void);
+const int cpu_is_krait_v2(void);
static inline int cpu_is_msm7x01(void)
{
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 51ace96..6d15f47 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, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,8 @@
#define SUBSYS_NAME_MAX_LENGTH 40
+struct subsys_device;
+
enum {
RESET_SOC = 1,
RESET_SUBSYS_COUPLED,
@@ -25,29 +27,23 @@
RESET_LEVEL_MAX
};
-struct subsys_data {
+struct subsys_desc {
const char *name;
- int (*shutdown) (const struct subsys_data *);
- int (*powerup) (const struct subsys_data *);
- void (*crash_shutdown) (const struct subsys_data *);
- int (*ramdump) (int, const struct subsys_data *);
- /* Internal use only */
- struct list_head list;
- void *notif_handle;
-
- struct mutex shutdown_lock;
- struct mutex powerup_lock;
-
- void *restart_order;
- struct subsys_data *single_restart_list[1];
+ int (*shutdown)(const struct subsys_desc *desc);
+ int (*powerup)(const struct subsys_desc *desc);
+ void (*crash_shutdown)(const struct subsys_desc *desc);
+ int (*ramdump)(int, const struct subsys_desc *desc);
};
#if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
-int get_restart_level(void);
-int subsystem_restart(const char *subsys_name);
-int ssr_register_subsystem(struct subsys_data *subsys);
+extern int get_restart_level(void);
+extern int subsystem_restart_dev(struct subsys_device *dev);
+extern int subsystem_restart(const char *name);
+
+extern struct subsys_device *subsys_register(struct subsys_desc *desc);
+extern void subsys_unregister(struct subsys_device *dev);
#else
@@ -56,16 +52,24 @@
return 0;
}
-static inline int subsystem_restart(const char *subsystem_name)
+static inline int subsystem_restart_dev(struct subsys_device *dev)
{
return 0;
}
-static inline int ssr_register_subsystem(struct subsys_data *subsys)
+static inline int subsystem_restart(const char *name)
{
return 0;
}
+static inline
+struct subsys_device *subsys_register(struct subsys_desc *desc)
+{
+ return NULL;
+}
+
+static inline void subsys_unregister(struct subsys_device *dev) { }
+
#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
#endif
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 42f0438..8f9464c 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -41,6 +41,11 @@
DEFINE_MUTEX(domain_mutex);
static atomic_t domain_nums = ATOMIC_INIT(-1);
+int msm_use_iommu()
+{
+ return iommu_present(&platform_bus_type);
+}
+
int msm_iommu_map_extra(struct iommu_domain *domain,
unsigned long start_iova,
unsigned long size,
@@ -165,6 +170,11 @@
if (size & (align - 1))
return -EINVAL;
+ if (!msm_use_iommu()) {
+ *iova_val = phys;
+ return 0;
+ }
+
ret = msm_allocate_iova_address(domain_no, partition_no, size, align,
&iova);
@@ -187,6 +197,9 @@
unsigned int partition_no,
unsigned long size)
{
+ if (!msm_use_iommu())
+ return;
+
iommu_unmap_range(msm_get_iommu_domain(domain_no), iova, size);
msm_free_iova_address(iova, domain_no, partition_no, size);
}
@@ -390,11 +403,6 @@
return -EINVAL;
}
-int msm_use_iommu()
-{
- return iommu_present(&platform_bus_type);
-}
-
static int __init iommu_domain_probe(struct platform_device *pdev)
{
struct iommu_domains_pdata *p = pdev->dev.platform_data;
diff --git a/arch/arm/mach-msm/krait-scm.c b/arch/arm/mach-msm/krait-scm.c
new file mode 100644
index 0000000..eb48d35
--- /dev/null
+++ b/arch/arm/mach-msm/krait-scm.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
+#include <linux/percpu.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/sysfs.h>
+#include <linux/sysdev.h>
+
+#include <mach/scm.h>
+
+#define CPU_CONFIG_CMD 5
+#define CPU_CONFIG_QUERY_CMD 6
+
+static int query_cpu_config(void)
+{
+ struct cpu_config_query_req_resp {
+ u32 id;
+ u32 arg0;
+ u32 arg1;
+ u32 arg2;
+ } request;
+ struct cpu_config_query_resp {
+ u32 ret0;
+ u32 ret1;
+ u32 ret2;
+ u32 ret3;
+ } response = {0};
+ int ret;
+
+ request.id = 1;
+ ret = scm_call(SCM_SVC_BOOT, CPU_CONFIG_QUERY_CMD, &request,
+ sizeof(request), &response, sizeof(response));
+ return ret ? : response.ret0;
+}
+
+static void set_cpu_config(int enable)
+{
+ struct cpu_config_req {
+ u32 id;
+ u32 arg0;
+ u32 arg1;
+ u32 arg2;
+ } request;
+
+ request.id = 1;
+ request.arg0 = enable;
+ scm_call(SCM_SVC_BOOT, CPU_CONFIG_CMD, &request, sizeof(request),
+ NULL, 0);
+}
+
+void enable_cpu_config(struct work_struct *work)
+{
+ set_cpu_config(1);
+}
+
+void disable_cpu_config(struct work_struct *work)
+{
+ set_cpu_config(0);
+}
+
+int cpu_config_on_each_cpu(bool enable)
+{
+ work_func_t func = enable ? enable_cpu_config : disable_cpu_config;
+ return schedule_on_each_cpu(func);
+}
+
+static ssize_t show_cpuctl(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", query_cpu_config());
+}
+
+static ssize_t store_cpuctl(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr, const char *buf,
+ size_t count)
+{
+ unsigned val;
+ int ret;
+
+ ret = kstrtouint(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+ ret = cpu_config_on_each_cpu(val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static SYSDEV_CLASS_ATTR(cpuctl, 0600, show_cpuctl, store_cpuctl);
+
+static int __init init_scm_cpu(void)
+{
+ return sysfs_create_file(&cpu_subsys.dev_root->kobj,
+ &attr_cpuctl.attr);
+}
+module_init(init_scm_cpu);
diff --git a/arch/arm/mach-msm/lpass-8660.c b/arch/arm/mach-msm/lpass-8660.c
index 1018360..be18b68 100644
--- a/arch/arm/mach-msm/lpass-8660.c
+++ b/arch/arm/mach-msm/lpass-8660.c
@@ -19,6 +19,7 @@
#include <linux/stringify.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/err.h>
#include <mach/irqs.h>
#include <mach/scm.h>
@@ -35,6 +36,8 @@
#define MODULE_NAME "lpass_8x60"
#define SCM_Q6_NMI_CMD 0x1
+static struct subsys_device *subsys_8x60_q6_dev;
+
/* Subsystem restart: QDSP6 data, functions */
static void *q6_ramdump_dev;
static void q6_fatal_fn(struct work_struct *);
@@ -44,7 +47,7 @@
static void q6_fatal_fn(struct work_struct *work)
{
pr_err("%s: Watchdog bite received from Q6!\n", MODULE_NAME);
- subsystem_restart("lpass");
+ subsystem_restart_dev(subsys_8x60_q6_dev);
enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
}
@@ -65,7 +68,7 @@
pr_info("subsystem-fatal-8x60: Q6 NMI was sent.\n");
}
-int subsys_q6_shutdown(const struct subsys_data *crashed_subsys)
+int subsys_q6_shutdown(const struct subsys_desc *crashed_subsys)
{
void __iomem *q6_wdog_addr =
ioremap_nocache(Q6SS_WDOG_ENABLE, 8);
@@ -82,7 +85,7 @@
return 0;
}
-int subsys_q6_powerup(const struct subsys_data *crashed_subsys)
+int subsys_q6_powerup(const struct subsys_desc *crashed_subsys)
{
int ret = pil_force_boot("q6");
enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
@@ -93,7 +96,7 @@
static struct ramdump_segment q6_segments[] = { {0x46700000, 0x47F00000 -
0x46700000}, {0x28400000, 0x12800} };
static int subsys_q6_ramdump(int enable,
- const struct subsys_data *crashed_subsys)
+ const struct subsys_desc *crashed_subsys)
{
if (enable)
return do_ramdump(q6_ramdump_dev, q6_segments,
@@ -102,7 +105,7 @@
return 0;
}
-void subsys_q6_crash_shutdown(const struct subsys_data *crashed_subsys)
+void subsys_q6_crash_shutdown(const struct subsys_desc *crashed_subsys)
{
send_q6_nmi();
}
@@ -117,7 +120,7 @@
return IRQ_HANDLED;
}
-static struct subsys_data subsys_8x60_q6 = {
+static struct subsys_desc subsys_8x60_q6 = {
.name = "lpass",
.shutdown = subsys_q6_shutdown,
.powerup = subsys_q6_powerup,
@@ -127,6 +130,7 @@
static void __exit lpass_fatal_exit(void)
{
+ subsys_unregister(subsys_8x60_q6_dev);
iounmap(q6_wakeup_intr);
free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
}
@@ -156,7 +160,9 @@
if (!q6_wakeup_intr)
pr_warn("lpass-8660: Unable to ioremap q6 wakeup address.");
- ret = ssr_register_subsystem(&subsys_8x60_q6);
+ subsys_8x60_q6_dev = subsys_register(&subsys_8x60_q6);
+ if (IS_ERR(subsys_8x60_q6_dev))
+ ret = PTR_ERR(subsys_8x60_q6_dev);
out:
return ret;
}
diff --git a/arch/arm/mach-msm/lpass-8960.c b/arch/arm/mach-msm/lpass-8960.c
index c58b0e1..b714a7f 100644
--- a/arch/arm/mach-msm/lpass-8960.c
+++ b/arch/arm/mach-msm/lpass-8960.c
@@ -152,7 +152,7 @@
pr_debug("%s: Q6 NMI was sent.\n", __func__);
}
-static int lpass_shutdown(const struct subsys_data *subsys)
+static int lpass_shutdown(const struct subsys_desc *subsys)
{
send_q6_nmi();
pil_force_shutdown("q6");
@@ -161,7 +161,7 @@
return 0;
}
-static int lpass_powerup(const struct subsys_data *subsys)
+static int lpass_powerup(const struct subsys_desc *subsys)
{
int ret = pil_force_boot("q6");
enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
@@ -170,7 +170,7 @@
/* RAM segments - address and size for 8960 */
static struct ramdump_segment q6_segments[] = { {0x8da00000, 0x8f200000 -
0x8da00000}, {0x28400000, 0x20000} };
-static int lpass_ramdump(int enable, const struct subsys_data *subsys)
+static int lpass_ramdump(int enable, const struct subsys_desc *subsys)
{
pr_debug("%s: enable[%d]\n", __func__, enable);
if (enable)
@@ -181,7 +181,7 @@
return 0;
}
-static void lpass_crash_shutdown(const struct subsys_data *subsys)
+static void lpass_crash_shutdown(const struct subsys_desc *subsys)
{
q6_crash_shutdown = 1;
send_q6_nmi();
@@ -198,7 +198,9 @@
return IRQ_HANDLED;
}
-static struct subsys_data lpass_8960 = {
+static struct subsys_device *lpass_8960_dev;
+
+static struct subsys_desc lpass_8960 = {
.name = "lpass",
.shutdown = lpass_shutdown,
.powerup = lpass_powerup,
@@ -208,7 +210,10 @@
static int __init lpass_restart_init(void)
{
- return ssr_register_subsystem(&lpass_8960);
+ lpass_8960_dev = subsys_register(&lpass_8960);
+ if (IS_ERR(lpass_8960_dev))
+ return PTR_ERR(lpass_8960_dev);
+ return 0;
}
static int __init lpass_fatal_init(void)
@@ -275,6 +280,7 @@
{
subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
subsys_notif_unregister_notifier(ssr_modem_notif_hdle, &mnb);
+ subsys_unregister(lpass_8960_dev);
free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
}
diff --git a/arch/arm/mach-msm/mdm.c b/arch/arm/mach-msm/mdm.c
index cbdc92a..4280fb4 100644
--- a/arch/arm/mach-msm/mdm.c
+++ b/arch/arm/mach-msm/mdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -73,14 +73,14 @@
}
-static int charm_subsys_shutdown(const struct subsys_data *crashed_subsys)
+static int charm_subsys_shutdown(const struct subsys_desc *crashed_subsys)
{
charm_ready = 0;
power_down_charm();
return 0;
}
-static int charm_subsys_powerup(const struct subsys_data *crashed_subsys)
+static int charm_subsys_powerup(const struct subsys_desc *crashed_subsys)
{
power_on_charm();
boot_type = CHARM_NORMAL_BOOT;
@@ -92,7 +92,7 @@
}
static int charm_subsys_ramdumps(int want_dumps,
- const struct subsys_data *crashed_subsys)
+ const struct subsys_desc *crashed_subsys)
{
charm_ram_dump_status = 0;
if (want_dumps) {
@@ -105,7 +105,9 @@
return charm_ram_dump_status;
}
-static struct subsys_data charm_subsystem = {
+static struct subsys_device *charm_subsys;
+
+static struct subsys_desc charm_subsystem = {
.shutdown = charm_subsys_shutdown,
.ramdump = charm_subsys_ramdumps,
.powerup = charm_subsys_powerup,
@@ -229,7 +231,7 @@
static void charm_status_fn(struct work_struct *work)
{
pr_info("Reseting the charm because status changed\n");
- subsystem_restart("external_modem");
+ subsystem_restart_dev(charm_subsys);
}
static DECLARE_WORK(charm_status_work, charm_status_fn);
@@ -239,7 +241,7 @@
pr_info("Reseting the charm due to an errfatal\n");
if (get_restart_level() == RESET_SOC)
pm8xxx_stay_on();
- subsystem_restart("external_modem");
+ subsystem_restart_dev(charm_subsys);
}
static DECLARE_WORK(charm_fatal_work, charm_fatal_fn);
@@ -349,7 +351,11 @@
atomic_notifier_chain_register(&panic_notifier_list, &charm_panic_blk);
charm_debugfs_init();
- ssr_register_subsystem(&charm_subsystem);
+ charm_subsys = subsys_register(&charm_subsystem);
+ if (IS_ERR(charm_subsys)) {
+ ret = PTR_ERR(charm_subsys);
+ goto fatal_err;
+ }
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 6e7086e..e74af2e 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -249,6 +249,33 @@
}
}
+static void mdm_image_upgrade(struct mdm_modem_drv *mdm_drv, int type)
+{
+ switch (type) {
+ case APQ_CONTROLLED_UPGRADE:
+ pr_debug("%s APQ controlled modem image upgrade\n", __func__);
+ mdm_drv->mdm_ready = 0;
+ mdm_toggle_soft_reset(mdm_drv);
+ break;
+ case MDM_CONTROLLED_UPGRADE:
+ pr_debug("%s MDM controlled modem image upgrade\n", __func__);
+ mdm_drv->mdm_ready = 0;
+ /*
+ * If we have no image currently present on the modem, then we
+ * would be in PBL, in which case the status gpio would not go
+ * high.
+ */
+ mdm_drv->disable_status_check = 1;
+ if (mdm_drv->usb_switch_gpio > 0) {
+ pr_info("%s Switching usb control to MDM\n", __func__);
+ gpio_direction_output(mdm_drv->usb_switch_gpio, 1);
+ } else
+ pr_err("%s usb switch gpio unavailable\n", __func__);
+ break;
+ default:
+ pr_err("%s invalid upgrade type\n", __func__);
+ }
+}
static struct mdm_ops mdm_cb = {
.power_on_mdm_cb = mdm_power_on_common,
.reset_mdm_cb = mdm_power_on_common,
@@ -256,6 +283,7 @@
.power_down_mdm_cb = mdm_power_down_common,
.debug_state_changed_cb = debug_state_changed,
.status_cb = mdm_status_changed,
+ .image_upgrade_cb = mdm_image_upgrade,
};
static int __init mdm_modem_probe(struct platform_device *pdev)
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 5b181e1..6b40cda 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -56,6 +56,7 @@
#define EXTERNAL_MODEM "external_modem"
static struct mdm_modem_drv *mdm_drv;
+static struct subsys_device *mdm_subsys_dev;
DECLARE_COMPLETION(mdm_needs_reload);
DECLARE_COMPLETION(mdm_boot);
@@ -150,11 +151,13 @@
* If the mdm modem did not pull the MDM2AP_STATUS gpio
* high then call subsystem_restart.
*/
- if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) {
- pr_err("%s: MDM2AP_STATUS gpio did not go high\n",
- __func__);
- mdm_drv->mdm_ready = 0;
- subsystem_restart(EXTERNAL_MODEM);
+ if (!mdm_drv->disable_status_check) {
+ if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) {
+ pr_err("%s: MDM2AP_STATUS gpio did not go high\n",
+ __func__);
+ mdm_drv->mdm_ready = 0;
+ subsystem_restart_dev(mdm_subsys_dev);
+ }
}
}
@@ -238,6 +241,15 @@
else
put_user(0, (unsigned long __user *) arg);
break;
+ case IMAGE_UPGRADE:
+ pr_debug("%s Image upgrade ioctl recieved\n", __func__);
+ if (mdm_drv->pdata->image_upgrade_supported &&
+ mdm_drv->ops->image_upgrade_cb) {
+ get_user(status, (unsigned long __user *) arg);
+ mdm_drv->ops->image_upgrade_cb(mdm_drv, status);
+ } else
+ pr_debug("%s Image upgrade not supported\n", __func__);
+ break;
default:
pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
ret = -EINVAL;
@@ -271,7 +283,7 @@
(gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1)) {
pr_info("%s: Reseting the mdm due to an errfatal\n", __func__);
mdm_drv->mdm_ready = 0;
- subsystem_restart(EXTERNAL_MODEM);
+ subsystem_restart_dev(mdm_subsys_dev);
}
return IRQ_HANDLED;
}
@@ -332,7 +344,7 @@
pr_info("%s: unexpected reset external modem\n", __func__);
mdm_drv->mdm_unexpected_reset_occurred = 1;
mdm_drv->mdm_ready = 0;
- subsystem_restart(EXTERNAL_MODEM);
+ subsystem_restart_dev(mdm_subsys_dev);
} else if (value == 1) {
cancel_delayed_work(&mdm2ap_status_check_work);
pr_info("%s: status = 1: mdm is now ready\n", __func__);
@@ -349,7 +361,7 @@
return IRQ_HANDLED;
}
-static int mdm_subsys_shutdown(const struct subsys_data *crashed_subsys)
+static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys)
{
mdm_drv->mdm_ready = 0;
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
@@ -363,11 +375,10 @@
mdm_drv->ops->reset_mdm_cb(mdm_drv);
else
mdm_drv->mdm_unexpected_reset_occurred = 0;
-
return 0;
}
-static int mdm_subsys_powerup(const struct subsys_data *crashed_subsys)
+static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
{
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
@@ -390,7 +401,7 @@
}
static int mdm_subsys_ramdumps(int want_dumps,
- const struct subsys_data *crashed_subsys)
+ const struct subsys_desc *crashed_subsys)
{
mdm_drv->mdm_ram_dump_status = 0;
if (want_dumps) {
@@ -411,7 +422,7 @@
return mdm_drv->mdm_ram_dump_status;
}
-static struct subsys_data mdm_subsystem = {
+static struct subsys_desc mdm_subsystem = {
.shutdown = mdm_subsys_shutdown,
.ramdump = mdm_subsys_ramdumps,
.powerup = mdm_subsys_powerup,
@@ -514,6 +525,12 @@
if (pres)
mdm_drv->mdm2ap_pblrdy = pres->start;
+ /*USB_SW*/
+ pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+ "USB_SW");
+ if (pres)
+ mdm_drv->usb_switch_gpio = pres->start;
+
mdm_drv->boot_type = CHARM_NORMAL_BOOT;
mdm_drv->ops = mdm_ops;
@@ -556,6 +573,13 @@
if (mdm_drv->ap2mdm_wakeup_gpio > 0)
gpio_request(mdm_drv->ap2mdm_wakeup_gpio, "AP2MDM_WAKEUP");
+ if (mdm_drv->usb_switch_gpio > 0) {
+ if (gpio_request(mdm_drv->usb_switch_gpio, "USB_SW")) {
+ pr_err("%s Failed to get usb switch gpio\n", __func__);
+ mdm_drv->usb_switch_gpio = -1;
+ }
+ }
+
gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
@@ -588,7 +612,11 @@
mdm_debugfs_init();
/* Register subsystem handlers */
- ssr_register_subsystem(&mdm_subsystem);
+ mdm_subsys_dev = subsys_register(&mdm_subsystem);
+ if (IS_ERR(mdm_subsys_dev)) {
+ ret = PTR_ERR(mdm_subsys_dev);
+ goto fatal_err;
+ }
/* ERR_FATAL irq. */
irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_errfatal_gpio);
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
index 7ac3727..7aba83d 100644
--- a/arch/arm/mach-msm/mdm_private.h
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -23,6 +23,7 @@
void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
void (*debug_state_changed_cb)(int value);
void (*status_cb)(struct mdm_modem_drv *mdm_drv, int value);
+ void (*image_upgrade_cb)(struct mdm_modem_drv *mdm_drv, int type);
};
/* Private mdm2 data structure */
@@ -37,6 +38,7 @@
unsigned ap2mdm_soft_reset_gpio;
unsigned ap2mdm_pmic_pwr_en_gpio;
unsigned mdm2ap_pblrdy;
+ unsigned usb_switch_gpio;
int mdm_errfatal_irq;
int mdm_status_irq;
@@ -46,6 +48,7 @@
enum charm_boot_type boot_type;
int mdm_debug_on;
int mdm_unexpected_reset_occurred;
+ int disable_status_check;
struct mdm_ops *ops;
struct mdm_platform_data *pdata;
diff --git a/arch/arm/mach-msm/modem-8660.c b/arch/arm/mach-msm/modem-8660.c
index 9c558e4..096ed9c 100644
--- a/arch/arm/mach-msm/modem-8660.c
+++ b/arch/arm/mach-msm/modem-8660.c
@@ -19,6 +19,7 @@
#include <linux/stringify.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/err.h>
#include <mach/irqs.h>
#include <mach/scm.h>
@@ -48,6 +49,8 @@
module_param(reset_modem, int, 0644);
#endif
+static struct subsys_device *modem_8660_dev;
+
/* Subsystem restart: Modem data, functions */
static void *modem_ramdump_dev;
static void modem_fatal_fn(struct work_struct *);
@@ -75,7 +78,7 @@
mb();
iounmap(hwio_modem_reset_addr);
- subsystem_restart("modem");
+ subsystem_restart_dev(modem_8660_dev);
enable_irq(MARM_WDOG_EXPIRED);
}
@@ -93,7 +96,7 @@
if (modem_state == 0 || modem_state & panic_smsm_states) {
- subsystem_restart("modem");
+ subsystem_restart_dev(modem_8660_dev);
enable_irq(MARM_WDOG_EXPIRED);
} else if (modem_state & reset_smsm_states) {
@@ -135,13 +138,13 @@
goto out;
}
pr_err("%s: Modem error fatal'ed.", MODULE_NAME);
- subsystem_restart("modem");
+ subsystem_restart_dev(modem_8660_dev);
}
out:
return NOTIFY_DONE;
}
-static int modem_shutdown(const struct subsys_data *crashed_subsys)
+static int modem_shutdown(const struct subsys_desc *crashed_subsys)
{
void __iomem *modem_wdog_addr;
@@ -178,7 +181,7 @@
return 0;
}
-static int modem_powerup(const struct subsys_data *crashed_subsys)
+static int modem_powerup(const struct subsys_desc *crashed_subsys)
{
int ret;
@@ -192,8 +195,7 @@
static struct ramdump_segment modem_segments[] = {
{0x42F00000, 0x46000000 - 0x42F00000} };
-static int modem_ramdump(int enable,
- const struct subsys_data *crashed_subsys)
+static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
{
if (enable)
return do_ramdump(modem_ramdump_dev, modem_segments,
@@ -202,8 +204,7 @@
return 0;
}
-static void modem_crash_shutdown(
- const struct subsys_data *crashed_subsys)
+static void modem_crash_shutdown(const struct subsys_desc *crashed_subsys)
{
/* If modem hasn't already crashed, send SMSM_RESET. */
if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
@@ -225,7 +226,7 @@
return IRQ_HANDLED;
}
-static struct subsys_data subsys_8660_modem = {
+static struct subsys_desc subsys_8660_modem = {
.name = "modem",
.shutdown = modem_shutdown,
.powerup = modem_powerup,
@@ -260,13 +261,16 @@
goto out;
}
- ret = ssr_register_subsystem(&subsys_8660_modem);
+ modem_8660_dev = subsys_register(&subsys_8660_modem);
+ if (IS_ERR(modem_8660_dev))
+ ret = PTR_ERR(modem_8660_dev);
out:
return ret;
}
static void __exit modem_8660_exit(void)
{
+ subsys_unregister(modem_8660_dev);
free_irq(MARM_WDOG_EXPIRED, NULL);
}
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index fd7b7b5..73b9b1f 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -35,6 +35,8 @@
static int crash_shutdown;
+static struct subsys_device *modem_8960_dev;
+
#define MAX_SSR_REASON_LEN 81U
#define Q6_FW_WDOG_ENABLE 0x08882024
#define Q6_SW_WDOG_ENABLE 0x08982024
@@ -66,7 +68,7 @@
static void restart_modem(void)
{
log_modem_sfr();
- subsystem_restart("modem");
+ subsystem_restart_dev(modem_8960_dev);
}
static void modem_wdog_check(struct work_struct *work)
@@ -101,7 +103,7 @@
}
}
-static int modem_shutdown(const struct subsys_data *subsys)
+static int modem_shutdown(const struct subsys_desc *subsys)
{
void __iomem *q6_fw_wdog_addr;
void __iomem *q6_sw_wdog_addr;
@@ -142,7 +144,7 @@
#define MODEM_WDOG_CHECK_TIMEOUT_MS 10000
-static int modem_powerup(const struct subsys_data *subsys)
+static int modem_powerup(const struct subsys_desc *subsys)
{
pil_force_boot("modem_fw");
pil_force_boot("modem");
@@ -153,7 +155,7 @@
return 0;
}
-void modem_crash_shutdown(const struct subsys_data *subsys)
+void modem_crash_shutdown(const struct subsys_desc *subsys)
{
crash_shutdown = 1;
smsm_reset_modem(SMSM_RESET);
@@ -176,8 +178,7 @@
static void *modemsw_ramdump_dev;
static void *smem_ramdump_dev;
-static int modem_ramdump(int enable,
- const struct subsys_data *crashed_subsys)
+static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
{
int ret = 0;
@@ -234,7 +235,7 @@
return IRQ_HANDLED;
}
-static struct subsys_data modem_8960 = {
+static struct subsys_desc modem_8960 = {
.name = "modem",
.shutdown = modem_shutdown,
.powerup = modem_powerup,
@@ -244,13 +245,16 @@
static int modem_subsystem_restart_init(void)
{
- return ssr_register_subsystem(&modem_8960);
+ modem_8960_dev = subsys_register(&modem_8960);
+ if (IS_ERR(modem_8960_dev))
+ return PTR_ERR(modem_8960_dev);
+ return 0;
}
static int modem_debug_set(void *data, u64 val)
{
if (val == 1)
- subsystem_restart("modem");
+ subsystem_restart_dev(modem_8960_dev);
return 0;
}
diff --git a/arch/arm/mach-msm/msm-krait-l2-accessors.c b/arch/arm/mach-msm/msm-krait-l2-accessors.c
index 3d341e3..41a2490 100644
--- a/arch/arm/mach-msm/msm-krait-l2-accessors.c
+++ b/arch/arm/mach-msm/msm-krait-l2-accessors.c
@@ -14,19 +14,83 @@
#include <linux/spinlock.h>
#include <linux/module.h>
#include <asm/mach-types.h>
+#include <asm/cputype.h>
DEFINE_RAW_SPINLOCK(l2_access_lock);
+#define L2CPMR 0x500
+#define L2CPUCPMR 0x501
+#define L2CPUVRF8 0x708
+#define CPUNDX_MASK (0x7 << 12)
+
+/*
+ * For Krait versions found in APQ8064v1.x, save L2CPUVRF8 before
+ * L2CPMR or L2CPUCPMR writes and restore it after to work around an
+ * issue where L2CPUVRF8 becomes corrupt.
+ */
+static bool l2cpuvrf8_needs_fix(u32 reg_addr)
+{
+ switch (read_cpuid_id()) {
+ case 0x510F06F0: /* KR28M4A10 */
+ case 0x510F06F1: /* KR28M4A10B */
+ case 0x510F06F2: /* KR28M4A11 */
+ break;
+ default:
+ return false;
+ };
+
+ switch (reg_addr & ~CPUNDX_MASK) {
+ case L2CPMR:
+ case L2CPUCPMR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static u32 l2cpuvrf8_fix_save(u32 reg_addr, u32 *l2cpuvrf8_val)
+{
+ u32 l2cpuvrf8_addr = L2CPUVRF8 | (reg_addr & CPUNDX_MASK);
+
+ mb();
+ asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+ "isb\n\t"
+ "mrc p15, 3, %[l2cpdr], c15, c0, 7\n\t"
+ : [l2cpdr]"=r" (*l2cpuvrf8_val)
+ : [l2cpselr]"r" (l2cpuvrf8_addr)
+ );
+
+ return l2cpuvrf8_addr;
+}
+
+static void l2cpuvrf8_fix_restore(u32 l2cpuvrf8_addr, u32 l2cpuvrf8_val)
+{
+ mb();
+ asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+ "isb\n\t"
+ "mcr p15, 3, %[l2cpdr], c15, c0, 7\n\t"
+ "isb\n\t"
+ :
+ : [l2cpselr]"r" (l2cpuvrf8_addr),
+ [l2cpdr]"r" (l2cpuvrf8_val)
+ );
+}
+
u32 set_get_l2_indirect_reg(u32 reg_addr, u32 val)
{
unsigned long flags;
+ u32 uninitialized_var(l2cpuvrf8_val), l2cpuvrf8_addr = 0;
u32 ret_val;
+
/* CP15 registers are not emulated on RUMI3. */
if (machine_is_msm8960_rumi3())
return 0;
raw_spin_lock_irqsave(&l2_access_lock, flags);
+ if (l2cpuvrf8_needs_fix(reg_addr))
+ l2cpuvrf8_addr = l2cpuvrf8_fix_save(reg_addr, &l2cpuvrf8_val);
+
mb();
asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
"isb\n\t"
@@ -36,6 +100,10 @@
: [l2cpdr_read]"=r" (ret_val)
: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
);
+
+ if (l2cpuvrf8_addr)
+ l2cpuvrf8_fix_restore(l2cpuvrf8_addr, l2cpuvrf8_val);
+
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
return ret_val;
@@ -45,11 +113,17 @@
void set_l2_indirect_reg(u32 reg_addr, u32 val)
{
unsigned long flags;
+ u32 uninitialized_var(l2cpuvrf8_val), l2cpuvrf8_addr = 0;
+
/* CP15 registers are not emulated on RUMI3. */
if (machine_is_msm8960_rumi3())
return;
raw_spin_lock_irqsave(&l2_access_lock, flags);
+
+ if (l2cpuvrf8_needs_fix(reg_addr))
+ l2cpuvrf8_addr = l2cpuvrf8_fix_save(reg_addr, &l2cpuvrf8_val);
+
mb();
asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
"isb\n\t"
@@ -58,6 +132,10 @@
:
: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
);
+
+ if (l2cpuvrf8_addr)
+ l2cpuvrf8_fix_restore(l2cpuvrf8_addr, l2cpuvrf8_val);
+
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
}
EXPORT_SYMBOL(set_l2_indirect_reg);
diff --git a/arch/arm/mach-msm/msm_bus/Makefile b/arch/arm/mach-msm/msm_bus/Makefile
index ab62c20..924577f 100644
--- a/arch/arm/mach-msm/msm_bus/Makefile
+++ b/arch/arm/mach-msm/msm_bus/Makefile
@@ -2,7 +2,9 @@
# Makefile for msm-bus driver specific files
#
obj-y += msm_bus_core.o msm_bus_fabric.o msm_bus_config.o msm_bus_arb.o
-obj-y += msm_bus_rpm.o msm_bus_bimc.o msm_bus_noc.o
+obj-y += msm_bus_bimc.o msm_bus_noc.o
+obj-$(CONFIG_MSM_RPM) += msm_bus_rpm.o
+obj-$(CONFIG_MSM_RPM_SMD) += msm_bus_rpm_smd.o
obj-$(CONFIG_ARCH_MSM8X60) += msm_bus_board_8660.o
obj-$(CONFIG_ARCH_MSM8960) += msm_bus_board_8960.o
obj-$(CONFIG_ARCH_MSM9615) += msm_bus_board_9615.o
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 823f14d..2072cb1 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1817,44 +1817,45 @@
info->node_info->id, info->node_info->priv_id, add_bw);
binfo = (struct msm_bus_bimc_info *)fab_pdata->hw_data;
- if (!info->node_info->qport) {
- MSM_BUS_DBG("No qos ports to update!\n");
- return;
- }
if (info->node_info->num_mports == 0) {
MSM_BUS_DBG("BIMC: Skip Master BW\n");
goto skip_mas_bw;
}
+ ports = info->node_info->num_mports;
bw = INTERLEAVED_BW(fab_pdata, add_bw, ports);
- ports = INTERLEAVED_VAL(fab_pdata, ports);
for (i = 0; i < ports; i++) {
- MSM_BUS_DBG("qport: %d\n", info->node_info->qport[i]);
sel_cd->mas[info->node_info->masterp[i]].bw += bw;
sel_cd->mas[info->node_info->masterp[i]].hw_id =
info->node_info->mas_hw_id;
- qbw.bw = sel_cd->mas[info->node_info->masterp[i]].bw;
- qbw.ws = info->node_info->ws;
- /* Threshold low = 90% of bw */
- qbw.thl = (90 * bw) / 100;
- /* Threshold medium = bw */
- qbw.thm = bw;
- /* Threshold high = 10% more than bw */
- qbw.thh = (110 * bw) / 100;
- /* Check if info is a shared master.
- * If it is, mark it dirty
- * If it isn't, then set QOS Bandwidth
- **/
- MSM_BUS_DBG("BIMC: Update mas_bw for ID: %d -> %ld\n",
+ MSM_BUS_DBG("BIMC: Update mas_bw for ID: %d -> %llu\n",
info->node_info->priv_id,
sel_cd->mas[info->node_info->masterp[i]].bw);
if (info->node_info->hw_sel == MSM_BUS_RPM)
sel_cd->mas[info->node_info->masterp[i]].dirty = 1;
- else
+ else {
+ if (!info->node_info->qport) {
+ MSM_BUS_DBG("No qos ports to update!\n");
+ break;
+ }
+ MSM_BUS_DBG("qport: %d\n", info->node_info->qport[i]);
+ qbw.bw = sel_cd->mas[info->node_info->masterp[i]].bw;
+ qbw.ws = info->node_info->ws;
+ /* Threshold low = 90% of bw */
+ qbw.thl = (90 * bw) / 100;
+ /* Threshold medium = bw */
+ qbw.thm = bw;
+ /* Threshold high = 10% more than bw */
+ qbw.thh = (110 * bw) / 100;
+ /* Check if info is a shared master.
+ * If it is, mark it dirty
+ * If it isn't, then set QOS Bandwidth
+ **/
msm_bus_bimc_set_qos_bw(binfo,
info->node_info->qport[i], &qbw);
+ }
}
skip_mas_bw:
@@ -1870,7 +1871,7 @@
sel_cd->slv[hop->node_info->slavep[i]].bw += bw;
sel_cd->slv[hop->node_info->slavep[i]].hw_id =
hop->node_info->slv_hw_id;
- MSM_BUS_DBG("BIMC: Update slave_bw: ID: %d -> %ld\n",
+ MSM_BUS_DBG("BIMC: Update slave_bw: ID: %d -> %llu\n",
hop->node_info->priv_id,
sel_cd->slv[hop->node_info->slavep[i]].bw);
MSM_BUS_DBG("BIMC: Update slave_bw: index: %d\n",
@@ -1893,6 +1894,7 @@
*fab_pdata, void *hw_data, void **cdata)
{
MSM_BUS_DBG("\nReached BIMC Commit\n");
+ msm_bus_remote_hw_commit(fab_pdata, hw_data, cdata);
return 0;
}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index 264afbd..333fe4b 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -123,7 +123,7 @@
struct msm_bus_node_hw_info {
bool dirty;
unsigned int hw_id;
- unsigned long bw;
+ uint64_t bw;
};
struct msm_bus_hw_algorithm {
@@ -202,6 +202,8 @@
int curr;
};
+int msm_bus_remote_hw_commit(struct msm_bus_fabric_registration
+ *fab_pdata, void *hw_data, void **cdata);
int msm_bus_fabric_device_register(struct msm_bus_fabric_device *fabric);
void msm_bus_fabric_device_unregister(struct msm_bus_fabric_device *fabric);
struct msm_bus_fabric_device *msm_bus_get_fabric_device(int fabid);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
index 5179d2a..2597e27 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -518,14 +518,12 @@
return;
}
- if (!info->node_info->qport) {
- MSM_BUS_DBG("NOC: No QoS Ports to update bw\n");
- return;
+ if (info->node_info->num_mports == 0) {
+ MSM_BUS_DBG("NOC: Skip Master BW\n");
+ goto skip_mas_bw;
}
ports = info->node_info->num_mports;
- qos_bw.ws = info->node_info->ws;
-
bw = INTERLEAVED_BW(fab_pdata, add_bw, ports);
MSM_BUS_DBG("NOC: Update bw for: %d: %ld\n",
@@ -534,26 +532,36 @@
sel_cd->mas[info->node_info->masterp[i]].bw += bw;
sel_cd->mas[info->node_info->masterp[i]].hw_id =
info->node_info->mas_hw_id;
- qos_bw.bw = sel_cd->mas[info->node_info->masterp[i]].bw;
- MSM_BUS_DBG("NOC: Update mas_bw for ID: %d, BW: %ld, QoS: %u\n",
+ MSM_BUS_DBG("NOC: Update mas_bw: ID: %d, BW: %llu ports:%d\n",
info->node_info->priv_id,
sel_cd->mas[info->node_info->masterp[i]].bw,
- qos_bw.ws);
+ ports);
/* Check if info is a shared master.
* If it is, mark it dirty
* If it isn't, then set QOS Bandwidth
**/
if (info->node_info->hw_sel == MSM_BUS_RPM)
sel_cd->mas[info->node_info->masterp[i]].dirty = 1;
- else
+ else {
+ if (!info->node_info->qport) {
+ MSM_BUS_DBG("No qos ports to update!\n");
+ break;
+ }
+ qos_bw.bw = sel_cd->mas[info->node_info->masterp[i]].
+ bw;
+ qos_bw.ws = info->node_info->ws;
msm_bus_noc_set_qos_bw(ninfo,
info->node_info->qport[i],
info->node_info->perm_mode, &qos_bw);
+ MSM_BUS_DBG("NOC: QoS: Update mas_bw: ws: %u\n",
+ qos_bw.ws);
+ }
}
+skip_mas_bw:
ports = hop->node_info->num_sports;
if (ports == 0) {
- MSM_BUS_ERR("\nDIVIDE BY 0, hop: %d\n",
+ MSM_BUS_DBG("\nDIVIDE BY 0, hop: %d\n",
hop->node_info->priv_id);
return;
}
@@ -562,7 +570,7 @@
sel_cd->slv[hop->node_info->slavep[i]].bw += bw;
sel_cd->slv[hop->node_info->slavep[i]].hw_id =
hop->node_info->slv_hw_id;
- MSM_BUS_DBG("NOC: Update slave_bw for ID: %d -> %ld\n",
+ MSM_BUS_DBG("NOC: Update slave_bw for ID: %d -> %llu\n",
hop->node_info->priv_id,
sel_cd->slv[hop->node_info->slavep[i]].bw);
MSM_BUS_DBG("NOC: Update slave_bw for hw_id: %d, index: %d\n",
@@ -581,6 +589,7 @@
*fab_pdata, void *hw_data, void **cdata)
{
MSM_BUS_DBG("\nReached NOC Commit\n");
+ msm_bus_remote_hw_commit(fab_pdata, hw_data, cdata);
return 0;
}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
index 4653431..2213132 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
@@ -946,6 +946,12 @@
return status;
}
+int msm_bus_remote_hw_commit(struct msm_bus_fabric_registration
+ *fab_pdata, void *hw_data, void **cdata)
+{
+ return 0;
+}
+
int msm_bus_rpm_hw_init(struct msm_bus_fabric_registration *pdata,
struct msm_bus_hw_algorithm *hw_algo)
{
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_rpm_smd.c b/arch/arm/mach-msm/msm_bus/msm_bus_rpm_smd.c
new file mode 100644
index 0000000..88fab96
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_rpm_smd.c
@@ -0,0 +1,238 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
+#include "msm_bus_core.h"
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/rpm-smd.h>
+
+/* Stubs for backward compatibility */
+void msm_bus_rpm_set_mt_mask()
+{
+}
+
+bool msm_bus_rpm_is_mem_interleaved(void)
+{
+ return true;
+}
+
+struct commit_data {
+ struct msm_bus_node_hw_info *mas_arb;
+ struct msm_bus_node_hw_info *slv_arb;
+};
+
+#ifdef CONFIG_DEBUG_FS
+void msm_bus_rpm_fill_cdata_buffer(int *curr, char *buf, const int max_size,
+ void *cdata, int nmasters, int nslaves, int ntslaves)
+{
+ int c;
+ struct commit_data *cd = (struct commit_data *)cdata;
+
+ *curr += scnprintf(buf + *curr, max_size - *curr, "\nMas BW:\n");
+ for (c = 0; c < nmasters; c++)
+ *curr += scnprintf(buf + *curr, max_size - *curr,
+ "%d: %llu\t", cd->mas_arb[c].hw_id,
+ cd->mas_arb[c].bw);
+ *curr += scnprintf(buf + *curr, max_size - *curr, "\nSlave BW:\n");
+ for (c = 0; c < nslaves; c++) {
+ *curr += scnprintf(buf + *curr, max_size - *curr,
+ "%d: %llu\t", cd->slv_arb[c].hw_id,
+ cd->slv_arb[c].bw);
+ }
+}
+#endif
+
+static int msm_bus_rpm_compare_cdata(
+ struct msm_bus_fabric_registration *fab_pdata,
+ struct commit_data *cd1, struct commit_data *cd2)
+{
+ size_t n;
+ int ret;
+
+ n = sizeof(struct msm_bus_node_hw_info) * fab_pdata->nmasters * 2;
+ ret = memcmp(cd1->mas_arb, cd2->mas_arb, n);
+ if (ret) {
+ MSM_BUS_DBG("Master Arb Data not equal\n");
+ return ret;
+ }
+
+ n = sizeof(struct msm_bus_node_hw_info) * fab_pdata->nslaves * 2;
+ ret = memcmp(cd1->slv_arb, cd2->slv_arb, n);
+ if (ret) {
+ MSM_BUS_DBG("Master Arb Data not equal\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int msm_bus_rpm_req(int ctx, uint32_t rsc_type, uint32_t key,
+ struct msm_bus_node_hw_info *hw_info, bool valid)
+{
+ struct msm_rpm_request *rpm_req;
+ int ret = 0, msg_id;
+
+ if (ctx == ACTIVE_CTX)
+ ctx = MSM_RPM_CTX_ACTIVE_SET;
+ else if (ctx == DUAL_CTX)
+ ctx = MSM_RPM_CTX_SLEEP_SET;
+
+ rpm_req = msm_rpm_create_request(ctx, rsc_type, hw_info->hw_id, 1);
+ if (rpm_req == NULL) {
+ MSM_BUS_WARN("RPM: Couldn't create RPM Request\n");
+ return -ENXIO;
+ }
+
+ if (valid) {
+ ret = msm_rpm_add_kvp_data(rpm_req, key, (const uint8_t *)
+ &hw_info->bw, (int)(sizeof(uint64_t)));
+ if (ret) {
+ MSM_BUS_WARN("RPM: Add KVP failed for RPM Req:%u\n",
+ rsc_type);
+ return ret;
+ }
+
+ MSM_BUS_DBG("Added Key: %d, Val: %llu, size: %d\n", key,
+ hw_info->bw, sizeof(uint64_t));
+ } else {
+ /* Invalidate RPM requests */
+ ret = msm_rpm_add_kvp_data(rpm_req, 0, NULL, 0);
+ if (ret) {
+ MSM_BUS_WARN("RPM: Add KVP failed for RPM Req:%u\n",
+ rsc_type);
+ return ret;
+ }
+ }
+
+ msg_id = msm_rpm_send_request(rpm_req);
+ if (!msg_id) {
+ MSM_BUS_WARN("RPM: No message ID for req\n");
+ return -ENXIO;
+ }
+
+ ret = msm_rpm_wait_for_ack(msg_id);
+ if (ret) {
+ MSM_BUS_WARN("RPM: Ack failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int msm_bus_rpm_commit_arb(struct msm_bus_fabric_registration
+ *fab_pdata, int ctx, void *rpm_data,
+ struct commit_data *cd, bool valid)
+{
+ int i, status = 0, rsc_type, key;
+
+ MSM_BUS_DBG("Context: %d\n", ctx);
+ rsc_type = RPM_BUS_MASTER_REQ;
+ key = RPM_MASTER_FIELD_BW;
+ for (i = 0; i < fab_pdata->nmasters; i++) {
+ if (cd->mas_arb[i].dirty) {
+ MSM_BUS_DBG("MAS HWID: %d, BW: %llu DIRTY: %d\n",
+ cd->mas_arb[i].hw_id,
+ cd->mas_arb[i].bw,
+ cd->mas_arb[i].dirty);
+ status = msm_bus_rpm_req(ctx, rsc_type, key,
+ &cd->mas_arb[i], valid);
+ if (status) {
+ MSM_BUS_ERR("RPM: Req fail: mas:%d, bw:%llu\n",
+ cd->mas_arb[i].hw_id,
+ cd->mas_arb[i].bw);
+ break;
+ } else {
+ cd->mas_arb[i].dirty = false;
+ }
+ }
+ }
+
+ rsc_type = RPM_BUS_SLAVE_REQ;
+ key = RPM_SLAVE_FIELD_BW;
+ for (i = 0; i < fab_pdata->nslaves; i++) {
+ if (cd->slv_arb[i].dirty) {
+ MSM_BUS_DBG("SLV HWID: %d, BW: %llu DIRTY: %d\n",
+ cd->slv_arb[i].hw_id,
+ cd->slv_arb[i].bw,
+ cd->slv_arb[i].dirty);
+ status = msm_bus_rpm_req(ctx, rsc_type, key,
+ &cd->slv_arb[i], valid);
+ if (status) {
+ MSM_BUS_ERR("RPM: Req fail: slv:%d, bw:%llu\n",
+ cd->slv_arb[i].hw_id,
+ cd->slv_arb[i].bw);
+ break;
+ } else {
+ cd->slv_arb[i].dirty = false;
+ }
+ }
+ }
+
+ return status;
+}
+
+/**
+* msm_bus_remote_hw_commit() - Commit the arbitration data to RPM
+* @fabric: Fabric for which the data should be committed
+**/
+int msm_bus_remote_hw_commit(struct msm_bus_fabric_registration
+ *fab_pdata, void *hw_data, void **cdata)
+{
+
+ int ret;
+ bool valid;
+ struct commit_data *dual_cd, *act_cd;
+ void *rpm_data = hw_data;
+
+ MSM_BUS_DBG("\nReached RPM Commit\n");
+ dual_cd = (struct commit_data *)cdata[DUAL_CTX];
+ act_cd = (struct commit_data *)cdata[ACTIVE_CTX];
+
+ /*
+ * If the arb data for active set and sleep set is
+ * different, commit both sets.
+ * If the arb data for active set and sleep set is
+ * the same, invalidate the sleep set.
+ */
+ ret = msm_bus_rpm_compare_cdata(fab_pdata, act_cd, dual_cd);
+ if (!ret)
+ /* Invalidate sleep set.*/
+ valid = false;
+ else
+ valid = true;
+
+ ret = msm_bus_rpm_commit_arb(fab_pdata, DUAL_CTX, rpm_data,
+ dual_cd, valid);
+ if (ret)
+ MSM_BUS_ERR("Error comiting fabric:%d in %d ctx\n",
+ fab_pdata->id, DUAL_CTX);
+
+ valid = true;
+ ret = msm_bus_rpm_commit_arb(fab_pdata, ACTIVE_CTX, rpm_data, act_cd,
+ valid);
+ if (ret)
+ MSM_BUS_ERR("Error comiting fabric:%d in %d ctx\n",
+ fab_pdata->id, ACTIVE_CTX);
+
+ return ret;
+}
+
+int msm_bus_rpm_hw_init(struct msm_bus_fabric_registration *pdata,
+ struct msm_bus_hw_algorithm *hw_algo)
+{
+ if (!pdata->ahb)
+ pdata->rpm_enabled = 1;
+ return 0;
+}
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 200d717..6dde576 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -722,6 +722,8 @@
.unlocked_ioctl = dsps_ioctl,
};
+static struct subsys_device *dsps_dev;
+
/**
* Fatal error handler
* Resets DSPS.
@@ -735,7 +737,7 @@
pr_err("%s: DSPS already resetting. Count %d\n", __func__,
atomic_read(&drv->crash_in_progress));
} else {
- subsystem_restart("dsps");
+ subsystem_restart_dev(dsps_dev);
}
}
@@ -765,7 +767,7 @@
* called by the restart notifier
*
*/
-static int dsps_shutdown(const struct subsys_data *subsys)
+static int dsps_shutdown(const struct subsys_desc *subsys)
{
pr_debug("%s\n", __func__);
disable_irq_nosync(drv->wdog_irq);
@@ -779,7 +781,7 @@
* called by the restart notifier
*
*/
-static int dsps_powerup(const struct subsys_data *subsys)
+static int dsps_powerup(const struct subsys_desc *subsys)
{
pr_debug("%s\n", __func__);
dsps_power_on_handler();
@@ -794,7 +796,7 @@
* called by the restart notifier
*
*/
-static void dsps_crash_shutdown(const struct subsys_data *subsys)
+static void dsps_crash_shutdown(const struct subsys_desc *subsys)
{
pr_debug("%s\n", __func__);
dsps_crash_shutdown_g = 1;
@@ -806,7 +808,7 @@
* called by the restart notifier
*
*/
-static int dsps_ramdump(int enable, const struct subsys_data *subsys)
+static int dsps_ramdump(int enable, const struct subsys_desc *subsys)
{
int ret = 0;
pr_debug("%s\n", __func__);
@@ -838,7 +840,7 @@
return ret;
}
-static struct subsys_data dsps_ssrops = {
+static struct subsys_desc dsps_ssrops = {
.name = "dsps",
.shutdown = dsps_shutdown,
.powerup = dsps_powerup,
@@ -919,9 +921,10 @@
goto smsm_register_err;
}
- ret = ssr_register_subsystem(&dsps_ssrops);
- if (ret) {
- pr_err("%s: ssr_register_subsystem fail %d\n", __func__,
+ dsps_dev = subsys_register(&dsps_ssrops);
+ if (IS_ERR(dsps_dev)) {
+ ret = PTR_ERR(dsps_dev);
+ pr_err("%s: subsys_register fail %d\n", __func__,
ret);
goto ssr_register_err;
}
@@ -953,6 +956,7 @@
{
pr_debug("%s.\n", __func__);
+ subsys_unregister(dsps_dev);
dsps_power_off_handler();
dsps_free_resources();
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index 9825ce5..8254502 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -235,7 +235,8 @@
int is_d0 = xo == &msm_xo_sources[MSM_XO_TCXO_D0];
int needs_workaround = cpu_is_msm8960() || cpu_is_apq8064() ||
cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_msm9615() || cpu_is_msm8627();
+ cpu_is_msm9615() || cpu_is_msm8627() ||
+ cpu_is_msm8960ab();
if (xo_voter->mode == mode)
return 0;
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index 43c7fc8..a233080 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -10,7 +10,6 @@
* GNU General Public License for more details.
*/
-#include <mach/ocmem_priv.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -18,10 +17,12 @@
#include <linux/rbtree.h>
#include <linux/genalloc.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <mach/ocmem_priv.h>
/* This code is to temporarily work around the default state of OCMEM
regions in Virtio. These registers will be read from DT in a subsequent
@@ -41,14 +42,6 @@
unsigned int p_tail;
};
-struct ocmem_plat_data {
- void __iomem *vbase;
- unsigned long size;
- unsigned long base;
- struct ocmem_partition *parts;
- unsigned nr_parts;
-};
-
struct ocmem_zone zones[OCMEM_CLIENT_MAX];
struct ocmem_zone *get_zone(unsigned id)
@@ -183,8 +176,216 @@
return pdata;
}
+int __devinit of_ocmem_parse_regions(struct device *dev,
+ struct ocmem_partition **part)
+{
+ const char *name;
+ struct device_node *child = NULL;
+ int nr_parts = 0;
+ int i = 0;
+ int rc = 0;
+ int id = -1;
+
+ /*Compute total partitions */
+ for_each_child_of_node(dev->of_node, child)
+ nr_parts++;
+
+ if (nr_parts == 0)
+ return 0;
+
+ *part = devm_kzalloc(dev, nr_parts * sizeof(**part),
+ GFP_KERNEL);
+
+ if (!*part)
+ return -ENOMEM;
+
+ for_each_child_of_node(dev->of_node, child)
+ {
+ const u32 *addr;
+ u32 min;
+ u64 size;
+ u64 p_start;
+
+ addr = of_get_address(child, 0, &size, NULL);
+
+ if (!addr) {
+ dev_err(dev, "Invalid addr for partition %d, ignored\n",
+ i);
+ continue;
+ }
+
+ rc = of_property_read_u32(child, "qcom,ocmem-part-min", &min);
+
+ if (rc) {
+ dev_err(dev, "No min for partition %d, ignored\n", i);
+ continue;
+ }
+
+ rc = of_property_read_string(child, "qcom,ocmem-part-name",
+ &name);
+
+ if (rc) {
+ dev_err(dev, "No name for partition %d, ignored\n", i);
+ continue;
+ }
+
+ id = get_id(name);
+
+ if (id < 0) {
+ dev_err(dev, "Ignoring invalid partition %s\n", name);
+ continue;
+ }
+
+ p_start = of_translate_address(child, addr);
+
+ if (p_start == OF_BAD_ADDR) {
+ dev_err(dev, "Invalid offset for partition %d\n", i);
+ continue;
+ }
+
+ (*part)[i].p_start = p_start;
+ (*part)[i].p_size = size;
+ (*part)[i].id = id;
+ (*part)[i].name = name;
+ (*part)[i].p_min = min;
+ (*part)[i].p_tail = of_property_read_bool(child, "tail");
+ i++;
+ }
+
+ return i;
+}
+
static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = pdev->dev.of_node;
+ struct ocmem_plat_data *pdata = NULL;
+ struct ocmem_partition *parts = NULL;
+ struct resource *ocmem_irq;
+ struct resource *dm_irq;
+ struct resource *ocmem_mem;
+ struct resource *reg_base;
+ struct resource *br_base;
+ struct resource *dm_base;
+ struct resource *ocmem_mem_io;
+ unsigned nr_parts = 0;
+ unsigned nr_regions = 0;
+
+ pdata = devm_kzalloc(dev, sizeof(struct ocmem_plat_data),
+ GFP_KERNEL);
+
+ if (!pdata) {
+ dev_err(dev, "Unable to allocate memory for platform data\n");
+ return NULL;
+ }
+
+ ocmem_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "ocmem_physical");
+ if (!ocmem_mem) {
+ dev_err(dev, "No OCMEM memory resource\n");
+ return NULL;
+ }
+
+ ocmem_mem_io = request_mem_region(ocmem_mem->start,
+ resource_size(ocmem_mem), pdev->name);
+
+ if (!ocmem_mem_io) {
+ dev_err(dev, "Could not claim OCMEM memory\n");
+ return NULL;
+ }
+
+ pdata->base = ocmem_mem->start;
+ pdata->size = resource_size(ocmem_mem);
+ pdata->vbase = devm_ioremap_nocache(dev, ocmem_mem->start,
+ resource_size(ocmem_mem));
+ if (!pdata->vbase) {
+ dev_err(dev, "Could not ioremap ocmem memory\n");
+ return NULL;
+ }
+
+ reg_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "ocmem_ctrl_physical");
+ if (!reg_base) {
+ dev_err(dev, "No OCMEM register resource\n");
+ return NULL;
+ }
+
+ pdata->reg_base = devm_ioremap_nocache(dev, reg_base->start,
+ resource_size(reg_base));
+ if (!pdata->reg_base) {
+ dev_err(dev, "Could not ioremap register map\n");
+ return NULL;
+ }
+
+ br_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "br_ctrl_physical");
+ if (!br_base) {
+ dev_err(dev, "No OCMEM BR resource\n");
+ return NULL;
+ }
+
+ pdata->br_base = devm_ioremap_nocache(dev, br_base->start,
+ resource_size(br_base));
+ if (!pdata->br_base) {
+ dev_err(dev, "Could not ioremap BR resource\n");
+ return NULL;
+ }
+
+ dm_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "dm_ctrl_physical");
+ if (!dm_base) {
+ dev_err(dev, "No OCMEM DM resource\n");
+ return NULL;
+ }
+
+ pdata->dm_base = devm_ioremap_nocache(dev, dm_base->start,
+ resource_size(dm_base));
+ if (!pdata->dm_base) {
+ dev_err(dev, "Could not ioremap DM resource\n");
+ return NULL;
+ }
+
+ ocmem_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+ "ocmem_irq");
+
+ if (!ocmem_irq) {
+ dev_err(dev, "No OCMEM IRQ resource\n");
+ return NULL;
+ }
+
+ dm_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+ "dm_irq");
+
+ if (!dm_irq) {
+ dev_err(dev, "No DM IRQ resource\n");
+ return NULL;
+ }
+
+ if (of_property_read_u32(node, "qcom,ocmem-num-regions",
+ &nr_regions)) {
+ dev_err(dev, "No OCMEM memory regions specified\n");
+ }
+
+ if (nr_regions == 0) {
+ dev_err(dev, "No hardware memory regions found\n");
+ return NULL;
+ }
+
+ /* Figure out the number of partititons */
+ nr_parts = of_ocmem_parse_regions(dev, &parts);
+ if (nr_parts <= 0) {
+ dev_err(dev, "No valid OCMEM partitions found\n");
+ goto pdata_error;
+ } else
+ dev_dbg(dev, "Found %d ocmem partitions\n", nr_parts);
+
+ pdata->nr_parts = nr_parts;
+ pdata->parts = parts;
+ pdata->nr_regions = nr_regions;
+ pdata->ocmem_irq = ocmem_irq->start;
+ pdata->dm_irq = dm_irq->start;
+ return pdata;
+pdata_error:
return NULL;
}
@@ -225,7 +426,7 @@
return -EBUSY;
}
- start = pdata->base + part->p_start;
+ start = part->p_start;
ret = gen_pool_add(zone->z_pool, start,
part->p_size, -1);
@@ -273,7 +474,7 @@
zone->z_end, part->p_size/SZ_1K);
}
- dev_info(dev, "Total active zones = %d\n", active_zones);
+ dev_dbg(dev, "Total active zones = %d\n", active_zones);
return 0;
}
@@ -282,7 +483,7 @@
struct device *dev = &pdev->dev;
void *ocmem_region_vbase = NULL;
- if (!pdev->dev.of_node->child) {
+ if (!pdev->dev.of_node) {
dev_info(dev, "Missing Configuration in Device Tree\n");
ocmem_pdata = parse_static_config(pdev);
} else {
@@ -297,6 +498,8 @@
BUG_ON(!IS_ALIGNED(ocmem_pdata->size, PAGE_SIZE));
BUG_ON(!IS_ALIGNED(ocmem_pdata->base, PAGE_SIZE));
+ dev_info(dev, "OCMEM Virtual addr %p\n", ocmem_pdata->vbase);
+
platform_set_drvdata(pdev, ocmem_pdata);
if (ocmem_zone_init(pdev))
@@ -316,7 +519,7 @@
writel_relaxed(REGION_ENABLE, ocmem_region_vbase);
writel_relaxed(REGION_ENABLE, ocmem_region_vbase + 4);
writel_relaxed(REGION_ENABLE, ocmem_region_vbase + 8);
- dev_info(dev, "initialized successfully\n");
+ dev_dbg(dev, "initialized successfully\n");
return 0;
}
@@ -326,7 +529,7 @@
}
static struct of_device_id msm_ocmem_dt_match[] = {
- { .compatible = "qcom,msm_ocmem",
+ { .compatible = "qcom,msm-ocmem",
},
{}
};
diff --git a/arch/arm/mach-msm/ocmem_notifier.c b/arch/arm/mach-msm/ocmem_notifier.c
index 58ad3d9..4754f44 100644
--- a/arch/arm/mach-msm/ocmem_notifier.c
+++ b/arch/arm/mach-msm/ocmem_notifier.c
@@ -75,7 +75,8 @@
return ret;
}
-void *ocmem_notifier_register(int client_id, struct notifier_block *nb)
+struct ocmem_notifier *ocmem_notifier_register(int client_id,
+ struct notifier_block *nb)
{
int ret = 0;
@@ -115,13 +116,12 @@
}
EXPORT_SYMBOL(ocmem_notifier_register);
-int ocmem_notifier_unregister(void *hndl, struct notifier_block *nb)
+int ocmem_notifier_unregister(struct ocmem_notifier *nc_hndl,
+ struct notifier_block *nb)
{
int ret = 0;
- struct ocmem_notifier *nc_hndl = (struct ocmem_notifier *) hndl;
-
if (!nc_hndl) {
pr_err("ocmem: Invalid notification handle\n");
return -EINVAL;
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 3f6eb95..540ffbb 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -565,18 +565,6 @@
static void msm_pil_debugfs_remove(struct pil_device *pil) { }
#endif
-static int __msm_pil_shutdown(struct device *dev, void *data)
-{
- pil_shutdown(to_pil_device(dev));
- return 0;
-}
-
-static int msm_pil_shutdown_at_boot(void)
-{
- return bus_for_each_dev(&pil_bus_type, NULL, NULL, __msm_pil_shutdown);
-}
-late_initcall(msm_pil_shutdown_at_boot);
-
static void pil_device_release(struct device *dev)
{
struct pil_device *pil = to_pil_device(dev);
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 48a236f..5e063a1 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -143,7 +143,7 @@
return krait_release_secondary_sim(0xf9088000, cpu);
if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_apq8064() || cpu_is_msm8627())
+ cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab())
return krait_release_secondary(0x02088000, cpu);
WARN(1, "unknown CPU case in release_secondary\n");
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 15a0b6a..e203667 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -24,7 +24,6 @@
#include <linux/smp.h>
#include <linux/suspend.h>
#include <linux/tick.h>
-#include <linux/delay.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
#include <mach/system.h>
@@ -591,7 +590,7 @@
static int64_t msm_pm_timer_enter_suspend(int64_t *period)
{
- int time = 0;
+ int64_t time = 0;
if (msm_pm_use_qtimer)
return sched_clock();
@@ -799,23 +798,6 @@
return 0;
}
-static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
-
-static DEFINE_PER_CPU_SHARED_ALIGNED(enum msm_pm_sleep_mode,
- msm_pm_last_slp_mode);
-
-bool msm_pm_verify_cpu_pc(unsigned int cpu)
-{
- enum msm_pm_sleep_mode mode = per_cpu(msm_pm_last_slp_mode, cpu);
-
- if (msm_pm_slp_sts)
- if ((mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) ||
- (mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE))
- return true;
-
- return false;
-}
-
void msm_pm_cpu_enter_lowpower(unsigned int cpu)
{
int i;
@@ -831,54 +813,14 @@
if (MSM_PM_DEBUG_HOTPLUG & msm_pm_debug_mask)
pr_notice("CPU%u: %s: shutting down cpu\n", cpu, __func__);
- if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE]) {
- per_cpu(msm_pm_last_slp_mode, cpu)
- = MSM_PM_SLEEP_MODE_POWER_COLLAPSE;
+ if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
msm_pm_power_collapse(false);
- } else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
- per_cpu(msm_pm_last_slp_mode, cpu)
- = MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
+ else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE])
msm_pm_power_collapse_standalone(false);
- } else if (allow[MSM_PM_SLEEP_MODE_RETENTION]) {
- per_cpu(msm_pm_last_slp_mode, cpu)
- = MSM_PM_SLEEP_MODE_RETENTION;
+ else if (allow[MSM_PM_SLEEP_MODE_RETENTION])
msm_pm_retention();
- } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
- per_cpu(msm_pm_last_slp_mode, cpu)
- = MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT;
+ else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT])
msm_pm_swfi();
- } else
- per_cpu(msm_pm_last_slp_mode, cpu) = MSM_PM_SLEEP_MODE_NR;
-}
-
-int msm_pm_wait_cpu_shutdown(unsigned int cpu)
-{
-
- int timeout = 10;
-
- if (!msm_pm_slp_sts)
- return 0;
-
- while (timeout--) {
-
- /*
- * Check for the SPM of the core being hotplugged to set
- * its sleep state.The SPM sleep state indicates that the
- * core has been power collapsed.
- */
-
- int acc_sts = __raw_readl(msm_pm_slp_sts->base_addr
- + cpu * msm_pm_slp_sts->cpu_offset);
- mb();
-
- if (acc_sts & msm_pm_slp_sts->mask)
- return 0;
-
- usleep(100);
- }
- pr_warn("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
- __func__, cpu);
- return -EBUSY;
}
static int msm_pm_enter(suspend_state_t state)
@@ -975,12 +917,6 @@
/******************************************************************************
* Initialization routine
*****************************************************************************/
-void __init msm_pm_init_sleep_status_data(
- struct msm_pm_sleep_status_data *data)
-{
- msm_pm_slp_sts = data;
-}
-
void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops)
{
if (ops)
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 70d54da..c722ff6 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -70,12 +70,6 @@
extern struct msm_pm_platform_data msm_pm_sleep_modes[];
-struct msm_pm_sleep_status_data {
- void *base_addr;
- uint32_t cpu_offset;
- uint32_t mask;
-};
-
struct msm_pm_sleep_ops {
void *(*lowest_limits)(bool from_idle,
enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
@@ -93,19 +87,11 @@
int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
void msm_pm_cpu_enter_lowpower(unsigned int cpu);
-void __init msm_pm_init_sleep_status_data(
- struct msm_pm_sleep_status_data *sleep_data);
-
-
#ifdef CONFIG_MSM_PM8X60
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
-int msm_pm_wait_cpu_shutdown(unsigned int cpu);
-bool msm_pm_verify_cpu_pc(unsigned int cpu);
void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops);
#else
static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
-static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; }
-static inline bool msm_pm_verify_cpu_pc(unsigned int cpu) { return true; }
static inline void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops) {}
#endif
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index ae7a3cd..7a8e4c3 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -1280,7 +1280,7 @@
static int64_t msm_pm_timer_enter_suspend(int64_t *period)
{
- int time = 0;
+ int64_t time = 0;
time = msm_timer_get_sclk_time(period);
if (!time)
diff --git a/arch/arm/mach-msm/qdsp5/audio_voicememo.c b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
index 03dd295..34e5b81 100644
--- a/arch/arm/mach-msm/qdsp5/audio_voicememo.c
+++ b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
@@ -459,7 +459,7 @@
if (datacb_data->pkt.fw_data.fw_ptr_status &&
be32_to_cpu(datacb_data->pkt.fw_data.rec_length) &&
be32_to_cpu(datacb_data->pkt.fw_data.rec_length)
- <= MAX_FRAME_SIZE) {
+ <= MAX_REC_BUF_SIZE) {
MM_DBG("Copy FW link:rec_buf_size \
= 0x%08x, rec_length=0x%08x\n",
@@ -484,7 +484,7 @@
} else if (datacb_data->pkt.rw_data.rw_ptr_status &&
be32_to_cpu(datacb_data->pkt.rw_data.rec_length) &&
be32_to_cpu(datacb_data->pkt.rw_data.rec_length)
- <= MAX_FRAME_SIZE) {
+ <= MAX_REC_BUF_SIZE) {
MM_DBG("Copy RW link:rec_buf_size \
=0x%08x, rec_length=0x%08x\n",
@@ -509,12 +509,12 @@
} else {
MM_ERR("FW: ptr_status %d, rec_length=0x%08x,"
"RW: ptr_status %d, rec_length=0x%08x\n",
- datacb_data->pkt.rw_data.fw_ptr_status, \
+ datacb_data->pkt.fw_data.fw_ptr_status, \
be32_to_cpu( \
datacb_data->pkt.fw_data.rec_length), \
- datacb_data->pkt.rw_data.fw_ptr_status, \
+ datacb_data->pkt.rw_data.rw_ptr_status, \
be32_to_cpu( \
- datacb_data->pkt.fw_data.rec_length));
+ datacb_data->pkt.rw_data.rec_length));
}
if (rec_status != RPC_VOC_REC_STAT_DONE) {
/* Not end of record */
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 2403c02..a0bfb27 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -372,10 +372,14 @@
if (q6.state == APR_Q6_NOIMG) {
q6.pil = pil_get("q6");
if (IS_ERR(q6.pil)) {
- rc = PTR_ERR(q6.pil);
- pr_err("APR: Unable to load q6 image, error:%d\n", rc);
- mutex_unlock(&q6.lock);
- return svc;
+ q6.pil = pil_get("adsp");
+ if (IS_ERR(q6.pil)) {
+ rc = PTR_ERR(q6.pil);
+ pr_err("APR: Unable to load q6 image, error:%d\n",
+ rc);
+ mutex_unlock(&q6.lock);
+ return svc;
+ }
}
q6.state = APR_Q6_LOADED;
}
diff --git a/arch/arm/mach-msm/ramdump.c b/arch/arm/mach-msm/ramdump.c
index a18acd6..21e81dd 100644
--- a/arch/arm/mach-msm/ramdump.c
+++ b/arch/arm/mach-msm/ramdump.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -222,6 +222,17 @@
return (void *)rd_dev;
}
+void destroy_ramdump_device(void *dev)
+{
+ struct ramdump_device *rd_dev = dev;
+
+ if (IS_ERR_OR_NULL(rd_dev))
+ return;
+
+ misc_deregister(&rd_dev->device);
+ kfree(rd_dev);
+}
+
int do_ramdump(void *handle, struct ramdump_segment *segments,
int nsegments)
{
diff --git a/arch/arm/mach-msm/ramdump.h b/arch/arm/mach-msm/ramdump.h
index 0b60a44..9006010 100644
--- a/arch/arm/mach-msm/ramdump.h
+++ b/arch/arm/mach-msm/ramdump.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This 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 @@
};
void *create_ramdump_device(const char *dev_name);
+void destroy_ramdump_device(void *dev);
int do_ramdump(void *handle, struct ramdump_segment *segments,
int nsegments);
diff --git a/arch/arm/mach-msm/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
index fdff231..a8af9e7 100644
--- a/arch/arm/mach-msm/rpm-regulator-smd.c
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -68,6 +68,7 @@
RPM_REGULATOR_PARAM_QUIET_MODE,
RPM_REGULATOR_PARAM_FREQ_REASON,
RPM_REGULATOR_PARAM_CORNER,
+ RPM_REGULATOR_PARAM_BYPASS,
RPM_REGULATOR_PARAM_MAX,
};
@@ -111,7 +112,8 @@
PARAM(HEAD_ROOM, 1, 0, 0, 1, "hr", 0, 0x7FFFFFFF, "qcom,init-head-room"),
PARAM(QUIET_MODE, 0, 1, 0, 0, "qm", 0, 2, "qcom,init-quiet-mode"),
PARAM(FREQ_REASON, 0, 1, 0, 1, "resn", 0, 8, "qcom,init-freq-reason"),
- PARAM(CORNER, 0, 1, 0, 0, "corn", 0, 5, "qcom,init-voltage-corner"),
+ PARAM(CORNER, 0, 1, 0, 0, "corn", 0, 6, "qcom,init-voltage-corner"),
+ PARAM(BYPASS, 1, 0, 0, 0, "bypa", 0, 1, "qcom,init-disallow-bypass"),
};
struct rpm_vreg_request {
@@ -440,6 +442,7 @@
RPM_VREG_AGGR_MAX(QUIET_MODE, param_aggr, param_reg);
RPM_VREG_AGGR_MAX(FREQ_REASON, param_aggr, param_reg);
RPM_VREG_AGGR_MAX(CORNER, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(BYPASS, param_aggr, param_reg);
}
static int rpm_vreg_aggregate_requests(struct rpm_regulator *regulator)
@@ -682,7 +685,7 @@
* regulator_set_voltage function to the actual corner values
* sent to the RPM.
*/
- corner = min_uV - RPM_REGULATOR_CORNER_RETENTION;
+ corner = min_uV - RPM_REGULATOR_CORNER_NONE;
if (corner < params[RPM_REGULATOR_PARAM_CORNER].min
|| corner > params[RPM_REGULATOR_PARAM_CORNER].max) {
@@ -716,7 +719,7 @@
struct rpm_regulator *reg = rdev_get_drvdata(rdev);
return reg->req.param[RPM_REGULATOR_PARAM_CORNER]
- + RPM_REGULATOR_CORNER_RETENTION;
+ + RPM_REGULATOR_CORNER_NONE;
}
static int rpm_vreg_set_mode(struct regulator_dev *rdev, unsigned int mode)
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index b8bb27b..697d504 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -24,6 +24,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
+#include <linux/string.h>
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/slab.h>
@@ -36,6 +37,19 @@
#include <mach/rpm-smd.h>
#include "rpm-notifier.h"
+/* Debug Definitions */
+
+enum {
+ MSM_RPM_LOG_REQUEST_PRETTY = BIT(0),
+ MSM_RPM_LOG_REQUEST_RAW = BIT(1),
+ MSM_RPM_LOG_REQUEST_SHOW_MSG_ID = BIT(2),
+};
+
+static int msm_rpm_debug_mask;
+module_param_named(
+ debug_mask, msm_rpm_debug_mask, int, S_IRUGO | S_IWUSR
+);
+
struct msm_rpm_driver_data {
const char *ch_name;
uint32_t ch_type;
@@ -492,6 +506,140 @@
}
}
+#define DEBUG_PRINT_BUFFER_SIZE 512
+
+static void msm_rpm_log_request(struct msm_rpm_request *cdata)
+{
+ char buf[DEBUG_PRINT_BUFFER_SIZE];
+ size_t buflen = DEBUG_PRINT_BUFFER_SIZE;
+ char name[5];
+ u32 value;
+ int i, j, prev_valid;
+ int valid_count = 0;
+ int pos = 0;
+
+ name[4] = 0;
+
+ for (i = 0; i < cdata->write_idx; i++)
+ if (cdata->kvp[i].valid)
+ valid_count++;
+
+ pos += scnprintf(buf + pos, buflen - pos, "%sRPM req: ", KERN_INFO);
+ if (msm_rpm_debug_mask & MSM_RPM_LOG_REQUEST_SHOW_MSG_ID)
+ pos += scnprintf(buf + pos, buflen - pos, "msg_id=%u, ",
+ cdata->msg_hdr.msg_id);
+ pos += scnprintf(buf + pos, buflen - pos, "s=%s",
+ (cdata->msg_hdr.set == MSM_RPM_CTX_ACTIVE_SET ? "act" : "slp"));
+
+ if ((msm_rpm_debug_mask & MSM_RPM_LOG_REQUEST_PRETTY)
+ && (msm_rpm_debug_mask & MSM_RPM_LOG_REQUEST_RAW)) {
+ /* Both pretty and raw formatting */
+ memcpy(name, &cdata->msg_hdr.resource_type, sizeof(uint32_t));
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", rsc_type=0x%08X (%s), rsc_id=%u; ",
+ cdata->msg_hdr.resource_type, name,
+ cdata->msg_hdr.resource_id);
+
+ for (i = 0, prev_valid = 0; i < cdata->write_idx; i++) {
+ if (!cdata->kvp[i].valid)
+ continue;
+
+ memcpy(name, &cdata->kvp[i].key, sizeof(uint32_t));
+ pos += scnprintf(buf + pos, buflen - pos,
+ "[key=0x%08X (%s), value=%s",
+ cdata->kvp[i].key, name,
+ (cdata->kvp[i].nbytes ? "0x" : "null"));
+
+ for (j = 0; j < cdata->kvp[i].nbytes; j++)
+ pos += scnprintf(buf + pos, buflen - pos,
+ "%02X ",
+ cdata->kvp[i].value[j]);
+
+ if (cdata->kvp[i].nbytes)
+ pos += scnprintf(buf + pos, buflen - pos, "(");
+
+ for (j = 0; j < cdata->kvp[i].nbytes; j += 4) {
+ value = 0;
+ memcpy(&value, &cdata->kvp[i].value[j],
+ min(sizeof(uint32_t),
+ cdata->kvp[i].nbytes - j));
+ pos += scnprintf(buf + pos, buflen - pos, "%u",
+ value);
+ if (j + 4 < cdata->kvp[i].nbytes)
+ pos += scnprintf(buf + pos,
+ buflen - pos, " ");
+ }
+ if (cdata->kvp[i].nbytes)
+ pos += scnprintf(buf + pos, buflen - pos, ")");
+ pos += scnprintf(buf + pos, buflen - pos, "]");
+ if (prev_valid + 1 < valid_count)
+ pos += scnprintf(buf + pos, buflen - pos, ", ");
+ prev_valid++;
+ }
+ } else if (msm_rpm_debug_mask & MSM_RPM_LOG_REQUEST_PRETTY) {
+ /* Pretty formatting only */
+ memcpy(name, &cdata->msg_hdr.resource_type, sizeof(uint32_t));
+ pos += scnprintf(buf + pos, buflen - pos, " %s %u; ", name,
+ cdata->msg_hdr.resource_id);
+
+ for (i = 0, prev_valid = 0; i < cdata->write_idx; i++) {
+ if (!cdata->kvp[i].valid)
+ continue;
+
+ memcpy(name, &cdata->kvp[i].key, sizeof(uint32_t));
+ pos += scnprintf(buf + pos, buflen - pos, "%s=%s",
+ name, (cdata->kvp[i].nbytes ? "" : "null"));
+
+ for (j = 0; j < cdata->kvp[i].nbytes; j += 4) {
+ value = 0;
+ memcpy(&value, &cdata->kvp[i].value[j],
+ min(sizeof(uint32_t),
+ cdata->kvp[i].nbytes - j));
+ pos += scnprintf(buf + pos, buflen - pos, "%u",
+ value);
+
+ if (j + 4 < cdata->kvp[i].nbytes)
+ pos += scnprintf(buf + pos,
+ buflen - pos, " ");
+ }
+ if (prev_valid + 1 < valid_count)
+ pos += scnprintf(buf + pos, buflen - pos, ", ");
+ prev_valid++;
+ }
+ } else {
+ /* Raw formatting only */
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", rsc_type=0x%08X, rsc_id=%u; ",
+ cdata->msg_hdr.resource_type,
+ cdata->msg_hdr.resource_id);
+
+ for (i = 0, prev_valid = 0; i < cdata->write_idx; i++) {
+ if (!cdata->kvp[i].valid)
+ continue;
+
+ pos += scnprintf(buf + pos, buflen - pos,
+ "[key=0x%08X, value=%s",
+ cdata->kvp[i].key,
+ (cdata->kvp[i].nbytes ? "0x" : "null"));
+ for (j = 0; j < cdata->kvp[i].nbytes; j++) {
+ pos += scnprintf(buf + pos, buflen - pos,
+ "%02X",
+ cdata->kvp[i].value[j]);
+ if (j + 1 < cdata->kvp[i].nbytes)
+ pos += scnprintf(buf + pos,
+ buflen - pos, " ");
+ }
+ pos += scnprintf(buf + pos, buflen - pos, "]");
+ if (prev_valid + 1 < valid_count)
+ pos += scnprintf(buf + pos, buflen - pos, ", ");
+ prev_valid++;
+ }
+ }
+
+ pos += scnprintf(buf + pos, buflen - pos, "\n");
+ printk(buf);
+}
+
static int msm_rpm_send_data(struct msm_rpm_request *cdata,
int msg_type, bool noirq)
{
@@ -546,6 +694,10 @@
tmpbuff += cdata->kvp[i].nbytes;
}
+ if (msm_rpm_debug_mask
+ & (MSM_RPM_LOG_REQUEST_PRETTY | MSM_RPM_LOG_REQUEST_RAW))
+ msm_rpm_log_request(cdata);
+
if (standalone) {
for (i = 0; (i < cdata->write_idx); i++)
cdata->kvp[i].valid = false;
diff --git a/arch/arm/mach-msm/rpm_resources.c b/arch/arm/mach-msm/rpm_resources.c
index 667ede0..a88e42e 100644
--- a/arch/arm/mach-msm/rpm_resources.c
+++ b/arch/arm/mach-msm/rpm_resources.c
@@ -1106,7 +1106,7 @@
static int __init msm_rpmrs_l2_init(void)
{
if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_apq8064() || cpu_is_msm8627()) {
+ cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab()) {
msm_pm_set_l2_flush_flag(0);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 54512ab..948dbbb 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -559,7 +559,11 @@
* on DEM-based targets. Grabbing a wakelock in this case will
* abort the power-down sequencing.
*/
- smsm_cb_snapshot(0);
+ if (smsm_info.intr_mask &&
+ (__raw_readl(SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_APPS))
+ & notify_mask)) {
+ smsm_cb_snapshot(0);
+ }
}
void smd_diag(void)
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index fdbc387..b9fe341 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -725,6 +725,8 @@
SMD_APPS_MODEM,
};
#endif
+module_param_named(loopback_edge, smd_ch_edge[LOOPBACK_INX],
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
static int smd_pkt_dummy_probe(struct platform_device *pdev)
{
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 4bcb9f7..817c2dc 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -265,8 +265,10 @@
[140] = MSM_CPU_8960AB,
[141] = MSM_CPU_8960AB,
- /* 8930AA ID */
+ /* 8930AA IDs */
[142] = MSM_CPU_8930AA,
+ [143] = MSM_CPU_8930AA,
+ [144] = MSM_CPU_8930AA,
/* Uninitialized IDs are not known to run Linux.
MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
@@ -796,6 +798,11 @@
};
}
+const int cpu_is_krait(void)
+{
+ return ((read_cpuid_id() & 0xFF00FC00) == 0x51000400);
+}
+
const int cpu_is_krait_v1(void)
{
switch (read_cpuid_id()) {
@@ -808,3 +815,22 @@
return 0;
};
}
+
+const int cpu_is_krait_v2(void)
+{
+ switch (read_cpuid_id()) {
+ case 0x511F04D0:
+ case 0x511F04D1:
+ case 0x511F04D2:
+ case 0x511F04D3:
+ case 0x511F04D4:
+
+ case 0x510F06F0:
+ case 0x510F06F1:
+ case 0x510F06F2:
+ return 1;
+
+ default:
+ return 0;
+ };
+}
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 9d2aedc..9e9b661 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -137,7 +137,7 @@
reg = saw_bases[cpu];
if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_apq8064() || cpu_is_msm8627()) {
+ cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab()) {
val = 0xA4;
reg += 0x14;
timeout = 512;
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index a9a25b3..65da903 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -17,7 +17,6 @@
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/io.h>
@@ -25,11 +24,13 @@
#include <linux/time.h>
#include <linux/wakelock.h>
#include <linux/suspend.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
#include <asm/current.h>
#include <mach/peripheral-loader.h>
-#include <mach/scm.h>
#include <mach/socinfo.h>
#include <mach/subsystem_notif.h>
#include <mach/subsystem_restart.h>
@@ -42,30 +43,40 @@
struct mutex shutdown_lock;
struct mutex powerup_lock;
- struct subsys_data *subsys_ptrs[];
-};
-
-struct restart_wq_data {
- struct subsys_data *subsys;
- struct wake_lock ssr_wake_lock;
- char wlname[64];
- int use_restart_order;
- struct work_struct work;
+ struct subsys_device *subsys_ptrs[];
};
struct restart_log {
struct timeval time;
- struct subsys_data *subsys;
+ struct subsys_device *dev;
struct list_head list;
};
-static int restart_level;
+struct subsys_device {
+ struct subsys_desc *desc;
+ struct list_head list;
+ struct wake_lock wake_lock;
+ char wlname[64];
+ struct work_struct work;
+ spinlock_t restart_lock;
+ bool restarting;
+
+ void *notify;
+
+ struct mutex shutdown_lock;
+ struct mutex powerup_lock;
+
+ void *restart_order;
+};
+
static int enable_ramdumps;
+module_param(enable_ramdumps, int, S_IRUGO | S_IWUSR);
+
struct workqueue_struct *ssr_wq;
static LIST_HEAD(restart_log_list);
static LIST_HEAD(subsystem_list);
-static DEFINE_SPINLOCK(subsystem_list_lock);
+static DEFINE_MUTEX(subsystem_list_lock);
static DEFINE_MUTEX(soc_order_reg_lock);
static DEFINE_MUTEX(restart_log_mutex);
@@ -122,10 +133,7 @@
static struct subsys_soc_restart_order **restart_orders;
static int n_restart_orders;
-module_param(enable_ramdumps, int, S_IRUGO | S_IWUSR);
-
-static struct subsys_soc_restart_order *_update_restart_order(
- struct subsys_data *subsys);
+static int restart_level = RESET_SOC;
int get_restart_level()
{
@@ -148,18 +156,14 @@
return ret;
switch (restart_level) {
-
case RESET_SOC:
case RESET_SUBSYS_COUPLED:
case RESET_SUBSYS_INDEPENDENT:
pr_info("Phase %d behavior activated.\n", restart_level);
- break;
-
+ break;
default:
restart_level = old_val;
return -EINVAL;
- break;
-
}
return 0;
}
@@ -167,62 +171,29 @@
module_param_call(restart_level, restart_level_set, param_get_int,
&restart_level, 0644);
-static struct subsys_data *_find_subsystem(const char *subsys_name)
-{
- struct subsys_data *subsys;
- unsigned long flags;
-
- spin_lock_irqsave(&subsystem_list_lock, flags);
- list_for_each_entry(subsys, &subsystem_list, list)
- if (!strncmp(subsys->name, subsys_name,
- SUBSYS_NAME_MAX_LENGTH)) {
- spin_unlock_irqrestore(&subsystem_list_lock, flags);
- return subsys;
- }
- spin_unlock_irqrestore(&subsystem_list_lock, flags);
-
- return NULL;
-}
-
-static struct subsys_soc_restart_order *_update_restart_order(
- struct subsys_data *subsys)
+static struct subsys_soc_restart_order *
+update_restart_order(struct subsys_device *dev)
{
int i, j;
-
- if (!subsys)
- return NULL;
-
- if (!subsys->name)
- return NULL;
+ struct subsys_soc_restart_order *order;
+ const char *name = dev->desc->name;
+ int len = SUBSYS_NAME_MAX_LENGTH;
mutex_lock(&soc_order_reg_lock);
for (j = 0; j < n_restart_orders; j++) {
- for (i = 0; i < restart_orders[j]->count; i++)
- if (!strncmp(restart_orders[j]->subsystem_list[i],
- subsys->name, SUBSYS_NAME_MAX_LENGTH)) {
-
- restart_orders[j]->subsys_ptrs[i] =
- subsys;
- mutex_unlock(&soc_order_reg_lock);
- return restart_orders[j];
+ order = restart_orders[j];
+ for (i = 0; i < order->count; i++) {
+ if (!strncmp(order->subsystem_list[i], name, len)) {
+ order->subsys_ptrs[i] = dev;
+ goto found;
}
+ }
}
-
+ order = NULL;
+found:
mutex_unlock(&soc_order_reg_lock);
- return NULL;
-}
-
-static void _send_notification_to_order(struct subsys_data
- **restart_list, int count,
- enum subsys_notif_type notif_type)
-{
- int i;
-
- for (i = 0; i < count; i++)
- if (restart_list[i])
- subsys_notif_queue_notification(
- restart_list[i]->notif_handle, notif_type);
+ return order;
}
static int max_restarts;
@@ -231,7 +202,7 @@
static long max_history_time = 3600;
module_param(max_history_time, long, 0644);
-static void do_epoch_check(struct subsys_data *subsys)
+static void do_epoch_check(struct subsys_device *dev)
{
int n = 0;
struct timeval *time_first = NULL, *curr_time;
@@ -251,7 +222,7 @@
r_log = kmalloc(sizeof(struct restart_log), GFP_KERNEL);
if (!r_log)
goto out;
- r_log->subsys = subsys;
+ r_log->dev = dev;
do_gettimeofday(&r_log->time);
curr_time = &r_log->time;
INIT_LIST_HEAD(&r_log->list);
@@ -289,42 +260,94 @@
mutex_unlock(&restart_log_mutex);
}
+static void for_each_subsys_device(struct subsys_device **list, unsigned count,
+ void *data, void (*fn)(struct subsys_device *, void *))
+{
+ while (count--) {
+ struct subsys_device *dev = *list++;
+ if (!dev)
+ continue;
+ fn(dev, data);
+ }
+}
+
+static void __send_notification_to_order(struct subsys_device *dev, void *data)
+{
+ enum subsys_notif_type type = (enum subsys_notif_type)data;
+
+ subsys_notif_queue_notification(dev->notify, type);
+}
+
+static void send_notification_to_order(struct subsys_device **l, unsigned n,
+ enum subsys_notif_type t)
+{
+ for_each_subsys_device(l, n, (void *)t, __send_notification_to_order);
+}
+
+static void subsystem_shutdown(struct subsys_device *dev, void *data)
+{
+ const char *name = dev->desc->name;
+
+ pr_info("[%p]: Shutting down %s\n", current, name);
+ if (dev->desc->shutdown(dev->desc) < 0)
+ panic("subsys-restart: [%p]: Failed to shutdown %s!",
+ current, name);
+}
+
+static void subsystem_ramdump(struct subsys_device *dev, void *data)
+{
+ const char *name = dev->desc->name;
+
+ if (dev->desc->ramdump)
+ if (dev->desc->ramdump(enable_ramdumps, dev->desc) < 0)
+ pr_warn("%s[%p]: Ramdump failed.\n", name, current);
+}
+
+static void subsystem_powerup(struct subsys_device *dev, void *data)
+{
+ const char *name = dev->desc->name;
+
+ pr_info("[%p]: Powering up %s\n", current, name);
+ if (dev->desc->powerup(dev->desc) < 0)
+ panic("[%p]: Failed to powerup %s!", current, name);
+}
+
static void subsystem_restart_wq_func(struct work_struct *work)
{
- struct restart_wq_data *r_work = container_of(work,
- struct restart_wq_data, work);
- struct subsys_data **restart_list;
- struct subsys_data *subsys = r_work->subsys;
+ struct subsys_device *dev = container_of(work,
+ struct subsys_device, work);
+ struct subsys_device **list;
+ struct subsys_desc *desc = dev->desc;
struct subsys_soc_restart_order *soc_restart_order = NULL;
-
struct mutex *powerup_lock;
struct mutex *shutdown_lock;
+ unsigned count;
+ unsigned long flags;
- int i;
- int restart_list_count = 0;
+ if (restart_level != RESET_SUBSYS_INDEPENDENT)
+ soc_restart_order = dev->restart_order;
- if (r_work->use_restart_order)
- soc_restart_order = subsys->restart_order;
-
- /* It's OK to not take the registration lock at this point.
+ /*
+ * It's OK to not take the registration lock at this point.
* This is because the subsystem list inside the relevant
* restart order is not being traversed.
*/
if (!soc_restart_order) {
- restart_list = subsys->single_restart_list;
- restart_list_count = 1;
- powerup_lock = &subsys->powerup_lock;
- shutdown_lock = &subsys->shutdown_lock;
+ list = &dev;
+ count = 1;
+ powerup_lock = &dev->powerup_lock;
+ shutdown_lock = &dev->shutdown_lock;
} else {
- restart_list = soc_restart_order->subsys_ptrs;
- restart_list_count = soc_restart_order->count;
+ list = soc_restart_order->subsys_ptrs;
+ count = soc_restart_order->count;
powerup_lock = &soc_restart_order->powerup_lock;
shutdown_lock = &soc_restart_order->shutdown_lock;
}
pr_debug("[%p]: Attempting to get shutdown lock!\n", current);
- /* Try to acquire shutdown_lock. If this fails, these subsystems are
+ /*
+ * Try to acquire shutdown_lock. If this fails, these subsystems are
* already being restarted - return.
*/
if (!mutex_trylock(shutdown_lock))
@@ -332,7 +355,8 @@
pr_debug("[%p]: Attempting to get powerup lock!\n", current);
- /* Now that we've acquired the shutdown lock, either we're the first to
+ /*
+ * Now that we've acquired the shutdown lock, either we're the first to
* restart these subsystems or some other thread is doing the powerup
* sequence for these subsystems. In the latter case, panic and bail
* out, since a subsystem died in its powerup sequence.
@@ -341,38 +365,23 @@
panic("%s[%p]: Subsystem died during powerup!",
__func__, current);
- do_epoch_check(subsys);
+ do_epoch_check(dev);
- /* Now it is necessary to take the registration lock. This is because
- * the subsystem list in the SoC restart order will be traversed
- * and it shouldn't be changed until _this_ restart sequence completes.
+ /*
+ * It's necessary to take the registration lock because the subsystem
+ * list in the SoC restart order will be traversed and it shouldn't be
+ * changed until _this_ restart sequence completes.
*/
mutex_lock(&soc_order_reg_lock);
pr_debug("[%p]: Starting restart sequence for %s\n", current,
- r_work->subsys->name);
+ desc->name);
+ send_notification_to_order(list, count, SUBSYS_BEFORE_SHUTDOWN);
+ for_each_subsys_device(list, count, NULL, subsystem_shutdown);
+ send_notification_to_order(list, count, SUBSYS_AFTER_SHUTDOWN);
- _send_notification_to_order(restart_list,
- restart_list_count,
- SUBSYS_BEFORE_SHUTDOWN);
-
- for (i = 0; i < restart_list_count; i++) {
-
- if (!restart_list[i])
- continue;
-
- pr_info("[%p]: Shutting down %s\n", current,
- restart_list[i]->name);
-
- if (restart_list[i]->shutdown(subsys) < 0)
- panic("subsys-restart: %s[%p]: Failed to shutdown %s!",
- __func__, current, restart_list[i]->name);
- }
-
- _send_notification_to_order(restart_list, restart_list_count,
- SUBSYS_AFTER_SHUTDOWN);
-
- /* Now that we've finished shutting down these subsystems, release the
+ /*
+ * Now that we've finished shutting down these subsystems, release the
* shutdown lock. If a subsystem restart request comes in for a
* subsystem in _this_ restart order after the unlock below, and
* before the powerup lock is released, panic and bail out.
@@ -380,40 +389,14 @@
mutex_unlock(shutdown_lock);
/* Collect ram dumps for all subsystems in order here */
- for (i = 0; i < restart_list_count; i++) {
- if (!restart_list[i])
- continue;
+ for_each_subsys_device(list, count, NULL, subsystem_ramdump);
- if (restart_list[i]->ramdump)
- if (restart_list[i]->ramdump(enable_ramdumps,
- subsys) < 0)
- pr_warn("%s[%p]: Ramdump failed.\n",
- restart_list[i]->name, current);
- }
-
- _send_notification_to_order(restart_list,
- restart_list_count,
- SUBSYS_BEFORE_POWERUP);
-
- for (i = restart_list_count - 1; i >= 0; i--) {
-
- if (!restart_list[i])
- continue;
-
- pr_info("[%p]: Powering up %s\n", current,
- restart_list[i]->name);
-
- if (restart_list[i]->powerup(subsys) < 0)
- panic("%s[%p]: Failed to powerup %s!", __func__,
- current, restart_list[i]->name);
- }
-
- _send_notification_to_order(restart_list,
- restart_list_count,
- SUBSYS_AFTER_POWERUP);
+ send_notification_to_order(list, count, SUBSYS_BEFORE_POWERUP);
+ for_each_subsys_device(list, count, NULL, subsystem_powerup);
+ send_notification_to_order(list, count, SUBSYS_AFTER_POWERUP);
pr_info("[%p]: Restart sequence for %s completed.\n",
- current, r_work->subsys->name);
+ current, desc->name);
mutex_unlock(powerup_lock);
@@ -422,123 +405,119 @@
pr_debug("[%p]: Released powerup lock!\n", current);
out:
- wake_unlock(&r_work->ssr_wake_lock);
- wake_lock_destroy(&r_work->ssr_wake_lock);
- kfree(r_work);
+ spin_lock_irqsave(&dev->restart_lock, flags);
+ wake_unlock(&dev->wake_lock);
+ dev->restarting = false;
+ spin_unlock_irqrestore(&dev->restart_lock, flags);
}
-static void __subsystem_restart(struct subsys_data *subsys)
+static void __subsystem_restart_dev(struct subsys_device *dev)
{
- struct restart_wq_data *data = NULL;
- int rc;
+ struct subsys_desc *desc = dev->desc;
+ unsigned long flags;
- pr_debug("Restarting %s [level=%d]!\n", subsys->name,
+ spin_lock_irqsave(&dev->restart_lock, flags);
+ if (!dev->restarting) {
+ pr_debug("Restarting %s [level=%d]!\n", desc->name,
restart_level);
- data = kzalloc(sizeof(struct restart_wq_data), GFP_ATOMIC);
- if (!data)
- panic("%s: Unable to allocate memory to restart %s.",
- __func__, subsys->name);
-
- data->subsys = subsys;
-
- if (restart_level != RESET_SUBSYS_INDEPENDENT)
- data->use_restart_order = 1;
-
- snprintf(data->wlname, sizeof(data->wlname), "ssr(%s)", subsys->name);
- wake_lock_init(&data->ssr_wake_lock, WAKE_LOCK_SUSPEND, data->wlname);
- wake_lock(&data->ssr_wake_lock);
-
- INIT_WORK(&data->work, subsystem_restart_wq_func);
- rc = queue_work(ssr_wq, &data->work);
- if (rc < 0)
- panic("%s: Unable to schedule work to restart %s (%d).",
- __func__, subsys->name, rc);
+ dev->restarting = true;
+ wake_lock(&dev->wake_lock);
+ queue_work(ssr_wq, &dev->work);
+ }
+ spin_unlock_irqrestore(&dev->restart_lock, flags);
}
-int subsystem_restart(const char *subsys_name)
+int subsystem_restart_dev(struct subsys_device *dev)
{
- struct subsys_data *subsys;
-
- if (!subsys_name) {
- pr_err("Invalid subsystem name.\n");
- return -EINVAL;
- }
+ const char *name = dev->desc->name;
pr_info("Restart sequence requested for %s, restart_level = %d.\n",
- subsys_name, restart_level);
-
- /* List of subsystems is protected by a lock. New subsystems can
- * still come in.
- */
- subsys = _find_subsystem(subsys_name);
-
- if (!subsys) {
- pr_warn("Unregistered subsystem %s!\n", subsys_name);
- return -EINVAL;
- }
+ name, restart_level);
switch (restart_level) {
case RESET_SUBSYS_COUPLED:
case RESET_SUBSYS_INDEPENDENT:
- __subsystem_restart(subsys);
+ __subsystem_restart_dev(dev);
break;
-
case RESET_SOC:
- panic("subsys-restart: Resetting the SoC - %s crashed.",
- subsys->name);
+ panic("subsys-restart: Resetting the SoC - %s crashed.", name);
break;
-
default:
panic("subsys-restart: Unknown restart level!\n");
- break;
-
+ break;
}
return 0;
}
+EXPORT_SYMBOL(subsystem_restart_dev);
+
+int subsystem_restart(const char *name)
+{
+ struct subsys_device *dev;
+
+ mutex_lock(&subsystem_list_lock);
+ list_for_each_entry(dev, &subsystem_list, list)
+ if (!strncmp(dev->desc->name, name, SUBSYS_NAME_MAX_LENGTH))
+ goto found;
+ dev = NULL;
+found:
+ mutex_unlock(&subsystem_list_lock);
+ if (dev)
+ return subsystem_restart_dev(dev);
+ return -ENODEV;
+}
EXPORT_SYMBOL(subsystem_restart);
-int ssr_register_subsystem(struct subsys_data *subsys)
+struct subsys_device *subsys_register(struct subsys_desc *desc)
{
- unsigned long flags;
+ struct subsys_device *dev;
- if (!subsys)
- goto err;
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
- if (!subsys->name)
- goto err;
+ dev->desc = desc;
+ dev->notify = subsys_notif_add_subsys(desc->name);
+ dev->restart_order = update_restart_order(dev);
- if (!subsys->powerup || !subsys->shutdown)
- goto err;
+ snprintf(dev->wlname, sizeof(dev->wlname), "ssr(%s)", desc->name);
+ wake_lock_init(&dev->wake_lock, WAKE_LOCK_SUSPEND, dev->wlname);
+ INIT_WORK(&dev->work, subsystem_restart_wq_func);
+ spin_lock_init(&dev->restart_lock);
- subsys->notif_handle = subsys_notif_add_subsys(subsys->name);
- subsys->restart_order = _update_restart_order(subsys);
- subsys->single_restart_list[0] = subsys;
+ mutex_init(&dev->shutdown_lock);
+ mutex_init(&dev->powerup_lock);
- mutex_init(&subsys->shutdown_lock);
- mutex_init(&subsys->powerup_lock);
+ mutex_lock(&subsystem_list_lock);
+ list_add(&dev->list, &subsystem_list);
+ mutex_unlock(&subsystem_list_lock);
- spin_lock_irqsave(&subsystem_list_lock, flags);
- list_add(&subsys->list, &subsystem_list);
- spin_unlock_irqrestore(&subsystem_list_lock, flags);
-
- return 0;
-
-err:
- return -EINVAL;
+ return dev;
}
-EXPORT_SYMBOL(ssr_register_subsystem);
+EXPORT_SYMBOL(subsys_register);
+
+void subsys_unregister(struct subsys_device *dev)
+{
+ if (IS_ERR_OR_NULL(dev))
+ return;
+ mutex_lock(&subsystem_list_lock);
+ list_del(&dev->list);
+ mutex_unlock(&subsystem_list_lock);
+ wake_lock_destroy(&dev->wake_lock);
+ kfree(dev);
+}
+EXPORT_SYMBOL(subsys_unregister);
static int ssr_panic_handler(struct notifier_block *this,
unsigned long event, void *ptr)
{
- struct subsys_data *subsys;
+ struct subsys_device *dev;
- list_for_each_entry(subsys, &subsystem_list, list)
- if (subsys->crash_shutdown)
- subsys->crash_shutdown(subsys);
+ list_for_each_entry(dev, &subsystem_list, list)
+ if (dev->desc->crash_shutdown)
+ dev->desc->crash_shutdown(dev->desc);
return NOTIFY_DONE;
}
@@ -569,7 +548,8 @@
}
if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627()) {
+ cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627() ||
+ cpu_is_msm8960ab()) {
if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
restart_orders = restart_orders_8960_sglte;
n_restart_orders =
@@ -594,20 +574,12 @@
static int __init subsys_restart_init(void)
{
- int ret = 0;
-
- restart_level = RESET_SOC;
-
ssr_wq = alloc_workqueue("ssr_wq", 0, 0);
-
if (!ssr_wq)
panic("Couldn't allocate workqueue for subsystem restart.\n");
- ret = ssr_init_soc_restart_orders();
-
- return ret;
+ return ssr_init_soc_restart_orders();
}
-
arch_initcall(subsys_restart_init);
MODULE_DESCRIPTION("Subsystem Restart Driver");
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 8d31683..668f4cc 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -965,7 +965,8 @@
return 0;
if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
- cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627())
+ cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627() ||
+ cpu_is_msm8960ab())
__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
if (__get_cpu_var(first_boot)) {
@@ -1062,7 +1063,8 @@
gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
} else if (cpu_is_msm8960() || cpu_is_apq8064() || cpu_is_msm8930() ||
- cpu_is_msm8930aa() || cpu_is_msm8627()) {
+ cpu_is_msm8930aa() || cpu_is_msm8627() ||
+ cpu_is_msm8960ab()) {
global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
dgt->freq = 6750000;
__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
@@ -1072,7 +1074,7 @@
gpt_hz = 32765;
sclk_hz = 32765;
if (!cpu_is_msm8930() && !cpu_is_msm8930aa() &&
- !cpu_is_msm8627()) {
+ !cpu_is_msm8627() && !cpu_is_msm8960ab()) {
gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
}
@@ -1123,8 +1125,9 @@
ce->irq = clock->irq;
if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
- cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_msm9615() || cpu_is_msm8625() || cpu_is_msm8627()) {
+ cpu_is_msm8930() || cpu_is_msm9615() || cpu_is_msm8625() ||
+ cpu_is_msm8627() || cpu_is_msm8930aa() ||
+ cpu_is_msm8960ab()) {
clock->percpu_evt = alloc_percpu(struct clock_event_device *);
if (!clock->percpu_evt) {
pr_err("msm_timer_init: memory allocation "
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 6e8d57c..4295d9b 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/wcnss_wlan.h>
+#include <linux/err.h>
#include <mach/irqs.h>
#include <mach/scm.h>
#include <mach/subsystem_restart.h>
@@ -37,6 +38,7 @@
static int riva_crash;
static int ss_restart_inprogress;
static int enable_riva_ssr;
+static struct subsys_device *riva_8960_dev;
static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
uint32_t new_state)
@@ -83,7 +85,7 @@
}
ss_restart_inprogress = true;
- subsystem_restart("riva");
+ subsystem_restart_dev(riva_8960_dev);
}
static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
@@ -100,7 +102,7 @@
panic(MODULE_NAME ": Watchdog bite received from Riva");
ss_restart_inprogress = true;
- subsystem_restart("riva");
+ subsystem_restart_dev(riva_8960_dev);
return IRQ_HANDLED;
}
@@ -126,7 +128,7 @@
}
/* Subsystem handlers */
-static int riva_shutdown(const struct subsys_data *subsys)
+static int riva_shutdown(const struct subsys_desc *subsys)
{
pil_force_shutdown("wcnss");
flush_delayed_work(&cancel_vote_work);
@@ -135,7 +137,7 @@
return 0;
}
-static int riva_powerup(const struct subsys_data *subsys)
+static int riva_powerup(const struct subsys_desc *subsys)
{
struct platform_device *pdev = wcnss_get_platform_device();
struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
@@ -162,7 +164,7 @@
static struct ramdump_segment riva_segments[] = {{0x8f200000,
0x8f700000 - 0x8f200000} };
-static int riva_ramdump(int enable, const struct subsys_data *subsys)
+static int riva_ramdump(int enable, const struct subsys_desc *subsys)
{
pr_debug("%s: enable[%d]\n", MODULE_NAME, enable);
if (enable)
@@ -174,14 +176,14 @@
}
/* Riva crash handler */
-static void riva_crash_shutdown(const struct subsys_data *subsys)
+static void riva_crash_shutdown(const struct subsys_desc *subsys)
{
pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
if (riva_crash != true)
smsm_riva_reset();
}
-static struct subsys_data riva_8960 = {
+static struct subsys_desc riva_8960 = {
.name = "riva",
.shutdown = riva_shutdown,
.powerup = riva_powerup,
@@ -208,7 +210,10 @@
static int __init riva_restart_init(void)
{
- return ssr_register_subsystem(&riva_8960);
+ riva_8960_dev = subsys_register(&riva_8960);
+ if (IS_ERR(riva_8960_dev))
+ return PTR_ERR(riva_8960_dev);
+ return 0;
}
static int __init riva_ssr_module_init(void)
@@ -253,6 +258,7 @@
static void __exit riva_ssr_module_exit(void)
{
+ subsys_unregister(riva_8960_dev);
free_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ, NULL);
}
diff --git a/block/test-iosched.c b/block/test-iosched.c
index 3c38734..0a033dc 100644
--- a/block/test-iosched.c
+++ b/block/test-iosched.c
@@ -127,7 +127,7 @@
test_pr_info("%s: request %d completed, err=%d",
__func__, test_rq->req_id, err);
- test_rq->req_completed = 1;
+ test_rq->req_completed = true;
test_rq->req_result = err;
check_test_completion();
@@ -173,6 +173,9 @@
bio->bi_size = nr_sects << 9;
bio->bi_sector = start_sec;
break;
+ case REQ_UNIQUE_SANITIZE:
+ bio->bi_rw = REQ_WRITE | REQ_SANITIZE;
+ break;
default:
test_pr_err("%s: Invalid request type %d", __func__,
req_unique);
@@ -204,8 +207,8 @@
blk_put_request(rq);
return -ENODEV;
}
- test_rq->req_completed = 0;
- test_rq->req_result = -1;
+ test_rq->req_completed = false;
+ test_rq->req_result = -EINVAL;
test_rq->rq = rq;
test_rq->is_err_expected = is_err_expcted;
rq->elv.priv[0] = (void *)test_rq;
@@ -347,8 +350,8 @@
ptd->num_of_write_bios += num_bios;
test_rq->req_id = ptd->wr_rd_next_req_id++;
- test_rq->req_completed = 0;
- test_rq->req_result = -1;
+ test_rq->req_completed = false;
+ test_rq->req_result = -EINVAL;
test_rq->rq = rq;
test_rq->is_err_expected = is_err_expcted;
rq->elv.priv[0] = (void *)test_rq;
@@ -519,10 +522,26 @@
static void free_test_requests(struct test_data *td)
{
struct test_request *test_rq;
+ struct bio *bio;
+
while (!list_empty(&td->test_queue)) {
test_rq = list_entry(td->test_queue.next, struct test_request,
queuelist);
list_del_init(&test_rq->queuelist);
+ /*
+ * If the request was not completed we need to free its BIOs
+ * and remove it from the packed list
+ */
+ if (!test_rq->req_completed) {
+ test_pr_info(
+ "%s: Freeing memory of an uncompleted request",
+ __func__);
+ list_del_init(&test_rq->rq->queuelist);
+ while ((bio = test_rq->rq->bio) != NULL) {
+ test_rq->rq->bio = bio->bi_next;
+ bio_put(bio);
+ }
+ }
blk_put_request(test_rq->rq);
kfree(test_rq->bios_buffer);
kfree(test_rq);
@@ -606,7 +625,8 @@
test_pr_info(
"%s: Another test is running, try again later",
__func__);
- return -EINVAL;
+ spin_unlock(&ptd->lock);
+ return -EBUSY;
}
if (ptd->start_sector == 0) {
@@ -698,9 +718,8 @@
return -EINVAL;
error:
- ptd->test_result = TEST_FAILED;
- ptd->test_info.testcase = 0;
post_test(ptd);
+ ptd->test_result = TEST_FAILED;
return ret;
}
EXPORT_SYMBOL(test_iosched_start_test);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index f9c5006..384c1bf 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -129,6 +129,7 @@
case MSM_CPU_8X60:
return APQ8060_TOOLS_ID;
case MSM_CPU_8960:
+ case MSM_CPU_8960AB:
return AO8960_TOOLS_ID;
case MSM_CPU_8064:
return APQ8064_TOOLS_ID;
@@ -156,6 +157,7 @@
switch (socinfo_get_msm_cpu()) {
case MSM_CPU_8960:
+ case MSM_CPU_8960AB:
case MSM_CPU_8064:
case MSM_CPU_8930:
case MSM_CPU_8930AA:
@@ -178,7 +180,8 @@
if (driver->use_device_tree)
return 1;
else if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627())
+ cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627() ||
+ cpu_is_msm8960ab())
return 1;
else
return 0;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index e9d654b..be71347 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -142,7 +142,7 @@
static LIST_HEAD(cpufreq_governor_list);
static DEFINE_MUTEX(cpufreq_governor_mutex);
-struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
+static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, int sysfs)
{
struct cpufreq_policy *data;
unsigned long flags;
@@ -166,7 +166,7 @@
if (!data)
goto err_out_put_module;
- if (!kobject_get(&data->kobj))
+ if (!sysfs && !kobject_get(&data->kobj))
goto err_out_put_module;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -179,16 +179,35 @@
err_out:
return NULL;
}
+
+struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
+{
+ return __cpufreq_cpu_get(cpu, 0);
+}
EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
+static struct cpufreq_policy *cpufreq_cpu_get_sysfs(unsigned int cpu)
+{
+ return __cpufreq_cpu_get(cpu, 1);
+}
+
+static void __cpufreq_cpu_put(struct cpufreq_policy *data, int sysfs)
+{
+ if (!sysfs)
+ kobject_put(&data->kobj);
+ module_put(cpufreq_driver->owner);
+}
void cpufreq_cpu_put(struct cpufreq_policy *data)
{
- kobject_put(&data->kobj);
- module_put(cpufreq_driver->owner);
+ __cpufreq_cpu_put(data, 0);
}
EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
+static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *data)
+{
+ __cpufreq_cpu_put(data, 1);
+}
/*********************************************************************
* EXTERNALLY AFFECTING FREQUENCY CHANGES *
@@ -643,7 +662,7 @@
struct cpufreq_policy *policy = to_policy(kobj);
struct freq_attr *fattr = to_attr(attr);
ssize_t ret = -EINVAL;
- policy = cpufreq_cpu_get(policy->cpu);
+ policy = cpufreq_cpu_get_sysfs(policy->cpu);
if (!policy)
goto no_policy;
@@ -657,7 +676,7 @@
unlock_policy_rwsem_read(policy->cpu);
fail:
- cpufreq_cpu_put(policy);
+ cpufreq_cpu_put_sysfs(policy);
no_policy:
return ret;
}
@@ -668,7 +687,7 @@
struct cpufreq_policy *policy = to_policy(kobj);
struct freq_attr *fattr = to_attr(attr);
ssize_t ret = -EINVAL;
- policy = cpufreq_cpu_get(policy->cpu);
+ policy = cpufreq_cpu_get_sysfs(policy->cpu);
if (!policy)
goto no_policy;
@@ -682,7 +701,7 @@
unlock_policy_rwsem_write(policy->cpu);
fail:
- cpufreq_cpu_put(policy);
+ cpufreq_cpu_put_sysfs(policy);
no_policy:
return ret;
}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 5798c94..785ba6c 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -994,7 +994,6 @@
rc = input_register_handler(&dbs_input_handler);
mutex_unlock(&dbs_mutex);
- mutex_init(&this_dbs_info->timer_mutex);
if (!ondemand_powersave_bias_setspeed(
this_dbs_info->cur_policy,
@@ -1071,6 +1070,9 @@
return -EFAULT;
}
for_each_possible_cpu(i) {
+ struct cpu_dbs_info_s *this_dbs_info =
+ &per_cpu(od_cpu_dbs_info, i);
+ mutex_init(&this_dbs_info->timer_mutex);
INIT_WORK(&per_cpu(dbs_refresh_work, i), dbs_refresh_callback);
}
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 2a191d5..fecce3f 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -572,6 +572,7 @@
if (podev->ce_support.sha_hmac) {
sreq.alg = QCE_HASH_SHA1_HMAC;
sreq.authkey = &handle->sha_ctxt.authkey[0];
+ sreq.authklen = QCEDEV_MAX_SHA_BLOCK_SIZE;
} else {
sreq.alg = QCE_HASH_SHA1;
@@ -582,7 +583,7 @@
if (podev->ce_support.sha_hmac) {
sreq.alg = QCE_HASH_SHA256_HMAC;
sreq.authkey = &handle->sha_ctxt.authkey[0];
-
+ sreq.authklen = QCEDEV_MAX_SHA_BLOCK_SIZE;
} else {
sreq.alg = QCE_HASH_SHA256;
sreq.authkey = NULL;
@@ -959,7 +960,6 @@
uint8_t *k_buf_src = NULL;
uint8_t *k_align_src = NULL;
- handle->sha_ctxt.first_blk = 0;
handle->sha_ctxt.last_blk = 1;
total = handle->sha_ctxt.trailing_buf_len;
@@ -977,9 +977,6 @@
CACHE_LINE_SIZE);
memcpy(k_align_src, &handle->sha_ctxt.trailing_buf[0], total);
}
- handle->sha_ctxt.last_blk = 1;
- handle->sha_ctxt.first_blk = 0;
-
qcedev_areq->sha_req.sreq.src = (struct scatterlist *) &sg_src;
sg_set_buf(qcedev_areq->sha_req.sreq.src, k_align_src, total);
sg_mark_end(qcedev_areq->sha_req.sreq.src);
@@ -1071,6 +1068,7 @@
int err = 0;
if (areq->sha_op_req.authklen <= QCEDEV_MAX_KEY_SIZE) {
+ qcedev_sha_init(areq, handle);
/* Verify Source Address */
if (!access_ok(VERIFY_READ,
(void __user *)areq->sha_op_req.authkey,
@@ -1082,6 +1080,7 @@
return -EFAULT;
} else {
struct qcedev_async_req authkey_areq;
+ uint8_t authkey[QCEDEV_MAX_SHA_BLOCK_SIZE];
init_completion(&authkey_areq.complete);
@@ -1091,6 +1090,8 @@
authkey_areq.sha_op_req.data[0].len = areq->sha_op_req.authklen;
authkey_areq.sha_op_req.data_len = areq->sha_op_req.authklen;
authkey_areq.sha_op_req.diglen = 0;
+ authkey_areq.handle = handle;
+
memset(&authkey_areq.sha_op_req.digest[0], 0,
QCEDEV_MAX_SHA_DIGEST);
if (areq->sha_op_req.alg == QCEDEV_ALG_SHA1_HMAC)
@@ -1106,8 +1107,11 @@
err = qcedev_sha_final(&authkey_areq, handle);
else
return err;
- memcpy(&handle->sha_ctxt.authkey[0],
- &handle->sha_ctxt.digest[0],
+ memcpy(&authkey[0], &handle->sha_ctxt.digest[0],
+ handle->sha_ctxt.diglen);
+ qcedev_sha_init(areq, handle);
+
+ memcpy(&handle->sha_ctxt.authkey[0], &authkey[0],
handle->sha_ctxt.diglen);
}
return err;
@@ -1209,7 +1213,6 @@
int err;
struct qcedev_control *podev = handle->cntl;
- qcedev_sha_init(areq, handle);
err = qcedev_set_hmac_auth_key(areq, handle);
if (err)
return err;
@@ -2098,12 +2101,19 @@
return 0;
};
+static struct of_device_id qcedev_match[] = {
+ { .compatible = "qcom,qcedev",
+ },
+ {}
+};
+
static struct platform_driver qcedev_plat_driver = {
.probe = qcedev_probe,
.remove = qcedev_remove,
.driver = {
.name = "qce",
.owner = THIS_MODULE,
+ .of_match_table = qcedev_match,
},
};
@@ -2222,7 +2232,7 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
MODULE_DESCRIPTION("Qualcomm DEV Crypto driver");
-MODULE_VERSION("1.26");
+MODULE_VERSION("1.27");
module_init(qcedev_init);
module_exit(qcedev_exit);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index a41a64b..c11c36e 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -3260,12 +3260,20 @@
return rc;
};
+
+static struct of_device_id qcrypto_match[] = {
+ { .compatible = "qcom,qcrypto",
+ },
+ {}
+};
+
static struct platform_driver _qualcomm_crypto = {
.probe = _qcrypto_probe,
.remove = _qcrypto_remove,
.driver = {
.owner = THIS_MODULE,
.name = "qcrypto",
+ .of_match_table = qcrypto_match,
},
};
@@ -3364,4 +3372,4 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
MODULE_DESCRIPTION("Qualcomm Crypto driver");
-MODULE_VERSION("1.21");
+MODULE_VERSION("1.22");
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index f5ee1d7..8ec9431 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -151,6 +151,7 @@
#define A3XX_GRAS_CL_USER_PLANE_Y5 0xCB5
#define A3XX_GRAS_CL_USER_PLANE_Z5 0xCB6
#define A3XX_GRAS_CL_USER_PLANE_W5 0xCB7
+#define A3XX_VFD_PERFCOUNTER0_SELECT 0xE44
#define A3XX_VPC_VPC_DEBUG_RAM_SEL 0xE61
#define A3XX_VPC_VPC_DEBUG_RAM_READ 0xE62
#define A3XX_UCHE_CACHE_INVALIDATE0_REG 0xEA0
@@ -289,6 +290,8 @@
#define RB_CLEAR_MODE_RESOLVE 1
#define RB_TILINGMODE_LINEAR 0
#define RB_REF_NEVER 0
+#define RB_FRAG_LESS 1
+#define RB_REF_ALWAYS 7
#define RB_STENCIL_KEEP 0
#define RB_RENDERING_PASS 0
#define RB_TILINGMODE_32X32 2
@@ -326,6 +329,7 @@
#define GRAS_SC_SCREEN_SCISSOR_BR_BR_Y 16
#define GRAS_SC_WINDOW_SCISSOR_BR_BR_X 0
#define GRAS_SC_WINDOW_SCISSOR_BR_BR_Y 16
+#define GRAS_SU_CTRLMODE_LINEHALFWIDTH 03
#define HLSQ_CONSTFSPRESERVEDRANGEREG_ENDENTRY 16
#define HLSQ_CONSTFSPRESERVEDRANGEREG_STARTENTRY 0
#define HLSQ_CTRL0REG_CHUNKDISABLE 26
@@ -396,6 +400,7 @@
#define RB_STENCILCONTROL_STENCIL_ZPASS 14
#define RB_STENCILCONTROL_STENCIL_ZPASS_BF 26
#define SP_FSCTRLREG0_FSFULLREGFOOTPRINT 10
+#define SP_FSCTRLREG0_FSHALFREGFOOTPRINT 4
#define SP_FSCTRLREG0_FSICACHEINVALID 2
#define SP_FSCTRLREG0_FSINOUTREGOVERLAP 18
#define SP_FSCTRLREG0_FSINSTRBUFFERMODE 1
@@ -408,13 +413,16 @@
#define SP_FSCTRLREG1_FSINITIALOUTSTANDING 20
#define SP_FSCTRLREG1_HALFPRECVAROFFSET 24
#define SP_FSMRTREG_REGID 0
+#define SP_FSMRTREG_PRECISION 8
#define SP_FSOUTREG_PAD0 2
#define SP_IMAGEOUTPUTREG_MRTFORMAT 0
+#define SP_IMAGEOUTPUTREG_DEPTHOUTMODE 3
#define SP_IMAGEOUTPUTREG_PAD0 6
#define SP_OBJOFFSETREG_CONSTOBJECTSTARTOFFSET 16
#define SP_OBJOFFSETREG_SHADEROBJOFFSETINIC 25
#define SP_SHADERLENGTH_LEN 0
#define SP_SPCTRLREG_CONSTMODE 18
+#define SP_SPCTRLREG_LOMODE 22
#define SP_SPCTRLREG_SLEEPMODE 20
#define SP_VSCTRLREG0_VSFULLREGFOOTPRINT 10
#define SP_VSCTRLREG0_VSICACHEINVALID 2
@@ -455,6 +463,7 @@
#define VFD_FETCHINSTRUCTIONS_STEPRATE 24
#define VFD_FETCHINSTRUCTIONS_SWITCHNEXT 17
#define VFD_THREADINGTHRESHOLD_REGID_VTXCNT 8
+#define VFD_THREADINGTHRESHOLD_REGID_THRESHOLD 0
#define VFD_THREADINGTHRESHOLD_RESERVED6 4
#define VPC_VPCATTR_LMSIZE 28
#define VPC_VPCATTR_THRHDASSIGN 12
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index ecff3ea..b72c847 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -289,6 +289,10 @@
KGSL_IOMMU_CONTEXT_USER))
goto done;
+ cmds += __adreno_add_idle_indirect_cmds(cmds,
+ device->mmu.setstate_memory.gpuaddr +
+ KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+
if (cpu_is_msm8960())
cmds += adreno_add_change_mh_phys_limit_cmds(cmds, 0xFFFFF000,
device->mmu.setstate_memory.gpuaddr +
@@ -357,10 +361,9 @@
*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
*cmds++ = 0x7fff;
- if (flags & KGSL_MMUFLAGS_TLBFLUSH)
- cmds += __adreno_add_idle_indirect_cmds(cmds,
- device->mmu.setstate_memory.gpuaddr +
- KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+ cmds += __adreno_add_idle_indirect_cmds(cmds,
+ device->mmu.setstate_memory.gpuaddr +
+ KGSL_IOMMU_SETSTATE_NOP_OFFSET);
}
if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
/*
@@ -544,53 +547,16 @@
static unsigned int
a3xx_getchipid(struct kgsl_device *device)
{
- unsigned int majorid = 0, minorid = 0, patchid = 0;
+ struct kgsl_device_platform_data *pdata =
+ kgsl_device_get_drvdata(device);
/*
- * We could detect the chipID from the hardware but it takes multiple
- * registers to find the right combination. Since we traffic exclusively
- * in system on chips, we can be (mostly) confident that a SOC version
- * will match a GPU (at this juncture at least). So do the lazy/quick
- * thing and set the chip_id based on the SoC
+ * All current A3XX chipids are detected at the SOC level. Leave this
+ * function here to support any future GPUs that have working
+ * chip ID registers
*/
- unsigned int version = socinfo_get_version();
-
- if (cpu_is_apq8064()) {
-
- /* A320 */
- majorid = 2;
- minorid = 0;
-
- /*
- * V1.1 has some GPU work arounds that we need to communicate
- * up to user space via the patchid
- */
-
- if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
- (SOCINFO_VERSION_MINOR(version) == 1))
- patchid = 1;
- else
- patchid = 0;
- } else if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
-
- /* A305 */
- majorid = 0;
- minorid = 5;
-
- /*
- * V1.2 has some GPU work arounds that we need to communicate
- * up to user space via the patchid
- */
-
- if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
- (SOCINFO_VERSION_MINOR(version) == 2))
- patchid = 2;
- else
- patchid = 0;
- }
-
- return (0x03 << 24) | (majorid << 16) | (minorid << 8) | patchid;
+ return pdata->chipid;
}
static unsigned int
@@ -598,7 +564,13 @@
{
unsigned int chipid = 0;
unsigned int coreid, majorid, minorid, patchid, revid;
- uint32_t soc_platform_version = socinfo_get_version();
+ struct kgsl_device_platform_data *pdata =
+ kgsl_device_get_drvdata(device);
+
+ /* If the chip id is set at the platform level, then just use that */
+
+ if (pdata->chipid != 0)
+ return pdata->chipid;
adreno_regread(device, REG_RBBM_PERIPHID1, &coreid);
adreno_regread(device, REG_RBBM_PERIPHID2, &majorid);
@@ -608,7 +580,7 @@
* adreno 22x gpus are indicated by coreid 2,
* but REG_RBBM_PERIPHID1 always contains 0 for this field
*/
- if (cpu_is_msm8960() || cpu_is_msm8x60())
+ if (cpu_is_msm8x60())
chipid = 2 << 24;
else
chipid = (coreid & 0xF) << 24;
@@ -620,13 +592,9 @@
patchid = ((revid >> 16) & 0xFF);
/* 8x50 returns 0 for patch release, but it should be 1 */
- /* 8960v3 returns 5 for patch release, but it should be 6 */
/* 8x25 returns 0 for minor id, but it should be 1 */
if (cpu_is_qsd8x50())
patchid = 1;
- else if (cpu_is_msm8960() &&
- SOCINFO_VERSION_MAJOR(soc_platform_version) == 3)
- patchid = 6;
else if (cpu_is_msm8625() && minorid == 0)
minorid = 1;
@@ -638,11 +606,18 @@
static unsigned int
adreno_getchipid(struct kgsl_device *device)
{
- if (cpu_is_apq8064() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_msm8627())
- return a3xx_getchipid(device);
- else
+ struct kgsl_device_platform_data *pdata =
+ kgsl_device_get_drvdata(device);
+
+ /*
+ * All A3XX chipsets will have pdata set, so assume !pdata->chipid is
+ * an A2XX processor
+ */
+
+ if (pdata->chipid == 0 || ADRENO_CHIPID_MAJOR(pdata->chipid) == 2)
return a2xx_getchipid(device);
+ else
+ return a3xx_getchipid(device);
}
static inline bool _rev_match(unsigned int id, unsigned int entry)
@@ -657,10 +632,10 @@
adreno_dev->chip_id = adreno_getchipid(&adreno_dev->dev);
- core = (adreno_dev->chip_id >> 24) & 0xff;
- major = (adreno_dev->chip_id >> 16) & 0xff;
- minor = (adreno_dev->chip_id >> 8) & 0xff;
- patchid = (adreno_dev->chip_id & 0xff);
+ core = ADRENO_CHIPID_CORE(adreno_dev->chip_id);
+ major = ADRENO_CHIPID_MAJOR(adreno_dev->chip_id);
+ minor = ADRENO_CHIPID_MINOR(adreno_dev->chip_id);
+ patchid = ADRENO_CHIPID_PATCH(adreno_dev->chip_id);
for (i = 0; i < ARRAY_SIZE(adreno_gpulist); i++) {
if (core == adreno_gpulist[i].core &&
@@ -741,7 +716,8 @@
int status = -EINVAL;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+ if (KGSL_STATE_DUMP_AND_RECOVER != device->state)
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
/* Power up the device */
kgsl_pwrctrl_enable(device);
@@ -785,7 +761,10 @@
status = adreno_ringbuffer_start(&adreno_dev->ringbuffer, init_ram);
if (status == 0) {
- mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
+ /* While recovery is on we do not want timer to
+ * fire and attempt to change any device state */
+ if (KGSL_STATE_DUMP_AND_RECOVER != device->state)
+ mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
return 0;
}
@@ -817,131 +796,290 @@
return 0;
}
+static void adreno_mark_context_status(struct kgsl_device *device,
+ int recovery_status)
+{
+ struct kgsl_context *context;
+ int next = 0;
+ /*
+ * Set the reset status of all contexts to
+ * INNOCENT_CONTEXT_RESET_EXT except for the bad context
+ * since thats the guilty party, if recovery failed then
+ * mark all as guilty
+ */
+ while ((context = idr_get_next(&device->context_idr, &next))) {
+ struct adreno_context *adreno_context = context->devctxt;
+ if (recovery_status) {
+ context->reset_status =
+ KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
+ adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
+ } else if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT !=
+ context->reset_status) {
+ if (adreno_context->flags & (CTXT_FLAGS_GPU_HANG ||
+ CTXT_FLAGS_GPU_HANG_RECOVERED))
+ context->reset_status =
+ KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
+ else
+ context->reset_status =
+ KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT;
+ }
+ next = next + 1;
+ }
+}
+
+static void adreno_set_max_ts_for_bad_ctxs(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ struct kgsl_context *context;
+ struct adreno_context *temp_adreno_context;
+ int next = 0;
+
+ while ((context = idr_get_next(&device->context_idr, &next))) {
+ temp_adreno_context = context->devctxt;
+ if (temp_adreno_context->flags & CTXT_FLAGS_GPU_HANG) {
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(context->id,
+ soptimestamp),
+ rb->timestamp[context->id]);
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(context->id,
+ eoptimestamp),
+ rb->timestamp[context->id]);
+ }
+ next = next + 1;
+ }
+}
+
+static void adreno_destroy_recovery_data(struct adreno_recovery_data *rec_data)
+{
+ vfree(rec_data->rb_buffer);
+ vfree(rec_data->bad_rb_buffer);
+}
+
+static int adreno_setup_recovery_data(struct kgsl_device *device,
+ struct adreno_recovery_data *rec_data)
+{
+ int ret = 0;
+ unsigned int ib1_sz, ib2_sz;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+
+ memset(rec_data, 0, sizeof(*rec_data));
+
+ adreno_regread(device, REG_CP_IB1_BUFSZ, &ib1_sz);
+ adreno_regread(device, REG_CP_IB2_BUFSZ, &ib2_sz);
+ if (ib1_sz || ib2_sz)
+ adreno_regread(device, REG_CP_IB1_BASE, &rec_data->ib1);
+
+ kgsl_sharedmem_readl(&device->memstore, &rec_data->context_id,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ current_context));
+
+ kgsl_sharedmem_readl(&device->memstore,
+ &rec_data->global_eop,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp));
+
+ rec_data->rb_buffer = vmalloc(rb->buffer_desc.size);
+ if (!rec_data->rb_buffer) {
+ KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
+ rb->buffer_desc.size);
+ return -ENOMEM;
+ }
+
+ rec_data->bad_rb_buffer = vmalloc(rb->buffer_desc.size);
+ if (!rec_data->bad_rb_buffer) {
+ KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
+ rb->buffer_desc.size);
+ ret = -ENOMEM;
+ goto done;
+ }
+
+done:
+ if (ret) {
+ vfree(rec_data->rb_buffer);
+ vfree(rec_data->bad_rb_buffer);
+ }
+ return ret;
+}
+
static int
-adreno_recover_hang(struct kgsl_device *device)
+_adreno_recover_hang(struct kgsl_device *device,
+ struct adreno_recovery_data *rec_data,
+ bool try_bad_commands)
{
int ret;
- unsigned int *rb_buffer;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ struct kgsl_context *context;
+ struct adreno_context *adreno_context = NULL;
+ struct adreno_context *last_active_ctx = adreno_dev->drawctxt_active;
+
+ context = idr_find(&device->context_idr, rec_data->context_id);
+ if (context == NULL) {
+ KGSL_DRV_ERR(device, "Last context unknown id:%d\n",
+ rec_data->context_id);
+ } else {
+ adreno_context = context->devctxt;
+ adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
+ }
+
+ /* Extract valid contents from rb which can still be executed after
+ * hang */
+ ret = adreno_ringbuffer_extract(rb, rec_data);
+ if (ret)
+ goto done;
+
+ /* restart device */
+ ret = adreno_stop(device);
+ if (ret) {
+ KGSL_DRV_ERR(device, "Device stop failed in recovery\n");
+ goto done;
+ }
+
+ ret = adreno_start(device, true);
+ if (ret) {
+ KGSL_DRV_ERR(device, "Device start failed in recovery\n");
+ goto done;
+ }
+
+ if (context)
+ kgsl_mmu_setstate(&device->mmu, adreno_context->pagetable,
+ KGSL_MEMSTORE_GLOBAL);
+
+ /* Do not try the bad caommands if recovery has failed bad commands
+ * once already */
+ if (!try_bad_commands)
+ rec_data->bad_rb_size = 0;
+
+ if (rec_data->bad_rb_size) {
+ int idle_ret;
+ /* submit the bad and good context commands and wait for
+ * them to pass */
+ adreno_ringbuffer_restore(rb, rec_data->bad_rb_buffer,
+ rec_data->bad_rb_size);
+ idle_ret = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ if (idle_ret) {
+ ret = adreno_stop(device);
+ if (ret) {
+ KGSL_DRV_ERR(device,
+ "Device stop failed in recovery\n");
+ goto done;
+ }
+ ret = adreno_start(device, true);
+ if (ret) {
+ KGSL_DRV_ERR(device,
+ "Device start failed in recovery\n");
+ goto done;
+ }
+ ret = idle_ret;
+ KGSL_DRV_ERR(device,
+ "Bad context commands hung in recovery\n");
+ } else {
+ KGSL_DRV_ERR(device,
+ "Bad context commands succeeded in recovery\n");
+ if (adreno_context)
+ adreno_context->flags = (adreno_context->flags &
+ ~CTXT_FLAGS_GPU_HANG) |
+ CTXT_FLAGS_GPU_HANG_RECOVERED;
+ adreno_dev->drawctxt_active = last_active_ctx;
+ }
+ }
+ /* If either the bad command sequence failed or we did not play it */
+ if (ret || !rec_data->bad_rb_size) {
+ adreno_ringbuffer_restore(rb, rec_data->rb_buffer,
+ rec_data->rb_size);
+ ret = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ if (ret) {
+ /* If we fail here we can try to invalidate another
+ * context and try recovering again */
+ ret = -EAGAIN;
+ goto done;
+ }
+ /* ringbuffer now has data from the last valid context id,
+ * so restore the active_ctx to the last valid context */
+ if (rec_data->last_valid_ctx_id) {
+ struct kgsl_context *last_ctx =
+ idr_find(&device->context_idr,
+ rec_data->last_valid_ctx_id);
+ if (last_ctx)
+ adreno_dev->drawctxt_active = last_ctx->devctxt;
+ }
+ }
+done:
+ return ret;
+}
+
+static int
+adreno_recover_hang(struct kgsl_device *device,
+ struct adreno_recovery_data *rec_data)
+{
+ int ret = 0;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
unsigned int timestamp;
- unsigned int num_rb_contents;
- unsigned int reftimestamp;
- unsigned int enable_ts;
- unsigned int soptimestamp;
- unsigned int eoptimestamp;
- unsigned int context_id;
- struct kgsl_context *context;
- struct adreno_context *adreno_context;
- int next = 0;
- KGSL_DRV_ERR(device, "Starting recovery from 3D GPU hang....\n");
- rb_buffer = vmalloc(rb->buffer_desc.size);
- if (!rb_buffer) {
- KGSL_MEM_ERR(device,
- "Failed to allocate memory for recovery: %x\n",
- rb->buffer_desc.size);
- return -ENOMEM;
- }
- /* Extract valid contents from rb which can stil be executed after
- * hang */
- ret = adreno_ringbuffer_extract(rb, rb_buffer, &num_rb_contents);
- if (ret)
- goto done;
- kgsl_sharedmem_readl(&device->memstore, &context_id,
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- current_context));
- context = idr_find(&device->context_idr, context_id);
- if (context == NULL) {
- KGSL_DRV_ERR(device, "Last context unknown id:%d\n",
- context_id);
- context_id = KGSL_MEMSTORE_GLOBAL;
- }
+ KGSL_DRV_ERR(device,
+ "Starting recovery from 3D GPU hang. Recovery parameters: IB1: 0x%X, "
+ "Bad context_id: %u, global_eop: 0x%x\n",
+ rec_data->ib1, rec_data->context_id, rec_data->global_eop);
timestamp = rb->timestamp[KGSL_MEMSTORE_GLOBAL];
KGSL_DRV_ERR(device, "Last issued global timestamp: %x\n", timestamp);
- kgsl_sharedmem_readl(&device->memstore, &reftimestamp,
- KGSL_MEMSTORE_OFFSET(context_id,
- ref_wait_ts));
- kgsl_sharedmem_readl(&device->memstore, &enable_ts,
- KGSL_MEMSTORE_OFFSET(context_id,
- ts_cmp_enable));
- kgsl_sharedmem_readl(&device->memstore, &soptimestamp,
- KGSL_MEMSTORE_OFFSET(context_id,
- soptimestamp));
- kgsl_sharedmem_readl(&device->memstore, &eoptimestamp,
- KGSL_MEMSTORE_OFFSET(context_id,
- eoptimestamp));
- /* Make sure memory is synchronized before restarting the GPU */
- mb();
- KGSL_CTXT_ERR(device,
- "Context id that caused a GPU hang: %d\n", context_id);
- /* restart device */
- ret = adreno_stop(device);
- if (ret)
- goto done;
- ret = adreno_start(device, true);
- if (ret)
- goto done;
- KGSL_DRV_ERR(device, "Device has been restarted after hang\n");
- /* Restore timestamp states */
- kgsl_sharedmem_writel(&device->memstore,
- KGSL_MEMSTORE_OFFSET(context_id, soptimestamp),
- soptimestamp);
- kgsl_sharedmem_writel(&device->memstore,
- KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp),
- eoptimestamp);
+ /* We may need to replay commands multiple times based on whether
+ * multiple contexts hang the GPU */
+ while (true) {
+ if (!ret)
+ ret = _adreno_recover_hang(device, rec_data, true);
+ else
+ ret = _adreno_recover_hang(device, rec_data, false);
- if (num_rb_contents) {
- kgsl_sharedmem_writel(&device->memstore,
- KGSL_MEMSTORE_OFFSET(context_id, ref_wait_ts),
- reftimestamp);
- kgsl_sharedmem_writel(&device->memstore,
- KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable),
- enable_ts);
- }
- /* Make sure all writes are posted before the GPU reads them */
- wmb();
- /* Mark the invalid context so no more commands are accepted from
- * that context */
-
- adreno_context = context->devctxt;
-
- KGSL_CTXT_ERR(device,
- "Context that caused a GPU hang: %d\n", adreno_context->id);
-
- adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
-
- /*
- * Set the reset status of all contexts to
- * INNOCENT_CONTEXT_RESET_EXT except for the bad context
- * since thats the guilty party
- */
- while ((context = idr_get_next(&device->context_idr, &next))) {
- if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT !=
- context->reset_status) {
- if (context->id != context_id)
- context->reset_status =
- KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT;
- else
- context->reset_status =
- KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
+ if (-EAGAIN == ret) {
+ /* setup new recovery parameters and retry, this
+ * means more than 1 contexts are causing hang */
+ adreno_destroy_recovery_data(rec_data);
+ adreno_setup_recovery_data(device, rec_data);
+ KGSL_DRV_ERR(device,
+ "Retry recovery from 3D GPU hang. Recovery parameters: "
+ "IB1: 0x%X, Bad context_id: %u, global_eop: 0x%x\n",
+ rec_data->ib1, rec_data->context_id,
+ rec_data->global_eop);
+ } else {
+ break;
}
- next = next + 1;
}
- /* Restore valid commands in ringbuffer */
- adreno_ringbuffer_restore(rb, rb_buffer, num_rb_contents);
+ if (ret)
+ goto done;
+
+ /* Restore correct states after recovery */
+ if (adreno_dev->drawctxt_active)
+ device->mmu.hwpagetable =
+ adreno_dev->drawctxt_active->pagetable;
+ else
+ device->mmu.hwpagetable = device->mmu.defaultpagetable;
rb->timestamp[KGSL_MEMSTORE_GLOBAL] = timestamp;
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp),
+ rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
done:
- vfree(rb_buffer);
+ adreno_set_max_ts_for_bad_ctxs(device);
+ adreno_mark_context_status(device, ret);
+ if (!ret)
+ KGSL_DRV_ERR(device, "Recovery succeeded\n");
+ else
+ KGSL_DRV_ERR(device, "Recovery failed\n");
return ret;
}
-int adreno_dump_and_recover(struct kgsl_device *device)
+int
+adreno_dump_and_recover(struct kgsl_device *device)
{
int result = -ETIMEDOUT;
+ struct adreno_recovery_data rec_data;
if (device->state == KGSL_STATE_HUNG)
goto done;
@@ -956,7 +1094,8 @@
INIT_COMPLETION(device->recovery_gate);
/* Detected a hang */
-
+ /* Get the recovery data as soon as hang is detected */
+ result = adreno_setup_recovery_data(device, &rec_data);
/*
* Trigger an automatic dump of the state to
* the console
@@ -969,11 +1108,14 @@
*/
kgsl_device_snapshot(device, 1);
- result = adreno_recover_hang(device);
- if (result)
+ result = adreno_recover_hang(device, &rec_data);
+ adreno_destroy_recovery_data(&rec_data);
+ if (result) {
kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
- else
+ } else {
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+ mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
+ }
complete_all(&device->recovery_gate);
}
done:
@@ -1201,7 +1343,8 @@
err:
KGSL_DRV_ERR(device, "spun too long waiting for RB to idle\n");
- if (!adreno_dump_and_recover(device)) {
+ if (KGSL_STATE_DUMP_AND_RECOVER != device->state &&
+ !adreno_dump_and_recover(device)) {
wait_time = jiffies + wait_timeout;
goto retry;
}
@@ -1595,10 +1738,9 @@
context_id, timestamp, context_id, ts_issued,
adreno_dev->ringbuffer.wptr);
if (!adreno_dump_and_recover(device)) {
- /* wait for idle after recovery as the
- * timestamp that this process wanted
- * to wait on may be invalid */
- if (!adreno_idle(device, KGSL_TIMEOUT_DEFAULT))
+ /* The timestamp that this process wanted
+ * to wait on may be invalid or expired now
+ * after successful recovery */
status = 0;
}
done:
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index e1d1eb9..57f4859 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -24,11 +24,15 @@
#define ADRENO_DEVICE(device) \
KGSL_CONTAINER_OF(device, struct adreno_device, dev)
+#define ADRENO_CHIPID_CORE(_id) (((_id) >> 24) & 0xFF)
+#define ADRENO_CHIPID_MAJOR(_id) (((_id) >> 16) & 0xFF)
+#define ADRENO_CHIPID_MINOR(_id) (((_id) >> 8) & 0xFF)
+#define ADRENO_CHIPID_PATCH(_id) ((_id) & 0xFF)
+
/* Flags to control command packet settings */
#define KGSL_CMD_FLAGS_NONE 0x00000000
#define KGSL_CMD_FLAGS_PMODE 0x00000001
#define KGSL_CMD_FLAGS_NO_TS_CMP 0x00000002
-#define KGSL_CMD_FLAGS_NOT_KERNEL_CMD 0x00000004
/* Command identifiers */
#define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF
@@ -110,6 +114,30 @@
unsigned int (*busy_cycles)(struct adreno_device *);
};
+/*
+ * struct adreno_recovery_data - Structure that contains all information to
+ * perform gpu recovery from hangs
+ * @ib1 - IB1 that the GPU was executing when hang happened
+ * @context_id - Context which caused the hang
+ * @global_eop - eoptimestamp at time of hang
+ * @rb_buffer - Buffer that holds the commands from good contexts
+ * @rb_size - Number of valid dwords in rb_buffer
+ * @bad_rb_buffer - Buffer that holds commands from the hanging context
+ * bad_rb_size - Number of valid dwords in bad_rb_buffer
+ * @last_valid_ctx_id - The last context from which commands were placed in
+ * ringbuffer before the GPU hung
+ */
+struct adreno_recovery_data {
+ unsigned int ib1;
+ unsigned int context_id;
+ unsigned int global_eop;
+ unsigned int *rb_buffer;
+ unsigned int rb_size;
+ unsigned int *bad_rb_buffer;
+ unsigned int bad_rb_size;
+ unsigned int last_valid_ctx_id;
+};
+
extern struct adreno_gpudev adreno_a2xx_gpudev;
extern struct adreno_gpudev adreno_a3xx_gpudev;
@@ -261,7 +289,6 @@
{
unsigned int *start = cmds;
- cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
*cmds++ = cp_type0_packet(MH_MMU_MPU_END, 1);
*cmds++ = new_phys_limit;
cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
@@ -274,7 +301,6 @@
{
unsigned int *start = cmds;
- cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
*cmds++ = cp_type0_packet(REG_CP_STATE_DEBUG_INDEX, 1);
*cmds++ = (cur_ctx_bank ? 0 : 0x20);
cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 6eebeb8..bb89067 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -500,26 +500,19 @@
*cmds++ = _SET(VFD_DECODEINSTRUCTIONS_WRITEMASK, 0x0F) |
_SET(VFD_DECODEINSTRUCTIONS_CONSTFILL, 1) |
_SET(VFD_DECODEINSTRUCTIONS_FORMAT, 2) |
- _SET(VFD_DECODEINSTRUCTIONS_REGID, 5) |
_SET(VFD_DECODEINSTRUCTIONS_SHIFTCNT, 12) |
_SET(VFD_DECODEINSTRUCTIONS_LASTCOMPVALID, 1);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 5);
*cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
/* HLSQ_CONTROL_0_REG */
- *cmds++ = _SET(HLSQ_CTRL0REG_FSTHREADSIZE, HLSQ_TWO_PIX_QUADS) |
+ *cmds++ = _SET(HLSQ_CTRL0REG_FSTHREADSIZE, HLSQ_FOUR_PIX_QUADS) |
_SET(HLSQ_CTRL0REG_FSSUPERTHREADENABLE, 1) |
- _SET(HLSQ_CTRL0REG_SPSHADERRESTART, 1) |
_SET(HLSQ_CTRL0REG_RESERVED2, 1) |
- _SET(HLSQ_CTRL0REG_CHUNKDISABLE, 1) |
- _SET(HLSQ_CTRL0REG_CONSTSWITCHMODE, 1) |
- _SET(HLSQ_CTRL0REG_LAZYUPDATEDISABLE, 1) |
- _SET(HLSQ_CTRL0REG_SPCONSTFULLUPDATE, 1) |
- _SET(HLSQ_CTRL0REG_TPFULLUPDATE, 1);
+ _SET(HLSQ_CTRL0REG_SPCONSTFULLUPDATE, 1);
/* HLSQ_CONTROL_1_REG */
*cmds++ = _SET(HLSQ_CTRL1REG_VSTHREADSIZE, HLSQ_TWO_VTX_QUADS) |
- _SET(HLSQ_CTRL1REG_VSSUPERTHREADENABLE, 1) |
- _SET(HLSQ_CTRL1REG_RESERVED1, 4);
+ _SET(HLSQ_CTRL1REG_VSSUPERTHREADENABLE, 1);
/* HLSQ_CONTROL_2_REG */
*cmds++ = _SET(HLSQ_CTRL2REG_PRIMALLOCTHRESHOLD, 31);
/* HLSQ_CONTROL_3_REG */
@@ -531,7 +524,7 @@
*cmds++ = _SET(HLSQ_VSCTRLREG_VSINSTRLENGTH, 1);
/* HLSQ_FS_CONTROL_REG */
*cmds++ = _SET(HLSQ_FSCTRLREG_FSCONSTLENGTH, 1) |
- _SET(HLSQ_FSCTRLREG_FSCONSTSTARTOFFSET, 272) |
+ _SET(HLSQ_FSCTRLREG_FSCONSTSTARTOFFSET, 128) |
_SET(HLSQ_FSCTRLREG_FSINSTRLENGTH, 1);
/* HLSQ_CONST_VSPRESV_RANGE_REG */
*cmds++ = 0x00000000;
@@ -547,8 +540,8 @@
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
*cmds++ = CP_REG(A3XX_SP_SP_CTRL_REG);
/* SP_SP_CTRL_REG */
- *cmds++ = _SET(SP_SPCTRLREG_CONSTMODE, 1) |
- _SET(SP_SPCTRLREG_SLEEPMODE, 1);
+ *cmds++ = _SET(SP_SPCTRLREG_SLEEPMODE, 1) |
+ _SET(SP_SPCTRLREG_LOMODE, 1);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 12);
*cmds++ = CP_REG(A3XX_SP_VS_CTRL_REG0);
@@ -556,15 +549,14 @@
*cmds++ = _SET(SP_VSCTRLREG0_VSTHREADMODE, SP_MULTI) |
_SET(SP_VSCTRLREG0_VSINSTRBUFFERMODE, SP_BUFFER_MODE) |
_SET(SP_VSCTRLREG0_VSICACHEINVALID, 1) |
- _SET(SP_VSCTRLREG0_VSFULLREGFOOTPRINT, 3) |
+ _SET(SP_VSCTRLREG0_VSFULLREGFOOTPRINT, 1) |
_SET(SP_VSCTRLREG0_VSTHREADSIZE, SP_TWO_VTX_QUADS) |
_SET(SP_VSCTRLREG0_VSSUPERTHREADMODE, 1) |
_SET(SP_VSCTRLREG0_VSLENGTH, 1);
/* SP_VS_CTRL_REG1 */
*cmds++ = _SET(SP_VSCTRLREG1_VSINITIALOUTSTANDING, 4);
/* SP_VS_PARAM_REG */
- *cmds++ = _SET(SP_VSPARAMREG_POSREGID, 1) |
- _SET(SP_VSPARAMREG_PSIZEREGID, 252);
+ *cmds++ = _SET(SP_VSPARAMREG_PSIZEREGID, 252);
/* SP_VS_OUT_REG_0 */
*cmds++ = 0x00000000;
/* SP_VS_OUT_REG_1 */
@@ -605,18 +597,17 @@
*cmds++ = _SET(SP_FSCTRLREG0_FSTHREADMODE, SP_MULTI) |
_SET(SP_FSCTRLREG0_FSINSTRBUFFERMODE, SP_BUFFER_MODE) |
_SET(SP_FSCTRLREG0_FSICACHEINVALID, 1) |
- _SET(SP_FSCTRLREG0_FSFULLREGFOOTPRINT, 2) |
+ _SET(SP_FSCTRLREG0_FSHALFREGFOOTPRINT, 1) |
_SET(SP_FSCTRLREG0_FSINOUTREGOVERLAP, 1) |
- _SET(SP_FSCTRLREG0_FSTHREADSIZE, SP_TWO_VTX_QUADS) |
+ _SET(SP_FSCTRLREG0_FSTHREADSIZE, SP_FOUR_PIX_QUADS) |
_SET(SP_FSCTRLREG0_FSSUPERTHREADMODE, 1) |
_SET(SP_FSCTRLREG0_FSLENGTH, 1);
/* SP_FS_CTRL_REG1 */
*cmds++ = _SET(SP_FSCTRLREG1_FSCONSTLENGTH, 1) |
- _SET(SP_FSCTRLREG1_FSINITIALOUTSTANDING, 2) |
_SET(SP_FSCTRLREG1_HALFPRECVAROFFSET, 63);
/* SP_FS_OBJ_OFFSET_REG */
- *cmds++ = _SET(SP_OBJOFFSETREG_CONSTOBJECTSTARTOFFSET, 272) |
- _SET(SP_OBJOFFSETREG_SHADEROBJOFFSETINIC, 1);
+ *cmds++ = _SET(SP_OBJOFFSETREG_CONSTOBJECTSTARTOFFSET, 128) |
+ _SET(SP_OBJOFFSETREG_SHADEROBJOFFSETINIC, 127);
/* SP_FS_OBJ_START_REG */
*cmds++ = 0x00000000;
@@ -630,12 +621,13 @@
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
*cmds++ = CP_REG(A3XX_SP_FS_OUTPUT_REG);
/* SP_FS_OUTPUT_REG */
- *cmds++ = _SET(SP_IMAGEOUTPUTREG_PAD0, SP_PIXEL_BASED);
+ *cmds++ = _SET(SP_IMAGEOUTPUTREG_DEPTHOUTMODE, SP_PIXEL_BASED);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 5);
*cmds++ = CP_REG(A3XX_SP_FS_MRT_REG_0);
/* SP_FS_MRT_REG_0 */
- *cmds++ = _SET(SP_FSMRTREG_REGID, 1);
+ *cmds++ = _SET(SP_FSMRTREG_PRECISION, 1);
+
/* SP_FS_MRT_REG_1 */
*cmds++ = 0x00000000;
/* SP_FS_MRT_REG_2 */
@@ -676,14 +668,21 @@
| (0 << CP_LOADSTATE_EXTSRCADDR_SHIFT);
/* (sy)(rpt3)mov.f32f32 r0.y, (r)r1.y; */
- *cmds++ = 0x00000005; *cmds++ = 0x30044b01;
+ *cmds++ = 0x00000000; *cmds++ = 0x13001000;
/* end; */
- *cmds++ = 0x00000000; *cmds++ = 0x03000000;
+ *cmds++ = 0x00000000; *cmds++ = 0x00000000;
/* nop; */
*cmds++ = 0x00000000; *cmds++ = 0x00000000;
/* nop; */
*cmds++ = 0x00000000; *cmds++ = 0x00000000;
+
+ *cmds++ = cp_type0_packet(A3XX_VFD_PERFCOUNTER0_SELECT, 1);
+ *cmds++ = 0x00000000;
+
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+
*cmds++ = cp_type3_packet(CP_LOAD_STATE, 10);
*cmds++ = (0 << CP_LOADSTATE_DSTOFFSET_SHIFT)
| (HLSQ_DIRECT << CP_LOADSTATE_STATESRC_SHIFT)
@@ -693,7 +692,7 @@
| (0 << CP_LOADSTATE_EXTSRCADDR_SHIFT);
/* (sy)(rpt3)mov.f32f32 r0.y, (r)c0.x; */
- *cmds++ = 0x00000000; *cmds++ = 0x30244b01;
+ *cmds++ = 0x00000000; *cmds++ = 0x30201b00;
/* end; */
*cmds++ = 0x00000000; *cmds++ = 0x03000000;
/* nop; */
@@ -701,6 +700,15 @@
/* nop; */
*cmds++ = 0x00000000; *cmds++ = 0x00000000;
+
+
+ *cmds++ = cp_type0_packet(A3XX_VFD_PERFCOUNTER0_SELECT, 1);
+ *cmds++ = 0x00000000;
+
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+
+
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
*cmds++ = CP_REG(A3XX_RB_MSAA_CONTROL);
/* RB_MSAA_CONTROL */
@@ -713,6 +721,23 @@
*cmds++ = _SET(RB_DEPTHCONTROL_Z_TEST_FUNC, RB_FRAG_NEVER);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
+ *cmds++ = CP_REG(A3XX_RB_STENCIL_CONTROL);
+ /* RB_STENCIL_CONTROL */
+ *cmds++ = _SET(RB_STENCILCONTROL_STENCIL_FUNC, RB_REF_NEVER) |
+ _SET(RB_STENCILCONTROL_STENCIL_FAIL, RB_STENCIL_KEEP) |
+ _SET(RB_STENCILCONTROL_STENCIL_ZPASS, RB_STENCIL_KEEP) |
+ _SET(RB_STENCILCONTROL_STENCIL_ZFAIL, RB_STENCIL_KEEP) |
+ _SET(RB_STENCILCONTROL_STENCIL_FUNC_BF, RB_REF_NEVER) |
+ _SET(RB_STENCILCONTROL_STENCIL_FAIL_BF, RB_STENCIL_KEEP) |
+ _SET(RB_STENCILCONTROL_STENCIL_ZPASS_BF, RB_STENCIL_KEEP) |
+ _SET(RB_STENCILCONTROL_STENCIL_ZFAIL_BF, RB_STENCIL_KEEP);
+
+ *cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
+ *cmds++ = CP_REG(A3XX_GRAS_SU_MODE_CONTROL);
+ /* GRAS_SU_MODE_CONTROL */
+ *cmds++ = 0x00000000;
+
+ *cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
*cmds++ = CP_REG(A3XX_RB_MRT_CONTROL0);
/* RB_MRT_CONTROL0 */
*cmds++ = _SET(RB_MRTCONTROL_READ_DEST_ENABLE, 1) |
@@ -777,7 +802,7 @@
/* VFD_INDEX_MIN */
*cmds++ = 0x00000000;
/* VFD_INDEX_MAX */
- *cmds++ = 0xFFFFFFFF;
+ *cmds++ = 0x155;
/* VFD_INSTANCEID_OFFSET */
*cmds++ = 0x00000000;
/* VFD_INDEX_OFFSET */
@@ -786,7 +811,7 @@
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
*cmds++ = CP_REG(A3XX_VFD_VS_THREADING_THRESHOLD);
/* VFD_VS_THREADING_THRESHOLD */
- *cmds++ = _SET(VFD_THREADINGTHRESHOLD_RESERVED6, 12) |
+ *cmds++ = _SET(VFD_THREADINGTHRESHOLD_REGID_THRESHOLD, 15) |
_SET(VFD_THREADINGTHRESHOLD_REGID_VTXCNT, 252);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
@@ -861,6 +886,46 @@
*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
*cmds++ = 0x00000000;
+
+ /* oxili_generate_context_roll_packets */
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG0, 1);
+ *cmds++ = 0x00000400;
+
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG0, 1);
+ *cmds++ = 0x00000400;
+
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_SIZE_REG, 1);
+ *cmds++ = 0x00008000; /* SP_VS_MEM_SIZE_REG */
+
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_SIZE_REG, 1);
+ *cmds++ = 0x00008000; /* SP_FS_MEM_SIZE_REG */
+
+ /* Clear cache invalidate bit when re-loading the shader control regs */
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG0, 1);
+ *cmds++ = _SET(SP_VSCTRLREG0_VSTHREADMODE, SP_MULTI) |
+ _SET(SP_VSCTRLREG0_VSINSTRBUFFERMODE, SP_BUFFER_MODE) |
+ _SET(SP_VSCTRLREG0_VSFULLREGFOOTPRINT, 1) |
+ _SET(SP_VSCTRLREG0_VSTHREADSIZE, SP_TWO_VTX_QUADS) |
+ _SET(SP_VSCTRLREG0_VSSUPERTHREADMODE, 1) |
+ _SET(SP_VSCTRLREG0_VSLENGTH, 1);
+
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG0, 1);
+ *cmds++ = _SET(SP_FSCTRLREG0_FSTHREADMODE, SP_MULTI) |
+ _SET(SP_FSCTRLREG0_FSINSTRBUFFERMODE, SP_BUFFER_MODE) |
+ _SET(SP_FSCTRLREG0_FSHALFREGFOOTPRINT, 1) |
+ _SET(SP_FSCTRLREG0_FSINOUTREGOVERLAP, 1) |
+ _SET(SP_FSCTRLREG0_FSTHREADSIZE, SP_FOUR_PIX_QUADS) |
+ _SET(SP_FSCTRLREG0_FSSUPERTHREADMODE, 1) |
+ _SET(SP_FSCTRLREG0_FSLENGTH, 1);
+
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_SIZE_REG, 1);
+ *cmds++ = 0x00000000; /* SP_VS_MEM_SIZE_REG */
+
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_SIZE_REG, 1);
+ *cmds++ = 0x00000000; /* SP_FS_MEM_SIZE_REG */
+
+ /* end oxili_generate_context_roll_packets */
+
/*
* Resolve using two draw calls with a dummy register
* write in between. This is a HLM workaround
@@ -904,7 +969,6 @@
return cmds;
}
-
static void build_shader_save_cmds(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt)
{
@@ -1172,12 +1236,13 @@
*cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
/* HLSQ_CONTROL_0_REG */
*cmds++ = _SET(HLSQ_CTRL0REG_FSTHREADSIZE, HLSQ_FOUR_PIX_QUADS) |
+ _SET(HLSQ_CTRL0REG_FSSUPERTHREADENABLE, 1) |
_SET(HLSQ_CTRL0REG_SPSHADERRESTART, 1) |
_SET(HLSQ_CTRL0REG_CHUNKDISABLE, 1) |
- _SET(HLSQ_CTRL0REG_SPCONSTFULLUPDATE, 1) |
- _SET(HLSQ_CTRL0REG_TPFULLUPDATE, 1);
+ _SET(HLSQ_CTRL0REG_SPCONSTFULLUPDATE, 1);
/* HLSQ_CONTROL_1_REG */
- *cmds++ = _SET(HLSQ_CTRL1REG_VSTHREADSIZE, HLSQ_TWO_VTX_QUADS);
+ *cmds++ = _SET(HLSQ_CTRL1REG_VSTHREADSIZE, HLSQ_TWO_VTX_QUADS) |
+ _SET(HLSQ_CTRL1REG_VSSUPERTHREADENABLE, 1);
/* HLSQ_CONTROL_2_REG */
*cmds++ = _SET(HLSQ_CTRL2REG_PRIMALLOCTHRESHOLD, 31);
/* HLSQ_CONTROL3_REG */
@@ -1204,6 +1269,9 @@
*cmds++ = 0x00000240;
*cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_VFD_PERFCOUNTER0_SELECT, 1);
+ *cmds++ = 0x00000000;
+
/* Texture memobjs */
*cmds++ = cp_type3_packet(CP_LOAD_STATE, 6);
*cmds++ = (16 << CP_LOADSTATE_DSTOFFSET_SHIFT)
@@ -1217,6 +1285,9 @@
*cmds++ = (shadow->pitch*4*8) << 9;
*cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_VFD_PERFCOUNTER0_SELECT, 1);
+ *cmds++ = 0x00000000;
+
/* Mipmap bases */
*cmds++ = cp_type3_packet(CP_LOAD_STATE, 16);
*cmds++ = (224 << CP_LOADSTATE_DSTOFFSET_SHIFT)
@@ -1240,6 +1311,9 @@
*cmds++ = 0x00000000;
*cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_VFD_PERFCOUNTER0_SELECT, 1);
+ *cmds++ = 0x00000000;
+
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 5);
*cmds++ = CP_REG(A3XX_HLSQ_VS_CONTROL_REG);
/* HLSQ_VS_CONTROL_REG */
@@ -1313,9 +1387,11 @@
*cmds++ = _SET(SP_FSCTRLREG0_FSTHREADMODE, SP_MULTI) |
_SET(SP_FSCTRLREG0_FSINSTRBUFFERMODE, SP_BUFFER_MODE) |
_SET(SP_FSCTRLREG0_FSICACHEINVALID, 1) |
- _SET(SP_FSCTRLREG0_FSFULLREGFOOTPRINT, 2) |
+ _SET(SP_FSCTRLREG0_FSHALFREGFOOTPRINT, 1) |
+ _SET(SP_FSCTRLREG0_FSFULLREGFOOTPRINT, 1) |
_SET(SP_FSCTRLREG0_FSINOUTREGOVERLAP, 1) |
_SET(SP_FSCTRLREG0_FSTHREADSIZE, SP_FOUR_PIX_QUADS) |
+ _SET(SP_FSCTRLREG0_FSSUPERTHREADMODE, 1) |
_SET(SP_FSCTRLREG0_PIXLODENABLE, 1) |
_SET(SP_FSCTRLREG0_FSLENGTH, 2);
/* SP_FS_CTRL_REG1 */
@@ -1324,7 +1400,7 @@
_SET(SP_FSCTRLREG1_HALFPRECVAROFFSET, 63);
/* SP_FS_OBJ_OFFSET_REG */
*cmds++ = _SET(SP_OBJOFFSETREG_CONSTOBJECTSTARTOFFSET, 128) |
- _SET(SP_OBJOFFSETREG_SHADEROBJOFFSETINIC, 1);
+ _SET(SP_OBJOFFSETREG_SHADEROBJOFFSETINIC, 126);
/* SP_FS_OBJ_START_REG */
*cmds++ = 0x00000000;
@@ -1343,7 +1419,7 @@
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 5);
*cmds++ = CP_REG(A3XX_SP_FS_MRT_REG_0);
/* SP_FS_MRT_REG0 */
- *cmds++ = _SET(SP_FSMRTREG_REGID, 4);
+ *cmds++ = _SET(SP_FSMRTREG_PRECISION, 1);
/* SP_FS_MRT_REG1 */
*cmds++ = 0;
/* SP_FS_MRT_REG2 */
@@ -1440,7 +1516,8 @@
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
*cmds++ = CP_REG(A3XX_SP_SP_CTRL_REG);
/* SP_SP_CTRL_REG */
- *cmds++ = _SET(SP_SPCTRLREG_SLEEPMODE, 1);
+ *cmds++ = _SET(SP_SPCTRLREG_SLEEPMODE, 1) |
+ _SET(SP_SPCTRLREG_LOMODE, 1);
/* Load vertex shader */
*cmds++ = cp_type3_packet(CP_LOAD_STATE, 10);
@@ -1451,7 +1528,7 @@
*cmds++ = (HLSQ_SP_VS_INSTR << CP_LOADSTATE_STATETYPE_SHIFT)
| (0 << CP_LOADSTATE_EXTSRCADDR_SHIFT);
/* (sy)end; */
- *cmds++ = 0x00000000; *cmds++ = 0x13000000;
+ *cmds++ = 0x00000000; *cmds++ = 0x13001000;
/* nop; */
*cmds++ = 0x00000000; *cmds++ = 0x00000000;
/* nop; */
@@ -1459,6 +1536,13 @@
/* nop; */
*cmds++ = 0x00000000; *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_VFD_PERFCOUNTER0_SELECT, 1);
+ *cmds++ = 0x00000000;
+
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+
+
/* Load fragment shader */
*cmds++ = cp_type3_packet(CP_LOAD_STATE, 18);
*cmds++ = (0 << CP_LOADSTATE_DSTOFFSET_SHIFT)
@@ -1468,21 +1552,27 @@
*cmds++ = (HLSQ_SP_FS_INSTR << CP_LOADSTATE_STATETYPE_SHIFT)
| (0 << CP_LOADSTATE_EXTSRCADDR_SHIFT);
/* (sy)(rpt1)bary.f (ei)r0.z, (r)0, r0.x; */
- *cmds++ = 0x00002000; *cmds++ = 0x57368902;
+ *cmds++ = 0x00002000; *cmds++ = 0x57309902;
/* (rpt5)nop; */
*cmds++ = 0x00000000; *cmds++ = 0x00000500;
/* sam (f32)r0.xyzw, r0.z, s#0, t#0; */
*cmds++ = 0x00000005; *cmds++ = 0xa0c01f00;
/* (sy)mov.f32f32 r1.x, r0.x; */
- *cmds++ = 0x00000000; *cmds++ = 0x30044004;
+ *cmds++ = 0x00000000; *cmds++ = 0x30040b00;
/* mov.f32f32 r1.y, r0.y; */
- *cmds++ = 0x00000001; *cmds++ = 0x20044005;
- /* mov.f32f32 r1.z, r0.z; */
- *cmds++ = 0x00000002; *cmds++ = 0x20044006;
- /* mov.f32f32 r1.w, r0.w; */
- *cmds++ = 0x00000003; *cmds++ = 0x20044007;
- /* end; */
*cmds++ = 0x00000000; *cmds++ = 0x03000000;
+ /* mov.f32f32 r1.z, r0.z; */
+ *cmds++ = 0x00000000; *cmds++ = 0x00000000;
+ /* mov.f32f32 r1.w, r0.w; */
+ *cmds++ = 0x00000000; *cmds++ = 0x00000000;
+ /* end; */
+ *cmds++ = 0x00000000; *cmds++ = 0x00000000;
+
+ *cmds++ = cp_type0_packet(A3XX_VFD_PERFCOUNTER0_SELECT, 1);
+ *cmds++ = 0x00000000;
+
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
*cmds++ = CP_REG(A3XX_VFD_CONTROL_0);
@@ -1535,16 +1625,16 @@
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
*cmds++ = CP_REG(A3XX_RB_DEPTH_CONTROL);
/* RB_DEPTH_CONTROL */
- *cmds++ = _SET(RB_DEPTHCONTROL_Z_TEST_FUNC, RB_FRAG_NEVER);
+ *cmds++ = _SET(RB_DEPTHCONTROL_Z_TEST_FUNC, RB_FRAG_LESS);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
*cmds++ = CP_REG(A3XX_RB_STENCIL_CONTROL);
/* RB_STENCIL_CONTROL */
- *cmds++ = _SET(RB_STENCILCONTROL_STENCIL_FUNC, RB_REF_NEVER) |
+ *cmds++ = _SET(RB_STENCILCONTROL_STENCIL_FUNC, RB_REF_ALWAYS) |
_SET(RB_STENCILCONTROL_STENCIL_FAIL, RB_STENCIL_KEEP) |
_SET(RB_STENCILCONTROL_STENCIL_ZPASS, RB_STENCIL_KEEP) |
_SET(RB_STENCILCONTROL_STENCIL_ZFAIL, RB_STENCIL_KEEP) |
- _SET(RB_STENCILCONTROL_STENCIL_FUNC_BF, RB_REF_NEVER) |
+ _SET(RB_STENCILCONTROL_STENCIL_FUNC_BF, RB_REF_ALWAYS) |
_SET(RB_STENCILCONTROL_STENCIL_FAIL_BF, RB_STENCIL_KEEP) |
_SET(RB_STENCILCONTROL_STENCIL_ZPASS_BF, RB_STENCIL_KEEP) |
_SET(RB_STENCILCONTROL_STENCIL_ZFAIL_BF, RB_STENCIL_KEEP);
@@ -1570,9 +1660,8 @@
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
*cmds++ = CP_REG(A3XX_RB_MRT_CONTROL0);
/* RB_MRT_CONTROL0 */
- *cmds++ = _SET(RB_MRTCONTROL_READ_DEST_ENABLE, 1) |
- _SET(RB_MRTCONTROL_ROP_CODE, 12) |
- _SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_ALWAYS) |
+ *cmds++ = _SET(RB_MRTCONTROL_ROP_CODE, 12) |
+ _SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_DISABLE) |
_SET(RB_MRTCONTROL_COMPONENT_ENABLE, 0xF);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
@@ -1587,7 +1676,8 @@
_SET(RB_MRTBLENDCONTROL_CLAMP_ENABLE, 1);
/* RB_MRT_CONTROL1 */
*cmds++ = _SET(RB_MRTCONTROL_READ_DEST_ENABLE, 1) |
- _SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_DISABLE) |
+ _SET(RB_MRTCONTROL_ROP_CODE, 12) |
+ _SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_ALWAYS) |
_SET(RB_MRTCONTROL_COMPONENT_ENABLE, 0xF);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
@@ -1602,7 +1692,8 @@
_SET(RB_MRTBLENDCONTROL_CLAMP_ENABLE, 1);
/* RB_MRT_CONTROL2 */
*cmds++ = _SET(RB_MRTCONTROL_READ_DEST_ENABLE, 1) |
- _SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_DISABLE) |
+ _SET(RB_MRTCONTROL_ROP_CODE, 12) |
+ _SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_ALWAYS) |
_SET(RB_MRTCONTROL_COMPONENT_ENABLE, 0xF);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
@@ -1617,7 +1708,8 @@
_SET(RB_MRTBLENDCONTROL_CLAMP_ENABLE, 1);
/* RB_MRT_CONTROL3 */
*cmds++ = _SET(RB_MRTCONTROL_READ_DEST_ENABLE, 1) |
- _SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_DISABLE) |
+ _SET(RB_MRTCONTROL_ROP_CODE, 12) |
+ _SET(RB_MRTCONTROL_DITHER_MODE, RB_DITHER_ALWAYS) |
_SET(RB_MRTCONTROL_COMPONENT_ENABLE, 0xF);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
@@ -1636,7 +1728,7 @@
/* VFD_INDEX_MIN */
*cmds++ = 0x00000000;
/* VFD_INDEX_MAX */
- *cmds++ = 0xFFFFFFFF;
+ *cmds++ = 340;
/* VFD_INDEX_OFFSET */
*cmds++ = 0x00000000;
/* TPL1_TP_VS_TEX_OFFSET */
@@ -1645,7 +1737,7 @@
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
*cmds++ = CP_REG(A3XX_VFD_VS_THREADING_THRESHOLD);
/* VFD_VS_THREADING_THRESHOLD */
- *cmds++ = _SET(VFD_THREADINGTHRESHOLD_RESERVED6, 12) |
+ *cmds++ = _SET(VFD_THREADINGTHRESHOLD_REGID_THRESHOLD, 15) |
_SET(VFD_THREADINGTHRESHOLD_REGID_VTXCNT, 252);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
@@ -1670,7 +1762,7 @@
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
*cmds++ = CP_REG(A3XX_GRAS_SU_MODE_CONTROL);
/* GRAS_SU_MODE_CONTROL */
- *cmds++ = 0x00000000;
+ *cmds++ = _SET(GRAS_SU_CTRLMODE_LINEHALFWIDTH, 2);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
*cmds++ = CP_REG(A3XX_GRAS_SC_WINDOW_SCISSOR_TL);
@@ -1726,6 +1818,46 @@
PC_DRAW_TRIANGLES) |
_SET(PC_PRIM_VTX_CONTROL_PROVOKING_VTX_LAST, 1);
+
+ /* oxili_generate_context_roll_packets */
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG0, 1);
+ *cmds++ = 0x00000400;
+
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG0, 1);
+ *cmds++ = 0x00000400;
+
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_SIZE_REG, 1);
+ *cmds++ = 0x00008000; /* SP_VS_MEM_SIZE_REG */
+
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_SIZE_REG, 1);
+ *cmds++ = 0x00008000; /* SP_FS_MEM_SIZE_REG */
+
+ /* Clear cache invalidate bit when re-loading the shader control regs */
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG0, 1);
+ *cmds++ = _SET(SP_VSCTRLREG0_VSTHREADMODE, SP_MULTI) |
+ _SET(SP_VSCTRLREG0_VSINSTRBUFFERMODE, SP_BUFFER_MODE) |
+ _SET(SP_VSCTRLREG0_VSFULLREGFOOTPRINT, 2) |
+ _SET(SP_VSCTRLREG0_VSTHREADSIZE, SP_TWO_VTX_QUADS) |
+ _SET(SP_VSCTRLREG0_VSLENGTH, 1);
+
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG0, 1);
+ *cmds++ = _SET(SP_FSCTRLREG0_FSTHREADMODE, SP_MULTI) |
+ _SET(SP_FSCTRLREG0_FSINSTRBUFFERMODE, SP_BUFFER_MODE) |
+ _SET(SP_FSCTRLREG0_FSHALFREGFOOTPRINT, 1) |
+ _SET(SP_FSCTRLREG0_FSFULLREGFOOTPRINT, 1) |
+ _SET(SP_FSCTRLREG0_FSINOUTREGOVERLAP, 1) |
+ _SET(SP_FSCTRLREG0_FSTHREADSIZE, SP_FOUR_PIX_QUADS) |
+ _SET(SP_FSCTRLREG0_FSSUPERTHREADMODE, 1) |
+ _SET(SP_FSCTRLREG0_FSLENGTH, 2);
+
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_SIZE_REG, 1);
+ *cmds++ = 0x00000000; /* SP_VS_MEM_SIZE_REG */
+
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_SIZE_REG, 1);
+ *cmds++ = 0x00000000; /* SP_FS_MEM_SIZE_REG */
+
+ /* end oxili_generate_context_roll_packets */
+
*cmds++ = cp_type3_packet(CP_DRAW_INDX, 3);
*cmds++ = 0x00000000; /* Viz query info */
*cmds++ = BUILD_PC_DRAW_INITIATOR(PC_DI_PT_RECTLIST,
@@ -1740,6 +1872,7 @@
return cmds;
}
+
static void build_regrestore_cmds(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt)
{
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 3eb1aba..5b14a69 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -44,6 +44,8 @@
#define CTXT_FLAGS_TRASHSTATE 0x00020000
/* per context timestamps enabled */
#define CTXT_FLAGS_PER_CONTEXT_TS 0x00040000
+/* Context has caused a GPU hang and recovered properly */
+#define CTXT_FLAGS_GPU_HANG_RECOVERED 0x00008000
struct kgsl_device;
struct adreno_device;
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 7bb65ca..3cc4bcf 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -699,6 +699,10 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct kgsl_memdesc **reg_map;
+ void *reg_map_array;
+ int num_iommu_units = 0;
+
mb();
if (adreno_is_a2xx(adreno_dev))
@@ -780,6 +784,10 @@
/* extract the latest ib commands from the buffer */
ib_list.count = 0;
i = 0;
+ /* get the register mapped array in case we are using IOMMU */
+ num_iommu_units = kgsl_mmu_get_reg_map_desc(&device->mmu,
+ ®_map_array);
+ reg_map = reg_map_array;
for (read_idx = 0; read_idx < num_item; ) {
uint32_t this_cmd = rb_copy[read_idx++];
if (adreno_cmd_is_ib(this_cmd)) {
@@ -792,7 +800,10 @@
ib_list.offsets[i],
ib_list.bases[i],
ib_list.sizes[i], 0);
- } else if (this_cmd == cp_type0_packet(MH_MMU_PT_BASE, 1)) {
+ } else if (this_cmd == cp_type0_packet(MH_MMU_PT_BASE, 1) ||
+ (num_iommu_units && this_cmd == (reg_map[0]->gpuaddr +
+ (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
+ KGSL_IOMMU_TTBR0))) {
KGSL_LOG_DUMP(device, "Current pagetable: %x\t"
"pagetable base: %x\n",
@@ -808,6 +819,8 @@
cur_pt_base);
}
}
+ if (num_iommu_units)
+ kfree(reg_map_array);
/* Restore cur_pt_base back to the pt_base of
the process in whose context the GPU hung */
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index afcceee..d54ce6b 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -493,7 +493,8 @@
*/
total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
total_sizedwords += !(flags & KGSL_CMD_FLAGS_NO_TS_CMP) ? 7 : 0;
- total_sizedwords += !(flags & KGSL_CMD_FLAGS_NOT_KERNEL_CMD) ? 2 : 0;
+ /* 2 dwords to store the start of command sequence */
+ total_sizedwords += 2;
if (adreno_is_a3xx(adreno_dev))
total_sizedwords += 7;
@@ -521,10 +522,9 @@
rcmd_gpu = rb->buffer_desc.gpuaddr
+ sizeof(uint)*(rb->wptr-total_sizedwords);
- if (!(flags & KGSL_CMD_FLAGS_NOT_KERNEL_CMD)) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
- }
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
+
if (flags & KGSL_CMD_FLAGS_PMODE) {
/* disable protected mode error checking */
GSL_RB_WRITE(ringcmds, rcmd_gpu,
@@ -926,8 +926,7 @@
adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
*timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
- drawctxt,
- KGSL_CMD_FLAGS_NOT_KERNEL_CMD,
+ drawctxt, 0,
&link[0], (cmds - link));
KGSL_CMD_INFO(device, "ctxt %d g %08x numibs %d ts %d\n",
@@ -943,187 +942,347 @@
*/
adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
#endif
+ /* If context hung and recovered then return error so that the
+ * application may handle it */
+ if (drawctxt->flags & CTXT_FLAGS_GPU_HANG_RECOVERED)
+ return -EDEADLK;
+ else
+ return 0;
- return 0;
}
-int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
- unsigned int *temp_rb_buffer,
- int *rb_size)
+static int _find_start_of_cmd_seq(struct adreno_ringbuffer *rb,
+ unsigned int *ptr,
+ bool inc)
{
- struct kgsl_device *device = rb->device;
- unsigned int rb_rptr;
- unsigned int retired_timestamp;
- unsigned int temp_idx = 0;
- unsigned int value;
+ int status = -EINVAL;
unsigned int val1;
- unsigned int val2;
- unsigned int val3;
- unsigned int copy_rb_contents = 0;
- struct kgsl_context *context;
- unsigned int context_id;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int start_ptr = *ptr;
- GSL_RB_GET_READPTR(rb, &rb->rptr);
-
- /* current_context is the context that is presently active in the
- * GPU, i.e the context in which the hang is caused */
- kgsl_sharedmem_readl(&device->memstore, &context_id,
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- current_context));
- KGSL_DRV_ERR(device, "Last context id: %d\n", context_id);
- context = idr_find(&device->context_idr, context_id);
- if (context == NULL) {
- KGSL_DRV_ERR(device,
- "GPU recovery from hang not possible because last"
- " context id is invalid.\n");
- return -EINVAL;
- }
- retired_timestamp = kgsl_readtimestamp(device, context,
- KGSL_TIMESTAMP_RETIRED);
- KGSL_DRV_ERR(device, "GPU successfully executed till ts: %x\n",
- retired_timestamp);
- /*
- * We need to go back in history by 4 dwords from the current location
- * of read pointer as 4 dwords are read to match the end of a command.
- * Also, take care of wrap around when moving back
- */
- if (rb->rptr >= 4)
- rb_rptr = (rb->rptr - 4) * sizeof(unsigned int);
- else
- rb_rptr = rb->buffer_desc.size -
- ((4 - rb->rptr) * sizeof(unsigned int));
- /* Read the rb contents going backwards to locate end of last
- * sucessfully executed command */
- while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
- kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
- if (value == retired_timestamp) {
- rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size);
- kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
- rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size);
- kgsl_sharedmem_readl(&rb->buffer_desc, &val2, rb_rptr);
- rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size);
- kgsl_sharedmem_readl(&rb->buffer_desc, &val3, rb_rptr);
- /* match the pattern found at the end of a command */
- if ((val1 == 2 &&
- val2 == cp_type3_packet(CP_INTERRUPT, 1)
- && val3 == CP_INT_CNTL__RB_INT_MASK) ||
- (val1 == cp_type3_packet(CP_EVENT_WRITE, 3)
- && val2 == CACHE_FLUSH_TS &&
- val3 == (rb->device->memstore.gpuaddr +
- KGSL_MEMSTORE_OFFSET(context_id,
- eoptimestamp)))) {
- rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size);
- KGSL_DRV_ERR(device,
- "Found end of last executed "
- "command at offset: %x\n",
- rb_rptr / sizeof(unsigned int));
+ while ((start_ptr / sizeof(unsigned int)) != rb->wptr) {
+ if (inc)
+ start_ptr = adreno_ringbuffer_inc_wrapped(start_ptr,
+ size);
+ else
+ start_ptr = adreno_ringbuffer_dec_wrapped(start_ptr,
+ size);
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val1, start_ptr);
+ if (KGSL_CMD_IDENTIFIER == val1) {
+ if ((start_ptr / sizeof(unsigned int)) != rb->wptr)
+ start_ptr = adreno_ringbuffer_dec_wrapped(
+ start_ptr, size);
+ *ptr = start_ptr;
+ status = 0;
break;
- } else {
- if (rb_rptr < (3 * sizeof(unsigned int)))
- rb_rptr = rb->buffer_desc.size -
- (3 * sizeof(unsigned int))
- + rb_rptr;
- else
- rb_rptr -= (3 * sizeof(unsigned int));
+ }
+ }
+ return status;
+}
+
+static int _find_cmd_seq_after_eop_ts(struct adreno_ringbuffer *rb,
+ unsigned int *rb_rptr,
+ unsigned int global_eop,
+ bool inc)
+{
+ int status = -EINVAL;
+ unsigned int temp_rb_rptr = *rb_rptr;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int val[3];
+ int i = 0;
+ bool check = false;
+
+ if (inc && temp_rb_rptr / sizeof(unsigned int) != rb->wptr)
+ return status;
+
+ do {
+ /* when decrementing we need to decrement first and
+ * then read make sure we cover all the data */
+ if (!inc)
+ temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
+ temp_rb_rptr, size);
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val[i],
+ temp_rb_rptr);
+
+ if (check && ((inc && val[i] == global_eop) ||
+ (!inc && (val[i] ==
+ cp_type3_packet(CP_MEM_WRITE, 2) ||
+ val[i] == CACHE_FLUSH_TS)))) {
+ /* decrement i, i.e i = (i - 1 + 3) % 3 if
+ * we are going forward, else increment i */
+ i = (i + 2) % 3;
+ if (val[i] == rb->device->memstore.gpuaddr +
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp)) {
+ int j = ((i + 2) % 3);
+ if ((inc && (val[j] == CACHE_FLUSH_TS ||
+ val[j] == cp_type3_packet(
+ CP_MEM_WRITE, 2))) ||
+ (!inc && val[j] == global_eop)) {
+ /* Found the global eop */
+ status = 0;
+ break;
+ }
}
+ /* if no match found then increment i again
+ * since we decremented before matching */
+ i = (i + 1) % 3;
+ }
+ if (inc)
+ temp_rb_rptr = adreno_ringbuffer_inc_wrapped(
+ temp_rb_rptr, size);
+
+ i = (i + 1) % 3;
+ if (2 == i)
+ check = true;
+ } while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr);
+ /* temp_rb_rptr points to the command stream after global eop,
+ * move backward till the start of command sequence */
+ if (!status) {
+ status = _find_start_of_cmd_seq(rb, &temp_rb_rptr, false);
+ if (!status) {
+ *rb_rptr = temp_rb_rptr;
+ KGSL_DRV_ERR(rb->device,
+ "Offset of cmd sequence after eop timestamp: 0x%x\n",
+ temp_rb_rptr / sizeof(unsigned int));
+ }
+ }
+ if (status)
+ KGSL_DRV_ERR(rb->device,
+ "Failed to find the command sequence after eop timestamp\n");
+ return status;
+}
+
+static int _find_hanging_ib_sequence(struct adreno_ringbuffer *rb,
+ unsigned int *rb_rptr,
+ unsigned int ib1)
+{
+ int status = -EINVAL;
+ unsigned int temp_rb_rptr = *rb_rptr;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int val[2];
+ int i = 0;
+ bool check = false;
+ bool ctx_switch = false;
+
+ while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
+
+ if (check && val[i] == ib1) {
+ /* decrement i, i.e i = (i - 1 + 2) % 2 */
+ i = (i + 1) % 2;
+ if (adreno_cmd_is_ib(val[i])) {
+ /* go till start of command sequence */
+ status = _find_start_of_cmd_seq(rb,
+ &temp_rb_rptr, false);
+ KGSL_DRV_ERR(rb->device,
+ "Found the hanging IB at offset 0x%x\n",
+ temp_rb_rptr / sizeof(unsigned int));
+ break;
+ }
+ /* if no match the increment i since we decremented
+ * before checking */
+ i = (i + 1) % 2;
+ }
+ /* Make sure you do not encounter a context switch twice, we can
+ * encounter it once for the bad context as the start of search
+ * can point to the context switch */
+ if (val[i] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
+ if (ctx_switch) {
+ KGSL_DRV_ERR(rb->device,
+ "Context switch encountered before bad "
+ "IB found\n");
+ break;
+ }
+ ctx_switch = true;
+ }
+ i = (i + 1) % 2;
+ if (1 == i)
+ check = true;
+ temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
+ size);
+ }
+ if (!status)
+ *rb_rptr = temp_rb_rptr;
+ return status;
+}
+
+static void _turn_preamble_on_for_ib_seq(struct adreno_ringbuffer *rb,
+ unsigned int rb_rptr)
+{
+ unsigned int temp_rb_rptr = rb_rptr;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int val[2];
+ int i = 0;
+ bool check = false;
+ bool cmd_start = false;
+
+ /* Go till the start of the ib sequence and turn on preamble */
+ while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
+ if (check && KGSL_START_OF_IB_IDENTIFIER == val[i]) {
+ /* decrement i */
+ i = (i + 1) % 2;
+ if (val[i] == cp_nop_packet(4)) {
+ temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
+ temp_rb_rptr, size);
+ kgsl_sharedmem_writel(&rb->buffer_desc,
+ temp_rb_rptr, cp_nop_packet(1));
+ }
+ KGSL_DRV_ERR(rb->device,
+ "Turned preamble on at offset 0x%x\n",
+ temp_rb_rptr / 4);
+ break;
+ }
+ /* If you reach beginning of next command sequence then exit
+ * First command encountered is the current one so don't break
+ * on that. */
+ if (KGSL_CMD_IDENTIFIER == val[i]) {
+ if (cmd_start)
+ break;
+ cmd_start = true;
}
- if (rb_rptr == 0)
- rb_rptr = rb->buffer_desc.size - sizeof(unsigned int);
- else
- rb_rptr -= sizeof(unsigned int);
+ i = (i + 1) % 2;
+ if (1 == i)
+ check = true;
+ temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
+ size);
}
+}
- if ((rb_rptr / sizeof(unsigned int)) == rb->wptr) {
- KGSL_DRV_ERR(device,
- "GPU recovery from hang not possible because last"
- " successful timestamp is overwritten\n");
- return -EINVAL;
- }
- /* rb_rptr is now pointing to the first dword of the command following
- * the last sucessfully executed command sequence. Assumption is that
- * GPU is hung in the command sequence pointed by rb_rptr */
- /* make sure the GPU is not hung in a command submitted by kgsl
- * itself */
- kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
- kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
- adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size));
- if (val1 == cp_nop_packet(1) && val2 == KGSL_CMD_IDENTIFIER) {
- KGSL_DRV_ERR(device,
- "GPU recovery from hang not possible because "
- "of hang in kgsl command\n");
- return -EINVAL;
- }
+static void _copy_valid_rb_content(struct adreno_ringbuffer *rb,
+ unsigned int rb_rptr, unsigned int *temp_rb_buffer,
+ int *rb_size, unsigned int *bad_rb_buffer,
+ int *bad_rb_size,
+ int *last_valid_ctx_id)
+{
+ unsigned int good_rb_idx = 0, cmd_start_idx = 0;
+ unsigned int val1 = 0;
+ struct kgsl_context *k_ctxt;
+ struct adreno_context *a_ctxt;
+ unsigned int bad_rb_idx = 0;
+ int copy_rb_contents = 0;
+ unsigned int temp_rb_rptr;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int good_cmd_start_idx = 0;
+ /* Walk the rb from the context switch. Omit any commands
+ * for an invalid context. */
while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
- kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
- rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size);
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
+
+ if (KGSL_CMD_IDENTIFIER == val1) {
+ /* Start is the NOP dword that comes before
+ * KGSL_CMD_IDENTIFIER */
+ cmd_start_idx = bad_rb_idx - 1;
+ if (copy_rb_contents)
+ good_cmd_start_idx = good_rb_idx - 1;
+ }
+
/* check for context switch indicator */
- if (value == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
- kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
- rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size);
- BUG_ON(value != cp_type3_packet(CP_MEM_WRITE, 2));
- kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
- rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size);
- BUG_ON(val1 != (device->memstore.gpuaddr +
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- current_context)));
- kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
- rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
- rb->buffer_desc.size);
+ if (val1 == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
+ unsigned int temp_idx, val2;
+ /* increment by 3 to get to the context_id */
+ temp_rb_rptr = rb_rptr + (3 * sizeof(unsigned int)) %
+ size;
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
+ temp_rb_rptr);
- /*
- * If other context switches were already lost and
- * and the current context is the one that is hanging,
- * then we cannot recover. Print an error message
- * and leave.
- */
-
- if ((copy_rb_contents == 0) && (value == context_id)) {
- KGSL_DRV_ERR(device, "GPU recovery could not "
- "find the previous context\n");
- return -EINVAL;
- }
-
- /*
- * If we were copying the commands and got to this point
- * then we need to remove the 3 commands that appear
- * before KGSL_CONTEXT_TO_MEM_IDENTIFIER
- */
- if (temp_idx)
- temp_idx -= 3;
/* if context switches to a context that did not cause
* hang then start saving the rb contents as those
* commands can be executed */
- if (value != context_id) {
+ k_ctxt = idr_find(&rb->device->context_idr, val2);
+ if (k_ctxt) {
+ a_ctxt = k_ctxt->devctxt;
+
+ /* If we are changing to a good context and were not
+ * copying commands then copy over commands to the good
+ * context */
+ if (!copy_rb_contents && ((k_ctxt &&
+ !(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) ||
+ !k_ctxt)) {
+ for (temp_idx = cmd_start_idx;
+ temp_idx < bad_rb_idx;
+ temp_idx++)
+ temp_rb_buffer[good_rb_idx++] =
+ bad_rb_buffer[temp_idx];
+ *last_valid_ctx_id = val2;
copy_rb_contents = 1;
- temp_rb_buffer[temp_idx++] = cp_nop_packet(1);
- temp_rb_buffer[temp_idx++] =
- KGSL_CMD_IDENTIFIER;
- temp_rb_buffer[temp_idx++] = cp_nop_packet(1);
- temp_rb_buffer[temp_idx++] =
- KGSL_CONTEXT_TO_MEM_IDENTIFIER;
- temp_rb_buffer[temp_idx++] =
- cp_type3_packet(CP_MEM_WRITE, 2);
- temp_rb_buffer[temp_idx++] = val1;
- temp_rb_buffer[temp_idx++] = value;
- } else {
+ } else if (copy_rb_contents && k_ctxt &&
+ (a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) {
+ /* If we are changing to bad context then remove
+ * the dwords we copied for this sequence from
+ * the good buffer */
+ good_rb_idx = good_cmd_start_idx;
copy_rb_contents = 0;
}
- } else if (copy_rb_contents)
- temp_rb_buffer[temp_idx++] = value;
+ }
+ }
+
+ if (copy_rb_contents)
+ temp_rb_buffer[good_rb_idx++] = val1;
+ /* Copy both good and bad commands for replay to the bad
+ * buffer */
+ bad_rb_buffer[bad_rb_idx++] = val1;
+
+ rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr, size);
+ }
+ *rb_size = good_rb_idx;
+ *bad_rb_size = bad_rb_idx;
+}
+
+int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
+ struct adreno_recovery_data *rec_data)
+{
+ int status;
+ struct kgsl_device *device = rb->device;
+ unsigned int rb_rptr = rb->wptr * sizeof(unsigned int);
+ struct kgsl_context *context;
+ struct adreno_context *adreno_context;
+
+ context = idr_find(&device->context_idr, rec_data->context_id);
+
+ /* Look for the command stream that is right after the global eop */
+ status = _find_cmd_seq_after_eop_ts(rb, &rb_rptr,
+ rec_data->global_eop + 1, false);
+ if (status)
+ goto done;
+
+ if (context) {
+ adreno_context = context->devctxt;
+
+ if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
+ if (rec_data->ib1) {
+ status = _find_hanging_ib_sequence(rb, &rb_rptr,
+ rec_data->ib1);
+ if (status)
+ goto copy_rb_contents;
+ }
+ _turn_preamble_on_for_ib_seq(rb, rb_rptr);
+ } else {
+ status = -EINVAL;
+ }
}
- *rb_size = temp_idx;
- return 0;
+copy_rb_contents:
+ _copy_valid_rb_content(rb, rb_rptr, rec_data->rb_buffer,
+ &rec_data->rb_size,
+ rec_data->bad_rb_buffer,
+ &rec_data->bad_rb_size,
+ &rec_data->last_valid_ctx_id);
+ /* If we failed to get the hanging IB sequence then we cannot execute
+ * commands from the bad context or preambles not supported */
+ if (status) {
+ rec_data->bad_rb_size = 0;
+ status = 0;
+ }
+ /* If there is no context then that means there are no commands for
+ * good case */
+ if (!context)
+ rec_data->rb_size = 0;
+done:
+ return status;
}
void
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 6429f46..4cc57c2 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -27,6 +27,7 @@
struct kgsl_device;
struct kgsl_device_private;
+struct adreno_recovery_data;
#define GSL_RB_MEMPTRS_SCRATCH_COUNT 8
struct kgsl_rbmemptrs {
@@ -114,8 +115,7 @@
void kgsl_cp_intrcallback(struct kgsl_device *device);
int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
- unsigned int *temp_rb_buffer,
- int *rb_size);
+ struct adreno_recovery_data *rec_data);
void
adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
@@ -139,4 +139,11 @@
return (val + sizeof(unsigned int)) % size;
}
+/* Decrement a value by 4 bytes with wrap-around based on size */
+static inline unsigned int adreno_ringbuffer_dec_wrapped(unsigned int val,
+ unsigned int size)
+{
+ return (val + size - sizeof(unsigned int)) % size;
+}
+
#endif /* __ADRENO_RINGBUFFER_H */
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 7ffa83b..8a3345b 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -23,6 +23,8 @@
#include <linux/regulator/consumer.h>
#include <linux/mm.h>
+#include <mach/kgsl.h>
+
#define KGSL_NAME "kgsl"
/* The number of memstore arrays limits the number of contexts allowed.
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 6df073a..fbf3bb4 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -121,7 +121,7 @@
return count;
mutex_lock(&device->mutex);
- for (i = 0; i < pwr->num_pwrlevels; i++) {
+ for (i = 0; i < pwr->num_pwrlevels - 1; i++) {
if (abs(pwr->pwrlevels[i].gpu_freq - val) < delta) {
if (max)
pwr->thermal_pwrlevel = i;
@@ -129,7 +129,7 @@
}
}
- if (i == pwr->num_pwrlevels)
+ if (i == (pwr->num_pwrlevels - 1))
goto done;
/*
diff --git a/drivers/iommu/msm_iommu-v2.c b/drivers/iommu/msm_iommu-v2.c
index 6e62e60..26e967d 100644
--- a/drivers/iommu/msm_iommu-v2.c
+++ b/drivers/iommu/msm_iommu-v2.c
@@ -128,7 +128,7 @@
return ret;
}
-static void __reset_iommu(void __iomem *base)
+static void __reset_iommu(void __iomem *base, int smt_size)
{
int i;
@@ -143,15 +143,15 @@
SET_SCR1(base, 0);
SET_SSDR_N(base, 0, 0);
- for (i = 0; i < MAX_NUM_SMR; i++)
+ for (i = 0; i < smt_size; i++)
SET_SMR_VALID(base, i, 0);
mb();
}
-static void __program_iommu(void __iomem *base)
+static void __program_iommu(void __iomem *base, int smt_size)
{
- __reset_iommu(base);
+ __reset_iommu(base, smt_size);
SET_CR0_SMCFCFG(base, 1);
SET_CR0_USFCFG(base, 1);
@@ -182,7 +182,7 @@
static void __program_context(void __iomem *base, int ctx, int ncb,
phys_addr_t pgtable, int redirect,
- u32 *sids, int len)
+ u32 *sids, int len, int smt_size)
{
unsigned int prrr, nmrr;
unsigned int pn;
@@ -227,10 +227,10 @@
/* Program the M2V tables for this context */
for (i = 0; i < len / sizeof(*sids); i++) {
- for (; num < MAX_NUM_SMR; num++)
+ for (; num < smt_size; num++)
if (GET_SMR_VALID(base, num) == 0)
break;
- BUG_ON(num >= MAX_NUM_SMR);
+ BUG_ON(num >= smt_size);
SET_SMR_VALID(base, num, 1);
SET_SMR_MASK(base, num, 0);
@@ -346,8 +346,7 @@
struct msm_iommu_drvdata *iommu_drvdata;
struct msm_iommu_ctx_drvdata *ctx_drvdata;
struct msm_iommu_ctx_drvdata *tmp_drvdata;
- u32 sids[MAX_NUM_SMR];
- int len = 0, ret;
+ int ret;
mutex_lock(&msm_iommu_lock);
@@ -375,14 +374,6 @@
goto fail;
}
- of_get_property(dev->of_node, "qcom,iommu-ctx-sids", &len);
- BUG_ON(len >= sizeof(sids));
- if (of_property_read_u32_array(dev->of_node, "qcom,iommu-ctx-sids",
- sids, len / sizeof(*sids))) {
- ret = -EINVAL;
- goto fail;
- }
-
ret = regulator_enable(iommu_drvdata->gdsc);
if (ret)
goto fail;
@@ -394,11 +385,12 @@
}
if (!msm_iommu_ctx_attached(dev->parent))
- __program_iommu(iommu_drvdata->base);
+ __program_iommu(iommu_drvdata->base, iommu_drvdata->nsmr);
__program_context(iommu_drvdata->base, ctx_drvdata->num,
iommu_drvdata->ncb, __pa(priv->pt.fl_table),
- priv->pt.redirect, sids, len);
+ priv->pt.redirect, ctx_drvdata->sids, ctx_drvdata->nsid,
+ iommu_drvdata->nsmr);
__disable_clocks(iommu_drvdata);
list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
diff --git a/drivers/iommu/msm_iommu_dev-v2.c b/drivers/iommu/msm_iommu_dev-v2.c
index 87e1a46..d3a088a 100644
--- a/drivers/iommu/msm_iommu_dev-v2.c
+++ b/drivers/iommu/msm_iommu_dev-v2.c
@@ -33,12 +33,25 @@
struct msm_iommu_drvdata *drvdata)
{
struct device_node *child;
- int ret;
+ int ret = 0;
+ u32 nsmr;
ret = device_move(&pdev->dev, &msm_iommu_root_dev->dev, DPM_ORDER_NONE);
if (ret)
- return ret;
+ goto fail;
+ ret = of_property_read_u32(pdev->dev.of_node, "qcom,iommu-smt-size",
+ &nsmr);
+ if (ret)
+ goto fail;
+
+ if (nsmr > MAX_NUM_SMR) {
+ pr_err("Invalid SMT size: %d\n", nsmr);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ drvdata->nsmr = nsmr;
for_each_child_of_node(pdev->dev.of_node, child) {
drvdata->ncb++;
if (!of_platform_device_create(child, NULL, &pdev->dev))
@@ -46,7 +59,8 @@
}
drvdata->name = dev_name(&pdev->dev);
- return 0;
+fail:
+ return ret;
}
static atomic_t msm_iommu_next_id = ATOMIC_INIT(-1);
@@ -149,6 +163,7 @@
{
struct resource *r, rp;
int irq, ret;
+ u32 nsid;
irq = platform_get_irq(pdev, 0);
if (irq > 0) {
@@ -181,6 +196,19 @@
&ctx_drvdata->name))
ctx_drvdata->name = dev_name(&pdev->dev);
+ if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-sids", &nsid))
+ return -EINVAL;
+
+ if (nsid >= sizeof(ctx_drvdata->sids))
+ return -EINVAL;
+
+ if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-sids",
+ ctx_drvdata->sids,
+ nsid / sizeof(*ctx_drvdata->sids))) {
+ return -EINVAL;
+ }
+ ctx_drvdata->nsid = nsid;
+
return 0;
}
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index d49bfa6..9240605 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -181,6 +181,20 @@
To compile this driver as a module, choose M here: the
module will be called leds-pmic-mpp.
+config LEDS_MSM_TRICOLOR
+ tristate "LED Support for Qualcomm tricolor LEDs"
+ depends on LEDS_CLASS && MSM_SMD
+ help
+ This option enables support for tricolor LEDs connected to
+ to Qualcomm reference boards. Red, green and blue color leds
+ are supported. These leds are turned on/off, blink on/off
+ by Modem upon receiving command through rpc from this driver.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called leds-msm-tricolor.
+
config LEDS_GPIO_PLATFORM
bool "Platform device bindings for GPIO LEDs"
depends on LEDS_GPIO
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index aa518d4..8edd465 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -52,6 +52,7 @@
obj-$(CONFIG_LEDS_PMIC_MPP) += leds-pmic-mpp.o
obj-$(CONFIG_LEDS_QCIBL) += leds-qci-backlight.o
obj-$(CONFIG_LEDS_MSM_PDM) += leds-msm-pdm.o
+obj-$(CONFIG_LEDS_MSM_TRICOLOR) += leds-msm-tricolor.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
diff --git a/drivers/leds/leds-msm-tricolor.c b/drivers/leds/leds-msm-tricolor.c
new file mode 100644
index 0000000..d0715ce
--- /dev/null
+++ b/drivers/leds/leds-msm-tricolor.c
@@ -0,0 +1,410 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+
+#include <linux/leds-msm-tricolor.h>
+#include <mach/msm_rpcrouter.h>
+
+#define LED_RPC_PROG 0x30000091
+#define LED_RPC_VER 0x00030001
+
+#define LED_SUBSCRIBE_PROC 0x03
+#define LED_SUBS_RCV_EVNT 0x01
+#define LED_SUBS_REGISTER 0x00
+#define LED_EVNT_CLASS_ALL 0x00
+#define LINUX_HOST 0x04
+#define LED_CMD_PROC 0x02
+#define TRICOLOR_LED_ID 0x0A
+
+enum tricolor_led_status {
+ ALL_OFF,
+ ALL_ON,
+ BLUE_ON,
+ BLUE_OFF,
+ RED_ON,
+ RED_OFF,
+ GREEN_ON,
+ GREEN_OFF,
+ BLUE_BLINK,
+ RED_BLINK,
+ GREEN_BLINK,
+ BLUE_BLINK_OFF,
+ RED_BLINK_OFF,
+ GREEN_BLINK_OFF,
+ LED_MAX,
+};
+
+struct led_cmd_data_type {
+ u32 cmd_data_type_ptr; /* cmd_data_type ptr */
+ u32 ver; /* version */
+ u32 id; /* command id */
+ u32 handle; /* handle returned from subscribe proc */
+ u32 disc_id1; /* discriminator id */
+ u32 input_ptr; /* input ptr length */
+ u32 input_val; /* command specific data */
+ u32 input_len; /* length of command input */
+ u32 disc_id2; /* discriminator id */
+ u32 output_len; /* length of output data */
+ u32 delayed; /* execution context for modem */
+};
+
+struct led_subscribe_req {
+ u32 subs_ptr; /* subscribe ptr */
+ u32 ver; /* version */
+ u32 srvc; /* command or event */
+ u32 req; /* subscribe or unsubscribe */
+ u32 host_os; /* host operating system */
+ u32 disc_id; /* discriminator id */
+ u32 event; /* event */
+ u32 cb_id; /* callback id */
+ u32 handle_ptr; /* handle ptr */
+ u32 handle_data; /* handle data */
+};
+
+struct tricolor_led_data {
+ struct led_classdev cdev;
+ struct msm_rpc_client *rpc_client;
+ bool blink_status;
+ struct mutex lock;
+ u8 color;
+};
+
+static struct led_subscribe_req *led_subs_req;
+
+static int led_send_cmd_arg(struct msm_rpc_client *client,
+ void *buffer, void *data)
+{
+ struct led_cmd_data_type *led_cmd = buffer;
+ enum tricolor_led_status status = *(enum tricolor_led_status *) data;
+
+ led_cmd->cmd_data_type_ptr = cpu_to_be32(0x01);
+ led_cmd->ver = cpu_to_be32(0x03);
+ led_cmd->id = cpu_to_be32(TRICOLOR_LED_ID);
+ led_cmd->handle = cpu_to_be32(led_subs_req->handle_data);
+ led_cmd->disc_id1 = cpu_to_be32(TRICOLOR_LED_ID);
+ led_cmd->input_ptr = cpu_to_be32(0x01);
+ led_cmd->input_val = cpu_to_be32(status);
+ led_cmd->input_len = cpu_to_be32(0x01);
+ led_cmd->disc_id2 = cpu_to_be32(TRICOLOR_LED_ID);
+ led_cmd->output_len = cpu_to_be32(0x00);
+ led_cmd->delayed = cpu_to_be32(0x00);
+
+ return sizeof(*led_cmd);
+}
+
+static int led_rpc_res(struct msm_rpc_client *client,
+ void *buffer, void *data)
+{
+ uint32_t result;
+
+ result = be32_to_cpu(*((uint32_t *)buffer));
+ pr_debug("%s: request completed: 0x%x\n", __func__, result);
+
+ return 0;
+}
+
+static void led_rpc_set_status(struct msm_rpc_client *client,
+ enum tricolor_led_status status)
+{
+ int rc;
+
+ rc = msm_rpc_client_req(client, LED_CMD_PROC,
+ led_send_cmd_arg, &status, led_rpc_res, NULL, -1);
+ if (rc)
+ pr_err("%s: RPC client request for led failed", __func__);
+
+}
+
+static ssize_t led_blink_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tricolor_led_data *led = dev_get_drvdata(dev);
+
+ return snprintf(buf, 2, "%d\n", led->blink_status);
+}
+
+static ssize_t led_blink_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tricolor_led_data *led = dev_get_drvdata(dev);
+ enum tricolor_led_status status;
+ unsigned long value;
+ int rc;
+
+ if (size > 2)
+ return -EINVAL;
+
+ rc = kstrtoul(buf, 10, &value);
+ if (rc)
+ return rc;
+
+
+ if (value < LED_OFF || value > led->cdev.max_brightness) {
+ dev_err(dev, "invalid brightness\n");
+ return -EINVAL;
+ }
+
+ switch (led->color) {
+ case LED_COLOR_RED:
+ status = value ? RED_BLINK : RED_BLINK_OFF;
+ break;
+ case LED_COLOR_GREEN:
+ status = value ? GREEN_BLINK : GREEN_BLINK_OFF;
+ break;
+ case LED_COLOR_BLUE:
+ status = value ? BLUE_BLINK : BLUE_BLINK_OFF;
+ break;
+ default:
+ dev_err(dev, "unknown led device\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&led->lock);
+ led->blink_status = !!value;
+ led->cdev.brightness = 0;
+
+ /* program the led blink */
+ led_rpc_set_status(led->rpc_client, status);
+ mutex_unlock(&led->lock);
+
+ return size;
+}
+
+static DEVICE_ATTR(blink, 0644, led_blink_show, led_blink_store);
+
+static void tricolor_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct tricolor_led_data *led;
+ enum tricolor_led_status status;
+
+ led = container_of(led_cdev, struct tricolor_led_data, cdev);
+
+ if (value < LED_OFF || value > led->cdev.max_brightness) {
+ dev_err(led->cdev.dev, "invalid brightness\n");
+ return;
+ }
+
+ switch (led->color) {
+ case LED_COLOR_RED:
+ status = value ? RED_ON : RED_OFF;
+ break;
+ case LED_COLOR_GREEN:
+ status = value ? GREEN_ON : GREEN_OFF;
+ break;
+ case LED_COLOR_BLUE:
+ status = value ? BLUE_ON : BLUE_OFF;
+ break;
+ default:
+ dev_err(led->cdev.dev, "unknown led device\n");
+ return;
+ }
+
+ mutex_lock(&led->lock);
+ led->blink_status = 0;
+ led->cdev.brightness = value;
+
+ /* program the led brightness */
+ led_rpc_set_status(led->rpc_client, status);
+ mutex_unlock(&led->lock);
+}
+
+static enum led_brightness tricolor_led_get(struct led_classdev *led_cdev)
+{
+ struct tricolor_led_data *led;
+
+ led = container_of(led_cdev, struct tricolor_led_data, cdev);
+
+ return led->cdev.brightness;
+}
+
+static int led_rpc_register_subs_arg(struct msm_rpc_client *client,
+ void *buffer, void *data)
+{
+ led_subs_req = buffer;
+
+ led_subs_req->subs_ptr = cpu_to_be32(0x1);
+ led_subs_req->ver = cpu_to_be32(0x1);
+ led_subs_req->srvc = cpu_to_be32(LED_SUBS_RCV_EVNT);
+ led_subs_req->req = cpu_to_be32(LED_SUBS_REGISTER);
+ led_subs_req->host_os = cpu_to_be32(LINUX_HOST);
+ led_subs_req->disc_id = cpu_to_be32(LED_SUBS_RCV_EVNT);
+ led_subs_req->event = cpu_to_be32(LED_EVNT_CLASS_ALL);
+ led_subs_req->cb_id = cpu_to_be32(0x1);
+ led_subs_req->handle_ptr = cpu_to_be32(0x1);
+ led_subs_req->handle_data = cpu_to_be32(0x0);
+
+ return sizeof(*led_subs_req);
+}
+
+static int led_cb_func(struct msm_rpc_client *client, void *buffer, int in_size)
+{
+ struct rpc_request_hdr *hdr = buffer;
+ int rc;
+
+ hdr->type = be32_to_cpu(hdr->type);
+ hdr->xid = be32_to_cpu(hdr->xid);
+ hdr->rpc_vers = be32_to_cpu(hdr->rpc_vers);
+ hdr->prog = be32_to_cpu(hdr->prog);
+ hdr->vers = be32_to_cpu(hdr->vers);
+ hdr->procedure = be32_to_cpu(hdr->procedure);
+
+ msm_rpc_start_accepted_reply(client, hdr->xid,
+ RPC_ACCEPTSTAT_SUCCESS);
+ rc = msm_rpc_send_accepted_reply(client, 0);
+ if (rc)
+ pr_err("%s: sending reply failed: %d\n", __func__, rc);
+
+ return rc;
+}
+
+static int __devinit tricolor_led_probe(struct platform_device *pdev)
+{
+ const struct led_platform_data *pdata = pdev->dev.platform_data;
+ struct msm_rpc_client *rpc_client;
+ struct led_info *curr_led;
+ struct tricolor_led_data *led, *tmp_led;
+ int rc, i, j;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "platform data not supplied\n");
+ return -EINVAL;
+ }
+
+ /* initialize rpc client */
+ rpc_client = msm_rpc_register_client("led", LED_RPC_PROG,
+ LED_RPC_VER, 0, led_cb_func);
+ rc = IS_ERR(rpc_client);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to initialize rpc_client\n");
+ return -EINVAL;
+ }
+
+ /* subscribe */
+ rc = msm_rpc_client_req(rpc_client, LED_SUBSCRIBE_PROC,
+ led_rpc_register_subs_arg, NULL,
+ led_rpc_res, NULL, -1);
+ if (rc) {
+ pr_err("%s: RPC client request failed for subscribe services\n",
+ __func__);
+ goto fail_mem_alloc;
+ }
+
+ led = devm_kzalloc(&pdev->dev, pdata->num_leds * sizeof(*led),
+ GFP_KERNEL);
+ if (!led) {
+ dev_err(&pdev->dev, "failed to alloc memory\n");
+ rc = -ENOMEM;
+ goto fail_mem_alloc;
+ }
+
+ for (i = 0; i < pdata->num_leds; i++) {
+ curr_led = &pdata->leds[i];
+ tmp_led = &led[i];
+
+ tmp_led->cdev.name = curr_led->name;
+ tmp_led->cdev.default_trigger = curr_led->default_trigger;
+ tmp_led->cdev.brightness_set = tricolor_led_set;
+ tmp_led->cdev.brightness_get = tricolor_led_get;
+ tmp_led->cdev.brightness = LED_OFF;
+ tmp_led->cdev.max_brightness = LED_FULL;
+ tmp_led->color = curr_led->flags;
+ tmp_led->rpc_client = rpc_client;
+ tmp_led->blink_status = false;
+
+ mutex_init(&tmp_led->lock);
+
+ rc = led_classdev_register(&pdev->dev, &tmp_led->cdev);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to register led %s(%d)\n",
+ tmp_led->cdev.name, rc);
+ goto fail_led_reg;
+ }
+
+ /* Add blink attributes */
+ rc = device_create_file(tmp_led->cdev.dev, &dev_attr_blink);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to create blink attr\n");
+ goto fail_blink_attr;
+ }
+ dev_set_drvdata(tmp_led->cdev.dev, tmp_led);
+ }
+
+ platform_set_drvdata(pdev, led);
+
+ return 0;
+
+fail_blink_attr:
+ j = i;
+ while (j)
+ device_remove_file(led[--j].cdev.dev, &dev_attr_blink);
+ i++;
+fail_led_reg:
+ while (i) {
+ led_classdev_unregister(&led[--i].cdev);
+ mutex_destroy(&led[i].lock);
+ }
+fail_mem_alloc:
+ msm_rpc_unregister_client(rpc_client);
+ return rc;
+}
+
+static int __devexit tricolor_led_remove(struct platform_device *pdev)
+{
+ const struct led_platform_data *pdata = pdev->dev.platform_data;
+ struct tricolor_led_data *led = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < pdata->num_leds; i++) {
+ led_classdev_unregister(&led[i].cdev);
+ device_remove_file(led[i].cdev.dev, &dev_attr_blink);
+ mutex_destroy(&led[i].lock);
+ }
+
+ msm_rpc_unregister_client(led->rpc_client);
+
+ return 0;
+}
+
+static struct platform_driver tricolor_led_driver = {
+ .probe = tricolor_led_probe,
+ .remove = __devexit_p(tricolor_led_remove),
+ .driver = {
+ .name = "msm-tricolor-leds",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init tricolor_led_init(void)
+{
+ return platform_driver_register(&tricolor_led_driver);
+}
+late_initcall(tricolor_led_init);
+
+static void __exit tricolor_led_exit(void)
+{
+ platform_driver_unregister(&tricolor_led_driver);
+}
+module_exit(tricolor_led_exit);
+
+MODULE_DESCRIPTION("MSM Tri-color LEDs driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:tricolor-led");
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index e22bc64..9ad79e9 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -63,15 +63,52 @@
*/
enum dmx_success {
- DMX_OK = 0, /* Received Ok */
- DMX_LENGTH_ERROR, /* Incorrect length */
- DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */
- DMX_CRC_ERROR, /* Incorrect CRC */
- DMX_FRAME_ERROR, /* Frame alignment error */
- DMX_FIFO_ERROR, /* Receiver FIFO overrun */
- DMX_MISSED_ERROR /* Receiver missed packet */
+ DMX_OK = 0, /* Received Ok */
+ DMX_OK_PES_END, /* Received ok, data reached end of PES packet */
+ DMX_OK_PCR, /* Received OK, data with new PCR/STC pair */
+ DMX_LENGTH_ERROR, /* Incorrect length */
+ DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */
+ DMX_CRC_ERROR, /* Incorrect CRC */
+ DMX_FRAME_ERROR, /* Frame alignment error */
+ DMX_FIFO_ERROR, /* Receiver FIFO overrun */
+ DMX_MISSED_ERROR /* Receiver missed packet */
} ;
+
+/*
+ * struct dmx_data_ready: Parameters for event notification callback.
+ * Event notification notifies demux device that data is written
+ * and available in the device's output buffer or provides
+ * notification on errors and other events. In the latter case
+ * data_length is zero.
+ */
+struct dmx_data_ready {
+ enum dmx_success status;
+
+ /*
+ * data_length may be 0 in case of DMX_OK_PES_END
+ * and in non-DMX_OK_XXX events. In DMX_OK_PES_END,
+ * data_length is for data comming after the end of PES.
+ */
+ int data_length;
+
+ union {
+ struct {
+ int start_gap;
+ int actual_length;
+ int disc_indicator_set;
+ int pes_length_mismatch;
+ u64 stc;
+ } pes_end;
+
+ struct {
+ u64 pcr;
+ u64 stc;
+ int disc_indicator_set;
+ } pcr;
+ };
+};
+
/*--------------------------------------------------------------------------*/
/* TS packet reception */
/*--------------------------------------------------------------------------*/
@@ -123,6 +160,10 @@
#define DMX_TS_PES_SUBTITLE DMX_TS_PES_SUBTITLE0
#define DMX_TS_PES_PCR DMX_TS_PES_PCR0
+struct dmx_ts_feed;
+typedef int (*dmx_ts_data_ready_cb)(
+ struct dmx_ts_feed *source,
+ struct dmx_data_ready *dmx_data_ready);
struct dmx_ts_feed {
int is_filtering; /* Set to non-zero when filtering in progress */
@@ -141,6 +182,8 @@
int (*get_decoder_buff_status)(
struct dmx_ts_feed *feed,
struct dmx_buffer_status *dmx_buffer_status);
+ int (*data_ready_cb)(struct dmx_ts_feed *feed,
+ dmx_ts_data_ready_cb callback);
};
/*--------------------------------------------------------------------------*/
@@ -155,6 +198,11 @@
void* priv; /* Pointer to private data of the API client */
};
+struct dmx_section_feed;
+typedef int (*dmx_section_data_ready_cb)(
+ struct dmx_section_filter *source,
+ struct dmx_data_ready *dmx_data_ready);
+
struct dmx_section_feed {
int is_filtering; /* Set to non-zero when filtering in progress */
struct dmx_demux* parent; /* Back-pointer */
@@ -177,6 +225,8 @@
struct dmx_section_filter* filter);
int (*start_filtering) (struct dmx_section_feed* feed);
int (*stop_filtering) (struct dmx_section_feed* feed);
+ int (*data_ready_cb)(struct dmx_section_feed *feed,
+ dmx_section_data_ready_cb callback);
};
/*--------------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 8e5127a..433e796 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -60,9 +60,302 @@
return dvb_ringbuffer_write(buf, src, len);
}
+static inline u32 dvb_dmxdev_advance_event_idx(u32 index)
+{
+ index++;
+ if (index >= DMX_EVENT_QUEUE_SIZE)
+ index = 0;
+
+ return index;
+}
+
+static inline void dvb_dmxdev_flush_events(struct dmxdev_events_queue *events)
+{
+ events->read_index = 0;
+ events->write_index = 0;
+ events->notified_index = 0;
+ events->bytes_read_no_event = 0;
+ events->current_event_data_size = 0;
+}
+
+static inline void dvb_dmxdev_flush_output(struct dvb_ringbuffer *buffer,
+ struct dmxdev_events_queue *events)
+{
+ dvb_dmxdev_flush_events(events);
+ dvb_ringbuffer_flush(buffer);
+}
+
+static int dvb_dmxdev_update_pes_event(struct dmx_filter_event *event,
+ int bytes_read)
+{
+ int start_delta;
+
+ if (event->params.pes.total_length <= bytes_read)
+ return event->params.pes.total_length;
+
+ /*
+ * only part of the data relevant to this event was read.
+ * Update the event's information to reflect the new state.
+ */
+ event->params.pes.total_length -= bytes_read;
+
+ start_delta = event->params.pes.start_offset -
+ event->params.pes.base_offset;
+
+ if (bytes_read <= start_delta) {
+ event->params.pes.base_offset +=
+ bytes_read;
+ } else {
+ start_delta =
+ bytes_read - start_delta;
+
+ event->params.pes.start_offset += start_delta;
+ event->params.pes.actual_length -= start_delta;
+
+ event->params.pes.base_offset =
+ event->params.pes.start_offset;
+ }
+
+ return 0;
+}
+
+static int dvb_dmxdev_update_section_event(struct dmx_filter_event *event,
+ int bytes_read)
+{
+ int start_delta;
+
+ if (event->params.section.total_length <= bytes_read)
+ return event->params.section.total_length;
+
+ /*
+ * only part of the data relevant to this event was read.
+ * Update the event's information to reflect the new state.
+ */
+
+ event->params.section.total_length -= bytes_read;
+
+ start_delta = event->params.section.start_offset -
+ event->params.section.base_offset;
+
+ if (bytes_read <= start_delta) {
+ event->params.section.base_offset +=
+ bytes_read;
+ } else {
+ start_delta =
+ bytes_read - start_delta;
+
+ event->params.section.start_offset += start_delta;
+ event->params.section.actual_length -= start_delta;
+
+ event->params.section.base_offset =
+ event->params.section.start_offset;
+ }
+
+ return 0;
+}
+
+static int dvb_dmxdev_update_rec_event(struct dmx_filter_event *event,
+ int bytes_read)
+{
+ if (event->params.recording_chunk.size <= bytes_read)
+ return event->params.recording_chunk.size;
+
+ /*
+ * only part of the data relevant to this event was read.
+ * Update the event's information to reflect the new state.
+ */
+ event->params.recording_chunk.size -= bytes_read;
+ event->params.recording_chunk.offset += bytes_read;
+
+ return 0;
+}
+
+static int dvb_dmxdev_add_event(struct dmxdev_events_queue *events,
+ struct dmx_filter_event *event)
+{
+ int res;
+ int new_write_index;
+ int data_event;
+
+ /* Check if we are adding an event that user already read its data */
+ if (events->bytes_read_no_event) {
+ data_event = 1;
+
+ if (event->type == DMX_EVENT_NEW_PES)
+ res = dvb_dmxdev_update_pes_event(event,
+ events->bytes_read_no_event);
+ else if (event->type == DMX_EVENT_NEW_SECTION)
+ res = dvb_dmxdev_update_section_event(event,
+ events->bytes_read_no_event);
+ else if (event->type == DMX_EVENT_NEW_REC_CHUNK)
+ res = dvb_dmxdev_update_rec_event(event,
+ events->bytes_read_no_event);
+ else
+ data_event = 0;
+
+ if (data_event) {
+ if (res) {
+ /*
+ * Data relevent to this event was fully
+ * consumed already, discard event.
+ */
+ events->bytes_read_no_event -= res;
+ return 0;
+ }
+ events->bytes_read_no_event = 0;
+ } else {
+ /*
+ * data was read beyond the non-data event,
+ * making it not relevant anymore
+ */
+ return 0;
+ }
+ }
+
+ new_write_index = dvb_dmxdev_advance_event_idx(events->write_index);
+ if (new_write_index == events->read_index) {
+ printk(KERN_ERR "dmxdev: events overflow\n");
+ return -EOVERFLOW;
+ }
+
+ events->queue[events->write_index] = *event;
+ events->write_index = new_write_index;
+
+ return 0;
+}
+
+static int dvb_dmxdev_remove_event(struct dmxdev_events_queue *events,
+ struct dmx_filter_event *event)
+{
+ if (events->notified_index == events->write_index)
+ return -ENODATA;
+
+ *event = events->queue[events->notified_index];
+
+ events->notified_index =
+ dvb_dmxdev_advance_event_idx(events->notified_index);
+
+ return 0;
+}
+
+static int dvb_dmxdev_update_events(struct dmxdev_events_queue *events,
+ int bytes_read)
+{
+ struct dmx_filter_event *event;
+ int res;
+ int data_event;
+
+ /*
+ * Go through all events that were notified and
+ * remove them from the events queue if their respective
+ * data was read.
+ */
+ while ((events->read_index != events->notified_index) &&
+ (bytes_read)) {
+ event = events->queue + events->read_index;
+
+ data_event = 1;
+
+ if (event->type == DMX_EVENT_NEW_PES)
+ res = dvb_dmxdev_update_pes_event(event, bytes_read);
+ else if (event->type == DMX_EVENT_NEW_SECTION)
+ res = dvb_dmxdev_update_section_event(event,
+ bytes_read);
+ else if (event->type == DMX_EVENT_NEW_REC_CHUNK)
+ res = dvb_dmxdev_update_rec_event(event, bytes_read);
+ else
+ data_event = 0;
+
+ if (data_event) {
+ if (res) {
+ /*
+ * Data relevent to this event was
+ * fully consumed, remove it from the queue.
+ */
+ bytes_read -= res;
+ events->read_index =
+ dvb_dmxdev_advance_event_idx(
+ events->read_index);
+ } else {
+ bytes_read = 0;
+ }
+ } else {
+ /*
+ * non-data event was already notified,
+ * no need to keep it
+ */
+ events->read_index = dvb_dmxdev_advance_event_idx(
+ events->read_index);
+ }
+ }
+
+ if (!bytes_read)
+ return 0;
+
+ /*
+ * If we reached here it means:
+ * bytes_read != 0
+ * events->read_index == events->notified_index
+ * Check if there are pending events in the queue
+ * which the user didn't read while their relevant data
+ * was read.
+ */
+ while ((events->notified_index != events->write_index) &&
+ (bytes_read)) {
+ event = events->queue + events->notified_index;
+
+ data_event = 1;
+
+ if (event->type == DMX_EVENT_NEW_PES)
+ res = dvb_dmxdev_update_pes_event(event, bytes_read);
+ else if (event->type == DMX_EVENT_NEW_SECTION)
+ res = dvb_dmxdev_update_section_event(event,
+ bytes_read);
+ else if (event->type == DMX_EVENT_NEW_REC_CHUNK)
+ res = dvb_dmxdev_update_rec_event(event, bytes_read);
+ else
+ data_event = 0;
+
+ if (data_event) {
+ if (res) {
+ /*
+ * Data relevent to this event was
+ * fully consumed, remove it from the queue.
+ */
+ bytes_read -= res;
+ events->notified_index =
+ dvb_dmxdev_advance_event_idx(
+ events->notified_index);
+ } else {
+ bytes_read = 0;
+ }
+ } else {
+ if (bytes_read)
+ /*
+ * data was read beyond the non-data event,
+ * making it not relevant anymore
+ */
+ events->notified_index =
+ dvb_dmxdev_advance_event_idx(
+ events->notified_index);
+ }
+
+ events->read_index = events->notified_index;
+ }
+
+ /*
+ * Check if data was read without having a respective
+ * event in the events-queue
+ */
+ if (bytes_read)
+ events->bytes_read_no_event += bytes_read;
+
+ return 0;
+}
+
static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
- int non_blocking, char __user *buf,
- size_t count, loff_t *ppos)
+ int non_blocking, char __user *buf,
+ size_t count, loff_t *ppos)
{
size_t todo;
ssize_t avail;
@@ -73,7 +366,7 @@
if (src->error) {
ret = src->error;
- dvb_ringbuffer_flush(src);
+ src->error = 0;
return ret;
}
@@ -94,7 +387,7 @@
if (src->error) {
ret = src->error;
- dvb_ringbuffer_flush(src);
+ src->error = 0;
break;
}
@@ -166,6 +459,8 @@
return -ENOMEM;
}
dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
+ dvb_dmxdev_flush_events(&dmxdev->dvr_output_events);
+
dvbdev->readers--;
} else if (!dvbdev->writers) {
dmxdev->dvr_in_exit = 0;
@@ -412,15 +707,24 @@
static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
+ ssize_t res;
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
if (dmxdev->exit)
return -ENODEV;
- return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+ res = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
file->f_flags & O_NONBLOCK,
buf, count, ppos);
+
+ if (res > 0) {
+ spin_lock_irq(&dmxdev->lock);
+ dvb_dmxdev_update_events(&dmxdev->dvr_output_events, res);
+ spin_unlock_irq(&dmxdev->lock);
+ }
+
+ return res;
}
static void dvr_input_work_func(struct work_struct *worker)
@@ -556,6 +860,27 @@
return 0;
}
+static int dvb_dvr_get_event(struct dmxdev *dmxdev,
+ unsigned int f_flags,
+ struct dmx_filter_event *event)
+{
+ int res;
+
+ if (!((f_flags & O_ACCMODE) == O_RDONLY))
+ return -EINVAL;
+
+ spin_lock_irq(&dmxdev->lock);
+
+ res = dvb_dmxdev_remove_event(&dmxdev->dvr_output_events, event);
+
+ if (event->type == DMX_EVENT_BUFFER_OVERFLOW)
+ dmxdev->dvr_buffer.error = 0;
+
+ spin_unlock_irq(&dmxdev->lock);
+
+ return res;
+}
+
static int dvb_dvr_get_buffer_status(struct dmxdev *dmxdev,
unsigned int f_flags,
struct dmx_buffer_status *dmx_buffer_status)
@@ -574,8 +899,7 @@
spin_lock_irq(lock);
dmx_buffer_status->error = buf->error;
- if (buf->error)
- dvb_ringbuffer_flush(buf);
+ buf->error = 0;
dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf);
dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf);
@@ -594,7 +918,7 @@
{
ssize_t buff_fullness;
- if (!(f_flags & O_ACCMODE) == O_RDONLY)
+ if (!((f_flags & O_ACCMODE) == O_RDONLY))
return -EINVAL;
if (!bytes_count)
@@ -606,6 +930,11 @@
return -EINVAL;
DVB_RINGBUFFER_SKIP(&dmxdev->dvr_buffer, bytes_count);
+
+ spin_lock_irq(&dmxdev->lock);
+ dvb_dmxdev_update_events(&dmxdev->dvr_output_events, bytes_count);
+ spin_unlock_irq(&dmxdev->lock);
+
wake_up_all(&dmxdev->dvr_buffer.queue);
return 0;
}
@@ -854,40 +1183,27 @@
struct dmxdev_feed *feed;
int ret;
- /*
- * Ask for status of decoder's buffer from underlying HW.
- * In case of PCR/STC extraction, the filter's ring-buffer
- * is used to gather the PCR/STC data and not using
- * an internal decoder buffer.
- */
- if (!(dmxdevfilter->dev->capabilities &
- DMXDEV_CAP_PCR_EXTRACTION) ||
- ((dmxdevfilter->params.pes.pes_type != DMX_PES_PCR0) &&
- (dmxdevfilter->params.pes.pes_type != DMX_PES_PCR1) &&
- (dmxdevfilter->params.pes.pes_type != DMX_PES_PCR2) &&
- (dmxdevfilter->params.pes.pes_type != DMX_PES_PCR3))) {
- list_for_each_entry(feed, &dmxdevfilter->feed.ts,
- next) {
- if (feed->ts->get_decoder_buff_status)
- ret = feed->ts->get_decoder_buff_status(
- feed->ts,
- dmx_buffer_status);
- else
- ret = -ENODEV;
+ /* Ask for status of decoder's buffer from underlying HW */
+ list_for_each_entry(feed, &dmxdevfilter->feed.ts,
+ next) {
+ if (feed->ts->get_decoder_buff_status)
+ ret = feed->ts->get_decoder_buff_status(
+ feed->ts,
+ dmx_buffer_status);
+ else
+ ret = -ENODEV;
- /*
- * There should not be more than one ts feed
- * in the list as this is DECODER feed.
- */
- spin_unlock_irq(&dmxdevfilter->dev->lock);
- return ret;
- }
+ /*
+ * There should not be more than one ts feed
+ * in the list as this is DECODER feed.
+ */
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+ return ret;
}
}
dmx_buffer_status->error = buf->error;
- if (buf->error)
- dvb_ringbuffer_flush(buf);
+ buf->error = 0;
dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf);
dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf);
@@ -918,11 +1234,33 @@
DVB_RINGBUFFER_SKIP(&dmxdevfilter->buffer, bytes_count);
+ spin_lock_irq(&dmxdevfilter->dev->lock);
+ dvb_dmxdev_update_events(&dmxdevfilter->events, bytes_count);
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+
wake_up_all(&dmxdevfilter->buffer.queue);
return 0;
}
+static int dvb_dmxdev_get_event(struct dmxdev_filter *dmxdevfilter,
+ struct dmx_filter_event *event)
+{
+ int res;
+
+ spin_lock_irq(&dmxdevfilter->dev->lock);
+
+ res = dvb_dmxdev_remove_event(&dmxdevfilter->events, event);
+
+ if (event->type == DMX_EVENT_BUFFER_OVERFLOW)
+ dmxdevfilter->buffer.error = 0;
+
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+ return res;
+
+}
+
static void dvb_dmxdev_filter_timeout(unsigned long data)
{
struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
@@ -954,6 +1292,7 @@
enum dmx_success success)
{
struct dmxdev_filter *dmxdevfilter = filter->priv;
+ struct dmx_filter_event event;
int ret;
if (dmxdevfilter->buffer.error) {
@@ -965,20 +1304,57 @@
spin_unlock(&dmxdevfilter->dev->lock);
return 0;
}
+
+ if ((buffer1_len + buffer2_len) == 0) {
+ if (DMX_CRC_ERROR == success) {
+ /* Section was dropped due to CRC error */
+ event.type = DMX_EVENT_SECTION_CRC_ERROR;
+ dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&dmxdevfilter->buffer.queue);
+ } else {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ }
+
+ return 0;
+ }
+
+ event.params.section.base_offset = dmxdevfilter->buffer.pwrite;
+ event.params.section.start_offset = dmxdevfilter->buffer.pwrite;
+
del_timer(&dmxdevfilter->timer);
dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n",
buffer1[0], buffer1[1],
buffer1[2], buffer1[3], buffer1[4], buffer1[5]);
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
buffer1_len);
- if (ret == buffer1_len) {
+ if (ret == buffer1_len)
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
buffer2_len);
- }
+
if (ret < 0) {
- dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+ dvb_dmxdev_flush_output(&dmxdevfilter->buffer,
+ &dmxdevfilter->events);
dmxdevfilter->buffer.error = ret;
+
+ event.type = DMX_EVENT_BUFFER_OVERFLOW;
+ } else {
+ event.type = DMX_EVENT_NEW_SECTION;
+ event.params.section.total_length =
+ buffer1_len + buffer2_len;
+ event.params.section.actual_length =
+ event.params.section.total_length;
+
+ if (success == DMX_MISSED_ERROR)
+ event.params.section.flags =
+ DMX_FILTER_CC_ERROR;
+ else
+ event.params.section.flags = 0;
}
+
+ dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+
if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
dmxdevfilter->state = DMXDEV_STATE_DONE;
spin_unlock(&dmxdevfilter->dev->lock);
@@ -993,46 +1369,298 @@
{
struct dmxdev_filter *dmxdevfilter = feed->priv;
struct dvb_ringbuffer *buffer;
+ struct dmxdev_events_queue *events;
+ struct dmx_filter_event event;
int ret;
spin_lock(&dmxdevfilter->dev->lock);
if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
- if ((dmxdevfilter->dev->capabilities &
- DMXDEV_CAP_PCR_EXTRACTION) &&
- ((dmxdevfilter->params.pes.pes_type == DMX_PES_PCR0) ||
- (dmxdevfilter->params.pes.pes_type == DMX_PES_PCR1) ||
- (dmxdevfilter->params.pes.pes_type == DMX_PES_PCR2) ||
- (dmxdevfilter->params.pes.pes_type == DMX_PES_PCR3))) {
- /*
- * Support for reporting PCR and STC pairs to user.
- * Reported data should have the following format:
- * <8 bit flags><64 bits of STC> <64bits of PCR>
- * STC and PCR values are in 27MHz.
- * The current flags that are defined:
- * 0x00000001: discontinuity_indicator
- */
- buffer = &dmxdevfilter->buffer;
- } else {
- spin_unlock(&dmxdevfilter->dev->lock);
- return 0;
- }
- } else if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
- || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+ spin_unlock(&dmxdevfilter->dev->lock);
+ return 0;
+ }
+
+ if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
+ || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) {
buffer = &dmxdevfilter->buffer;
- else
+ events = &dmxdevfilter->events;
+ } else {
buffer = &dmxdevfilter->dev->dvr_buffer;
+ events = &dmxdevfilter->dev->dvr_output_events;
+ }
if (buffer->error) {
spin_unlock(&dmxdevfilter->dev->lock);
wake_up_all(&buffer->queue);
return 0;
}
- ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
- if (ret == buffer1_len)
- ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
- if (ret < 0) {
- dvb_ringbuffer_flush(buffer);
- buffer->error = ret;
+
+ if (dmxdevfilter->state != DMXDEV_STATE_GO) {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ return 0;
+ }
+
+ if (dmxdevfilter->params.pes.output == DMX_OUT_TAP) {
+ if ((success == DMX_OK) &&
+ (!events->current_event_data_size)) {
+ events->current_event_start_offset = buffer->pwrite;
+ } else if (success == DMX_OK_PES_END) {
+ event.type = DMX_EVENT_NEW_PES;
+
+ event.params.pes.actual_length =
+ events->current_event_data_size;
+ event.params.pes.total_length =
+ events->current_event_data_size;
+
+ event.params.pes.base_offset =
+ events->current_event_start_offset;
+ event.params.pes.start_offset =
+ events->current_event_start_offset;
+
+ event.params.pes.flags = 0;
+ event.params.pes.stc = 0;
+
+ dvb_dmxdev_add_event(events, &event);
+ events->current_event_data_size = 0;
+ }
+ } else {
+ if (!events->current_event_data_size) {
+ events->current_event_start_offset =
+ buffer->pwrite;
+ }
+ }
+
+ if (buffer1_len + buffer2_len) {
+ ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
+ if (ret == buffer1_len)
+ ret = dvb_dmxdev_buffer_write(buffer, buffer2,
+ buffer2_len);
+ if (ret < 0) {
+ dvb_dmxdev_flush_output(buffer, events);
+ buffer->error = ret;
+
+ event.type = DMX_EVENT_BUFFER_OVERFLOW;
+ dvb_dmxdev_add_event(events, &event);
+ } else {
+ events->current_event_data_size +=
+ (buffer1_len + buffer2_len);
+
+ if (((dmxdevfilter->params.pes.output ==
+ DMX_OUT_TS_TAP) ||
+ (dmxdevfilter->params.pes.output ==
+ DMX_OUT_TSDEMUX_TAP)) &&
+ (events->current_event_data_size >=
+ dmxdevfilter->params.pes.rec_chunk_size)) {
+
+ event.type = DMX_EVENT_NEW_REC_CHUNK;
+ event.params.recording_chunk.offset =
+ events->current_event_start_offset;
+
+ event.params.recording_chunk.size =
+ events->current_event_data_size;
+
+ dvb_dmxdev_add_event(events, &event);
+ events->current_event_data_size = 0;
+ }
+ }
+ }
+
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&buffer->queue);
+ return 0;
+}
+
+static int dvb_dmxdev_section_event_cb(struct dmx_section_filter *filter,
+ struct dmx_data_ready *dmx_data_ready)
+{
+ int res;
+ struct dmxdev_filter *dmxdevfilter = filter->priv;
+ struct dmx_filter_event event;
+ int free;
+
+ if (dmxdevfilter->buffer.error) {
+ wake_up_all(&dmxdevfilter->buffer.queue);
+ return 0;
+ }
+
+ spin_lock(&dmxdevfilter->dev->lock);
+
+ if (dmxdevfilter->state != DMXDEV_STATE_GO) {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ return 0;
+ }
+
+ if (dmx_data_ready->data_length == 0) {
+ if (DMX_CRC_ERROR == dmx_data_ready->status) {
+ /* Section was dropped due to CRC error */
+ event.type = DMX_EVENT_SECTION_CRC_ERROR;
+ dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&dmxdevfilter->buffer.queue);
+ } else {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ }
+ return 0;
+ }
+
+ free = dvb_ringbuffer_free(&dmxdevfilter->buffer);
+
+ if ((DMX_OVERRUN_ERROR == dmx_data_ready->status) ||
+ (dmx_data_ready->data_length > free)) {
+ dvb_dmxdev_flush_output(&dmxdevfilter->buffer,
+ &dmxdevfilter->events);
+
+ dprintk("dmxdev: buffer overflow\n");
+
+ dmxdevfilter->buffer.error = -EOVERFLOW;
+
+ event.type = DMX_EVENT_BUFFER_OVERFLOW;
+ dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&dmxdevfilter->buffer.queue);
+ return 0;
+ }
+
+ event.type = DMX_EVENT_NEW_SECTION;
+ event.params.section.base_offset = dmxdevfilter->buffer.pwrite;
+ event.params.section.start_offset = dmxdevfilter->buffer.pwrite;
+ event.params.section.total_length = dmx_data_ready->data_length;
+ event.params.section.actual_length = dmx_data_ready->data_length;
+
+ if (dmx_data_ready->status == DMX_MISSED_ERROR)
+ event.params.section.flags = DMX_FILTER_CC_ERROR;
+ else
+ event.params.section.flags = 0;
+
+ res = dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+ DVB_RINGBUFFER_PUSH(&dmxdevfilter->buffer, dmx_data_ready->data_length);
+
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&dmxdevfilter->buffer.queue);
+
+ return res;
+}
+
+static int dvb_dmxdev_ts_event_cb(struct dmx_ts_feed *feed,
+ struct dmx_data_ready *dmx_data_ready)
+{
+ struct dmxdev_filter *dmxdevfilter = feed->priv;
+ struct dvb_ringbuffer *buffer;
+ struct dmxdev_events_queue *events;
+ struct dmx_filter_event event;
+ int free;
+
+ spin_lock(&dmxdevfilter->dev->lock);
+
+ if (dmxdevfilter->state != DMXDEV_STATE_GO) {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ return 0;
+ }
+
+ if (dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) {
+ buffer = &dmxdevfilter->buffer;
+ events = &dmxdevfilter->events;
+ } else {
+ buffer = &dmxdevfilter->dev->dvr_buffer;
+ events = &dmxdevfilter->dev->dvr_output_events;
+ }
+
+ if (dmx_data_ready->status == DMX_OK_PCR) {
+ event.type = DMX_EVENT_NEW_PCR;
+ event.params.pcr.pcr = dmx_data_ready->pcr.pcr;
+ event.params.pcr.stc = dmx_data_ready->pcr.stc;
+ if (dmx_data_ready->pcr.disc_indicator_set)
+ event.params.pcr.flags =
+ DMX_FILTER_DISCONTINUITY_INDEICATOR;
+ else
+ event.params.pcr.flags = 0;
+
+ dvb_dmxdev_add_event(events, &event);
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&buffer->queue);
+ return 0;
+ }
+
+ if ((dmxdevfilter->params.pes.output == DMX_OUT_DECODER) ||
+ (buffer->error)) {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&buffer->queue);
+ return 0;
+ }
+
+ free = dvb_ringbuffer_free(&dmxdevfilter->buffer);
+
+ if ((DMX_OVERRUN_ERROR == dmx_data_ready->status) ||
+ (dmx_data_ready->data_length > free)) {
+ dvb_dmxdev_flush_output(buffer, events);
+
+ dprintk("dmxdev: buffer overflow\n");
+
+ buffer->error = -EOVERFLOW;
+
+ event.type = DMX_EVENT_BUFFER_OVERFLOW;
+ dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+
+ spin_unlock(&dmxdevfilter->dev->lock);
+ return 0;
+ }
+
+ if (dmxdevfilter->params.pes.output == DMX_OUT_TAP) {
+ if ((dmx_data_ready->status == DMX_OK) &&
+ (!events->current_event_data_size)) {
+ events->current_event_start_offset =
+ dmxdevfilter->buffer.pwrite;
+ } else if (dmx_data_ready->status == DMX_OK_PES_END) {
+ event.type = DMX_EVENT_NEW_PES;
+
+ event.params.pes.base_offset =
+ events->current_event_start_offset;
+ event.params.pes.start_offset =
+ events->current_event_start_offset +
+ dmx_data_ready->pes_end.start_gap;
+
+ event.params.pes.actual_length =
+ dmx_data_ready->pes_end.actual_length;
+ event.params.pes.total_length =
+ events->current_event_data_size;
+
+ event.params.pes.flags = 0;
+ if (dmx_data_ready->pes_end.disc_indicator_set)
+ event.params.pes.flags |=
+ DMX_FILTER_DISCONTINUITY_INDEICATOR;
+ if (dmx_data_ready->pes_end.pes_length_mismatch)
+ event.params.pes.flags |=
+ DMX_FILTER_PES_LENGTH_ERROR;
+
+ event.params.pes.stc = dmx_data_ready->pes_end.stc;
+ dvb_dmxdev_add_event(events, &event);
+
+ events->current_event_data_size = 0;
+ }
+ } else {
+ if (!events->current_event_data_size)
+ events->current_event_start_offset =
+ dmxdevfilter->buffer.pwrite;
+ }
+
+ events->current_event_data_size += dmx_data_ready->data_length;
+ DVB_RINGBUFFER_PUSH(&dmxdevfilter->buffer, dmx_data_ready->data_length);
+
+ if ((dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP) ||
+ (dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)) {
+ if (events->current_event_data_size >=
+ dmxdevfilter->params.pes.rec_chunk_size) {
+ event.type = DMX_EVENT_NEW_REC_CHUNK;
+ event.params.recording_chunk.offset =
+ events->current_event_start_offset;
+
+ event.params.recording_chunk.size =
+ events->current_event_data_size;
+
+ dvb_dmxdev_add_event(events, &event);
+
+ events->current_event_data_size = 0;
+ }
}
spin_unlock(&dmxdevfilter->dev->lock);
wake_up_all(&buffer->queue);
@@ -1144,7 +1772,10 @@
return -EINVAL;
}
- dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+ spin_lock_irq(&dmxdevfilter->dev->lock);
+ dvb_dmxdev_flush_output(&dmxdevfilter->buffer, &dmxdevfilter->events);
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+
wake_up_all(&dmxdevfilter->buffer.queue);
return 0;
@@ -1213,6 +1844,15 @@
tsfeed = feed->ts;
tsfeed->priv = filter;
+ if (tsfeed->data_ready_cb) {
+ ret = tsfeed->data_ready_cb(tsfeed, dvb_dmxdev_ts_event_cb);
+
+ if (ret < 0) {
+ dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+ return ret;
+ }
+ }
+
ret = tsfeed->set(tsfeed, feed->pid,
ts_type, ts_pes,
filter->pes_buffer_size, timeout);
@@ -1270,7 +1910,9 @@
spin_unlock_irq(&filter->dev->lock);
}
- dvb_ringbuffer_flush(&filter->buffer);
+ spin_lock_irq(&filter->dev->lock);
+ dvb_dmxdev_flush_output(&filter->buffer, &filter->events);
+ spin_unlock_irq(&filter->dev->lock);
switch (filter->type) {
case DMXDEV_TYPE_SEC:
@@ -1295,14 +1937,27 @@
/* if no feed found, try to allocate new one */
if (!*secfeed) {
ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
- secfeed,
- dvb_dmxdev_section_callback);
+ secfeed,
+ dvb_dmxdev_section_callback);
if (ret < 0) {
printk("DVB (%s): could not alloc feed\n",
__func__);
return ret;
}
+ if ((*secfeed)->data_ready_cb) {
+ ret = (*secfeed)->data_ready_cb(
+ *secfeed,
+ dvb_dmxdev_section_event_cb);
+
+ if (ret < 0) {
+ printk(KERN_ERR "DVB (%s): could not set event cb\n",
+ __func__);
+ dvb_dmxdev_feed_restart(filter);
+ return ret;
+ }
+ }
+
ret = (*secfeed)->set(*secfeed, para->pid, 32768,
(para->flags & DMX_CHECK_CRC) ? 1 : 0);
if (ret < 0) {
@@ -1348,6 +2003,16 @@
break;
}
case DMXDEV_TYPE_PES:
+ if (filter->params.pes.rec_chunk_size <
+ DMX_REC_BUFF_CHUNK_MIN_SIZE)
+ filter->params.pes.rec_chunk_size =
+ DMX_REC_BUFF_CHUNK_MIN_SIZE;
+
+ if (filter->params.pes.rec_chunk_size >=
+ filter->buffer.size)
+ filter->params.pes.rec_chunk_size =
+ filter->buffer.size >> 2;
+
list_for_each_entry(feed, &filter->feed.ts, next) {
ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
if (ret < 0) {
@@ -1391,6 +2056,8 @@
file->private_data = dmxdevfilter;
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
+ dvb_dmxdev_flush_events(&dmxdevfilter->events);
+
dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
init_timer(&dmxdevfilter->timer);
@@ -1607,8 +2274,14 @@
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);
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
+
+ if (ret > 0) {
+ spin_lock_irq(&dmxdevfilter->dev->lock);
+ dvb_dmxdev_update_events(&dmxdevfilter->events, ret);
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+ }
mutex_unlock(&dmxdevfilter->mutex);
return ret;
@@ -1764,6 +2437,15 @@
*(enum dmx_playback_mode_t *)parg);
break;
+ case DMX_GET_EVENT:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_get_event(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
case DMX_GET_STC:
if (!dmxdev->demux->get_stc) {
ret = -EINVAL;
@@ -1823,10 +2505,15 @@
return 0;
if (dmxdevfilter->buffer.error)
- mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
+ mask |= (POLLIN | POLLRDNORM | POLLERR);
if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
- mask |= (POLLIN | POLLRDNORM | POLLPRI);
+ mask |= (POLLIN | POLLRDNORM);
+
+ if (dmxdevfilter->events.notified_index !=
+ dmxdevfilter->events.write_index) {
+ mask |= POLLPRI;
+ }
return mask;
}
@@ -1952,6 +2639,10 @@
ret = dvb_dvr_feed_data(dmxdev, file->f_flags, arg);
break;
+ case DMX_GET_EVENT:
+ ret = dvb_dvr_get_event(dmxdev, file->f_flags, parg);
+ break;
+
default:
ret = -EINVAL;
break;
@@ -1978,10 +2669,14 @@
poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
if (dmxdev->dvr_buffer.error)
- mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
+ mask |= (POLLIN | POLLRDNORM | POLLERR);
if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
- mask |= (POLLIN | POLLRDNORM | POLLPRI);
+ mask |= (POLLIN | POLLRDNORM);
+
+ if (dmxdev->dvr_output_events.notified_index !=
+ dmxdev->dvr_output_events.write_index)
+ mask |= POLLPRI;
} else {
poll_wait(file, &dmxdev->dvr_input_buffer.queue, wait);
if (dmxdev->dvr_input_buffer.error)
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 4c52e84..6fa7054 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -62,6 +62,35 @@
struct list_head next;
};
+struct dmxdev_events_queue {
+#define DMX_EVENT_QUEUE_SIZE 500 /* number of events */
+ /*
+ * indices used to manage events queue.
+ * read_index advanced when relevent data is read
+ * from the buffer.
+ * notified_index is the index from which next events
+ * are returned.
+ * read_index <= notified_index <= write_index
+ *
+ * If user reads the data without getting the respective
+ * event first, the read/notified indices are updated
+ * automatically to reflect the actual data that exist
+ * in the buffer.
+ */
+ u32 read_index;
+ u32 write_index;
+ u32 notified_index;
+
+ /* Bytes read by user without having respective event in the queue */
+ u32 bytes_read_no_event;
+
+ /* internal tracking of PES and recording events */
+ u32 current_event_data_size;
+ u32 current_event_start_offset;
+
+ struct dmx_filter_event queue[DMX_EVENT_QUEUE_SIZE];
+};
+
struct dmxdev_filter {
union {
struct dmx_section_filter *sec;
@@ -78,6 +107,8 @@
struct dmx_pes_filter_params pes;
} params;
+ struct dmxdev_events_queue events;
+
enum dmxdev_type type;
enum dmxdev_state state;
struct dmxdev *dev;
@@ -88,6 +119,8 @@
/* relevent for decoder PES */
unsigned long pes_buffer_size;
+ u32 rec_chunk_size;
+
/* only for sections */
struct timer_list timer;
int todo;
@@ -105,10 +138,9 @@
int filternum;
int capabilities;
-#define DMXDEV_CAP_DUPLEX 0x1
-#define DMXDEV_CAP_PULL_MODE 0x2
-#define DMXDEV_CAP_PCR_EXTRACTION 0x4
-#define DMXDEV_CAP_INDEXING 0x8
+#define DMXDEV_CAP_DUPLEX 0x1
+#define DMXDEV_CAP_PULL_MODE 0x2
+#define DMXDEV_CAP_INDEXING 0x4
enum dmx_playback_mode_t playback_mode;
dmx_source_t source;
@@ -120,6 +152,8 @@
struct dmx_frontend *dvr_orig_fe;
struct dvb_ringbuffer dvr_buffer;
+ struct dmxdev_events_queue dvr_output_events;
+
struct dvb_ringbuffer dvr_input_buffer;
struct workqueue_struct *dvr_input_workqueue;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index bc72fee..0be6a22 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -145,8 +145,15 @@
/* PUSI ? */
if (buf[1] & 0x40) {
- feed->peslen = 0xfffa;
+ if (feed->pusi_seen)
+ /* We had seen PUSI before, this means
+ * that previous PES can be closed now.
+ */
+ feed->cb.ts(NULL, 0, NULL, 0,
+ &feed->feed.ts, DMX_OK_PES_END);
+
feed->pusi_seen = 1;
+ feed->peslen = 0;
}
if (feed->pusi_seen == 0)
@@ -204,6 +211,11 @@
if (dvb_demux_performancecheck)
demux->total_crc_time +=
dvb_dmx_calc_time_delta(pre_crc_time);
+
+ /* Notify on CRC error */
+ feed->cb.sec(NULL, 0, NULL, 0,
+ &f->filter, DMX_CRC_ERROR);
+
return -1;
}
@@ -1053,6 +1065,25 @@
return ret;
}
+static int dmx_ts_feed_data_ready_cb(struct dmx_ts_feed *feed,
+ dmx_ts_data_ready_cb callback)
+{
+ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+ mutex_lock(&dvbdmx->mutex);
+
+ if (dvbdmxfeed->state == DMX_STATE_GO) {
+ mutex_unlock(&dvbdmx->mutex);
+ return -EINVAL;
+ }
+
+ dvbdmxfeed->data_ready_cb.ts = callback;
+
+ mutex_unlock(&dvbdmx->mutex);
+ return 0;
+}
+
static int dmx_ts_set_indexing_params(
struct dmx_ts_feed *ts_feed,
struct dmx_indexing_video_params *params)
@@ -1084,7 +1115,7 @@
feed->cb.ts = callback;
feed->demux = demux;
feed->pid = 0xffff;
- feed->peslen = 0xfffa;
+ feed->peslen = 0;
feed->buffer = NULL;
memset(&feed->indexing_params, 0,
sizeof(struct dmx_indexing_video_params));
@@ -1105,6 +1136,7 @@
(*ts_feed)->set = dmx_ts_feed_set;
(*ts_feed)->set_indexing_params = dmx_ts_set_indexing_params;
(*ts_feed)->get_decoder_buff_status = dmx_ts_feed_decoder_buff_status;
+ (*ts_feed)->data_ready_cb = dmx_ts_feed_data_ready_cb;
if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
feed->state = DMX_STATE_FREE;
@@ -1312,6 +1344,26 @@
return ret;
}
+
+static int dmx_section_feed_data_ready_cb(struct dmx_section_feed *feed,
+ dmx_section_data_ready_cb callback)
+{
+ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+ mutex_lock(&dvbdmx->mutex);
+
+ if (dvbdmxfeed->state == DMX_STATE_GO) {
+ mutex_unlock(&dvbdmx->mutex);
+ return -EINVAL;
+ }
+
+ dvbdmxfeed->data_ready_cb.sec = callback;
+
+ mutex_unlock(&dvbdmx->mutex);
+ return 0;
+}
+
static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
struct dmx_section_filter *filter)
{
@@ -1381,6 +1433,7 @@
(*feed)->start_filtering = dmx_section_feed_start_filtering;
(*feed)->stop_filtering = dmx_section_feed_stop_filtering;
(*feed)->release_filter = dmx_section_feed_release_filter;
+ (*feed)->data_ready_cb = dmx_section_feed_data_ready_cb;
mutex_unlock(&dvbdmx->mutex);
return 0;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index ebe34ad..3970a6c 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -78,6 +78,11 @@
dmx_section_cb sec;
} cb;
+ union {
+ dmx_ts_data_ready_cb ts;
+ dmx_section_data_ready_cb sec;
+ } data_ready_cb;
+
struct dvb_demux *demux;
void *priv;
int type;
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
index 8b591a6..4093fa5 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
@@ -111,6 +111,10 @@
#define DVB_RINGBUFFER_SKIP(rbuf,num) \
(rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size
+/* advance write ptr by <num> bytes */
+#define DVB_RINGBUFFER_PUSH(rbuf, num) \
+ ((rbuf)->pwrite = (((rbuf)->pwrite+(num))%(rbuf)->size))
+
/*
** read <len> bytes from ring buffer into <buf>
** <usermem> specifies whether <buf> resides in user space
diff --git a/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
index 738d730..4b0e7be 100644
--- a/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
+++ b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
@@ -192,18 +192,18 @@
struct mpq_streambuffer *sbuff,
u8 *buf, size_t len)
{
- int actual_len;
+ ssize_t actual_len;
actual_len = dvb_ringbuffer_avail(&sbuff->raw_data);
if (actual_len < len)
len = actual_len;
- if (actual_len)
- dvb_ringbuffer_read(&sbuff->raw_data, buf, actual_len);
+ if (len)
+ dvb_ringbuffer_read(&sbuff->raw_data, buf, len);
wake_up_all(&sbuff->raw_data.queue);
- return actual_len;
+ return len;
}
EXPORT_SYMBOL(mpq_streambuffer_data_read);
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
index 7223377..a01cf5b 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -33,16 +33,6 @@
sizeof(struct mpq_streambuffer_packet_header) + \
sizeof(struct mpq_adapter_video_meta_data)))
-/*
- * PCR/STC information length saved in ring-buffer.
- * PCR / STC are saved in ring-buffer in the following form:
- * <8 bit flags><64 bits of STC> <64bits of PCR>
- * STC and PCR values are in 27MHz.
- * The current flags that are defined:
- * 0x00000001: discontinuity_indicator
- */
-#define PCR_STC_LEN 17
-
/* Number of demux devices, has default of linux configuration */
static int mpq_demux_device_num = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
@@ -839,7 +829,7 @@
ion_alloc(mpq_demux->ion_client,
actual_buffer_size,
SZ_4K,
- ION_HEAP(ION_CP_MM_HEAP_ID));
+ (ION_HEAP(ION_CP_MM_HEAP_ID) | CACHED));
if (IS_ERR_OR_NULL(feed_data->payload_buff_handle)) {
ret = PTR_ERR(feed_data->payload_buff_handle);
@@ -1906,10 +1896,9 @@
struct dvb_demux_feed *feed,
const u8 *buf)
{
- int i;
u64 pcr;
u64 stc;
- u8 output[PCR_STC_LEN];
+ struct dmx_data_ready data;
struct mpq_demux *mpq_demux = feed->demux->priv;
const struct ts_packet_header *ts_header;
const struct ts_adaptation_field *adaptation_field;
@@ -1960,17 +1949,13 @@
stc += buf[188];
stc *= 256; /* convert from 105.47 KHZ to 27MHz */
- output[0] = adaptation_field->discontinuity_indicator;
+ data.data_length = 0;
+ data.pcr.pcr = pcr;
+ data.pcr.stc = stc;
+ data.pcr.disc_indicator_set = adaptation_field->discontinuity_indicator;
+ data.status = DMX_OK_PCR;
+ feed->data_ready_cb.ts(&feed->feed.ts, &data);
- for (i = 1; i <= 8; i++)
- output[i] = (stc >> ((8-i) << 3)) & 0xFF;
-
- for (i = 9; i <= 16; i++)
- output[i] = (pcr >> ((16-i) << 3)) & 0xFF;
-
- feed->cb.ts(output, PCR_STC_LEN,
- NULL, 0,
- &feed->feed.ts, DMX_OK);
return 0;
}
EXPORT_SYMBOL(mpq_dmx_process_pcr_packet);
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
index e7d6b74..bd1ecfe 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -641,7 +641,6 @@
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
- DMXDEV_CAP_PCR_EXTRACTION |
DMXDEV_CAP_INDEXING;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index f374d91..fd94e80 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -752,7 +752,6 @@
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
- DMXDEV_CAP_PCR_EXTRACTION |
DMXDEV_CAP_INDEXING;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
index 74b7c22..e4858fa 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
@@ -139,7 +139,6 @@
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
- DMXDEV_CAP_PCR_EXTRACTION |
DMXDEV_CAP_INDEXING;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 23d11c3..c0a35f9 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -103,6 +103,7 @@
struct hci_fm_ch_det_threshold ch_det_threshold;
struct hci_fm_data_rd_rsp default_data;
struct hci_fm_spur_data spur_data;
+ unsigned char is_station_valid;
};
static struct video_device *priv_videodev;
@@ -2645,6 +2646,9 @@
ctrl->value = radio->ch_det_threshold.sinr_samples;
break;
+ case V4L2_CID_PRIVATE_VALID_CHANNEL:
+ ctrl->value = radio->is_station_valid;
+ break;
default:
retval = -EINVAL;
}
@@ -2811,6 +2815,8 @@
struct hci_fm_tx_rt tx_rt = {0};
struct hci_fm_def_data_rd_req rd_txgain;
struct hci_fm_def_data_wr_req wr_txgain;
+ char sinr_th, sinr;
+ __u8 intf_det_low_th, intf_det_high_th, intf_det_out;
switch (ctrl->id) {
case V4L2_CID_PRIVATE_IRIS_TX_TONE:
@@ -3281,6 +3287,40 @@
case V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE:
update_spur_table(radio);
break;
+ case V4L2_CID_PRIVATE_VALID_CHANNEL:
+ retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("%s: Failed to determine channel's validity\n",
+ __func__);
+ return retval;
+ } else {
+ sinr_th = radio->ch_det_threshold.sinr;
+ intf_det_low_th = radio->ch_det_threshold.low_th;
+ intf_det_high_th = radio->ch_det_threshold.high_th;
+ }
+
+ retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("%s: Failed to determine channel's validity\n",
+ __func__);
+ return retval;
+ } else
+ sinr = radio->fm_st_rsp.station_rsp.sinr;
+
+ retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("%s: Failed to determine channel's validity\n",
+ __func__);
+ return retval;
+ } else
+ intf_det_out = radio->st_dbg_param.in_det_out;
+
+ if ((sinr >= sinr_th) && (intf_det_out >= intf_det_low_th) &&
+ (intf_det_out <= intf_det_high_th))
+ radio->is_station_valid = VALID_CHANNEL;
+ else
+ radio->is_station_valid = INVALID_CHANNEL;
+ break;
default:
retval = -EINVAL;
}
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index 9c791e4..fb5aea0 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -291,6 +291,54 @@
by QUP in the board file as QUP is used by
applications other than camera.
+config MSM_CSI20_HEADER
+ bool "Qualcomm MSM CSI 2.0 Header"
+ depends on MSM_CAMERA
+ ---help---
+ Enable support for CSI drivers to include 2.0
+ header. This header has register macros and its
+ values and bit mask for register configuration bits
+ This config macro is required targets based on 8960,
+ 8930 and 8064 platforms.
+
+config MSM_CSI30_HEADER
+ bool "Qualcomm MSM CSI 3.0 Header"
+ depends on MSM_CAMERA
+ ---help---
+ Enable support for CSI drivers to include 3.0
+ header. This header has register macros and its
+ values and bit mask for register configuration bits
+ This config macro is required for targets based on
+ 8064 platforms.
+
+config MSM_CSIPHY
+ bool "Qualcomm MSM Camera Serial Interface Physical receiver support"
+ depends on MSM_CAMERA
+ ---help---
+ Enable support for Camera Serial Interface
+ Physical receiver. It deserializes packets and
+ supports detection of packet start and stop
+ signalling.
+
+config MSM_CSID
+ bool "Qualcomm MSM Camera Serial Interface decoder support"
+ depends on MSM_CAMERA
+ ---help---
+ Enable support for Camera Serial Interface decoder.
+ It supports lane merging and decoding of packets
+ based on cid which is mapped to a virtual channel
+ and datatype.
+
+config MSM_CSI2_REGISTER
+ bool "Qualcomm MSM CSI2 Register"
+ depends on MSM_CAMERA
+ ---help---
+ Register CSIPHY, CSID and ISPIF subdevices during
+ msm_open. Different CSI components are registered
+ based on platform. This macro specifies registering
+ of CSIPHY, CSID and ISPIF subdevices to receive data
+ from sensor.
+
config S5K3L1YX
bool "Sensor S5K3L1YX (BAYER 12M)"
depends on MSM_CAMERA
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 5703d88..eb45271 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -12,10 +12,11 @@
EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
EXTRA_CFLAGS += -Idrivers/media/video/msm/server
obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o msm_vfe_stats_buf.o
- obj-$(CONFIG_MSM_CAMERA) += server/ eeprom/ sensors/ actuators/ csi/
+ obj-$(CONFIG_MSM_CAMERA) += server/
+ obj-$(CONFIG_MSM_CAM_IRQ_ROUTER) += msm_camirq_router.o
+ obj-$(CONFIG_MSM_CAMERA) += eeprom/ sensors/ actuators/ csi/
obj-$(CONFIG_MSM_CPP) += cpp/
obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
- obj-$(CONFIG_MSM_CAM_IRQ_ROUTER) += msm_camirq_router.o
else
obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
endif
diff --git a/drivers/media/video/msm/csi/Makefile b/drivers/media/video/msm/csi/Makefile
index f7cb408..d11e2d2 100644
--- a/drivers/media/video/msm/csi/Makefile
+++ b/drivers/media/video/msm/csi/Makefile
@@ -1,7 +1,14 @@
GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
-EXTRA_CFLAGS += -Idrivers/media/video/msm
+ccflags-y += -Idrivers/media/video/msm
+ifeq ($(CONFIG_MSM_CSI20_HEADER),y)
+ ccflags-y += -Idrivers/media/video/msm/csi/include/csi2.0
+else ifeq ($(CONFIG_MSM_CSI30_HEADER),y)
+ ccflags-y += -Idrivers/media/video/msm/csi/include/csi3.0
+endif
+obj-$(CONFIG_MSM_CSI2_REGISTER) += msm_csi2_register.o
+obj-$(CONFIG_MSM_CSIPHY) += msm_csiphy.o
+obj-$(CONFIG_MSM_CSID) += msm_csid.o
obj-$(CONFIG_ARCH_MSM8960) += msm_csi2_register.o msm_csiphy.o msm_csid.o msm_ispif.o
obj-$(CONFIG_ARCH_MSM7X27A) += msm_csic_register.o msm_csic.o
obj-$(CONFIG_ARCH_MSM8X60) += msm_csic_register.o msm_csic.o
obj-$(CONFIG_ARCH_MSM7X30) += msm_csic_register.o msm_csic.o
-
diff --git a/drivers/media/video/msm/csi/include/csi2.0/msm_csid_hwreg.h b/drivers/media/video/msm/csi/include/csi2.0/msm_csid_hwreg.h
new file mode 100644
index 0000000..c79748c
--- /dev/null
+++ b/drivers/media/video/msm/csi/include/csi2.0/msm_csid_hwreg.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_HWREG_H
+#define MSM_CSID_HWREG_H
+
+/* MIPI CSID registers */
+#define CSID_HW_VERSION_ADDR 0x0
+#define CSID_CORE_CTRL_0_ADDR 0x4
+#define CSID_CORE_CTRL_1_ADDR 0x4
+#define CSID_RST_CMD_ADDR 0x8
+#define CSID_CID_LUT_VC_0_ADDR 0xc
+#define CSID_CID_LUT_VC_1_ADDR 0x10
+#define CSID_CID_LUT_VC_2_ADDR 0x14
+#define CSID_CID_LUT_VC_3_ADDR 0x18
+#define CSID_CID_n_CFG_ADDR 0x1C
+#define CSID_IRQ_CLEAR_CMD_ADDR 0x5c
+#define CSID_IRQ_MASK_ADDR 0x60
+#define CSID_IRQ_STATUS_ADDR 0x64
+#define CSID_CAPTURED_UNMAPPED_LONG_PKT_HDR_ADDR 0x68
+#define CSID_CAPTURED_MMAPPED_LONG_PKT_HDR_ADDR 0x6c
+#define CSID_CAPTURED_SHORT_PKT_ADDR 0x70
+#define CSID_CAPTURED_LONG_PKT_HDR_ADDR 0x74
+#define CSID_CAPTURED_LONG_PKT_FTR_ADDR 0x78
+#define CSID_PIF_MISR_DL0_ADDR 0x7C
+#define CSID_PIF_MISR_DL1_ADDR 0x80
+#define CSID_PIF_MISR_DL2_ADDR 0x84
+#define CSID_PIF_MISR_DL3_ADDR 0x88
+#define CSID_STATS_TOTAL_PKTS_RCVD_ADDR 0x8C
+#define CSID_STATS_ECC_ADDR 0x90
+#define CSID_STATS_CRC_ADDR 0x94
+#define CSID_TG_CTRL_ADDR 0x9C
+#define CSID_TG_VC_CFG_ADDR 0xA0
+#define CSID_TG_DT_n_CFG_0_ADDR 0xA8
+#define CSID_TG_DT_n_CFG_1_ADDR 0xAC
+#define CSID_TG_DT_n_CFG_2_ADDR 0xB0
+#define CSID_RST_DONE_IRQ_BITSHIFT 11
+#define CSID_RST_STB_ALL 0x7FFF
+#define CSID_DL_INPUT_SEL_SHIFT 0x2
+#define CSID_PHY_SEL_SHIFT 0x17
+
+#endif
diff --git a/drivers/media/video/msm/csi/include/csi2.0/msm_csiphy_hwreg.h b/drivers/media/video/msm/csi/include/csi2.0/msm_csiphy_hwreg.h
new file mode 100644
index 0000000..93d1fc4
--- /dev/null
+++ b/drivers/media/video/msm/csi/include/csi2.0/msm_csiphy_hwreg.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_HWREG_H
+#define MSM_CSIPHY_HWREG_H
+
+/*MIPI CSI PHY registers*/
+#define MIPI_CSIPHY_HW_VERSION_ADDR 0x180
+#define MIPI_CSIPHY_LNn_CFG1_ADDR 0x0
+#define MIPI_CSIPHY_LNn_CFG2_ADDR 0x4
+#define MIPI_CSIPHY_LNn_CFG3_ADDR 0x8
+#define MIPI_CSIPHY_LNn_CFG4_ADDR 0xC
+#define MIPI_CSIPHY_LNn_CFG5_ADDR 0x10
+#define MIPI_CSIPHY_LNCK_CFG1_ADDR 0x100
+#define MIPI_CSIPHY_LNCK_CFG2_ADDR 0x104
+#define MIPI_CSIPHY_LNCK_CFG3_ADDR 0x108
+#define MIPI_CSIPHY_LNCK_CFG4_ADDR 0x10C
+#define MIPI_CSIPHY_LNCK_CFG5_ADDR 0x110
+#define MIPI_CSIPHY_LNCK_MISC1_ADDR 0x128
+#define MIPI_CSIPHY_GLBL_RESET_ADDR 0x140
+#define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR 0x144
+#define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR 0x180
+#define MIPI_CSIPHY_INTERRUPT_MASK0_ADDR 0x1A0
+#define MIPI_CSIPHY_INTERRUPT_MASK_VAL 0x6F
+#define MIPI_CSIPHY_INTERRUPT_MASK_ADDR 0x1A4
+#define MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR 0x1C0
+#define MIPI_CSIPHY_INTERRUPT_CLEAR_ADDR 0x1C4
+#define MIPI_CSIPHY_MODE_CONFIG_SHIFT 0x4
+#define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR 0x1E0
+#define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR 0x1E8
+
+#endif
diff --git a/drivers/media/video/msm/csi/include/csi3.0/msm_csid_hwreg.h b/drivers/media/video/msm/csi/include/csi3.0/msm_csid_hwreg.h
new file mode 100644
index 0000000..27d5a06
--- /dev/null
+++ b/drivers/media/video/msm/csi/include/csi3.0/msm_csid_hwreg.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_HWREG_H
+#define MSM_CSID_HWREG_H
+
+/* MIPI CSID registers */
+#define CSID_HW_VERSION_ADDR 0x0
+#define CSID_CORE_CTRL_0_ADDR 0x4
+#define CSID_CORE_CTRL_1_ADDR 0x8
+#define CSID_RST_CMD_ADDR 0xC
+#define CSID_CID_LUT_VC_0_ADDR 0x10
+#define CSID_CID_LUT_VC_1_ADDR 0x14
+#define CSID_CID_LUT_VC_2_ADDR 0x18
+#define CSID_CID_LUT_VC_3_ADDR 0x1C
+#define CSID_CID_n_CFG_ADDR 0x20
+#define CSID_IRQ_CLEAR_CMD_ADDR 0x60
+#define CSID_IRQ_MASK_ADDR 0x64
+#define CSID_IRQ_STATUS_ADDR 0x68
+#define CSID_CAPTURED_UNMAPPED_LONG_PKT_HDR_ADDR 0x6C
+#define CSID_CAPTURED_MMAPPED_LONG_PKT_HDR_ADDR 0x70
+#define CSID_CAPTURED_SHORT_PKT_ADDR 0x74
+#define CSID_CAPTURED_LONG_PKT_HDR_ADDR 0x78
+#define CSID_CAPTURED_LONG_PKT_FTR_ADDR 0x7C
+#define CSID_PIF_MISR_DL0_ADDR 0x80
+#define CSID_PIF_MISR_DL1_ADDR 0x84
+#define CSID_PIF_MISR_DL2_ADDR 0x88
+#define CSID_PIF_MISR_DL3_ADDR 0x8C
+#define CSID_STATS_TOTAL_PKTS_RCVD_ADDR 0x90
+#define CSID_STATS_ECC_ADDR 0x94
+#define CSID_STATS_CRC_ADDR 0x98
+#define CSID_TG_CTRL_ADDR 0xA0
+#define CSID_TG_VC_CFG_ADDR 0xA4
+#define CSID_TG_DT_n_CFG_0_ADDR 0xAC
+#define CSID_TG_DT_n_CFG_1_ADDR 0xB0
+#define CSID_TG_DT_n_CFG_2_ADDR 0xB4
+#define CSID_RST_DONE_IRQ_BITSHIFT 11
+#define CSID_RST_STB_ALL 0x7FFF
+#define CSID_DL_INPUT_SEL_SHIFT 0x4
+#define CSID_PHY_SEL_SHIFT 0x17
+
+#endif
diff --git a/drivers/media/video/msm/csi/include/csi3.0/msm_csiphy_hwreg.h b/drivers/media/video/msm/csi/include/csi3.0/msm_csiphy_hwreg.h
new file mode 100644
index 0000000..79791bd
--- /dev/null
+++ b/drivers/media/video/msm/csi/include/csi3.0/msm_csiphy_hwreg.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_HWREG_H
+#define MSM_CSIPHY_HWREG_H
+
+/*MIPI CSI PHY registers*/
+#define MIPI_CSIPHY_LNn_CFG1_ADDR 0x0
+#define MIPI_CSIPHY_LNn_CFG2_ADDR 0x4
+#define MIPI_CSIPHY_LNn_CFG3_ADDR 0x8
+#define MIPI_CSIPHY_LNn_CFG4_ADDR 0xC
+#define MIPI_CSIPHY_LNn_CFG5_ADDR 0x10
+#define MIPI_CSIPHY_LNCK_CFG1_ADDR 0x100
+#define MIPI_CSIPHY_LNCK_CFG2_ADDR 0x104
+#define MIPI_CSIPHY_LNCK_CFG3_ADDR 0x108
+#define MIPI_CSIPHY_LNCK_CFG4_ADDR 0x10C
+#define MIPI_CSIPHY_LNCK_CFG5_ADDR 0x110
+#define MIPI_CSIPHY_LNCK_MISC1_ADDR 0x128
+#define MIPI_CSIPHY_GLBL_RESET_ADDR 0x140
+#define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR 0x144
+#define MIPI_CSIPHY_HW_VERSION_ADDR 0x188
+#define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR 0x18C
+#define MIPI_CSIPHY_INTERRUPT_MASK0_ADDR 0x1AC
+#define MIPI_CSIPHY_INTERRUPT_MASK_VAL 0x3F
+#define MIPI_CSIPHY_INTERRUPT_MASK_ADDR 0x1B0
+#define MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR 0x1CC
+#define MIPI_CSIPHY_INTERRUPT_CLEAR_ADDR 0x1D0
+#define MIPI_CSIPHY_MODE_CONFIG_SHIFT 0x4
+#define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR 0x1EC
+#define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR 0x1F4
+
+#endif
diff --git a/drivers/media/video/msm/csi/msm_csi2_register.c b/drivers/media/video/msm/csi/msm_csi2_register.c
index 7b85ded..aa539ff 100644
--- a/drivers/media/video/msm/csi/msm_csi2_register.c
+++ b/drivers/media/video/msm/csi/msm_csi2_register.c
@@ -16,48 +16,28 @@
#include "msm_csi_register.h"
int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
- int core_index,
- int (*msm_mctl_subdev_match_core)(struct device *, void *))
+ int core_index, struct msm_cam_server_dev *server_dev)
{
int rc = -ENODEV;
- struct device_driver *driver;
- struct device *dev;
/* register csiphy subdev */
- driver = driver_find(MSM_CSIPHY_DRV_NAME, &platform_bus_type);
- if (!driver)
+ p_mctl->csiphy_sdev = server_dev->csiphy_device[core_index];
+ if (!p_mctl->csiphy_sdev)
goto out;
-
- dev = driver_find_device(driver, NULL, (void *)core_index,
- msm_mctl_subdev_match_core);
- if (!dev)
- goto out;
-
- p_mctl->csiphy_sdev = dev_get_drvdata(dev);
+ v4l2_set_subdev_hostdata(p_mctl->csiphy_sdev, p_mctl);
/* register csid subdev */
- driver = driver_find(MSM_CSID_DRV_NAME, &platform_bus_type);
- if (!driver)
+ p_mctl->csid_sdev = server_dev->csid_device[core_index];
+ if (!p_mctl->csid_sdev)
goto out;
-
- dev = driver_find_device(driver, NULL, (void *)core_index,
- msm_mctl_subdev_match_core);
- if (!dev)
- goto out;
-
- p_mctl->csid_sdev = dev_get_drvdata(dev);
+ v4l2_set_subdev_hostdata(p_mctl->csid_sdev, p_mctl);
/* register ispif subdev */
- driver = driver_find(MSM_ISPIF_DRV_NAME, &platform_bus_type);
- if (!driver)
+ p_mctl->ispif_sdev = server_dev->ispif_device[0];
+ if (!p_mctl->ispif_sdev)
goto out;
+ v4l2_set_subdev_hostdata(p_mctl->ispif_sdev, p_mctl);
- dev = driver_find_device(driver, NULL, 0,
- msm_mctl_subdev_match_core);
- if (!dev)
- goto out;
-
- p_mctl->ispif_sdev = dev_get_drvdata(dev);
rc = 0;
return rc;
out:
diff --git a/drivers/media/video/msm/csi/msm_csi_register.h b/drivers/media/video/msm/csi/msm_csi_register.h
index 578b609..ebb001c 100644
--- a/drivers/media/video/msm/csi/msm_csi_register.h
+++ b/drivers/media/video/msm/csi/msm_csi_register.h
@@ -13,4 +13,4 @@
int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
int core_index,
- int (*msm_mctl_subdev_match_core)(struct device *, void *));
+ struct msm_cam_server_dev *server_dev);
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
index dbb4f32..bcb7bb3 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -463,6 +463,12 @@
msm_cam_register_subdev_node(
&new_csic_dev->subdev, &sd_info);
+ media_entity_init(&new_csic_dev->subdev.entity, 0, NULL, 0);
+ new_csic_dev->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ new_csic_dev->subdev.entity.group_id = CSIC_DEV;
+ new_csic_dev->subdev.entity.name = pdev->name;
+ new_csic_dev->subdev.entity.revision =
+ new_csic_dev->subdev.devnode->num;
return 0;
csic_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csic_register.c b/drivers/media/video/msm/csi/msm_csic_register.c
index 7ccaff2..dc3641a 100644
--- a/drivers/media/video/msm/csi/msm_csic_register.c
+++ b/drivers/media/video/msm/csi/msm_csic_register.c
@@ -16,23 +16,14 @@
#include "msm_csi_register.h"
int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
- int core_index,
- int (*msm_mctl_subdev_match_core)(struct device *, void *))
+ int core_index, struct msm_cam_server_dev *server_dev)
{
int rc = -ENODEV;
- struct device_driver *driver;
- struct device *dev;
- driver = driver_find(MSM_CSIC_DRV_NAME, &platform_bus_type);
- if (!driver)
+ p_mctl->csic_sdev = server_dev->csic_device[core_index];
+ if (!p_mctl->csic_sdev)
goto out;
-
- dev = driver_find_device(driver, NULL, (void *)core_index,
- msm_mctl_subdev_match_core);
- if (!dev)
- goto out;
-
- p_mctl->csic_sdev = dev_get_drvdata(dev);
+ v4l2_set_subdev_hostdata(p_mctl->csic_sdev, p_mctl);
rc = 0;
p_mctl->ispif_sdev = NULL;
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index 1ab4e66..6ee87b7 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -14,47 +14,16 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <mach/board.h>
#include <mach/camera.h>
#include <media/msm_isp.h>
#include "msm_csid.h"
+#include "msm_csid_hwreg.h"
#include "msm.h"
#define V4L2_IDENT_CSID 50002
-/* MIPI CSID registers */
-#define CSID_HW_VERSION_ADDR 0x0
-#define CSID_CORE_CTRL_ADDR 0x4
-#define CSID_RST_CMD_ADDR 0x8
-#define CSID_CID_LUT_VC_0_ADDR 0xc
-#define CSID_CID_LUT_VC_1_ADDR 0x10
-#define CSID_CID_LUT_VC_2_ADDR 0x14
-#define CSID_CID_LUT_VC_3_ADDR 0x18
-#define CSID_CID_n_CFG_ADDR 0x1C
-#define CSID_IRQ_CLEAR_CMD_ADDR 0x5c
-#define CSID_IRQ_MASK_ADDR 0x60
-#define CSID_IRQ_STATUS_ADDR 0x64
-#define CSID_CAPTURED_UNMAPPED_LONG_PKT_HDR_ADDR 0x68
-#define CSID_CAPTURED_MMAPPED_LONG_PKT_HDR_ADDR 0x6c
-#define CSID_CAPTURED_SHORT_PKT_ADDR 0x70
-#define CSID_CAPTURED_LONG_PKT_HDR_ADDR 0x74
-#define CSID_CAPTURED_LONG_PKT_FTR_ADDR 0x78
-#define CSID_PIF_MISR_DL0_ADDR 0x7C
-#define CSID_PIF_MISR_DL1_ADDR 0x80
-#define CSID_PIF_MISR_DL2_ADDR 0x84
-#define CSID_PIF_MISR_DL3_ADDR 0x88
-#define CSID_STATS_TOTAL_PKTS_RCVD_ADDR 0x8C
-#define CSID_STATS_ECC_ADDR 0x90
-#define CSID_STATS_CRC_ADDR 0x94
-#define CSID_TG_CTRL_ADDR 0x9C
-#define CSID_TG_VC_CFG_ADDR 0xA0
-#define CSID_TG_DT_n_CFG_0_ADDR 0xA8
-#define CSID_TG_DT_n_CFG_1_ADDR 0xAC
-#define CSID_TG_DT_n_CFG_2_ADDR 0xB0
-#define CSID_TG_DT_n_CFG_3_ADDR 0xD8
-#define CSID_RST_DONE_IRQ_BITSHIFT 11
-#define CSID_RST_STB_ALL 0x7FFF
-
#define DBG_CSID 0
static int msm_csid_cid_lut(
@@ -64,7 +33,7 @@
int rc = 0, i = 0;
uint32_t val = 0;
- for (i = 0; i < csid_lut_params->num_cid && i < 4; i++) {
+ for (i = 0; i < csid_lut_params->num_cid && i < 16; i++) {
if (csid_lut_params->vc_cfg[i].dt < 0x12 ||
csid_lut_params->vc_cfg[i].dt > 0x37) {
CDBG("%s: unsupported data type 0x%x\n",
@@ -72,13 +41,13 @@
return rc;
}
val = msm_camera_io_r(csidbase + CSID_CID_LUT_VC_0_ADDR +
- (csid_lut_params->vc_cfg[i].cid >> 2) * 4)
- & ~(0xFF << csid_lut_params->vc_cfg[i].cid * 8);
- val |= csid_lut_params->vc_cfg[i].dt <<
- csid_lut_params->vc_cfg[i].cid * 8;
+ (csid_lut_params->vc_cfg[i].cid >> 2) * 4)
+ & ~(0xFF << ((csid_lut_params->vc_cfg[i].cid % 4) * 8));
+ val |= (csid_lut_params->vc_cfg[i].dt <<
+ ((csid_lut_params->vc_cfg[i].cid % 4) * 8));
msm_camera_io_w(val, csidbase + CSID_CID_LUT_VC_0_ADDR +
(csid_lut_params->vc_cfg[i].cid >> 2) * 4);
- val = csid_lut_params->vc_cfg[i].decode_format << 4 | 0x3;
+ val = (csid_lut_params->vc_cfg[i].decode_format << 4) | 0x3;
msm_camera_io_w(val, csidbase + CSID_CID_n_CFG_ADDR +
(csid_lut_params->vc_cfg[i].cid * 4));
}
@@ -113,13 +82,16 @@
csid_params = cfg_params->parms;
val = csid_params->lane_cnt - 1;
- val |= csid_params->lane_assign << 2;
- val |= 0x1 << 10;
- val |= 0x1 << 11;
- val |= 0x1 << 12;
- val |= 0x1 << 13;
- val |= 0x1 << 28;
- msm_camera_io_w(val, csidbase + CSID_CORE_CTRL_ADDR);
+ val |= csid_params->lane_assign << CSID_DL_INPUT_SEL_SHIFT;
+ if (csid_dev->hw_version < 0x30000000) {
+ val |= (0xF << 10);
+ msm_camera_io_w(val, csidbase + CSID_CORE_CTRL_0_ADDR);
+ } else {
+ msm_camera_io_w(val, csidbase + CSID_CORE_CTRL_0_ADDR);
+ val = csid_params->phy_sel << CSID_PHY_SEL_SHIFT;
+ val |= 0xF;
+ msm_camera_io_w(val, csidbase + CSID_CORE_CTRL_1_ADDR);
+ }
rc = msm_csid_cid_lut(&csid_params->lut_params, csidbase);
if (rc < 0)
@@ -317,6 +289,10 @@
platform_set_drvdata(pdev, &new_csid_dev->subdev);
mutex_init(&new_csid_dev->mutex);
+ if (pdev->dev.of_node)
+ of_property_read_u32((&pdev->dev)->of_node,
+ "cell-index", &pdev->id);
+
new_csid_dev->mem = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "csid");
if (!new_csid_dev->mem) {
@@ -344,6 +320,13 @@
sd_info.sd_index = pdev->id;
sd_info.irq_num = new_csid_dev->irq->start;
msm_cam_register_subdev_node(&new_csid_dev->subdev, &sd_info);
+
+ media_entity_init(&new_csid_dev->subdev.entity, 0, NULL, 0);
+ new_csid_dev->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ new_csid_dev->subdev.entity.group_id = CSID_DEV;
+ new_csid_dev->subdev.entity.name = pdev->name;
+ new_csid_dev->subdev.entity.revision =
+ new_csid_dev->subdev.devnode->num;
return 0;
csid_no_resource:
@@ -352,11 +335,19 @@
return 0;
}
+static const struct of_device_id msm_csid_dt_match[] = {
+ {.compatible = "qcom,csid"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_csid_dt_match);
+
static struct platform_driver csid_driver = {
.probe = csid_probe,
.driver = {
.name = MSM_CSID_DRV_NAME,
.owner = THIS_MODULE,
+ .of_match_table = msm_csid_dt_match,
},
};
diff --git a/drivers/media/video/msm/csi/msm_csiphy.c b/drivers/media/video/msm/csi/msm_csiphy.c
index 4693a8a..bec7ae3 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.c
+++ b/drivers/media/video/msm/csi/msm_csiphy.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/of.h>
#include <linux/module.h>
#include <mach/board.h>
#include <mach/camera.h>
@@ -20,50 +21,19 @@
#include <media/msm_isp.h>
#include "msm_csiphy.h"
#include "msm.h"
-
+#include "msm_csiphy_hwreg.h"
#define DBG_CSIPHY 0
#define V4L2_IDENT_CSIPHY 50003
-
-/*MIPI CSI PHY registers*/
-#define MIPI_CSIPHY_LNn_CFG1_ADDR 0x0
-#define MIPI_CSIPHY_LNn_CFG2_ADDR 0x4
-#define MIPI_CSIPHY_LNn_CFG3_ADDR 0x8
-#define MIPI_CSIPHY_LNn_CFG4_ADDR 0xC
-#define MIPI_CSIPHY_LNn_CFG5_ADDR 0x10
-#define MIPI_CSIPHY_LNCK_CFG1_ADDR 0x100
-#define MIPI_CSIPHY_LNCK_CFG2_ADDR 0x104
-#define MIPI_CSIPHY_LNCK_CFG3_ADDR 0x108
-#define MIPI_CSIPHY_LNCK_CFG4_ADDR 0x10C
-#define MIPI_CSIPHY_LNCK_CFG5_ADDR 0x110
-#define MIPI_CSIPHY_LNCK_MISC1_ADDR 0x128
-#define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR 0x1E0
-#define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR 0x1E8
-#define MIPI_CSIPHY_T_WAKEUP_CFG1_ADDR 0x1EC
-#define MIPI_CSIPHY_GLBL_RESET_ADDR 0x0140
-#define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR 0x0144
-#define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR 0x0180
-#define MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR 0x0184
-#define MIPI_CSIPHY_INTERRUPT_STATUS2_ADDR 0x0188
-#define MIPI_CSIPHY_INTERRUPT_STATUS3_ADDR 0x018C
-#define MIPI_CSIPHY_INTERRUPT_STATUS4_ADDR 0x0190
-#define MIPI_CSIPHY_INTERRUPT_MASK0_ADDR 0x01A0
-#define MIPI_CSIPHY_INTERRUPT_MASK1_ADDR 0x01A4
-#define MIPI_CSIPHY_INTERRUPT_MASK2_ADDR 0x01A8
-#define MIPI_CSIPHY_INTERRUPT_MASK3_ADDR 0x01AC
-#define MIPI_CSIPHY_INTERRUPT_MASK4_ADDR 0x01B0
-#define MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR 0x01C0
-#define MIPI_CSIPHY_INTERRUPT_CLEAR1_ADDR 0x01C4
-#define MIPI_CSIPHY_INTERRUPT_CLEAR2_ADDR 0x01C8
-#define MIPI_CSIPHY_INTERRUPT_CLEAR3_ADDR 0x01CC
-#define MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR 0x01D0
+#define CSIPHY_VERSION_V3 0x10
int msm_csiphy_config(struct csiphy_cfg_params *cfg_params)
{
int rc = 0;
int j = 0;
uint32_t val = 0;
- uint8_t lane_cnt = 0, lane_mask = 0;
+ uint8_t lane_cnt = 0;
+ uint16_t lane_mask = 0;
struct csiphy_device *csiphy_dev;
struct msm_camera_csiphy_params *csiphy_params;
void __iomem *csiphybase;
@@ -73,7 +43,8 @@
return -ENOMEM;
csiphy_params = cfg_params->parms;
- lane_mask = csiphy_params->lane_mask;
+ csiphy_dev->lane_mask[csiphy_dev->pdev->id] |= csiphy_params->lane_mask;
+ lane_mask = csiphy_dev->lane_mask[csiphy_dev->pdev->id];
lane_cnt = csiphy_params->lane_cnt;
if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) {
CDBG("%s: unsupported lane cnt %d\n",
@@ -81,13 +52,30 @@
return rc;
}
- val = 0x3;
- msm_camera_io_w((csiphy_params->lane_mask << 2) | val,
- csiphybase + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
msm_camera_io_w(0x1, csiphybase + MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR);
msm_camera_io_w(0x1, csiphybase + MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR);
- while (lane_mask & 0xf) {
+ if (csiphy_dev->hw_version != CSIPHY_VERSION_V3) {
+ val = 0x3;
+ msm_camera_io_w((lane_mask << 2) | val,
+ csiphybase + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
+ msm_camera_io_w(0x10, csiphybase + MIPI_CSIPHY_LNCK_CFG2_ADDR);
+ msm_camera_io_w(csiphy_params->settle_cnt,
+ csiphybase + MIPI_CSIPHY_LNCK_CFG3_ADDR);
+ msm_camera_io_w(0x24,
+ csiphybase + MIPI_CSIPHY_INTERRUPT_MASK0_ADDR);
+ msm_camera_io_w(0x24,
+ csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR);
+ } else {
+ val = 0x1;
+ msm_camera_io_w((lane_mask << 1) | val,
+ csiphybase + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
+ msm_camera_io_w(csiphy_params->combo_mode <<
+ MIPI_CSIPHY_MODE_CONFIG_SHIFT,
+ csiphybase + MIPI_CSIPHY_GLBL_RESET_ADDR);
+ }
+
+ while (lane_mask & 0x1f) {
if (!(lane_mask & 0x1)) {
j++;
lane_mask >>= 1;
@@ -97,66 +85,33 @@
csiphybase + MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*j);
msm_camera_io_w(csiphy_params->settle_cnt,
csiphybase + MIPI_CSIPHY_LNn_CFG3_ADDR + 0x40*j);
- msm_camera_io_w(0x6F,
- csiphybase + MIPI_CSIPHY_INTERRUPT_MASK0_ADDR +
- 0x4*(j+1));
- msm_camera_io_w(0x6F,
- csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR +
- 0x4*(j+1));
+ msm_camera_io_w(MIPI_CSIPHY_INTERRUPT_MASK_VAL, csiphybase +
+ MIPI_CSIPHY_INTERRUPT_MASK_ADDR + 0x4*j);
+ msm_camera_io_w(MIPI_CSIPHY_INTERRUPT_MASK_VAL, csiphybase +
+ MIPI_CSIPHY_INTERRUPT_CLEAR_ADDR + 0x4*j);
j++;
lane_mask >>= 1;
}
- msm_camera_io_w(0x10, csiphybase + MIPI_CSIPHY_LNCK_CFG2_ADDR);
- msm_camera_io_w(csiphy_params->settle_cnt,
- csiphybase + MIPI_CSIPHY_LNCK_CFG3_ADDR);
-
- msm_camera_io_w(0x24,
- csiphybase + MIPI_CSIPHY_INTERRUPT_MASK0_ADDR);
- msm_camera_io_w(0x24,
- csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR);
return rc;
}
static irqreturn_t msm_csiphy_irq(int irq_num, void *data)
{
uint32_t irq;
+ int i;
struct csiphy_device *csiphy_dev = data;
- irq = msm_camera_io_r(
- csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR);
- msm_camera_io_w(irq,
- csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR);
- CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS0 = 0x%x\n",
- __func__, csiphy_dev->pdev->id, irq);
-
- irq = msm_camera_io_r(
- csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR);
- msm_camera_io_w(irq,
- csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR1_ADDR);
- CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS1 = 0x%x\n",
- __func__, csiphy_dev->pdev->id, irq);
-
- irq = msm_camera_io_r(
- csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS2_ADDR);
- msm_camera_io_w(irq,
- csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR2_ADDR);
- CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS2 = 0x%x\n",
- __func__, csiphy_dev->pdev->id, irq);
-
- irq = msm_camera_io_r(
- csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS3_ADDR);
- msm_camera_io_w(irq,
- csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR3_ADDR);
- CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS3 = 0x%x\n",
- __func__, csiphy_dev->pdev->id, irq);
-
- irq = msm_camera_io_r(
- csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS4_ADDR);
- msm_camera_io_w(irq,
- csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR);
- CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS4 = 0x%x\n",
- __func__, csiphy_dev->pdev->id, irq);
+ for (i = 0; i < 5; i++) {
+ irq = msm_camera_io_r(
+ csiphy_dev->base +
+ MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR + 0x4*i);
+ msm_camera_io_w(irq,
+ csiphy_dev->base +
+ MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR + 0x4*i);
+ CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS%d = 0x%x\n",
+ __func__, csiphy_dev->pdev->id, i, irq);
+ }
msm_camera_io_w(0x1, csiphy_dev->base + 0x164);
msm_camera_io_w(0x0, csiphy_dev->base + 0x164);
return IRQ_HANDLED;
@@ -193,9 +148,16 @@
return rc;
}
+ if (csiphy_dev->ref_count++) {
+ CDBG("%s csiphy refcount = %d\n", __func__,
+ csiphy_dev->ref_count);
+ return rc;
+ }
+
csiphy_dev->base = ioremap(csiphy_dev->mem->start,
resource_size(csiphy_dev->mem));
if (!csiphy_dev->base) {
+ csiphy_dev->ref_count--;
rc = -ENOMEM;
return rc;
}
@@ -204,6 +166,7 @@
csiphy_dev->csiphy_clk, ARRAY_SIZE(csiphy_clk_info), 1);
if (rc < 0) {
+ csiphy_dev->ref_count--;
iounmap(csiphy_dev->base);
csiphy_dev->base = NULL;
return rc;
@@ -214,17 +177,51 @@
#endif
msm_csiphy_reset(csiphy_dev);
+ csiphy_dev->hw_version =
+ msm_camera_io_r(csiphy_dev->base + MIPI_CSIPHY_HW_VERSION_ADDR);
+
return 0;
}
-static int msm_csiphy_release(struct v4l2_subdev *sd)
+static int msm_csiphy_release(struct v4l2_subdev *sd, void *arg)
{
struct csiphy_device *csiphy_dev;
- int i;
+ int i = 0;
+ struct msm_camera_csi_lane_params *csi_lane_params;
+ uint16_t csi_lane_mask;
csiphy_dev = v4l2_get_subdevdata(sd);
- for (i = 0; i < 4; i++)
- msm_camera_io_w(0x0, csiphy_dev->base +
- MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
+ csi_lane_params = (struct msm_camera_csi_lane_params *)arg;
+ csi_lane_mask = csi_lane_params->csi_lane_mask;
+
+ if (!csiphy_dev || !csiphy_dev->ref_count) {
+ pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__);
+ return 0;
+ }
+
+ if (csiphy_dev->hw_version != CSIPHY_VERSION_V3) {
+ csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0;
+ for (i = 0; i < 4; i++)
+ msm_camera_io_w(0x0, csiphy_dev->base +
+ MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
+ } else {
+ csiphy_dev->lane_mask[csiphy_dev->pdev->id] &=
+ ~(csi_lane_params->csi_lane_mask);
+ i = 0;
+ while (csi_lane_mask & 0x1F) {
+ if (csi_lane_mask & 0x1) {
+ msm_camera_io_w(0x0, csiphy_dev->base +
+ MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
+ }
+ csi_lane_mask >>= 1;
+ i++;
+ }
+ }
+
+ if (--csiphy_dev->ref_count) {
+ CDBG("%s csiphy refcount = %d\n", __func__,
+ csiphy_dev->ref_count);
+ return 0;
+ }
msm_camera_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_LNCK_CFG2_ADDR);
msm_camera_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
@@ -258,7 +255,7 @@
rc = msm_csiphy_init(sd);
break;
case VIDIOC_MSM_CSIPHY_RELEASE:
- rc = msm_csiphy_release(sd);
+ rc = msm_csiphy_release(sd, arg);
break;
default:
pr_err("%s: command not found\n", __func__);
@@ -301,6 +298,10 @@
mutex_init(&new_csiphy_dev->mutex);
+ if (pdev->dev.of_node)
+ of_property_read_u32((&pdev->dev)->of_node,
+ "cell-index", &pdev->id);
+
new_csiphy_dev->mem = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "csiphy");
if (!new_csiphy_dev->mem) {
@@ -340,6 +341,13 @@
sd_info.irq_num = new_csiphy_dev->irq->start;
msm_cam_register_subdev_node(
&new_csiphy_dev->subdev, &sd_info);
+
+ media_entity_init(&new_csiphy_dev->subdev.entity, 0, NULL, 0);
+ new_csiphy_dev->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ new_csiphy_dev->subdev.entity.group_id = CSIPHY_DEV;
+ new_csiphy_dev->subdev.entity.name = pdev->name;
+ new_csiphy_dev->subdev.entity.revision =
+ new_csiphy_dev->subdev.devnode->num;
return 0;
csiphy_no_resource:
@@ -348,11 +356,19 @@
return 0;
}
+static const struct of_device_id msm_csiphy_dt_match[] = {
+ {.compatible = "qcom,csiphy"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_csiphy_dt_match);
+
static struct platform_driver csiphy_driver = {
.probe = csiphy_probe,
.driver = {
.name = MSM_CSIPHY_DRV_NAME,
.owner = THIS_MODULE,
+ .of_match_table = msm_csiphy_dt_match,
},
};
diff --git a/drivers/media/video/msm/csi/msm_csiphy.h b/drivers/media/video/msm/csi/msm_csiphy.h
index 522a1c1..1fab9c1 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.h
+++ b/drivers/media/video/msm/csi/msm_csiphy.h
@@ -17,6 +17,8 @@
#include <linux/io.h>
#include <media/v4l2-subdev.h>
+#define MAX_CSIPHY 3
+
struct csiphy_device {
struct platform_device *pdev;
struct v4l2_subdev subdev;
@@ -25,8 +27,11 @@
struct resource *io;
void __iomem *base;
struct mutex mutex;
+ uint32_t hw_version;
struct clk *csiphy_clk[2];
+ uint8_t ref_count;
+ uint16_t lane_mask[MAX_CSIPHY];
};
struct csiphy_cfg_params {
@@ -35,12 +40,12 @@
};
#define VIDIOC_MSM_CSIPHY_CFG \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct csiphy_cfg_params)
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 7, void *)
#define VIDIOC_MSM_CSIPHY_INIT \
_IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct v4l2_subdev*)
#define VIDIOC_MSM_CSIPHY_RELEASE \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct v4l2_subdev*)
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 9, void *)
#endif
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index 0f16bbf..1494644 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -517,7 +517,6 @@
if (rc < 0)
return rc;
}
-
rc = msm_ispif_reset();
return rc;
}
@@ -693,6 +692,12 @@
sd_info.sd_index = pdev->id;
sd_info.irq_num = ispif->irq->start;
msm_cam_register_subdev_node(&ispif->subdev, &sd_info);
+
+ media_entity_init(&ispif->subdev.entity, 0, NULL, 0);
+ ispif->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ ispif->subdev.entity.group_id = ISPIF_DEV;
+ ispif->subdev.entity.name = pdev->name;
+ ispif->subdev.entity.revision = ispif->subdev.devnode->num;
return 0;
ispif_no_mem:
diff --git a/drivers/media/video/msm/gemini/msm_gemini_sync.c b/drivers/media/video/msm/gemini/msm_gemini_sync.c
index ae3de13..e878329 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_sync.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_sync.c
@@ -485,10 +485,12 @@
} else {
buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd,
buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
- &buf_p->handle) + buf_cmd.offset;
+ &buf_p->handle) + buf_cmd.offset + buf_cmd.y_off;
}
buf_p->y_len = buf_cmd.y_len;
- buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len;
+
+ buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len +
+ buf_cmd.cbcr_off;
buf_p->cbcr_len = buf_cmd.cbcr_len;
buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
GMN_DBG("%s: y_addr=%x,y_len=%x,cbcr_addr=%x,cbcr_len=%x\n", __func__,
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.h b/drivers/media/video/msm/io/msm_camera_i2c.h
index a0cdd77..188a176 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.h
+++ b/drivers/media/video/msm/io/msm_camera_i2c.h
@@ -53,9 +53,9 @@
struct msm_camera_i2c_reg_conf {
uint16_t reg_addr;
uint16_t reg_data;
- int16_t mask;
enum msm_camera_i2c_data_type dt;
enum msm_camera_i2c_cmd_type cmd_type;
+ int16_t mask;
};
struct msm_camera_i2c_reg_tbl {
diff --git a/drivers/media/video/msm/io/msm_io_8960.c b/drivers/media/video/msm/io/msm_io_8960.c
index f9c454a..699425a 100644
--- a/drivers/media/video/msm/io/msm_io_8960.c
+++ b/drivers/media/video/msm/io/msm_io_8960.c
@@ -87,6 +87,14 @@
} else
CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
break;
+ case S_LIVESHOT:
+ if (bus_perf_client) {
+ rc = msm_bus_scale_client_update_request(
+ bus_perf_client, 5);
+ CDBG("%s: S_LIVESHOT rc = %d\n", __func__, rc);
+ } else
+ CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
case S_DEFAULT:
break;
default:
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index b67af4f..3222f905 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -92,6 +92,33 @@
return rc;
}
+static int msm_camera_v4l2_private_g_ctrl(struct file *f, void *pctx,
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+ int rc = -EINVAL;
+ struct msm_cam_v4l2_device *pcam = video_drvdata(f);
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
+
+ WARN_ON(pctx != f->private_data);
+
+ mutex_lock(&pcam->vid_lock);
+ switch (ioctl_ptr->id) {
+ case MSM_V4L2_PID_INST_HANDLE:
+ COPY_TO_USER(rc, (void __user *)ioctl_ptr->ioctl_ptr,
+ (void *)&pcam_inst->inst_handle, sizeof(uint32_t));
+ if (rc)
+ ERR_COPY_TO_USER();
+ break;
+ default:
+ pr_err("%s Unsupported ioctl %d ", __func__, ioctl_ptr->id);
+ break;
+ }
+ mutex_unlock(&pcam->vid_lock);
+ return rc;
+}
+
static int msm_camera_v4l2_g_ctrl(struct file *f, void *pctx,
struct v4l2_control *c)
{
@@ -686,7 +713,9 @@
struct msm_cam_v4l2_dev_inst *pcam_inst;
pcam_inst = container_of(f->private_data,
struct msm_cam_v4l2_dev_inst, eventHandle);
- pcam_inst->image_mode = a->parm.capture.extendedmode;
+ pcam_inst->image_mode = (a->parm.capture.extendedmode & 0x7F);
+ SET_IMG_MODE(pcam_inst->inst_handle, pcam_inst->image_mode);
+ SET_VIDEO_INST_IDX(pcam_inst->inst_handle, pcam_inst->my_index);
pcam_inst->pcam->dev_inst_map[pcam_inst->image_mode] = pcam_inst;
pcam_inst->path = msm_vidbuf_get_path(pcam_inst->image_mode);
D("%spath=%d,rc=%d\n", __func__,
@@ -745,6 +774,12 @@
case MSM_CAM_V4L2_IOCTL_PRIVATE_S_CTRL:
rc = msm_camera_v4l2_private_s_ctrl(file, fh, ioctl_ptr);
break;
+ case MSM_CAM_V4L2_IOCTL_PRIVATE_G_CTRL:
+ rc = msm_camera_v4l2_private_g_ctrl(file, fh, ioctl_ptr);
+ break;
+ default:
+ pr_err("%s Unsupported ioctl cmd %d ", __func__, cmd);
+ break;
}
return rc;
}
@@ -876,13 +911,8 @@
}
pmctl->pcam_ptr = pcam;
- rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
+ msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
pcam->pvdev);
- if (rc < 0) {
- pr_err("%s: msm_setup_v4l2_event_queue failed %d",
- __func__, rc);
- goto mctl_event_q_setup_failed;
- }
}
pcam_inst->vbqueue_initialized = 0;
rc = 0;
@@ -905,9 +935,8 @@
return rc;
msm_send_open_server_failed:
- v4l2_fh_del(&pcam_inst->eventHandle);
- v4l2_fh_exit(&pcam_inst->eventHandle);
-mctl_event_q_setup_failed:
+ msm_destroy_v4l2_event_queue(&pcam_inst->eventHandle);
+
if (pmctl->mctl_release)
if (pmctl->mctl_release(pmctl) < 0)
pr_err("%s: mctl_release failed\n", __func__);
@@ -1051,10 +1080,11 @@
D("%s index %d nodeid %d count %d\n", __func__, pcam_inst->my_index,
pcam->vnode_id, pcam->use_count);
pcam->dev_inst[pcam_inst->my_index] = NULL;
- if (pcam_inst->my_index == 0) {
- v4l2_fh_del(&pcam_inst->eventHandle);
- v4l2_fh_exit(&pcam_inst->eventHandle);
- }
+ if (pcam_inst->my_index == 0)
+ msm_destroy_v4l2_event_queue(&pcam_inst->eventHandle);
+
+ CLR_VIDEO_INST_IDX(pcam_inst->inst_handle);
+ CLR_IMG_MODE(pcam_inst->inst_handle);
mutex_unlock(&pcam_inst->inst_lock);
mutex_destroy(&pcam_inst->inst_lock);
kfree(pcam_inst);
@@ -1137,18 +1167,6 @@
return 0;
}
-int msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle,
- struct video_device *pvdev)
-{
- int rc = 0;
- /* v4l2_fh support */
- spin_lock_init(&pvdev->fh_lock);
- INIT_LIST_HEAD(&pvdev->fh_list);
-
- v4l2_fh_init(eventHandle, pvdev);
- v4l2_fh_add(eventHandle);
- return rc;
-}
static struct v4l2_file_operations g_msm_fops = {
.owner = THIS_MODULE,
@@ -1201,7 +1219,7 @@
pvdev->fops = &g_msm_fops;
pvdev->ioctl_ops = &g_msm_ioctl_ops;
pvdev->minor = -1;
- pvdev->vfl_type = 1;
+ pvdev->vfl_type = VFL_TYPE_GRABBER;
media_entity_init(&pvdev->entity, 0, NULL, 0);
pvdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 08278ff..d77defd 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -61,6 +61,7 @@
#define MSM_IRQ_ROUTER_DRV_NAME "msm_cam_irq_router"
#define MSM_CPP_DRV_NAME "msm_cpp"
+#define MAX_NUM_SENSOR_DEV 3
#define MAX_NUM_CSIPHY_DEV 3
#define MAX_NUM_CSID_DEV 4
#define MAX_NUM_CSIC_DEV 3
@@ -71,22 +72,6 @@
#define MAX_NUM_JPEG_DEV 3
#define MAX_NUM_CPP_DEV 1
-enum msm_cam_subdev_type {
- CSIPHY_DEV,
- CSID_DEV,
- CSIC_DEV,
- ISPIF_DEV,
- VFE_DEV,
- AXI_DEV,
- VPE_DEV,
- SENSOR_DEV,
- ACTUATOR_DEV,
- EEPROM_DEV,
- GESTURE_DEV,
- IRQ_ROUTER_DEV,
- CPP_DEV,
-};
-
/* msm queue management APIs*/
#define msm_dequeue(queue, member) ({ \
@@ -137,7 +122,7 @@
struct msm_free_buf {
uint8_t num_planes;
- int32_t image_mode;
+ uint32_t inst_handle;
uint32_t ch_paddr[VIDEO_MAX_PLANES];
uint32_t vb;
};
@@ -315,7 +300,6 @@
/* vfe subdevice */
struct v4l2_subdev *sd;
- struct v4l2_subdev *sd_vpe;
};
struct msm_isp_buf_info {
@@ -339,7 +323,7 @@
enum v4l2_mbus_pixelcode sensor_pxlcode;
struct msm_cam_v4l2_device *pcam;
int my_index;
- int image_mode;
+ uint32_t image_mode;
int path;
int buf_count;
/* buffer offsets, if any */
@@ -351,6 +335,7 @@
struct img_plane_info plane_info;
int vbqueue_initialized;
struct mutex inst_lock;
+ uint32_t inst_handle;
};
struct msm_cam_mctl_node {
@@ -540,10 +525,11 @@
struct mutex server_lock;
struct mutex server_queue_lock;
/*v4l2 subdevs*/
+ struct v4l2_subdev *sensor_device[MAX_NUM_SENSOR_DEV];
struct v4l2_subdev *csiphy_device[MAX_NUM_CSIPHY_DEV];
struct v4l2_subdev *csid_device[MAX_NUM_CSID_DEV];
struct v4l2_subdev *csic_device[MAX_NUM_CSIC_DEV];
- struct v4l2_subdev *ispif_device;
+ struct v4l2_subdev *ispif_device[MAX_NUM_ISPIF_DEV];
struct v4l2_subdev *vfe_device[MAX_NUM_VFE_DEV];
struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];
struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];
@@ -562,6 +548,18 @@
struct msm_cam_server_irqmap_entry hw_irqmap[CAMERA_SS_IRQ_MAX];
};
+enum msm_cam_buf_lookup_type {
+ BUF_LOOKUP_INVALID,
+ BUF_LOOKUP_BY_IMG_MODE,
+ BUF_LOOKUP_BY_INST_HANDLE,
+};
+
+struct msm_cam_buf_handle {
+ uint16_t buf_lookup_type;
+ uint32_t image_mode;
+ uint32_t inst_handle;
+};
+
/* ISP related functions */
void msm_isp_vfe_dev_init(struct v4l2_subdev *vd);
/*
@@ -577,78 +575,69 @@
int msm_mctl_buf_init(struct msm_cam_v4l2_device *pcam);
int msm_mctl_init_user_formats(struct msm_cam_v4l2_device *pcam);
int msm_mctl_buf_done(struct msm_cam_media_controller *pmctl,
- int msg_type, struct msm_free_buf *buf,
- uint32_t frame_id);
+ struct msm_cam_buf_handle *buf_handle,
+ struct msm_free_buf *buf,
+ uint32_t frame_id);
int msm_mctl_buf_done_pp(struct msm_cam_media_controller *pmctl,
- int msg_type, struct msm_free_buf *frame, int dirty, int node_type);
+ struct msm_cam_buf_handle *buf_handle,
+ struct msm_free_buf *frame, int dirty, int node_type);
int msm_mctl_reserve_free_buf(struct msm_cam_media_controller *pmctl,
- struct msm_cam_v4l2_dev_inst *pcam_inst,
- int path, struct msm_free_buf *free_buf);
+ struct msm_cam_v4l2_dev_inst *pcam_inst,
+ struct msm_cam_buf_handle *buf_handle,
+ struct msm_free_buf *free_buf);
int msm_mctl_release_free_buf(struct msm_cam_media_controller *pmctl,
- struct msm_cam_v4l2_dev_inst *pcam_inst,
- int path, struct msm_free_buf *free_buf);
+ struct msm_cam_v4l2_dev_inst *pcam_inst,
+ struct msm_free_buf *free_buf);
/*Memory(PMEM) functions*/
int msm_register_pmem(struct hlist_head *ptype, void __user *arg,
- struct ion_client *client);
+ struct ion_client *client);
int msm_pmem_table_del(struct hlist_head *ptype, void __user *arg,
- struct ion_client *client);
+ struct ion_client *client);
int msm_pmem_region_get_phy_addr(struct hlist_head *ptype,
struct msm_mem_map_info *mem_map, int32_t *phyaddr);
uint8_t msm_pmem_region_lookup(struct hlist_head *ptype,
int pmem_type, struct msm_pmem_region *reg, uint8_t maxcount);
uint8_t msm_pmem_region_lookup_2(struct hlist_head *ptype,
- int pmem_type,
- struct msm_pmem_region *reg,
- uint8_t maxcount);
+ int pmem_type, struct msm_pmem_region *reg,
+ uint8_t maxcount);
unsigned long msm_pmem_stats_vtop_lookup(
- struct msm_cam_media_controller *mctl,
- unsigned long buffer,
- int fd);
+ struct msm_cam_media_controller *mctl,
+ unsigned long buffer, int fd);
unsigned long msm_pmem_stats_ptov_lookup(
struct msm_cam_media_controller *mctl,
unsigned long addr, int *fd);
-int msm_vfe_subdev_init(struct v4l2_subdev *sd,
- struct msm_cam_media_controller *mctl);
+int msm_vfe_subdev_init(struct v4l2_subdev *sd);
void msm_vfe_subdev_release(struct v4l2_subdev *sd);
int msm_isp_subdev_ioctl(struct v4l2_subdev *sd,
struct msm_vfe_cfg_cmd *cfgcmd, void *data);
-int msm_vpe_subdev_init(struct v4l2_subdev *sd,
- struct msm_cam_media_controller *mctl);
+int msm_vpe_subdev_init(struct v4l2_subdev *sd);
int msm_gemini_subdev_init(struct v4l2_subdev *gemini_sd);
void msm_vpe_subdev_release(void);
void msm_gemini_subdev_release(struct v4l2_subdev *gemini_sd);
int msm_mctl_is_pp_msg_type(struct msm_cam_media_controller *p_mctl,
int msg_type);
int msm_mctl_do_pp(struct msm_cam_media_controller *p_mctl,
- int msg_type, uint32_t y_phy, uint32_t frame_id);
+ int msg_type, uint32_t y_phy, uint32_t frame_id);
int msm_mctl_pp_ioctl(struct msm_cam_media_controller *p_mctl,
- unsigned int cmd, unsigned long arg);
+ unsigned int cmd, unsigned long arg);
int msm_mctl_pp_notify(struct msm_cam_media_controller *pmctl,
- struct msm_mctl_pp_frame_info *pp_frame_info);
+ struct msm_mctl_pp_frame_info *pp_frame_info);
int msm_mctl_img_mode_to_inst_index(struct msm_cam_media_controller *pmctl,
- int out_type, int node_type);
+ int out_type, int node_type);
struct msm_frame_buffer *msm_mctl_buf_find(
struct msm_cam_media_controller *pmctl,
struct msm_cam_v4l2_dev_inst *pcam_inst, int del_buf,
- int msg_type, struct msm_free_buf *fbuf);
+ struct msm_free_buf *fbuf);
void msm_mctl_gettimeofday(struct timeval *tv);
-struct msm_frame_buffer *msm_mctl_get_free_buf(
- struct msm_cam_media_controller *pmctl,
- int msg_type);
-int msm_mctl_put_free_buf(
- struct msm_cam_media_controller *pmctl,
- int msg_type, struct msm_frame_buffer *buf);
int msm_mctl_check_pp(struct msm_cam_media_controller *p_mctl,
- int msg_type, int *pp_divert_type, int *pp_type);
+ int msg_type, int *pp_divert_type, int *pp_type);
int msm_mctl_do_pp_divert(
struct msm_cam_media_controller *p_mctl,
- int msg_type, struct msm_free_buf *fbuf,
+ struct msm_cam_buf_handle *buf_handle,
+ struct msm_free_buf *fbuf,
uint32_t frame_id, int pp_type);
-int msm_mctl_buf_del(struct msm_cam_media_controller *pmctl,
- int msg_type,
- struct msm_frame_buffer *my_buf);
int msm_mctl_pp_release_free_frame(
struct msm_cam_media_controller *p_mctl,
void __user *arg);
@@ -656,26 +645,29 @@
struct msm_cam_media_controller *p_mctl,
void __user *arg);
int msm_mctl_set_pp_key(struct msm_cam_media_controller *p_mctl,
- void __user *arg);
+ void __user *arg);
int msm_mctl_pp_done(
struct msm_cam_media_controller *p_mctl,
void __user *arg);
int msm_mctl_pp_divert_done(
struct msm_cam_media_controller *p_mctl,
void __user *arg);
-int msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle,
- struct video_device *pvdev);
+void msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle,
+ struct video_device *pvdev);
+void msm_destroy_v4l2_event_queue(struct v4l2_fh *eventHandle);
int msm_setup_mctl_node(struct msm_cam_v4l2_device *pcam);
struct msm_cam_v4l2_dev_inst *msm_mctl_get_pcam_inst(
- struct msm_cam_media_controller *pmctl,
- int image_mode);
+ struct msm_cam_media_controller *pmctl,
+ struct msm_cam_buf_handle *buf_handle);
int msm_mctl_buf_return_buf(struct msm_cam_media_controller *pmctl,
- int image_mode, struct msm_frame_buffer *buf);
+ int image_mode, struct msm_frame_buffer *buf);
int msm_mctl_pp_mctl_divert_done(struct msm_cam_media_controller *p_mctl,
- void __user *arg);
+ void __user *arg);
void msm_release_ion_client(struct kref *ref);
int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
struct msm_cam_subdev_info *sd_info);
+int msm_mctl_find_sensor_subdevs(struct msm_cam_media_controller *p_mctl,
+ int core_index);
int msm_server_open_client(int *p_qidx);
int msm_server_send_ctrl(struct msm_ctrl_cmd *out, int ctrl_id);
int msm_server_close_client(int idx);
@@ -683,7 +675,7 @@
int *p_active);
int msm_cam_server_close_mctl_session(struct msm_cam_v4l2_device *pcam);
long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl,
- unsigned int cmd, unsigned long evt);
+ unsigned int cmd, unsigned long evt);
int msm_mctl_pp_get_vpe_buf_info(struct msm_mctl_pp_frame_info *zoom);
void msm_queue_init(struct msm_device_queue *queue, const char *name);
void msm_enqueue(struct msm_device_queue *queue, struct list_head *entry);
diff --git a/drivers/media/video/msm/msm_camirq_router.c b/drivers/media/video/msm/msm_camirq_router.c
index 52dd175..25a561f 100644
--- a/drivers/media/video/msm/msm_camirq_router.c
+++ b/drivers/media/video/msm/msm_camirq_router.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
#include <mach/irqs.h>
#include <media/msm_isp.h>
#include <media/v4l2-device.h>
@@ -207,6 +208,10 @@
v4l2_set_subdevdata(&irqrouter_ctrl->subdev, irqrouter_ctrl);
irqrouter_ctrl->pdev = pdev;
+ if (pdev->dev.of_node)
+ of_property_read_u32((&pdev->dev)->of_node,
+ "cell-index", &pdev->id);
+
msm_irqrouter_send_default_irqmap(irqrouter_ctrl);
media_entity_init(&irqrouter_ctrl->subdev.entity, 0, NULL, 0);
@@ -237,16 +242,27 @@
static int __exit irqrouter_exit(struct platform_device *pdev)
{
+ struct v4l2_subdev *subdev = dev_get_drvdata(&pdev->dev);
+ struct irqrouter_ctrl_type *irqrouter_ctrl =
+ v4l2_get_subdevdata(subdev);
kfree(irqrouter_ctrl);
return 0;
}
+static const struct of_device_id msm_irqrouter_dt_match[] = {
+ {.compatible = "qcom,irqrouter"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_irqrouter_dt_match);
+
static struct platform_driver msm_irqrouter_driver = {
.probe = irqrouter_probe,
.remove = irqrouter_exit,
.driver = {
.name = MSM_IRQ_ROUTER_DRV_NAME,
.owner = THIS_MODULE,
+ .of_match_table = msm_irqrouter_dt_match,
},
};
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 5fcb62b..67e7c02 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -168,7 +168,9 @@
struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
struct msm_frame_info *frame_info =
(struct msm_frame_info *)vdata->evt_msg.data;
- uint32_t vfe_id, image_mode;
+ uint32_t vfe_id;
+ struct msm_cam_buf_handle buf_handle;
+
if (!pcam) {
pr_debug("%s pcam is null. return\n", __func__);
msm_isp_sync_free(vdata);
@@ -176,10 +178,13 @@
}
if (frame_info) {
vfe_id = frame_info->path;
- image_mode = frame_info->image_mode;
+ buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE;
+ buf_handle.inst_handle = frame_info->inst_handle;
} else {
vfe_id = vdata->evt_msg.msg_id;
- image_mode = msm_isp_vfe_msg_to_img_mode(pmctl, vfe_id);
+ buf_handle.buf_lookup_type = BUF_LOOKUP_BY_IMG_MODE;
+ buf_handle.image_mode =
+ msm_isp_vfe_msg_to_img_mode(pmctl, vfe_id);
}
switch (vdata->type) {
@@ -189,14 +194,14 @@
D("%s Got V32_START_*: Getting ping addr id = %d",
__func__, vfe_id);
msm_mctl_reserve_free_buf(pmctl, NULL,
- image_mode, &free_buf);
+ &buf_handle, &free_buf);
cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR;
cfgcmd.value = &vfe_id;
vfe_params.vfe_cfg = &cfgcmd;
vfe_params.data = (void *)&free_buf;
rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
msm_mctl_reserve_free_buf(pmctl, NULL,
- image_mode, &free_buf);
+ &buf_handle, &free_buf);
cfgcmd.cmd_type = CMD_CONFIG_PONG_ADDR;
cfgcmd.value = &vfe_id;
vfe_params.vfe_cfg = &cfgcmd;
@@ -208,7 +213,7 @@
pr_debug("%s Got V32_CAPTURE: getting buffer for id = %d",
__func__, vfe_id);
msm_mctl_reserve_free_buf(pmctl, NULL,
- image_mode, &free_buf);
+ &buf_handle, &free_buf);
cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR;
cfgcmd.value = &vfe_id;
vfe_params.vfe_cfg = &cfgcmd;
@@ -216,7 +221,7 @@
rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
temp_free_buf = free_buf;
if (msm_mctl_reserve_free_buf(pmctl, NULL,
- image_mode, &free_buf)) {
+ &buf_handle, &free_buf)) {
/* Write the same buffer into PONG */
free_buf = temp_free_buf;
}
@@ -254,7 +259,7 @@
D("%s Got OUTPUT_IRQ: Getting free buf id = %d",
__func__, vfe_id);
msm_mctl_reserve_free_buf(pmctl, NULL,
- image_mode, &free_buf);
+ &buf_handle, &free_buf);
cfgcmd.cmd_type = CMD_CONFIG_FREE_BUF_ADDR;
cfgcmd.value = &vfe_id;
vfe_params.vfe_cfg = &cfgcmd;
@@ -320,10 +325,10 @@
}
case NOTIFY_VFE_MSG_OUT: {
uint8_t msgid;
- int32_t image_mode = -1;
+ struct msm_cam_buf_handle buf_handle;
struct isp_msg_output *isp_output =
(struct isp_msg_output *)arg;
- if (isp_output->buf.image_mode < 0) {
+ if (!isp_output->buf.inst_handle) {
switch (isp_output->output_id) {
case MSG_ID_OUTPUT_P:
msgid = VFE_MSG_OUTPUT_P;
@@ -356,19 +361,22 @@
rc = -EINVAL;
break;
}
- if (!rc)
- image_mode =
+ if (!rc) {
+ buf_handle.buf_lookup_type =
+ BUF_LOOKUP_BY_IMG_MODE;
+ buf_handle.image_mode =
msm_isp_vfe_msg_to_img_mode(pmctl, msgid);
+ }
} else {
- image_mode = isp_output->buf.image_mode;
+ buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE;
+ buf_handle.inst_handle = isp_output->buf.inst_handle;
}
isp_event->isp_data.isp_msg.msg_id =
isp_output->output_id;
isp_event->isp_data.isp_msg.frame_id =
isp_output->frameCounter;
buf = isp_output->buf;
- BUG_ON(image_mode < 0);
- msm_mctl_buf_done(pmctl, image_mode,
+ msm_mctl_buf_done(pmctl, &buf_handle,
&buf, isp_output->frameCounter);
}
break;
@@ -498,32 +506,8 @@
return -EINVAL;
}
- rc = msm_iommu_map_contig_buffer(
- (unsigned long)IMEM_Y_PING_OFFSET, CAMERA_DOMAIN, GEN_POOL,
- ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
- SZ_4K, IOMMU_WRITE | IOMMU_READ,
- (unsigned long *)&mctl->ping_imem_y);
- mctl->ping_imem_cbcr = mctl->ping_imem_y + IMEM_Y_SIZE;
- if (rc < 0) {
- pr_err("%s: ping iommu mapping returned error %d\n",
- __func__, rc);
- mctl->ping_imem_y = 0;
- mctl->ping_imem_cbcr = 0;
- }
- msm_iommu_map_contig_buffer(
- (unsigned long)IMEM_Y_PONG_OFFSET, CAMERA_DOMAIN, GEN_POOL,
- ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
- SZ_4K, IOMMU_WRITE | IOMMU_READ,
- (unsigned long *)&mctl->pong_imem_y);
- mctl->pong_imem_cbcr = mctl->pong_imem_y + IMEM_Y_SIZE;
- if (rc < 0) {
- pr_err("%s: pong iommu mapping returned error %d\n",
- __func__, rc);
- mctl->pong_imem_y = 0;
- mctl->pong_imem_cbcr = 0;
- }
-
- rc = msm_vfe_subdev_init(sd, mctl);
+ rc = v4l2_subdev_call(sd, core, ioctl,
+ VIDIOC_MSM_VFE_INIT, NULL);
if (rc < 0) {
pr_err("%s: vfe_init failed at %d\n",
__func__, rc);
@@ -535,17 +519,8 @@
struct v4l2_subdev *sd)
{
D("%s\n", __func__);
- msm_vfe_subdev_release(sd);
- msm_iommu_unmap_contig_buffer(mctl->ping_imem_y,
- CAMERA_DOMAIN, GEN_POOL,
- ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
- msm_iommu_unmap_contig_buffer(mctl->pong_imem_y,
- CAMERA_DOMAIN, GEN_POOL,
- ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
- mctl->ping_imem_y = 0;
- mctl->ping_imem_cbcr = 0;
- mctl->pong_imem_y = 0;
- mctl->pong_imem_cbcr = 0;
+ v4l2_subdev_call(sd, core, ioctl,
+ VIDIOC_MSM_VFE_RELEASE, NULL);
}
static int msm_config_vfe(struct v4l2_subdev *sd,
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index be6c543..4bbc47c 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -418,94 +418,6 @@
return rc;
}
-static int msm_mctl_subdev_match_core(struct device *dev, void *data)
-{
- int core_index = (int)data;
- struct platform_device *pdev = to_platform_device(dev);
-
- if (pdev->id == core_index)
- return 1;
- else
- return 0;
-}
-
-static int msm_mctl_register_subdevs(struct msm_cam_media_controller *p_mctl,
- int core_index)
-{
- struct device_driver *driver;
- struct device *dev;
- int rc = -ENODEV;
-
- struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
- struct msm_camera_sensor_info *sinfo =
- (struct msm_camera_sensor_info *) s_ctrl->sensordata;
- struct msm_camera_device_platform_data *pdata = sinfo->pdata;
-
- rc = msm_csi_register_subdevs(p_mctl, core_index,
- msm_mctl_subdev_match_core);
-
- if (rc < 0)
- goto out;
-
- /* register vfe subdev */
- driver = driver_find(MSM_VFE_DRV_NAME, &platform_bus_type);
- if (!driver)
- goto out;
-
- dev = driver_find_device(driver, NULL, 0,
- msm_mctl_subdev_match_core);
- if (!dev)
- goto out;
-
- p_mctl->isp_sdev->sd = dev_get_drvdata(dev);
-
- if (pdata->is_vpe) {
- /* register vfe subdev */
- driver = driver_find(MSM_VPE_DRV_NAME, &platform_bus_type);
- if (!driver)
- goto out;
-
- dev = driver_find_device(driver, NULL, 0,
- msm_mctl_subdev_match_core);
- if (!dev)
- goto out;
-
- p_mctl->vpe_sdev = dev_get_drvdata(dev);
- }
-
- rc = 0;
-
-
- /* register gemini subdev */
- driver = driver_find(MSM_GEMINI_DRV_NAME, &platform_bus_type);
- if (!driver) {
- pr_err("%s:%d:Gemini: Failure: goto out\n",
- __func__, __LINE__);
- goto out;
- }
- pr_debug("%s:%d:Gemini: driver_find_device Gemini driver 0x%x\n",
- __func__, __LINE__, (uint32_t)driver);
- dev = driver_find_device(driver, NULL, NULL,
- msm_mctl_subdev_match_core);
- if (!dev) {
- pr_err("%s:%d:Gemini: Failure goto out\n",
- __func__, __LINE__);
- goto out;
- }
- p_mctl->gemini_sdev = dev_get_drvdata(dev);
- pr_debug("%s:%d:Gemini: After dev_get_drvdata gemini_sdev=0x%x\n",
- __func__, __LINE__, (uint32_t)p_mctl->gemini_sdev);
-
- if (p_mctl->gemini_sdev == NULL) {
- pr_err("%s:%d:Gemini: Failure gemini_sdev is null\n",
- __func__, __LINE__);
- goto out;
- }
- rc = 0;
-out:
- return rc;
-}
-
static int msm_mctl_open(struct msm_cam_media_controller *p_mctl,
const char *const apps_id)
{
@@ -529,9 +441,9 @@
wake_lock(&p_mctl->wake_lock);
csid_core = camdev->csid_core;
- rc = msm_mctl_register_subdevs(p_mctl, csid_core);
+ rc = msm_mctl_find_sensor_subdevs(p_mctl, csid_core);
if (rc < 0) {
- pr_err("%s: msm_mctl_register_subdevs failed:%d\n",
+ pr_err("%s: msm_mctl_find_sensor_subdevs failed:%d\n",
__func__, rc);
goto register_sdev_failed;
}
@@ -592,38 +504,6 @@
goto msm_csi_version;
}
- /* ISP first*/
- if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_open) {
- rc = p_mctl->isp_sdev->isp_open(
- p_mctl->isp_sdev->sd, p_mctl);
- if (rc < 0) {
- pr_err("%s: isp init failed: %d\n",
- __func__, rc);
- goto isp_open_failed;
- }
- }
-
- if (p_mctl->axi_sdev) {
- rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
- VIDIOC_MSM_AXI_INIT, p_mctl);
- if (rc < 0) {
- pr_err("%s: axi initialization failed %d\n",
- __func__, rc);
- goto axi_init_failed;
- }
- }
-
- if (camdev->is_vpe) {
- rc = v4l2_subdev_call(p_mctl->vpe_sdev, core, ioctl,
- VIDIOC_MSM_VPE_INIT, p_mctl);
- if (rc < 0) {
- pr_err("%s: vpe initialization failed %d\n",
- __func__, rc);
- goto vpe_init_failed;
- }
- }
-
-
pm_qos_add_request(&p_mctl->pm_qos_req_list,
PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
pm_qos_update_request(&p_mctl->pm_qos_req_list,
@@ -635,19 +515,9 @@
D("%s: camera is already open", __func__);
}
mutex_unlock(&p_mctl->lock);
-
return rc;
-vpe_init_failed:
- if (p_mctl->axi_sdev)
- if (v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
- VIDIOC_MSM_AXI_RELEASE, NULL) < 0)
- pr_err("%s: axi release failed %d\n", __func__, rc);
-axi_init_failed:
- if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
- p_mctl->isp_sdev->isp_release(p_mctl, p_mctl->isp_sdev->sd);
msm_csi_version:
-isp_open_failed:
if (p_mctl->csic_sdev)
if (v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
VIDIOC_MSM_CSIC_RELEASE, NULL) < 0)
@@ -660,7 +530,8 @@
csid_init_failed:
if (p_mctl->csiphy_sdev)
if (v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
- VIDIOC_MSM_CSIPHY_RELEASE, NULL) < 0)
+ VIDIOC_MSM_CSIPHY_RELEASE,
+ sinfo->sensor_platform_info->csi_lane_params) < 0)
pr_err("%s: csiphy release failed %d\n", __func__, rc);
csiphy_init_failed:
if (p_mctl->act_sdev)
@@ -683,7 +554,6 @@
struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
struct msm_camera_sensor_info *sinfo =
(struct msm_camera_sensor_info *) s_ctrl->sensordata;
- struct msm_camera_device_platform_data *camdev = sinfo->pdata;
v4l2_subdev_call(p_mctl->sensor_sdev, core, ioctl,
VIDIOC_MSM_SENSOR_RELEASE, NULL);
@@ -693,7 +563,7 @@
VIDIOC_MSM_CSIC_RELEASE, NULL);
}
- if (camdev->is_vpe) {
+ if (p_mctl->vpe_sdev) {
v4l2_subdev_call(p_mctl->vpe_sdev, core, ioctl,
VIDIOC_MSM_VPE_RELEASE, NULL);
}
@@ -703,7 +573,8 @@
VIDIOC_MSM_AXI_RELEASE, NULL);
}
- if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
+ if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release
+ && p_mctl->isp_sdev->sd)
p_mctl->isp_sdev->isp_release(p_mctl,
p_mctl->isp_sdev->sd);
@@ -714,7 +585,8 @@
if (p_mctl->csiphy_sdev) {
v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
- VIDIOC_MSM_CSIPHY_RELEASE, NULL);
+ VIDIOC_MSM_CSIPHY_RELEASE,
+ sinfo->sensor_platform_info->csi_lane_params);
}
if (p_mctl->act_sdev) {
@@ -830,6 +702,7 @@
pmctl->eeprom_sdev = pcam->eeprom_sdev;
pmctl->sensor_sdev = pcam->sensor_sdev;
pmctl->sdata = pcam->sdata;
+ v4l2_set_subdev_hostdata(pcam->sensor_sdev, pmctl);
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
pmctl->client = msm_ion_client_create(-1, "camera");
@@ -853,6 +726,8 @@
mutex_destroy(&pmctl->lock);
wake_lock_destroy(&pmctl->wake_lock);
+ /*clear out mctl fields*/
+ memset(pmctl, 0, sizeof(struct msm_cam_media_controller));
msm_cam_server_free_mctl(pcam->mctl_handle);
return rc;
}
@@ -917,12 +792,9 @@
}
D("%s active %d\n", __func__, pcam->mctl_node.active);
- rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
- pcam->mctl_node.pvdev);
- if (rc < 0) {
- mutex_unlock(&pcam->mctl_node.dev_lock);
- return rc;
- }
+ msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
+ pcam->mctl_node.pvdev);
+
pcam_inst->vbqueue_initialized = 0;
kref_get(&pmctl->refcount);
f->private_data = &pcam_inst->eventHandle;
@@ -1005,8 +877,10 @@
vb2_queue_release(&pcam_inst->vid_bufq);
D("%s Closing down instance %p ", __func__, pcam_inst);
pcam->mctl_node.dev_inst[pcam_inst->my_index] = NULL;
- v4l2_fh_del(&pcam_inst->eventHandle);
- v4l2_fh_exit(&pcam_inst->eventHandle);
+ msm_destroy_v4l2_event_queue(&pcam_inst->eventHandle);
+ CLR_MCTLPP_INST_IDX(pcam_inst->inst_handle);
+ CLR_IMG_MODE(pcam_inst->inst_handle);
+
mutex_destroy(&pcam_inst->inst_lock);
kfree(pcam_inst);
@@ -1579,7 +1453,9 @@
struct msm_cam_v4l2_dev_inst *pcam_inst;
pcam_inst = container_of(f->private_data,
struct msm_cam_v4l2_dev_inst, eventHandle);
- pcam_inst->image_mode = a->parm.capture.extendedmode;
+ pcam_inst->image_mode = (a->parm.capture.extendedmode & 0x7F);
+ SET_IMG_MODE(pcam_inst->inst_handle, pcam_inst->image_mode);
+ SET_MCTLPP_INST_IDX(pcam_inst->inst_handle, pcam_inst->my_index);
pcam_inst->pcam->mctl_node.dev_inst_map[pcam_inst->image_mode] =
pcam_inst;
pcam_inst->path = msm_mctl_vidbuf_get_path(pcam_inst->image_mode);
@@ -1624,6 +1500,51 @@
return rc;
}
+static int msm_mctl_v4l2_private_g_ctrl(struct file *f, void *pctx,
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+ int rc = -EINVAL;
+ struct msm_cam_v4l2_device *pcam = video_drvdata(f);
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
+
+ WARN_ON(pctx != f->private_data);
+
+ mutex_lock(&pcam->mctl_node.dev_lock);
+ switch (ioctl_ptr->id) {
+ case MSM_V4L2_PID_INST_HANDLE:
+ COPY_TO_USER(rc, (void __user *)ioctl_ptr->ioctl_ptr,
+ (void *)&pcam_inst->inst_handle, sizeof(uint32_t));
+ if (rc)
+ ERR_COPY_TO_USER();
+ break;
+ default:
+ pr_err("%s Unsupported ioctl %d ", __func__, ioctl_ptr->id);
+ break;
+ }
+ mutex_unlock(&pcam->mctl_node.dev_lock);
+ return rc;
+}
+
+static long msm_mctl_v4l2_private_ioctl(struct file *file, void *fh,
+ bool valid_prio, int cmd, void *arg)
+{
+ int rc = -EINVAL;
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+ D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
+
+ switch (cmd) {
+ case MSM_CAM_V4L2_IOCTL_PRIVATE_G_CTRL:
+ rc = msm_mctl_v4l2_private_g_ctrl(file, fh, ioctl_ptr);
+ break;
+ default:
+ pr_err("%s Unsupported ioctl cmd %d ", __func__, cmd);
+ break;
+ }
+ return rc;
+}
+
/* mctl node v4l2_ioctl_ops */
static const struct v4l2_ioctl_ops g_msm_mctl_ioctl_ops = {
.vidioc_querycap = msm_mctl_v4l2_querycap,
@@ -1663,6 +1584,7 @@
/* event subscribe/unsubscribe */
.vidioc_subscribe_event = msm_mctl_v4l2_subscribe_event,
.vidioc_unsubscribe_event = msm_mctl_v4l2_unsubscribe_event,
+ .vidioc_default = msm_mctl_v4l2_private_ioctl,
};
int msm_setup_mctl_node(struct msm_cam_v4l2_device *pcam)
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index cd86a80..befd213 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -368,7 +368,7 @@
struct msm_frame_buffer *msm_mctl_buf_find(
struct msm_cam_media_controller *pmctl,
struct msm_cam_v4l2_dev_inst *pcam_inst, int del_buf,
- int image_mode, struct msm_free_buf *fbuf)
+ struct msm_free_buf *fbuf)
{
struct msm_frame_buffer *buf = NULL, *tmp;
uint32_t buf_phyaddr = 0;
@@ -409,14 +409,13 @@
int msm_mctl_buf_done_proc(
struct msm_cam_media_controller *pmctl,
struct msm_cam_v4l2_dev_inst *pcam_inst,
- int image_mode, struct msm_free_buf *fbuf,
+ struct msm_free_buf *fbuf,
uint32_t *frame_id, int gen_timestamp)
{
struct msm_frame_buffer *buf = NULL;
int del_buf = 1;
- buf = msm_mctl_buf_find(pmctl, pcam_inst, del_buf,
- image_mode, fbuf);
+ buf = msm_mctl_buf_find(pmctl, pcam_inst, del_buf, fbuf);
if (!buf) {
pr_err("%s: buf=0x%x not found\n",
__func__, fbuf->ch_paddr[0]);
@@ -434,48 +433,81 @@
int msm_mctl_buf_done(struct msm_cam_media_controller *p_mctl,
- int image_mode, struct msm_free_buf *fbuf,
- uint32_t frame_id)
+ struct msm_cam_buf_handle *buf_handle,
+ struct msm_free_buf *fbuf,
+ uint32_t frame_id)
{
struct msm_cam_v4l2_dev_inst *pcam_inst;
int idx, rc;
int pp_divert_type = 0, pp_type = 0;
+ uint32_t image_mode;
+
+ if (!p_mctl || !buf_handle || !fbuf) {
+ pr_err("%s Invalid argument. ", __func__);
+ return -EINVAL;
+ }
+ if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_IMG_MODE)
+ image_mode = buf_handle->image_mode;
+ else
+ image_mode = GET_IMG_MODE(buf_handle->inst_handle);
+
+ if (image_mode > MSM_V4L2_EXT_CAPTURE_MODE_MAX) {
+ pr_err("%s Invalid image mode %d ", __func__, image_mode);
+ return -EINVAL;
+ }
msm_mctl_check_pp(p_mctl, image_mode, &pp_divert_type, &pp_type);
D("%s: pp_type=%d, pp_divert_type = %d, frame_id = 0x%x image_mode %d",
__func__, pp_type, pp_divert_type, frame_id, image_mode);
- if (pp_type || pp_divert_type)
- rc = msm_mctl_do_pp_divert(p_mctl,
- image_mode, fbuf, frame_id, pp_type);
- else {
- idx = msm_mctl_img_mode_to_inst_index(
- p_mctl, image_mode, 0);
- if (idx < 0) {
- /* check mctl node */
- if ((image_mode >= 0) &&
- p_mctl->pcam_ptr->mctl_node.
- dev_inst_map[image_mode]) {
- int index = p_mctl->pcam_ptr->mctl_node.
- dev_inst_map[image_mode]->my_index;
- pcam_inst = p_mctl->pcam_ptr->mctl_node.
- dev_inst[index];
- D("%s: Mctl node index %d inst %p",
- __func__, index, pcam_inst);
- rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
- image_mode, fbuf,
- &frame_id, 1);
- D("%s mctl node buf done %d\n", __func__, 0);
- return rc;
+ if (pp_type || pp_divert_type) {
+ rc = msm_mctl_do_pp_divert(p_mctl, buf_handle,
+ fbuf, frame_id, pp_type);
+ } else {
+ /* Find the instance on which vb2_buffer_done() needs to be
+ * called, so that the user can get the buffer.
+ * If the lookup type is
+ * - By instance handle:
+ * Either mctl_pp inst idx or video inst idx should be set.
+ * Try to get the MCTL_PP inst idx first, if its not set,
+ * fall back to video inst idx. Once we get the inst idx,
+ * get the pcam_inst from the corresponding dev_inst[] map.
+ * If neither are set, its a serious error, trigger a BUG_ON.
+ * - By image mode:
+ * Legacy usecase. Use the image mode and get the pcam_inst
+ * from the video node.
+ */
+ if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_INST_HANDLE) {
+ idx = GET_MCTLPP_INST_IDX(buf_handle->inst_handle);
+ if (idx > MSM_DEV_INST_MAX) {
+ idx = GET_VIDEO_INST_IDX(
+ buf_handle->inst_handle);
+ BUG_ON(idx > MSM_DEV_INST_MAX);
+ pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
} else {
- pr_err("%s Invalid instance, dropping buffer\n",
- __func__);
- return idx;
+ pcam_inst = p_mctl->pcam_ptr->mctl_node.
+ dev_inst[idx];
}
+ } else if (buf_handle->buf_lookup_type ==
+ BUF_LOOKUP_BY_IMG_MODE) {
+ idx = msm_mctl_img_mode_to_inst_index(p_mctl,
+ buf_handle->image_mode, 0);
+ if (idx < 0) {
+ pr_err("%s Invalid idx %d ", __func__, idx);
+ return -EINVAL;
+ }
+ pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
+ } else {
+ pr_err("%s Invalid buffer lookup type %d", __func__,
+ buf_handle->buf_lookup_type);
+ return -EINVAL;
}
- pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
+ if (!pcam_inst) {
+ pr_err("%s Invalid instance, Dropping buffer. ",
+ __func__);
+ return -EINVAL;
+ }
rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
- image_mode, fbuf,
- &frame_id, 1);
+ fbuf, &frame_id, 1);
}
return rc;
}
@@ -508,58 +540,99 @@
return ret;
}
-struct msm_cam_v4l2_dev_inst *msm_mctl_get_pcam_inst(
- struct msm_cam_media_controller *pmctl,
- int image_mode)
+struct msm_cam_v4l2_dev_inst *msm_mctl_get_inst_by_img_mode(
+ struct msm_cam_media_controller *pmctl, uint32_t img_mode)
{
struct msm_cam_v4l2_dev_inst *pcam_inst = NULL;
struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
int idx;
- if (image_mode >= 0) {
- /* Valid image mode. Search the mctl node first.
- * If mctl node doesnt have the instance, then
- * search in the user's video node */
- if (pmctl->vfe_output_mode == VFE_OUTPUTS_MAIN_AND_THUMB
+ /* Valid image mode. Search the mctl node first.
+ * If mctl node doesnt have the instance, then
+ * search in the user's video node */
+ if (pmctl->vfe_output_mode == VFE_OUTPUTS_MAIN_AND_THUMB
|| pmctl->vfe_output_mode == VFE_OUTPUTS_THUMB_AND_MAIN) {
- if (pcam->mctl_node.dev_inst_map[image_mode]
- && is_buffer_queued(pcam, image_mode)) {
- idx =
- pcam->mctl_node.dev_inst_map[image_mode]
- ->my_index;
- pcam_inst = pcam->mctl_node.dev_inst[idx];
- D("%s Found instance %p in mctl node device\n",
- __func__, pcam_inst);
- } else if (pcam->dev_inst_map[image_mode]) {
- idx = pcam->dev_inst_map[image_mode]->my_index;
- pcam_inst = pcam->dev_inst[idx];
- D("%s Found instance %p in video device\n",
+ if (pcam->mctl_node.dev_inst_map[img_mode]
+ && is_buffer_queued(pcam, img_mode)) {
+ idx = pcam->mctl_node.dev_inst_map[img_mode]->my_index;
+ pcam_inst = pcam->mctl_node.dev_inst[idx];
+ D("%s Found instance %p in mctl node device\n",
__func__, pcam_inst);
- }
- } else {
- if (pcam->mctl_node.dev_inst_map[image_mode]) {
- idx = pcam->mctl_node.dev_inst_map[image_mode]
- ->my_index;
- pcam_inst = pcam->mctl_node.dev_inst[idx];
- D("%s Found instance %p in mctl node device\n",
+ } else if (pcam->dev_inst_map[img_mode]) {
+ idx = pcam->dev_inst_map[img_mode]->my_index;
+ pcam_inst = pcam->dev_inst[idx];
+ D("%s Found instance %p in video device\n",
__func__, pcam_inst);
- } else if (pcam->dev_inst_map[image_mode]) {
- idx = pcam->dev_inst_map[image_mode]->my_index;
- pcam_inst = pcam->dev_inst[idx];
- D("%s Found instance %p in video device\n",
- __func__, pcam_inst);
- }
}
- } else
- pr_err("%s Invalid image mode %d. Return NULL\n",
- __func__, image_mode);
+ } else {
+ if (pcam->mctl_node.dev_inst_map[img_mode]) {
+ idx = pcam->mctl_node.dev_inst_map[img_mode]->my_index;
+ pcam_inst = pcam->mctl_node.dev_inst[idx];
+ D("%s Found instance %p in mctl node device\n",
+ __func__, pcam_inst);
+ } else if (pcam->dev_inst_map[img_mode]) {
+ idx = pcam->dev_inst_map[img_mode]->my_index;
+ pcam_inst = pcam->dev_inst[idx];
+ D("%s Found instance %p in video device\n",
+ __func__, pcam_inst);
+ }
+ }
+ return pcam_inst;
+}
+
+struct msm_cam_v4l2_dev_inst *msm_mctl_get_pcam_inst(
+ struct msm_cam_media_controller *pmctl,
+ struct msm_cam_buf_handle *buf_handle)
+{
+ struct msm_cam_v4l2_dev_inst *pcam_inst = NULL;
+ struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
+ int idx;
+
+ /* Get the pcam instance on based on the following rules:
+ * If the lookup type is
+ * - By instance handle:
+ * Either mctl_pp inst idx or video inst idx should be set.
+ * Try to get the MCTL_PP inst idx first, if its not set,
+ * fall back to video inst idx. Once we get the inst idx,
+ * get the pcam_inst from the corresponding dev_inst[] map.
+ * If neither are set, its a serious error, trigger a BUG_ON.
+ * - By image mode:(Legacy usecase)
+ * If vfe is in configured in snapshot mode, first check if
+ * mctl pp node has a instance created for this image mode
+ * and if there is a buffer queued for that instance.
+ * If so, return that instance, otherwise get the pcam instance
+ * for this image_mode from the video instance.
+ * If the vfe is configured in any other mode, then first check
+ * if mctl pp node has a instance created for this image mode,
+ * otherwise get the pcam instance for this image mode from the
+ * video instance.
+ */
+ if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_INST_HANDLE) {
+ idx = GET_MCTLPP_INST_IDX(buf_handle->inst_handle);
+ if (idx > MSM_DEV_INST_MAX) {
+ idx = GET_VIDEO_INST_IDX(buf_handle->inst_handle);
+ BUG_ON(idx > MSM_DEV_INST_MAX);
+ pcam_inst = pcam->dev_inst[idx];
+ } else {
+ pcam_inst = pcam->mctl_node.dev_inst[idx];
+ }
+ } else if ((buf_handle->buf_lookup_type == BUF_LOOKUP_BY_IMG_MODE)
+ && (buf_handle->image_mode >= 0 &&
+ buf_handle->image_mode < MSM_V4L2_EXT_CAPTURE_MODE_MAX)) {
+ pcam_inst = msm_mctl_get_inst_by_img_mode(pmctl,
+ buf_handle->image_mode);
+ } else {
+ pr_err("%s Invalid buffer lookup type %d", __func__,
+ buf_handle->buf_lookup_type);
+ }
return pcam_inst;
}
int msm_mctl_reserve_free_buf(
- struct msm_cam_media_controller *pmctl,
- struct msm_cam_v4l2_dev_inst *pref_pcam_inst,
- int image_mode, struct msm_free_buf *free_buf)
+ struct msm_cam_media_controller *pmctl,
+ struct msm_cam_v4l2_dev_inst *pref_pcam_inst,
+ struct msm_cam_buf_handle *buf_handle,
+ struct msm_free_buf *free_buf)
{
struct msm_cam_v4l2_dev_inst *pcam_inst = pref_pcam_inst;
unsigned long flags = 0;
@@ -568,8 +641,8 @@
int rc = -EINVAL, i;
uint32_t buf_idx, plane_offset = 0;
- if (!free_buf || !pmctl) {
- pr_err("%s: free_buf/pmctl is null\n", __func__);
+ if (!free_buf || !pmctl || !buf_handle) {
+ pr_err("%s: Invalid argument passed\n", __func__);
return rc;
}
memset(free_buf, 0, sizeof(struct msm_free_buf));
@@ -579,7 +652,7 @@
* If the preferred camera instance is NULL, get the
* camera instance using the image mode passed */
if (!pcam_inst)
- pcam_inst = msm_mctl_get_pcam_inst(pmctl, image_mode);
+ pcam_inst = msm_mctl_get_pcam_inst(pmctl, buf_handle);
if (!pcam_inst || !pcam_inst->streamon) {
pr_err("%s: stream is turned off\n", __func__);
@@ -641,7 +714,7 @@
int msm_mctl_release_free_buf(struct msm_cam_media_controller *pmctl,
struct msm_cam_v4l2_dev_inst *pcam_inst,
- int image_mode, struct msm_free_buf *free_buf)
+ struct msm_free_buf *free_buf)
{
unsigned long flags = 0;
struct msm_frame_buffer *buf = NULL;
@@ -677,20 +750,39 @@
}
int msm_mctl_buf_done_pp(struct msm_cam_media_controller *pmctl,
- int image_mode, struct msm_free_buf *frame, int dirty, int node_type)
+ struct msm_cam_buf_handle *buf_handle,
+ struct msm_free_buf *frame, int dirty, int node_type)
{
- struct msm_cam_v4l2_dev_inst *pcam_inst;
+ struct msm_cam_v4l2_dev_inst *pcam_inst = NULL;
int rc = 0, idx;
- idx = msm_mctl_img_mode_to_inst_index(pmctl, image_mode, node_type);
- if (idx < 0) {
- pr_err("%s Invalid instance, buffer not released\n", __func__);
- return idx;
+ if (!pmctl || !buf_handle) {
+ pr_err("%s Invalid argument ", __func__);
+ return -EINVAL;
}
- if (node_type)
- pcam_inst = pmctl->pcam_ptr->mctl_node.dev_inst[idx];
- else
- pcam_inst = pmctl->pcam_ptr->dev_inst[idx];
+
+ if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_INST_HANDLE) {
+ idx = GET_MCTLPP_INST_IDX(buf_handle->inst_handle);
+ if (idx > MSM_DEV_INST_MAX) {
+ idx = GET_VIDEO_INST_IDX(buf_handle->inst_handle);
+ BUG_ON(idx > MSM_DEV_INST_MAX);
+ pcam_inst = pmctl->pcam_ptr->dev_inst[idx];
+ } else {
+ pcam_inst = pmctl->pcam_ptr->mctl_node.dev_inst[idx];
+ }
+ } else if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_IMG_MODE) {
+ idx = msm_mctl_img_mode_to_inst_index(pmctl,
+ buf_handle->image_mode, node_type);
+ if (idx < 0) {
+ pr_err("%s Invalid instance, buffer not released\n",
+ __func__);
+ return idx;
+ }
+ if (node_type)
+ pcam_inst = pmctl->pcam_ptr->mctl_node.dev_inst[idx];
+ else
+ pcam_inst = pmctl->pcam_ptr->dev_inst[idx];
+ }
if (!pcam_inst) {
pr_err("%s Invalid instance, cannot send buf to user",
__func__);
@@ -701,121 +793,12 @@
__func__, pcam_inst, frame->ch_paddr[0], dirty);
if (dirty)
/* the frame is dirty, not going to disptach to app */
- rc = msm_mctl_release_free_buf(pmctl, pcam_inst,
- image_mode, frame);
+ rc = msm_mctl_release_free_buf(pmctl, pcam_inst, frame);
else
- rc = msm_mctl_buf_done_proc(pmctl, pcam_inst,
- image_mode, frame, NULL, 0);
+ rc = msm_mctl_buf_done_proc(pmctl, pcam_inst, frame, NULL, 0);
return rc;
}
-struct msm_frame_buffer *msm_mctl_get_free_buf(
- struct msm_cam_media_controller *pmctl,
- int image_mode)
-{
- struct msm_cam_v4l2_dev_inst *pcam_inst;
- unsigned long flags = 0;
- struct msm_frame_buffer *buf = NULL;
- int rc = -EINVAL, idx;
-
- idx = msm_mctl_img_mode_to_inst_index(pmctl,
- image_mode, 0);
- if (idx < 0) {
- pr_err("%s Invalid instance, cant get buffer\n", __func__);
- return NULL;
- }
- pcam_inst = pmctl->pcam_ptr->dev_inst[idx];
- if (!pcam_inst->streamon) {
- D("%s: stream 0x%p is off\n", __func__, pcam_inst);
- return NULL;
- }
- spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
- if (!list_empty(&pcam_inst->free_vq)) {
- list_for_each_entry(buf, &pcam_inst->free_vq, list) {
- if (buf->state == MSM_BUFFER_STATE_QUEUED) {
- buf->state = MSM_BUFFER_STATE_RESERVED;
- rc = 0;
- break;
- }
- }
- }
- if (rc != 0) {
- D("%s:No free buffer available: inst = 0x%p ",
- __func__, pcam_inst);
- buf = NULL;
- }
- spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
- return buf;
-}
-
-int msm_mctl_put_free_buf(
- struct msm_cam_media_controller *pmctl,
- int image_mode, struct msm_frame_buffer *my_buf)
-{
- struct msm_cam_v4l2_dev_inst *pcam_inst;
- unsigned long flags = 0;
- int rc = 0, idx;
- struct msm_frame_buffer *buf = NULL;
-
- idx = msm_mctl_img_mode_to_inst_index(pmctl,
- image_mode, 0);
- if (idx < 0) {
- pr_err("%s Invalid instance, cant put buffer\n", __func__);
- return idx;
- }
- pcam_inst = pmctl->pcam_ptr->dev_inst[idx];
- if (!pcam_inst->streamon) {
- D("%s: stream 0x%p is off\n", __func__, pcam_inst);
- return rc;
- }
- spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
- if (!list_empty(&pcam_inst->free_vq)) {
- list_for_each_entry(buf, &pcam_inst->free_vq, list) {
- if (my_buf == buf) {
- buf->state = MSM_BUFFER_STATE_QUEUED;
- spin_unlock_irqrestore(&pcam_inst->vq_irqlock,
- flags);
- return 0;
- }
- }
- }
- spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
- return rc;
-}
-
-int msm_mctl_buf_del(struct msm_cam_media_controller *pmctl,
- int image_mode,
- struct msm_frame_buffer *my_buf)
-{
- struct msm_cam_v4l2_dev_inst *pcam_inst;
- struct msm_frame_buffer *buf = NULL;
- unsigned long flags = 0;
- int idx;
-
- idx = msm_mctl_img_mode_to_inst_index(pmctl,
- image_mode, 0);
- if (idx < 0) {
- pr_err("%s Invalid instance, cant delete buffer\n", __func__);
- return idx;
- }
- pcam_inst = pmctl->pcam_ptr->dev_inst[idx];
- D("%s: idx = %d, pinst=0x%p", __func__, idx, pcam_inst);
- spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
- if (!list_empty(&pcam_inst->free_vq)) {
- list_for_each_entry(buf, &pcam_inst->free_vq, list) {
- if (my_buf == buf) {
- list_del_init(&buf->list);
- spin_unlock_irqrestore(&pcam_inst->vq_irqlock,
- flags);
- return 0;
- }
- }
- }
- spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
- pr_err("%s: buf 0x%p not found", __func__, my_buf);
- return -EINVAL;
-}
-
int msm_mctl_buf_return_buf(struct msm_cam_media_controller *pmctl,
int image_mode, struct msm_frame_buffer *rbuf)
{
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index abcee4b..dcb7c51 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -153,61 +153,96 @@
spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
return 0;
}
+
static struct msm_cam_v4l2_dev_inst *msm_mctl_get_pcam_inst_for_divert(
- struct msm_cam_media_controller *pmctl,
- int image_mode, struct msm_free_buf *fbuf, int *node_type)
+ struct msm_cam_media_controller *pmctl,
+ struct msm_cam_buf_handle *buf_handle,
+ struct msm_free_buf *fbuf, int *node_type)
{
struct msm_cam_v4l2_dev_inst *pcam_inst = NULL;
struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
int idx;
+ uint32_t img_mode;
- if (image_mode >= 0) {
- /* Valid image mode. Search the mctl node first.
- * If mctl node doesnt have the instance, then
- * search in the user's video node */
- if (pcam->mctl_node.dev_inst_map[image_mode]
- && is_buf_in_queue(pcam, fbuf, image_mode)) {
- idx =
- pcam->mctl_node.dev_inst_map[image_mode]->my_index;
- pcam_inst = pcam->mctl_node.dev_inst[idx];
- *node_type = MCTL_NODE;
- D("%s Found instance %p in mctl node device\n",
- __func__, pcam_inst);
- } else if (pcam->dev_inst_map[image_mode]) {
- idx = pcam->dev_inst_map[image_mode]->my_index;
+ if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_INST_HANDLE) {
+ idx = GET_MCTLPP_INST_IDX(buf_handle->inst_handle);
+ if (idx > MSM_DEV_INST_MAX) {
+ idx = GET_VIDEO_INST_IDX(buf_handle->inst_handle);
+ BUG_ON(idx > MSM_DEV_INST_MAX);
pcam_inst = pcam->dev_inst[idx];
*node_type = VIDEO_NODE;
- D("%s Found instance %p in video device",
- __func__, pcam_inst);
- } else
+ } else {
+ pcam_inst = pcam->mctl_node.dev_inst[idx];
+ *node_type = MCTL_NODE;
+ }
+ } else if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_IMG_MODE) {
+ img_mode = buf_handle->image_mode;
+ if (img_mode >= 0 && img_mode < MSM_V4L2_EXT_CAPTURE_MODE_MAX) {
+ /* Valid image mode. Search the mctl node first.
+ * If mctl node doesnt have the instance, then
+ * search in the user's video node */
+ if (pcam->mctl_node.dev_inst_map[img_mode]
+ && is_buf_in_queue(pcam, fbuf, img_mode)) {
+ idx = pcam->mctl_node.
+ dev_inst_map[img_mode]->my_index;
+ pcam_inst = pcam->mctl_node.dev_inst[idx];
+ *node_type = MCTL_NODE;
+ D("%s Found instance %p in mctl node device\n",
+ __func__, pcam_inst);
+ } else if (pcam->dev_inst_map[img_mode]) {
+ idx = pcam->dev_inst_map[img_mode]->my_index;
+ pcam_inst = pcam->dev_inst[idx];
+ *node_type = VIDEO_NODE;
+ D("%s Found instance %p in video device",
+ __func__, pcam_inst);
+ } else {
+ pr_err("%s Cannot find instance for %d.\n",
+ __func__, img_mode);
+ }
+ } else {
pr_err("%s Invalid image mode %d. Return NULL\n",
- __func__, image_mode);
+ __func__, buf_handle->image_mode);
+ }
+ } else {
+ pr_err("%s Invalid buffer lookup type ", __func__);
}
- return pcam_inst;
+ return pcam_inst;
}
int msm_mctl_do_pp_divert(
struct msm_cam_media_controller *p_mctl,
- int image_mode, struct msm_free_buf *fbuf,
+ struct msm_cam_buf_handle *buf_handle,
+ struct msm_free_buf *fbuf,
uint32_t frame_id, int pp_type)
{
struct msm_cam_v4l2_dev_inst *pcam_inst;
- int rc = 0, i, buf_idx;
+ int rc = 0, i, buf_idx, node;
int del_buf = 0; /* delete from free queue */
struct msm_cam_evt_divert_frame div;
struct msm_frame_buffer *vb = NULL;
struct videobuf2_contig_pmem *mem;
- int node;
+ uint32_t image_mode;
- pcam_inst = msm_mctl_get_pcam_inst_for_divert
- (p_mctl, image_mode, fbuf, &node);
+ if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_IMG_MODE) {
+ image_mode = buf_handle->image_mode;
+ div.frame.inst_handle = 0;
+ } else if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_INST_HANDLE) {
+ image_mode = GET_IMG_MODE(buf_handle->inst_handle);
+ div.frame.inst_handle = buf_handle->inst_handle;
+ } else {
+ pr_err("%s Invalid buffer lookup type %d ", __func__,
+ buf_handle->buf_lookup_type);
+ return -EINVAL;
+ }
+
+ pcam_inst = msm_mctl_get_pcam_inst_for_divert(p_mctl,
+ buf_handle, fbuf, &node);
if (!pcam_inst) {
pr_err("%s Invalid instance. Cannot divert frame.\n",
__func__);
return -EINVAL;
}
- vb = msm_mctl_buf_find(p_mctl, pcam_inst,
- del_buf, image_mode, fbuf);
+ vb = msm_mctl_buf_find(p_mctl, pcam_inst, del_buf, fbuf);
if (!vb)
return -EINVAL;
@@ -392,50 +427,16 @@
struct msm_mctl_pp_cmd *pp_cmd)
{
int rc = 0;
- struct msm_mctl_pp_frame_buffer pp_buffer;
- struct msm_frame_buffer *buf = NULL;
- void __user *argp = (void __user *)pp_cmd->value;
- int img_mode;
unsigned long flags;
switch (pp_cmd->id) {
- case MCTL_CMD_GET_FRAME_BUFFER: {
- if (copy_from_user(&pp_buffer, pp_cmd->value,
- sizeof(pp_buffer)))
- return -EFAULT;
- img_mode = msm_mctl_pp_path_to_img_mode(pp_buffer.path);
- if (img_mode < 0) {
- pr_err("%s Invalid image mode\n", __func__);
- return img_mode;
- }
- buf = msm_mctl_get_free_buf(p_mctl, img_mode);
- pp_buffer.buf_handle = (uint32_t)buf;
- if (copy_to_user((void *)argp,
- &pp_buffer,
- sizeof(struct msm_mctl_pp_frame_buffer))) {
- ERR_COPY_TO_USER();
- rc = -EFAULT;
- }
- break;
- }
- case MCTL_CMD_PUT_FRAME_BUFFER: {
- if (copy_from_user(&pp_buffer, pp_cmd->value,
- sizeof(pp_buffer)))
- return -EFAULT;
- img_mode = msm_mctl_pp_path_to_img_mode(pp_buffer.path);
- if (img_mode < 0) {
- pr_err("%s Invalid image mode\n", __func__);
- return img_mode;
- }
- buf = (struct msm_frame_buffer *)pp_buffer.buf_handle;
- msm_mctl_put_free_buf(p_mctl, img_mode, buf);
- break;
- }
case MCTL_CMD_DIVERT_FRAME_PP_PATH: {
struct msm_mctl_pp_divert_pp divert_pp;
if (copy_from_user(&divert_pp, pp_cmd->value,
- sizeof(divert_pp)))
+ sizeof(divert_pp))) {
+ ERR_COPY_FROM_USER();
return -EFAULT;
+ }
D("%s: PP_PATH, path=%d",
__func__, divert_pp.path);
spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
@@ -490,17 +491,20 @@
struct msm_cam_media_controller *p_mctl,
void __user *arg)
{
- struct msm_cam_evt_divert_frame frame;
+ struct msm_cam_evt_divert_frame div_frame;
int image_mode, rc = 0;
struct msm_free_buf free_buf;
struct msm_cam_v4l2_dev_inst *pcam_inst;
+ struct msm_cam_buf_handle buf_handle;
memset(&free_buf, 0, sizeof(struct msm_free_buf));
- if (copy_from_user(&frame, arg,
- sizeof(struct msm_cam_evt_divert_frame)))
+ if (copy_from_user(&div_frame, arg,
+ sizeof(struct msm_cam_evt_divert_frame))) {
+ ERR_COPY_FROM_USER();
return -EFAULT;
+ }
- image_mode = frame.image_mode;
+ image_mode = div_frame.image_mode;
if (image_mode <= 0) {
pr_err("%s Invalid image mode %d", __func__, image_mode);
return -EINVAL;
@@ -511,17 +515,25 @@
pr_err("%s Instance already closed ", __func__);
return -EINVAL;
}
+ if (div_frame.frame.inst_handle) {
+ buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE;
+ buf_handle.inst_handle = div_frame.frame.inst_handle;
+ } else {
+ buf_handle.buf_lookup_type = BUF_LOOKUP_BY_IMG_MODE;
+ buf_handle.image_mode = image_mode;
+ }
rc = msm_mctl_reserve_free_buf(p_mctl, pcam_inst,
- image_mode, &free_buf);
+ &buf_handle, &free_buf);
if (rc == 0) {
- msm_mctl_pp_get_phy_addr(pcam_inst, free_buf.vb, &frame.frame);
- if (copy_to_user((void *)arg, &frame, sizeof(frame))) {
+ msm_mctl_pp_get_phy_addr(pcam_inst,
+ free_buf.vb, &div_frame.frame);
+ if (copy_to_user((void *)arg, &div_frame, sizeof(div_frame))) {
ERR_COPY_TO_USER();
rc = -EFAULT;
}
}
D("%s: reserve free buf got buffer %d from %p rc = %d, phy = 0x%x",
- __func__, frame.frame.buf_idx,
+ __func__, div_frame.frame.buf_idx,
pcam_inst, rc, free_buf.ch_paddr[0]);
return rc;
}
@@ -535,10 +547,13 @@
struct msm_pp_frame *frame;
int image_mode, rc = 0;
struct msm_free_buf free_buf;
+ struct msm_cam_buf_handle buf_handle;
if (copy_from_user(&div_frame, arg,
- sizeof(struct msm_cam_evt_divert_frame)))
+ sizeof(struct msm_cam_evt_divert_frame))) {
+ ERR_COPY_FROM_USER();
return -EFAULT;
+ }
image_mode = div_frame.image_mode;
if (image_mode < 0) {
@@ -551,15 +566,21 @@
else
free_buf.ch_paddr[0] = frame->sp.phy_addr;
- pcam_inst = msm_mctl_get_pcam_inst(p_mctl, image_mode);
+ if (div_frame.frame.inst_handle) {
+ buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE;
+ buf_handle.inst_handle = div_frame.frame.inst_handle;
+ } else {
+ buf_handle.buf_lookup_type = BUF_LOOKUP_BY_IMG_MODE;
+ buf_handle.image_mode = image_mode;
+ }
+ pcam_inst = msm_mctl_get_pcam_inst(p_mctl, &buf_handle);
if (!pcam_inst) {
pr_err("%s Invalid instance. Cannot release frame.\n",
__func__);
return -EINVAL;
}
- rc = msm_mctl_release_free_buf(p_mctl, pcam_inst,
- image_mode, &free_buf);
+ rc = msm_mctl_release_free_buf(p_mctl, pcam_inst, &free_buf);
D("%s: release free buf, rc = %d, phy = 0x%x",
__func__, rc, free_buf.ch_paddr[0]);
@@ -573,11 +594,13 @@
unsigned long flags;
spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
if (copy_from_user(&p_mctl->pp_info.pp_key,
- arg, sizeof(p_mctl->pp_info.pp_key)))
+ arg, sizeof(p_mctl->pp_info.pp_key))) {
+ ERR_COPY_FROM_USER();
rc = -EFAULT;
- else
+ } else {
D("%s: mctl=0x%p, pp_key_setting=0x%x",
__func__, p_mctl, p_mctl->pp_info.pp_key);
+ }
spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
return rc;
}
@@ -591,12 +614,24 @@
int dirty = 0;
struct msm_free_buf buf;
unsigned long flags;
+ struct msm_cam_buf_handle buf_handle;
- if (copy_from_user(&frame, arg, sizeof(frame)))
+ if (copy_from_user(&frame, arg, sizeof(frame))) {
+ ERR_COPY_FROM_USER();
return -EFAULT;
+ }
spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
- image_mode = msm_mctl_pp_path_to_img_mode(frame.path);
+ if (frame.inst_handle) {
+ buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE;
+ buf_handle.inst_handle = frame.inst_handle;
+ image_mode = GET_IMG_MODE(frame.inst_handle);
+ } else {
+ buf_handle.buf_lookup_type = BUF_LOOKUP_BY_IMG_MODE;
+ buf_handle.image_mode =
+ msm_mctl_pp_path_to_img_mode(frame.path);
+ image_mode = buf_handle.image_mode;
+ }
if (image_mode < 0) {
pr_err("%s Invalid image mode\n", __func__);
return image_mode;
@@ -622,8 +657,7 @@
buf.ch_paddr[0] = frame.sp.phy_addr + frame.sp.y_off;
}
spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
- /* here buf.addr is phy_addr */
- rc = msm_mctl_buf_done_pp(p_mctl, image_mode, &buf, dirty, 0);
+ rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle, &buf, dirty, 0);
return rc;
}
@@ -636,10 +670,14 @@
int dirty = 0;
struct msm_free_buf buf;
unsigned long flags;
+ struct msm_cam_buf_handle buf_handle;
+
D("%s enter\n", __func__);
- if (copy_from_user(&frame, arg, sizeof(frame)))
+ if (copy_from_user(&frame, arg, sizeof(frame))) {
+ ERR_COPY_FROM_USER();
return -EFAULT;
+ }
spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
D("%s Frame path: %d\n", __func__, frame.path);
@@ -665,6 +703,14 @@
goto err;
}
+ if (frame.inst_handle) {
+ buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE;
+ buf_handle.inst_handle = frame.inst_handle;
+ } else {
+ buf_handle.buf_lookup_type = BUF_LOOKUP_BY_IMG_MODE;
+ buf_handle.image_mode = image_mode;
+ }
+
if (frame.num_planes > 1)
buf.ch_paddr[0] = frame.mp[0].phy_addr +
frame.mp[0].data_offset;
@@ -673,7 +719,7 @@
spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
D("%s Frame done id: %d\n", __func__, frame.frame_id);
- rc = msm_mctl_buf_done_pp(p_mctl, image_mode,
+ rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle,
&buf, dirty, frame.node_type);
return rc;
err:
diff --git a/drivers/media/video/msm/msm_vfe31.h b/drivers/media/video/msm/msm_vfe31.h
index 1d66621..bec5f58 100644
--- a/drivers/media/video/msm/msm_vfe31.h
+++ b/drivers/media/video/msm/msm_vfe31.h
@@ -325,8 +325,8 @@
#define V31_OPERATION_CFG_LEN 32
#define V31_AXI_OUT_OFF 0x00000038
-#define V31_AXI_OUT_LEN 212
-#define V31_AXI_CH_INF_LEN 24
+#define V31_AXI_OUT_LEN 220
+#define V31_AXI_CH_INF_LEN 32
#define V31_AXI_CFG_LEN 47
#define V31_FRAME_SKIP_OFF 0x00000504
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
index bc99b2d..18168ee 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -643,7 +643,7 @@
vfe31_ctrl->vfebase + VFE_GLOBAL_RESET);
}
-static void vfe31_subdev_notify(int id, int path, int image_mode)
+static void vfe31_subdev_notify(int id, int path, uint32_t inst_handle)
{
struct msm_vfe_resp rp;
struct msm_frame_info frame_info;
@@ -652,7 +652,7 @@
memset(&rp, 0, sizeof(struct msm_vfe_resp));
CDBG("vfe31_subdev_notify : msgId = %d\n", id);
rp.evt_msg.type = MSM_CAMERA_MSG;
- frame_info.image_mode = image_mode;
+ frame_info.inst_handle = inst_handle;
frame_info.path = path;
rp.evt_msg.data = &frame_info;
rp.type = id;
@@ -663,20 +663,21 @@
static int vfe31_config_axi(int mode, uint32_t *ao)
{
uint32_t *ch_info;
- uint32_t *axi_cfg = ao+V31_AXI_RESERVED;
+ uint32_t *axi_cfg = ao + V31_AXI_RESERVED;
/* Update the corresponding write masters for each output*/
ch_info = axi_cfg + V31_AXI_CFG_LEN;
vfe31_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
vfe31_ctrl->outpath.out0.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
- vfe31_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info;
- vfe31_ctrl->outpath.out0.image_mode = 0x0000FFFF & (*ch_info++ >> 16);
+ vfe31_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++;
+ vfe31_ctrl->outpath.out0.inst_handle = *ch_info++;
vfe31_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
vfe31_ctrl->outpath.out1.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
- vfe31_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info;
- vfe31_ctrl->outpath.out1.image_mode = 0x0000FFFF & (*ch_info++ >> 16);
+ vfe31_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info++;
+ vfe31_ctrl->outpath.out1.inst_handle = *ch_info++;
vfe31_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
vfe31_ctrl->outpath.out2.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
vfe31_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
+ vfe31_ctrl->outpath.out2.inst_handle = *ch_info++;
switch (mode) {
case OUTPUT_PRIM:
@@ -713,7 +714,7 @@
msm_camera_io_memcpy(vfe31_ctrl->vfebase +
vfe31_cmd[VFE_CMD_AXI_OUT_CFG].offset, axi_cfg,
vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length - V31_AXI_CH_INF_LEN -
- V31_AXI_RESERVED);
+ V31_AXI_RESERVED_LEN);
return 0;
}
@@ -1301,14 +1302,14 @@
{
struct vfe31_output_ch *outch = NULL;
struct msm_free_buf *b = NULL;
- uint32_t image_mode = 0;
+ uint32_t inst_handle = 0;
if (path == VFE_MSG_OUTPUT_PRIMARY)
- image_mode = vfe31_ctrl->outpath.out0.image_mode;
+ inst_handle = vfe31_ctrl->outpath.out0.inst_handle;
else
- image_mode = vfe31_ctrl->outpath.out1.image_mode;
+ inst_handle = vfe31_ctrl->outpath.out1.inst_handle;
- vfe31_subdev_notify(id, path, image_mode);
+ vfe31_subdev_notify(id, path, inst_handle);
outch = vfe31_get_ch(path);
if (outch->free_buf.ch_paddr[0])
b = &outch->free_buf;
@@ -1318,14 +1319,14 @@
{
struct vfe31_output_ch *outch = NULL;
int rc = 0;
- uint32_t image_mode = 0;
+ uint32_t inst_handle = 0;
if (path == VFE_MSG_OUTPUT_PRIMARY)
- image_mode = vfe31_ctrl->outpath.out0.image_mode;
+ inst_handle = vfe31_ctrl->outpath.out0.inst_handle;
else
- image_mode = vfe31_ctrl->outpath.out1.image_mode;
+ inst_handle = vfe31_ctrl->outpath.out1.inst_handle;
- vfe31_subdev_notify(id, path, image_mode);
+ vfe31_subdev_notify(id, path, inst_handle);
outch = vfe31_get_ch(path);
if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
/* Configure Preview Ping Pong */
@@ -1477,16 +1478,26 @@
case VFE_CMD_START_RECORDING:
pr_info("vfe31_proc_general: cmdID = %s\n",
vfe31_general_cmd[cmd->id]);
+ if (copy_from_user(&temp1, (void __user *)(cmd->value),
+ sizeof(uint32_t))) {
+ pr_err("%s Error copying inst_handle for recording\n",
+ __func__);
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
if (vfe31_ctrl->operation_mode ==
- VFE_OUTPUTS_PREVIEW_AND_VIDEO)
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+ vfe31_ctrl->outpath.out1.inst_handle = temp1;
rc = vfe31_configure_pingpong_buffers(
VFE_MSG_V31_START_RECORDING,
VFE_MSG_OUTPUT_SECONDARY);
- else if (vfe31_ctrl->operation_mode ==
- VFE_OUTPUTS_VIDEO_AND_PREVIEW)
+ } else if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+ vfe31_ctrl->outpath.out0.inst_handle = temp1;
rc = vfe31_configure_pingpong_buffers(
VFE_MSG_V31_START_RECORDING,
VFE_MSG_OUTPUT_PRIMARY);
+ }
if (rc < 0) {
pr_err("%s error configuring pingpong buffers"
" for video", __func__);
@@ -1916,6 +1927,14 @@
break;
case VFE_CMD_LIVESHOT:
+ if (copy_from_user(&temp1, (void __user *)(cmd->value),
+ sizeof(uint32_t))) {
+ pr_err("%s Error copying inst_handle for liveshot ",
+ __func__);
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ vfe31_ctrl->outpath.out0.inst_handle = temp1;
/* Configure primary channel */
rc = vfe31_configure_pingpong_buffers(VFE_MSG_V31_CAPTURE,
VFE_MSG_OUTPUT_PRIMARY);
@@ -2715,12 +2734,12 @@
}
static void vfe_send_outmsg(struct v4l2_subdev *sd, uint8_t msgid,
uint32_t ch0_paddr, uint32_t ch1_paddr,
- uint32_t ch2_paddr, uint32_t image_mode)
+ uint32_t ch2_paddr, uint32_t inst_handle)
{
struct isp_msg_output msg;
msg.output_id = msgid;
- msg.buf.image_mode = image_mode;
+ msg.buf.inst_handle = inst_handle;
msg.buf.ch_paddr[0] = ch0_paddr;
msg.buf.ch_paddr[1] = ch1_paddr;
msg.buf.ch_paddr[2] = ch2_paddr;
@@ -2803,7 +2822,7 @@
vfe_send_outmsg(&vfe31_ctrl->subdev,
MSG_ID_OUTPUT_PRIMARY, ch0_paddr,
ch1_paddr, ch2_paddr,
- vfe31_ctrl->outpath.out0.image_mode);
+ vfe31_ctrl->outpath.out0.inst_handle);
if (vfe31_ctrl->liveshot_state == VFE_STATE_STOPPED)
vfe31_ctrl->liveshot_state = VFE_STATE_IDLE;
@@ -2876,7 +2895,7 @@
vfe_send_outmsg(&vfe31_ctrl->subdev,
MSG_ID_OUTPUT_SECONDARY, ch0_paddr,
ch1_paddr, ch2_paddr,
- vfe31_ctrl->outpath.out1.image_mode);
+ vfe31_ctrl->outpath.out1.inst_handle);
} else {
vfe31_ctrl->outpath.out1.frame_drop_cnt++;
CDBG("path_irq_1 - no free buffer!\n");
@@ -3138,18 +3157,6 @@
CDBG("%s: droppedStatsFrameCount = %d", __func__,
vfe31_ctrl->csStatsControl.droppedStatsFrameCount);
}
- if (!(vfe31_ctrl->csStatsControl.ackPending)) {
- vfe31_ctrl->csStatsControl.bufToRender =
- vfe31_process_stats_irq_common(STATS_CS_NUM,
- vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
- vfe_send_stats_msg(
- vfe31_ctrl->csStatsControl.bufToRender,
- STATS_CS_NUM);
- } else {
- vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
- CDBG("%s: droppedStatsFrameCount = %d", __func__,
- vfe31_ctrl->csStatsControl.droppedStatsFrameCount);
- }
}
static void vfe31_process_stats(uint32_t status_bits)
@@ -3553,15 +3560,25 @@
struct msm_cam_media_controller *pmctl =
(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
struct msm_isp_cmd vfecmd;
- struct msm_camvfe_params *vfe_params =
- (struct msm_camvfe_params *)arg;
- struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
- void *data = vfe_params->data;
+ struct msm_camvfe_params *vfe_params;
+ struct msm_vfe_cfg_cmd *cmd;
+ void *data;
long rc = 0;
struct vfe_cmd_stats_buf *scfg = NULL;
struct vfe_cmd_stats_ack *sack = NULL;
+ if (subdev_cmd == VIDIOC_MSM_VFE_INIT) {
+ CDBG("%s init\n", __func__);
+ return msm_vfe_subdev_init(sd);
+ } else if (subdev_cmd == VIDIOC_MSM_VFE_RELEASE) {
+ msm_vfe_subdev_release(sd);
+ return 0;
+ }
+ vfe_params = (struct msm_camvfe_params *)arg;
+ cmd = vfe_params->vfe_cfg;
+ data = vfe_params->data;
+
switch (cmd->cmd_type) {
case VFE_CMD_STATS_REQBUF:
case VFE_CMD_STATS_ENQUEUEBUF:
@@ -3587,186 +3604,190 @@
return -EFAULT;
}
} else {
- /* here eith stats release or frame release. */
- if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
- cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
- cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
- /* then must be stats release. */
- if (!data) {
- pr_err("%s: data = NULL, cmd->cmd_type = %d",
- __func__, cmd->cmd_type);
- return -EFAULT;
- }
- sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
+ /* here eith stats release or frame release. */
+ if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
+ /* then must be stats release. */
+ if (!data) {
+ pr_err("%s: data = NULL," \
+ "cmd->cmd_type = %d\n",
+ __func__, cmd->cmd_type);
+ return -EFAULT;
+ }
+ sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
GFP_ATOMIC);
- if (!sack) {
- pr_err("%s: no mem for cmd->cmd_type = %d",
- __func__, cmd->cmd_type);
- return -ENOMEM;
+ if (!sack) {
+ pr_err("%s: no mem for" \
+ "cmd->cmd_type = %d\n",
+ __func__, cmd->cmd_type);
+ return -ENOMEM;
+ }
+
+ sack->nextStatsBuf = *(uint32_t *)data;
+ }
+ }
+
+ CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+ if ((cmd->cmd_type == CMD_STATS_AF_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_AWB_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_RS_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
+ scfg = NULL;
+ goto vfe31_config_done;
+ }
+ switch (cmd->cmd_type) {
+ case CMD_GENERAL: {
+ rc = vfe31_proc_general(pmctl, &vfecmd);
+ }
+ break;
+ case CMD_CONFIG_PING_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe31_output_ch *outch = vfe31_get_ch(path);
+ outch->ping = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_CONFIG_PONG_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe31_output_ch *outch = vfe31_get_ch(path);
+ outch->pong = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_CONFIG_FREE_BUF_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe31_output_ch *outch = vfe31_get_ch(path);
+ outch->free_buf = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_SNAP_BUF_RELEASE:
+ break;
+
+ case CMD_AXI_CFG_PRIM: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
}
- sack->nextStatsBuf = *(uint32_t *)data;
- }
- }
-
- CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
-
- if ((cmd->cmd_type == CMD_STATS_AF_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_AWB_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_RS_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
- scfg = NULL;
- goto vfe31_config_done;
- }
- switch (cmd->cmd_type) {
- case CMD_GENERAL: {
- rc = vfe31_proc_general(pmctl, &vfecmd);
- }
- break;
- case CMD_CONFIG_PING_ADDR: {
- int path = *((int *)cmd->value);
- struct vfe31_output_ch *outch = vfe31_get_ch(path);
- outch->ping = *((struct msm_free_buf *)data);
- }
- break;
-
- case CMD_CONFIG_PONG_ADDR: {
- int path = *((int *)cmd->value);
- struct vfe31_output_ch *outch = vfe31_get_ch(path);
- outch->pong = *((struct msm_free_buf *)data);
- }
- break;
-
- case CMD_CONFIG_FREE_BUF_ADDR: {
- int path = *((int *)cmd->value);
- struct vfe31_output_ch *outch = vfe31_get_ch(path);
- outch->free_buf = *((struct msm_free_buf *)data);
- }
- break;
-
- case CMD_SNAP_BUF_RELEASE:
- break;
-
- case CMD_AXI_CFG_PRIM: {
- uint32_t *axio = NULL;
- axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
- GFP_ATOMIC);
- if (!axio) {
- rc = -ENOMEM;
- break;
- }
-
- if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_PRIM, axio);
kfree(axio);
- rc = -EFAULT;
+ }
break;
- }
- vfe31_config_axi(OUTPUT_PRIM, axio);
- kfree(axio);
- }
- break;
- case CMD_AXI_CFG_PRIM_ALL_CHNLS: {
- uint32_t *axio = NULL;
- axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
- GFP_ATOMIC);
- if (!axio) {
- rc = -ENOMEM;
- break;
- }
+ case CMD_AXI_CFG_PRIM_ALL_CHNLS: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
- if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_PRIM_ALL_CHNLS, axio);
kfree(axio);
- rc = -EFAULT;
+ }
break;
- }
- vfe31_config_axi(OUTPUT_PRIM_ALL_CHNLS, axio);
- kfree(axio);
- }
- break;
- case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC: {
- uint32_t *axio = NULL;
- axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
- GFP_ATOMIC);
- if (!axio) {
- rc = -ENOMEM;
- break;
- }
+ case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
- if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_PRIM|OUTPUT_SEC, axio);
kfree(axio);
- rc = -EFAULT;
+ }
break;
- }
- vfe31_config_axi(OUTPUT_PRIM|OUTPUT_SEC, axio);
- kfree(axio);
- }
- break;
- case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC_ALL_CHNLS: {
- uint32_t *axio = NULL;
- axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
- GFP_ATOMIC);
- if (!axio) {
- rc = -ENOMEM;
- break;
- }
+ case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC_ALL_CHNLS: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
- if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi
+ (OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS, axio);
kfree(axio);
- rc = -EFAULT;
+ }
break;
- }
- vfe31_config_axi(OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS, axio);
- kfree(axio);
- }
- break;
- case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC: {
- uint32_t *axio = NULL;
- axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
GFP_ATOMIC);
- if (!axio) {
- rc = -ENOMEM;
- break;
- }
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
- if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi
+ (OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC, axio);
kfree(axio);
- rc = -EFAULT;
+ }
break;
- }
- vfe31_config_axi(OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC, axio);
- kfree(axio);
- }
- break;
- case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC_ALL_CHNLS: {
- pr_err("%s Invalid/Unsupported AXI configuration %x",
- __func__, cmd->cmd_type);
- }
- break;
+ case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC_ALL_CHNLS: {
+ pr_err("%s Invalid/Unsupported AXI configuration %x",
+ __func__, cmd->cmd_type);
+ }
+ break;
- case CMD_AXI_START:
- /* No need to decouple AXI/VFE for VFE3.1*/
- break;
+ case CMD_AXI_START:
+ /* No need to decouple AXI/VFE for VFE3.1*/
+ break;
- case CMD_AXI_STOP:
- /* No need to decouple AXI/VFE for VFE3.1*/
- break;
+ case CMD_AXI_STOP:
+ /* No need to decouple AXI/VFE for VFE3.1*/
+ break;
- default:
- pr_err("%s Unsupported AXI configuration %x ", __func__,
- cmd->cmd_type);
- break;
+ default:
+ pr_err("%s Unsupported AXI configuration %x ", __func__,
+ cmd->cmd_type);
+ break;
}
}
vfe31_config_done:
@@ -3867,11 +3888,15 @@
usleep_range(10000, 15000);
}
-int msm_vfe_subdev_init(struct v4l2_subdev *sd,
- struct msm_cam_media_controller *mctl)
+int msm_vfe_subdev_init(struct v4l2_subdev *sd)
{
int rc = 0;
- v4l2_set_subdev_hostdata(sd, mctl);
+ struct msm_cam_media_controller *mctl;
+ mctl = v4l2_get_subdev_hostdata(sd);
+ if (mctl == NULL) {
+ rc = -EINVAL;
+ goto mctl_failed;
+ }
spin_lock_init(&vfe31_ctrl->stop_flag_lock);
spin_lock_init(&vfe31_ctrl->state_lock);
@@ -3951,6 +3976,7 @@
iounmap(vfe31_ctrl->vfebase);
vfe_remap_failed:
disable_irq(vfe31_ctrl->vfeirq->start);
+mctl_failed:
return rc;
}
@@ -4076,6 +4102,12 @@
sd_info.sd_index = 0;
sd_info.irq_num = vfe31_ctrl->vfeirq->start;
msm_cam_register_subdev_node(&vfe31_ctrl->subdev, &sd_info);
+
+ media_entity_init(&vfe31_ctrl->subdev.entity, 0, NULL, 0);
+ vfe31_ctrl->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ vfe31_ctrl->subdev.entity.group_id = VFE_DEV;
+ vfe31_ctrl->subdev.entity.name = pdev->name;
+ vfe31_ctrl->subdev.entity.revision = vfe31_ctrl->subdev.devnode->num;
return 0;
vfe31_no_resource:
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.h b/drivers/media/video/msm/msm_vfe31_v4l2.h
index 2cba995..6396966 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.h
@@ -217,10 +217,11 @@
#define V31_OPERATION_CFG_LEN 32
#define V31_AXI_OUT_OFF 0x00000038
-#define V31_AXI_OUT_LEN 212
-#define V31_AXI_CH_INF_LEN 24
+#define V31_AXI_OUT_LEN 240
+#define V31_AXI_CH_INF_LEN 48
#define V31_AXI_CFG_LEN 47
#define V31_AXI_RESERVED 1
+#define V31_AXI_RESERVED_LEN 4
#define V31_FRAME_SKIP_OFF 0x00000504
#define V31_FRAME_SKIP_LEN 32
@@ -696,7 +697,7 @@
struct vfe31_output_ch {
struct list_head free_buf_queue;
spinlock_t free_buf_lock;
- uint16_t image_mode;
+ uint32_t inst_handle;
int8_t ch0;
int8_t ch1;
int8_t ch2;
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index c6dd143..38179e6 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -393,7 +393,7 @@
vfe32_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
}
-static void vfe32_subdev_notify(int id, int path, int image_mode,
+static void vfe32_subdev_notify(int id, int path, uint32_t inst_handle,
struct v4l2_subdev *sd, struct vfe_share_ctrl_t *share_ctrl)
{
struct msm_vfe_resp rp;
@@ -403,7 +403,7 @@
CDBG("vfe32_subdev_notify : msgId = %d\n", id);
memset(&rp, 0, sizeof(struct msm_vfe_resp));
rp.evt_msg.type = MSM_CAMERA_MSG;
- frame_info.image_mode = image_mode;
+ frame_info.inst_handle = inst_handle;
frame_info.path = path;
rp.evt_msg.data = &frame_info;
rp.type = id;
@@ -423,27 +423,27 @@
axi_ctrl->share_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
axi_ctrl->share_ctrl->outpath.out0.ch1 =
0x0000FFFF & (*ch_info++ >> 16);
- axi_ctrl->share_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info;
- axi_ctrl->share_ctrl->outpath.out0.image_mode =
- 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++;
+ axi_ctrl->share_ctrl->outpath.out0.inst_handle = *ch_info++;
+
axi_ctrl->share_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
axi_ctrl->share_ctrl->outpath.out1.ch1 =
0x0000FFFF & (*ch_info++ >> 16);
- axi_ctrl->share_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info;
- axi_ctrl->share_ctrl->outpath.out1.image_mode =
- 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info++;
+ axi_ctrl->share_ctrl->outpath.out1.inst_handle = *ch_info++;
+
axi_ctrl->share_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
axi_ctrl->share_ctrl->outpath.out2.ch1 =
0x0000FFFF & (*ch_info++ >> 16);
- axi_ctrl->share_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info;
- axi_ctrl->share_ctrl->outpath.out2.image_mode =
- 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
+ axi_ctrl->share_ctrl->outpath.out2.inst_handle = *ch_info++;
+
axi_ctrl->share_ctrl->outpath.out3.ch0 = 0x0000FFFF & *ch_info;
axi_ctrl->share_ctrl->outpath.out3.ch1 =
0x0000FFFF & (*ch_info++ >> 16);
- axi_ctrl->share_ctrl->outpath.out3.ch2 = 0x0000FFFF & *ch_info;
- axi_ctrl->share_ctrl->outpath.out3.image_mode =
- 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out3.ch2 = 0x0000FFFF & *ch_info++;
+ axi_ctrl->share_ctrl->outpath.out3.inst_handle = *ch_info++;
+
axi_ctrl->share_ctrl->outpath.output_mode = 0;
if (mode & OUTPUT_TERT1)
@@ -956,6 +956,8 @@
vfe32_ctrl->share_ctrl->vfe_capture_count =
vfe32_ctrl->share_ctrl->outpath.out0.capture_cnt;
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_LIVESHOT);
vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_START_REQUESTED;
msm_camera_io_w_mb(1, vfe32_ctrl->
share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
@@ -968,6 +970,8 @@
vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_STOP_REQUESTED;
msm_camera_io_w_mb(1,
vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camio_bus_scale_cfg(
+ pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
}
static int vfe32_zsl(
@@ -1464,18 +1468,18 @@
{
struct vfe32_output_ch *outch = NULL;
struct msm_free_buf *b = NULL;
- uint32_t image_mode = 0;
+ uint32_t inst_handle = 0;
if (path == VFE_MSG_OUTPUT_PRIMARY)
- image_mode = axi_ctrl->share_ctrl->outpath.out0.image_mode;
+ inst_handle = axi_ctrl->share_ctrl->outpath.out0.inst_handle;
else if (path == VFE_MSG_OUTPUT_SECONDARY)
- image_mode = axi_ctrl->share_ctrl->outpath.out1.image_mode;
+ inst_handle = axi_ctrl->share_ctrl->outpath.out1.inst_handle;
else if (path == VFE_MSG_OUTPUT_TERTIARY1)
- image_mode = axi_ctrl->share_ctrl->outpath.out2.image_mode;
+ inst_handle = axi_ctrl->share_ctrl->outpath.out2.inst_handle;
else if (path == VFE_MSG_OUTPUT_TERTIARY2)
- image_mode = axi_ctrl->share_ctrl->outpath.out3.image_mode;
+ inst_handle = axi_ctrl->share_ctrl->outpath.out3.inst_handle;
- vfe32_subdev_notify(id, path, image_mode,
+ vfe32_subdev_notify(id, path, inst_handle,
&axi_ctrl->subdev, axi_ctrl->share_ctrl);
outch = vfe32_get_ch(path, axi_ctrl->share_ctrl);
if (outch->free_buf.ch_paddr[0])
@@ -1487,17 +1491,17 @@
{
struct vfe32_output_ch *outch = NULL;
int rc = 0;
- uint32_t image_mode = 0;
+ uint32_t inst_handle = 0;
if (path == VFE_MSG_OUTPUT_PRIMARY)
- image_mode = vfe32_ctrl->share_ctrl->outpath.out0.image_mode;
+ inst_handle = vfe32_ctrl->share_ctrl->outpath.out0.inst_handle;
else if (path == VFE_MSG_OUTPUT_SECONDARY)
- image_mode = vfe32_ctrl->share_ctrl->outpath.out1.image_mode;
+ inst_handle = vfe32_ctrl->share_ctrl->outpath.out1.inst_handle;
else if (path == VFE_MSG_OUTPUT_TERTIARY1)
- image_mode = vfe32_ctrl->share_ctrl->outpath.out2.image_mode;
+ inst_handle = vfe32_ctrl->share_ctrl->outpath.out2.inst_handle;
else if (path == VFE_MSG_OUTPUT_TERTIARY2)
- image_mode = vfe32_ctrl->share_ctrl->outpath.out3.image_mode;
+ inst_handle = vfe32_ctrl->share_ctrl->outpath.out3.inst_handle;
- vfe32_subdev_notify(id, path, image_mode,
+ vfe32_subdev_notify(id, path, inst_handle,
&vfe32_ctrl->subdev, vfe32_ctrl->share_ctrl);
outch = vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
@@ -1704,18 +1708,30 @@
case VFE_CMD_START_RECORDING:
pr_info("vfe32_proc_general: cmdID = %s\n",
vfe32_general_cmd[cmd->id]);
+ if (copy_from_user(&temp1, (void __user *)(cmd->value),
+ sizeof(uint32_t))) {
+ pr_err("%s Error copying inst_handle for recording\n",
+ __func__);
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
if (vfe32_ctrl->share_ctrl->operation_mode &
- VFE_OUTPUTS_PREVIEW_AND_VIDEO)
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+ vfe32_ctrl->share_ctrl->outpath.out1.inst_handle =
+ temp1;
rc = vfe32_configure_pingpong_buffers(
VFE_MSG_V32_START_RECORDING,
VFE_MSG_OUTPUT_SECONDARY,
vfe32_ctrl);
- else if (vfe32_ctrl->share_ctrl->operation_mode &
- VFE_OUTPUTS_VIDEO_AND_PREVIEW)
+ } else if (vfe32_ctrl->share_ctrl->operation_mode &
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+ vfe32_ctrl->share_ctrl->outpath.out0.inst_handle =
+ temp1;
rc = vfe32_configure_pingpong_buffers(
VFE_MSG_V32_START_RECORDING,
VFE_MSG_OUTPUT_PRIMARY,
vfe32_ctrl);
+ }
if (rc < 0) {
pr_err("%s error configuring pingpong buffers"
" for video", __func__);
@@ -2187,6 +2203,14 @@
break;
case VFE_CMD_LIVESHOT:
+ if (copy_from_user(&temp1, (void __user *)(cmd->value),
+ sizeof(uint32_t))) {
+ pr_err("%s Error copying inst_handle for liveshot ",
+ __func__);
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ vfe32_ctrl->share_ctrl->outpath.out0.inst_handle = temp1;
/* Configure primary channel */
rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_CAPTURE,
VFE_MSG_OUTPUT_PRIMARY, vfe32_ctrl);
@@ -3452,12 +3476,12 @@
static void vfe_send_outmsg(
struct axi_ctrl_t *axi_ctrl, uint8_t msgid,
uint32_t ch0_paddr, uint32_t ch1_paddr,
- uint32_t ch2_paddr, uint32_t image_mode)
+ uint32_t ch2_paddr, uint32_t inst_handle)
{
struct isp_msg_output msg;
msg.output_id = msgid;
- msg.buf.image_mode = image_mode;
+ msg.buf.inst_handle = inst_handle;
msg.buf.ch_paddr[0] = ch0_paddr;
msg.buf.ch_paddr[1] = ch1_paddr;
msg.buf.ch_paddr[2] = ch2_paddr;
@@ -3559,7 +3583,7 @@
vfe_send_outmsg(axi_ctrl,
MSG_ID_OUTPUT_PRIMARY, ch0_paddr,
ch1_paddr, ch2_paddr,
- axi_ctrl->share_ctrl->outpath.out0.image_mode);
+ axi_ctrl->share_ctrl->outpath.out0.inst_handle);
} else {
axi_ctrl->share_ctrl->outpath.out0.frame_drop_cnt++;
@@ -3637,7 +3661,7 @@
vfe_send_outmsg(axi_ctrl,
MSG_ID_OUTPUT_SECONDARY, ch0_paddr,
ch1_paddr, ch2_paddr,
- axi_ctrl->share_ctrl->outpath.out1.image_mode);
+ axi_ctrl->share_ctrl->outpath.out1.inst_handle);
} else {
axi_ctrl->share_ctrl->outpath.out1.frame_drop_cnt++;
@@ -3678,7 +3702,7 @@
vfe_send_outmsg(axi_ctrl,
MSG_ID_OUTPUT_TERTIARY1, ch0_paddr,
0, 0,
- axi_ctrl->share_ctrl->outpath.out2.image_mode);
+ axi_ctrl->share_ctrl->outpath.out2.inst_handle);
} else {
axi_ctrl->share_ctrl->outpath.out2.frame_drop_cnt++;
@@ -3719,7 +3743,7 @@
vfe_send_outmsg(axi_ctrl,
MSG_ID_OUTPUT_TERTIARY2, ch0_paddr,
0, 0,
- axi_ctrl->share_ctrl->outpath.out3.image_mode);
+ axi_ctrl->share_ctrl->outpath.out3.inst_handle);
} else {
axi_ctrl->share_ctrl->outpath.out3.frame_drop_cnt++;
pr_err("path_irq irq - no free buffer for rdi1!\n");
@@ -3762,6 +3786,8 @@
/* spin_lock_irqsave(&ctrl->state_lock, flags); */
struct isp_msg_stats msgStats;
msgStats.frameCounter = vfe32_ctrl->share_ctrl->vfeFrameId;
+ if (vfe32_ctrl->simultaneous_sof_stat)
+ msgStats.frameCounter--;
msgStats.buffer = bufAddress;
switch (statsNum) {
case statsAeNum:{
@@ -3844,6 +3870,9 @@
uint32_t temp;
msgStats.frame_id = vfe32_ctrl->share_ctrl->vfeFrameId;
+ if (vfe32_ctrl->simultaneous_sof_stat)
+ msgStats.frame_id--;
+
msgStats.status_bits = status_bits;
msgStats.aec.buff = vfe32_ctrl->aecStatsControl.bufToRender;
@@ -4204,7 +4233,9 @@
{
unsigned long flags;
struct axi_ctrl_t *axi_ctrl = (struct axi_ctrl_t *)data;
+ struct vfe32_ctrl_type *vfe32_ctrl = axi_ctrl->share_ctrl->vfe32_ctrl;
struct vfe32_isr_queue_cmd *qcmd = NULL;
+ int stat_interrupt;
CDBG("=== axi32_do_tasklet start ===\n");
@@ -4224,11 +4255,32 @@
spin_unlock_irqrestore(&axi_ctrl->tasklet_lock,
flags);
+ if (axi_ctrl->share_ctrl->stats_comp) {
+ stat_interrupt = (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK);
+ } else {
+ stat_interrupt =
+ (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_AEC) |
+ (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_AWB) |
+ (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_AF) |
+ (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_IHIST) |
+ (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_RS) |
+ (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_CS);
+ }
if (qcmd->vfeInterruptStatus0 &
- VFE_IRQ_STATUS0_CAMIF_SOF_MASK)
+ VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
+ if (stat_interrupt)
+ vfe32_ctrl->simultaneous_sof_stat = 1;
v4l2_subdev_notify(&axi_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_CAMIF_SOF_MASK);
+ }
/* interrupt to be processed, *qcmd has the payload. */
if (qcmd->vfeInterruptStatus0 &
@@ -4335,6 +4387,7 @@
(void *)VFE_IRQ_STATUS0_SYNC_TIMER2);
}
}
+ vfe32_ctrl->simultaneous_sof_stat = 0;
kfree(qcmd);
}
CDBG("=== axi32_do_tasklet end ===\n");
@@ -4486,10 +4539,9 @@
struct vfe32_ctrl_type *vfe32_ctrl =
(struct vfe32_ctrl_type *)v4l2_get_subdevdata(sd);
struct msm_isp_cmd vfecmd;
- struct msm_camvfe_params *vfe_params =
- (struct msm_camvfe_params *)arg;
- struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
- void *data = vfe_params->data;
+ struct msm_camvfe_params *vfe_params;
+ struct msm_vfe_cfg_cmd *cmd;
+ void *data;
long rc = 0;
struct vfe_cmd_stats_buf *scfg = NULL;
@@ -4500,6 +4552,17 @@
return -EFAULT;
}
+ CDBG("%s\n", __func__);
+ if (subdev_cmd == VIDIOC_MSM_VFE_INIT) {
+ CDBG("%s init\n", __func__);
+ return msm_vfe_subdev_init(sd);
+ } else if (subdev_cmd == VIDIOC_MSM_VFE_RELEASE) {
+ msm_vfe_subdev_release(sd);
+ return 0;
+ }
+ vfe_params = (struct msm_camvfe_params *)arg;
+ cmd = vfe_params->vfe_cfg;
+ data = vfe_params->data;
switch (cmd->cmd_type) {
case CMD_VFE_PROCESS_IRQ:
vfe32_process_irq(vfe32_ctrl, (uint32_t) data);
@@ -4639,12 +4702,17 @@
.core = &msm_vfe_subdev_core_ops,
};
-int msm_axi_subdev_init(struct v4l2_subdev *sd,
- struct msm_cam_media_controller *mctl)
+int msm_axi_subdev_init(struct v4l2_subdev *sd)
{
int rc = 0;
struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
- v4l2_set_subdev_hostdata(sd, mctl);
+ struct msm_cam_media_controller *mctl;
+ mctl = v4l2_get_subdev_hostdata(sd);
+ if (mctl == NULL) {
+ pr_err("%s: mctl is NULL\n", __func__);
+ rc = -EINVAL;
+ goto mctl_failed;
+ }
spin_lock_init(&axi_ctrl->tasklet_lock);
INIT_LIST_HEAD(&axi_ctrl->tasklet_q);
spin_lock_init(&axi_ctrl->share_ctrl->sd_notify_lock);
@@ -4692,16 +4760,15 @@
axi_ctrl->share_ctrl->vfebase = NULL;
remap_failed:
disable_irq(axi_ctrl->vfeirq->start);
+mctl_failed:
return rc;
}
-int msm_vfe_subdev_init(struct v4l2_subdev *sd,
- struct msm_cam_media_controller *mctl)
+int msm_vfe_subdev_init(struct v4l2_subdev *sd)
{
int rc = 0;
struct vfe32_ctrl_type *vfe32_ctrl =
(struct vfe32_ctrl_type *)v4l2_get_subdevdata(sd);
- v4l2_set_subdev_hostdata(sd, mctl);
spin_lock_init(&vfe32_ctrl->share_ctrl->stop_flag_lock);
spin_lock_init(&vfe32_ctrl->state_lock);
@@ -5169,8 +5236,7 @@
int rc = -ENOIOCTLCMD;
switch (cmd) {
case VIDIOC_MSM_AXI_INIT:
- rc = msm_axi_subdev_init(sd,
- (struct msm_cam_media_controller *)arg);
+ rc = msm_axi_subdev_init(sd);
break;
case VIDIOC_MSM_AXI_CFG:
rc = msm_axi_config(sd, arg);
@@ -5259,6 +5325,12 @@
sd_info.irq_num = 0;
msm_cam_register_subdev_node(&axi_ctrl->subdev, &sd_info);
+ media_entity_init(&axi_ctrl->subdev.entity, 0, NULL, 0);
+ axi_ctrl->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ axi_ctrl->subdev.entity.group_id = AXI_DEV;
+ axi_ctrl->subdev.entity.name = pdev->name;
+ axi_ctrl->subdev.entity.revision = axi_ctrl->subdev.devnode->num;
+
v4l2_subdev_init(&vfe32_ctrl->subdev, &msm_vfe_subdev_ops);
vfe32_ctrl->subdev.internal_ops = &msm_vfe_internal_ops;
vfe32_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -5297,6 +5369,19 @@
axi_ctrl->fs_vfe = NULL;
}
+ /* Register subdev node before requesting irq since
+ * irq_num is needed by msm_cam_server */
+ sd_info.sdev_type = VFE_DEV;
+ sd_info.sd_index = 0;
+ sd_info.irq_num = axi_ctrl->vfeirq->start;
+ msm_cam_register_subdev_node(&vfe32_ctrl->subdev, &sd_info);
+
+ media_entity_init(&vfe32_ctrl->subdev.entity, 0, NULL, 0);
+ vfe32_ctrl->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ vfe32_ctrl->subdev.entity.group_id = VFE_DEV;
+ vfe32_ctrl->subdev.entity.name = pdev->name;
+ vfe32_ctrl->subdev.entity.revision = vfe32_ctrl->subdev.devnode->num;
+
/* Request for this device irq from the camera server. If the
* IRQ Router is present on this target, the interrupt will be
* handled by the camera server and the interrupt service
@@ -5336,10 +5421,6 @@
axi32_do_tasklet, (unsigned long)axi_ctrl);
vfe32_ctrl->pdev = pdev;
- sd_info.sdev_type = VFE_DEV;
- sd_info.sd_index = 0;
- sd_info.irq_num = axi_ctrl->vfeirq->start;
- msm_cam_register_subdev_node(&vfe32_ctrl->subdev, &sd_info);
return 0;
vfe32_no_resource:
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index 542bbf8..9336cfb 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -241,8 +241,8 @@
#define V32_OPERATION_CFG_LEN 44
#define V32_AXI_OUT_OFF 0x00000038
-#define V32_AXI_OUT_LEN 224
-#define V32_AXI_CH_INF_LEN 32
+#define V32_AXI_OUT_LEN 240
+#define V32_AXI_CH_INF_LEN 48
#define V32_AXI_CFG_LEN 47
#define V32_AXI_BUS_FMT_OFF 1
#define V32_AXI_BUS_FMT_LEN 4
@@ -756,7 +756,7 @@
struct vfe32_output_ch {
struct list_head free_buf_queue;
spinlock_t free_buf_lock;
- uint16_t image_mode;
+ uint32_t inst_handle;
int8_t ch0;
int8_t ch1;
int8_t ch2;
@@ -1006,6 +1006,8 @@
uint32_t snapshot_frame_cnt;
struct msm_stats_bufq_ctrl stats_ctrl;
struct msm_stats_ops stats_ops;
+
+ uint32_t simultaneous_sof_stat;
};
#define statsAeNum 0
@@ -1026,19 +1028,4 @@
uint32_t statsBuf[VFE_STATS_BUFFER_COUNT];
};
-#define VIDIOC_MSM_AXI_INIT \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 18, struct msm_cam_media_controller *)
-
-#define VIDIOC_MSM_AXI_RELEASE \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 19, struct msm_cam_media_controller *)
-
-#define VIDIOC_MSM_AXI_CFG \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 20, void *)
-
-#define VIDIOC_MSM_AXI_IRQ \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 21, void *)
-
-#define VIDIOC_MSM_AXI_BUF_CFG \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 22, void *)
-
#endif /* __MSM_VFE32_H__ */
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 96047d5..64e0385 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -585,7 +585,7 @@
struct isp_msg_output msg;
msg.output_id = msgid;
- msg.buf.image_mode = -1;
+ msg.buf.inst_handle = 0;
msg.buf.ch_paddr[0] = ch0_paddr;
msg.buf.ch_paddr[1] = ch1_paddr;
msg.frameCounter = vfe2x_ctrl->vfeFrameId;
@@ -1182,12 +1182,11 @@
unsigned int subdev_cmd, void *arg)
{
struct msm_isp_cmd vfecmd;
- struct msm_camvfe_params *vfe_params =
- (struct msm_camvfe_params *)arg;
- struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
+ struct msm_camvfe_params *vfe_params;
+ struct msm_vfe_cfg_cmd *cmd;
struct table_cmd *table_pending;
long rc = 0;
- void *data = vfe_params->data;
+ void *data;
struct msm_pmem_region *regptr;
unsigned char buf[256];
@@ -1208,6 +1207,18 @@
struct vfe_outputack fack;
CDBG("msm_vfe_subdev_ioctl is called\n");
+ if (subdev_cmd == VIDIOC_MSM_VFE_INIT) {
+ CDBG("%s init\n", __func__);
+ return msm_vfe_subdev_init(sd);
+ } else if (subdev_cmd == VIDIOC_MSM_VFE_RELEASE) {
+ msm_vfe_subdev_release(sd);
+ return 0;
+ }
+
+ vfe_params = (struct msm_camvfe_params *)arg;
+ cmd = vfe_params->vfe_cfg;
+ data = vfe_params->data;
+
if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
@@ -1954,11 +1965,16 @@
{"vfe_clk", 192000000},
};
-int msm_vfe_subdev_init(struct v4l2_subdev *sd,
- struct msm_cam_media_controller *mctl)
+int msm_vfe_subdev_init(struct v4l2_subdev *sd)
{
int rc = 0;
- v4l2_set_subdev_hostdata(sd, mctl);
+ struct msm_cam_media_controller *mctl;
+ mctl = v4l2_get_subdev_hostdata(sd);
+ if (mctl == NULL) {
+ pr_err("%s: mctl is NULL\n", __func__);
+ rc = -EINVAL;
+ goto mctl_failed;
+ }
spin_lock_init(&vfe2x_ctrl->sd_notify_lock);
spin_lock_init(&vfe2x_ctrl->table_lock);
@@ -2011,11 +2027,11 @@
kfree(extdata);
init_fail:
extlen = 0;
+mctl_failed:
return rc;
}
-int msm_vpe_subdev_init(struct v4l2_subdev *sd,
- struct msm_cam_media_controller *mctl)
+int msm_vpe_subdev_init(struct v4l2_subdev *sd)
{
return 0;
}
@@ -2101,6 +2117,12 @@
sd_info.sd_index = 0;
sd_info.irq_num = 0;
msm_cam_register_subdev_node(&vfe2x_ctrl->subdev, &sd_info);
+
+ media_entity_init(&vfe2x_ctrl->subdev.entity, 0, NULL, 0);
+ vfe2x_ctrl->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ vfe2x_ctrl->subdev.entity.group_id = VFE_DEV;
+ vfe2x_ctrl->subdev.entity.name = pdev->name;
+ vfe2x_ctrl->subdev.entity.revision = vfe2x_ctrl->subdev.devnode->num;
return 0;
}
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index 2b58f44..58fc153 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -603,10 +603,11 @@
static int msm_vpe_resource_init(void);
-int msm_vpe_subdev_init(struct v4l2_subdev *sd,
- struct msm_cam_media_controller *mctl)
+int msm_vpe_subdev_init(struct v4l2_subdev *sd)
{
int rc = 0;
+ struct msm_cam_media_controller *mctl;
+ mctl = v4l2_get_subdev_hostdata(sd);
D("%s:begin", __func__);
if (atomic_read(&vpe_init_done)) {
pr_err("%s: VPE has been initialized", __func__);
@@ -619,7 +620,6 @@
atomic_set(&vpe_init_done, 0);
return rc;
}
- v4l2_set_subdev_hostdata(sd, mctl);
spin_lock_init(&vpe_ctrl->lock);
D("%s:end", __func__);
return rc;
@@ -843,9 +843,7 @@
switch (cmd) {
case VIDIOC_MSM_VPE_INIT: {
- struct msm_cam_media_controller *mctl =
- (struct msm_cam_media_controller *)arg;
- msm_vpe_subdev_init(sd, mctl);
+ msm_vpe_subdev_init(sd);
break;
}
@@ -980,7 +978,7 @@
platform_set_drvdata(pdev, &vpe_ctrl->subdev);
media_entity_init(&vpe_ctrl->subdev.entity, 0, NULL, 0);
- vpe_ctrl->subdev.entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+ vpe_ctrl->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
vpe_ctrl->subdev.entity.group_id = VPE_DEV;
vpe_ctrl->subdev.entity.name = vpe_ctrl->subdev.name;
diff --git a/drivers/media/video/msm/msm_vpe.h b/drivers/media/video/msm/msm_vpe.h
index 5cf0309..6516ea1 100644
--- a/drivers/media/video/msm/msm_vpe.h
+++ b/drivers/media/video/msm/msm_vpe.h
@@ -180,14 +180,5 @@
int32_t phase_step_y;
};
-#define VIDIOC_MSM_VPE_INIT \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_cam_media_controller *)
-
-#define VIDIOC_MSM_VPE_RELEASE \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_cam_media_controller *)
-
-#define VIDIOC_MSM_VPE_CFG \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 17, struct msm_mctl_pp_params *)
-
#endif /*_MSM_VPE_H_*/
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index be1efe0..72f3f3d 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -284,7 +284,6 @@
int update_type, int res)
{
int32_t rc = 0;
-
s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
msleep(30);
if (update_type == MSM_SENSOR_REG_INIT) {
@@ -792,8 +791,15 @@
sizeof(s_ctrl->sensor_v4l2_subdev.name), "%s", id->name);
v4l2_i2c_subdev_init(&s_ctrl->sensor_v4l2_subdev, client,
s_ctrl->sensor_v4l2_subdev_ops);
-
+ s_ctrl->sensor_v4l2_subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ media_entity_init(&s_ctrl->sensor_v4l2_subdev.entity, 0, NULL, 0);
+ s_ctrl->sensor_v4l2_subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ s_ctrl->sensor_v4l2_subdev.entity.group_id = SENSOR_DEV;
+ s_ctrl->sensor_v4l2_subdev.entity.name =
+ s_ctrl->sensor_v4l2_subdev.name;
msm_sensor_register(&s_ctrl->sensor_v4l2_subdev);
+ s_ctrl->sensor_v4l2_subdev.entity.revision =
+ s_ctrl->sensor_v4l2_subdev.devnode->num;
goto power_down;
probe_fail:
pr_err("%s %s_i2c_probe failed\n", __func__, client->name);
diff --git a/drivers/media/video/msm/sensors/ov7692_v4l2.c b/drivers/media/video/msm/sensors/ov7692_v4l2.c
index 6fc1da1..71d436e 100644
--- a/drivers/media/video/msm/sensors/ov7692_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_v4l2.c
@@ -173,24 +173,33 @@
};
static struct msm_camera_i2c_reg_conf ov7692_saturation[][4] = {
- {{0x81, 0x33, 0xCC}, {0xd8, 0x00, 0x00}, {0xd9, 0x00, 0x00},
- {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL0*/
- {{0x81, 0x33, 0xCC}, {0xd8, 0x10, 0x00}, {0xd9, 0x10, 0x00},
- {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL1*/
- {{0x81, 0x33, 0xCC}, {0xd8, 0x20, 0x00}, {0xd9, 0x20, 0x00},
- {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL2*/
- {{0x81, 0x33, 0xCC}, {0xd8, 0x30, 0x00}, {0xd9, 0x30, 0x00},
- {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL3*/
- {{0x81, 0x33, 0xCC}, {0xd8, 0x40, 0x00}, {0xd9, 0x40, 0x00},
- {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL4*/
- {{0x81, 0x33, 0xCC}, {0xd8, 0x50, 0x00}, {0xd9, 0x50, 0x00},
- {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL5*/
- {{0x81, 0x33, 0xCC}, {0xd8, 0x60, 0x00}, {0xd9, 0x60, 0x00},
- {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL6*/
- {{0x81, 0x33, 0xCC}, {0xd8, 0x70, 0x00}, {0xd9, 0x70, 0x00},
- {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL7*/
- {{0x81, 0x33, 0xCC}, {0xd8, 0x80, 0x00}, {0xd9, 0x80, 0x00},
- {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL8*/
+ {{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x00, 0x00, 0x00, 0x00},
+ {0xd9, 0x00, 0x00, 0x00, 0x00},
+ {0xd2, 0x02, 0x00, 0x00, 0x00},},/* SATURATION LEVEL0*/
+ {{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x10, 0x00, 0x00, 0x00},
+ {0xd9, 0x10, 0x00, 0x00, 0x00},
+ {0xd2, 0x02, 0x00, 0x00, 0x00},}, /* SATURATION LEVEL1*/
+ {{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x20, 0x00, 0x00, 0x00},
+ {0xd9, 0x20, 0x00, 0x00, 0x00},
+ {0xd2, 0x02, 0x00, 0x00, 0x00},}, /* SATURATION LEVEL2*/
+ {{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x30, 0x00, 0x00, 0x00},
+ {0xd9, 0x30, 0x00, 0x00, 0x00},
+ {0xd2, 0x02, 0x00, 0x00, 0x00},}, /* SATURATION LEVEL3*/
+ {{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x40, 0x00, 0x00, 0x00},
+ {0xd9, 0x40, 0x00, 0x00, 0x00},
+ {0xd2, 0x02, 0x00, 0x00, 0x00},}, /* SATURATION LEVEL4*/
+ {{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x50, 0x00, 0x00, 0x00},
+ {0xd9, 0x50, 0x00, 0x00, 0x00},
+ {0xd2, 0x02, 0x00, 0x00, 0x00},}, /* SATURATION LEVEL5*/
+ {{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x60, 0x00, 0x00, 0x00},
+ {0xd9, 0x60, 0x00, 0x00, 0x00},
+ {0xd2, 0x02, 0x00, 0x00, 0x00},}, /* SATURATION LEVEL6*/
+ {{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x70, 0x00, 0x00, 0x00},
+ {0xd9, 0x70, 0x00, 0x00, 0x00},
+ {0xd2, 0x02, 0x00, 0x00, 0x00},}, /* SATURATION LEVEL7*/
+ {{0x81, 0x33, 0x00, 0x00, 0xCC}, {0xd8, 0x80, 0x00, 0x00, 0x00},
+ {0xd9, 0x80, 0x00, 0x00, 0x00},
+ {0xd2, 0x02, 0x00, 0x00, 0x00},}, /* SATURATION LEVEL8*/
};
static struct msm_camera_i2c_conf_array ov7692_saturation_confs[][1] = {
{{ov7692_saturation[0], ARRAY_SIZE(ov7692_saturation[0]), 0,
@@ -327,12 +336,18 @@
.data_type = MSM_CAMERA_I2C_BYTE_DATA,
};
static struct msm_camera_i2c_reg_conf ov7692_sharpness[][2] = {
- {{0xb4, 0x20, 0xDF}, {0xb6, 0x00, 0xE0},}, /* SHARPNESS LEVEL 0*/
- {{0xb4, 0x20, 0xDF}, {0xb6, 0x01, 0xE0},}, /* SHARPNESS LEVEL 1*/
- {{0xb4, 0x00, 0xDF}, {0xb6, 0x00, 0xE0},}, /* SHARPNESS LEVEL 2*/
- {{0xb4, 0x20, 0xDF}, {0xb6, 0x66, 0xE0},}, /* SHARPNESS LEVEL 3*/
- {{0xb4, 0x20, 0xDF}, {0xb6, 0x99, 0xE0},}, /* SHARPNESS LEVEL 4*/
- {{0xb4, 0x20, 0xDF}, {0xb6, 0xcc, 0xE0},}, /* SHARPNESS LEVEL 5*/
+ {{0xb4, 0x20, 0x00, 0x00, 0xDF},
+ {0xb6, 0x00, 0x00, 0x00, 0xE0},}, /* SHARPNESS LEVEL 0*/
+ {{0xb4, 0x20, 0x00, 0x00, 0xDF},
+ {0xb6, 0x01, 0x00, 0x00, 0xE0},}, /* SHARPNESS LEVEL 1*/
+ {{0xb4, 0x00, 0x00, 0x00, 0xDF},
+ {0xb6, 0x00, 0x00, 0x00, 0xE0},}, /* SHARPNESS LEVEL 2*/
+ {{0xb4, 0x20, 0x00, 0x00, 0xDF},
+ {0xb6, 0x66, 0x00, 0x00, 0xE0},}, /* SHARPNESS LEVEL 3*/
+ {{0xb4, 0x20, 0x00, 0x00, 0xDF},
+ {0xb6, 0x99, 0x00, 0x00, 0xE0},}, /* SHARPNESS LEVEL 4*/
+ {{0xb4, 0x20, 0x00, 0x00, 0xDF},
+ {0xb6, 0xcc, 0x00, 0x00, 0xE0},}, /* SHARPNESS LEVEL 5*/
};
static struct msm_camera_i2c_conf_array ov7692_sharpness_confs[][1] = {
@@ -407,13 +422,13 @@
};
static struct msm_camera_i2c_reg_conf ov7692_iso[][1] = {
- {{0x14, 0x20, 0x8F},}, /*ISO_AUTO*/
- {{0x14, 0x20, 0x8F},}, /*ISO_DEBLUR*/
- {{0x14, 0x00, 0x8F},}, /*ISO_100*/
- {{0x14, 0x10, 0x8F},}, /*ISO_200*/
- {{0x14, 0x20, 0x8F},}, /*ISO_400*/
- {{0x14, 0x30, 0x8F},}, /*ISO_800*/
- {{0x14, 0x40, 0x8F},}, /*ISO_1600*/
+ {{0x14, 0x20, 0x00, 0x00, 0x8F},}, /*ISO_AUTO*/
+ {{0x14, 0x20, 0x00, 0x00, 0x8F},}, /*ISO_DEBLUR*/
+ {{0x14, 0x00, 0x00, 0x00, 0x8F},}, /*ISO_100*/
+ {{0x14, 0x10, 0x00, 0x00, 0x8F},}, /*ISO_200*/
+ {{0x14, 0x20, 0x00, 0x00, 0x8F},}, /*ISO_400*/
+ {{0x14, 0x30, 0x00, 0x00, 0x8F},}, /*ISO_800*/
+ {{0x14, 0x40, 0x00, 0x00, 0x8F},}, /*ISO_1600*/
};
@@ -453,7 +468,7 @@
};
static struct msm_camera_i2c_reg_conf ov7692_no_effect[] = {
- {0x81, 0x00, 0xDF},
+ {0x81, 0x00, 0x00, 0x00, 0xDF},
{0x28, 0x00,},
{0xd2, 0x00,},
{0xda, 0x80,},
@@ -467,32 +482,41 @@
};
static struct msm_camera_i2c_reg_conf ov7692_special_effect[][5] = {
- {{0x81, 0x20, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,}, {0xda, 0x80,},
- {0xdb, 0x80,},}, /*for special effect OFF*/
- {{0x81, 0x20, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,}, {0xda, 0x80,},
- {0xdb, 0x80,},}, /*for special effect MONO*/
- {{0x81, 0x20, 0xDF}, {0x28, 0x80,}, {0xd2, 0x40,}, {0xda, 0x80,},
- {0xdb, 0x80,},}, /*for special efefct Negative*/
- {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
- {-1, -1, -1},}, /*Solarize is not supported by sensor*/
- {{0x81, 0x20, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,}, {0xda, 0x40,},
- {0xdb, 0xa0,},}, /*for sepia*/
- {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
- {-1, -1, -1},}, /* Posteraize not supported */
- {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
- {-1, -1, -1},}, /* White board not supported*/
- {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
- {-1, -1, -1},}, /*Blackboard not supported*/
- {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
- {-1, -1, -1},}, /*Aqua not supported*/
- {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
- {-1, -1, -1},}, /*Emboss not supported */
- {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
- {-1, -1, -1},}, /*sketch not supported*/
- {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
- {-1, -1, -1},}, /*Neon not supported*/
- {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
- {-1, -1, -1},}, /*MAX value*/
+ {{0x81, 0x20, 0x00, 0x00, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,},
+ {0xda, 0x80,}, {0xdb, 0x80,},}, /*for special effect OFF*/
+ {{0x81, 0x20, 0x00, 0x00, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,},
+ {0xda, 0x80,}, {0xdb, 0x80,},}, /*for special effect MONO*/
+ {{0x81, 0x20, 0x00, 0x00, 0xDF}, {0x28, 0x80,}, {0xd2, 0x40,},
+ {0xda, 0x80,}, {0xdb, 0x80,},}, /*for special efefct Negative*/
+ {{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},},/*Solarize is not supported by sensor*/
+ {{0x81, 0x20, 0x00, 0x00, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,},
+ {0xda, 0x40,}, {0xdb, 0xa0,},}, /*for sepia*/
+ {{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},}, /* Posteraize not supported */
+ {{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},}, /* White board not supported*/
+ {{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},}, /*Blackboard not supported*/
+ {{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},}, /*Aqua not supported*/
+ {{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},}, /*Emboss not supported */
+ {{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},}, /*sketch not supported*/
+ {{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},}, /*Neon not supported*/
+ {{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},}, /*MAX value*/
};
static struct msm_camera_i2c_conf_array ov7692_special_effect_confs[][1] = {
@@ -551,9 +575,12 @@
};
static struct msm_camera_i2c_reg_conf ov7692_antibanding[][2] = {
- {{0x13, 0x20, 0xDF}, {0x14, 0x16, 0xE8},}, /*ANTIBANDING 60HZ*/
- {{0x13, 0x20, 0xDF}, {0x14, 0x17, 0xE8},}, /*ANTIBANDING 50HZ*/
- {{0x13, 0x20, 0xDF}, {0x14, 0x14, 0xE8},}, /* ANTIBANDING AUTO*/
+ {{0x13, 0x20, 0x00, 0x00, 0xDF},
+ {0x14, 0x16, 0x00, 0x00, 0xE8},}, /*ANTIBANDING 60HZ*/
+ {{0x13, 0x20, 0x00, 0x00, 0xDF},
+ {0x14, 0x17, 0x00, 0x00, 0xE8},}, /*ANTIBANDING 50HZ*/
+ {{0x13, 0x20, 0x00, 0x00, 0xDF},
+ {0x14, 0x14, 0x00, 0x00, 0xE8},}, /* ANTIBANDING AUTO*/
};
@@ -583,16 +610,16 @@
};
static struct msm_camera_i2c_reg_conf ov7692_wb_oem[][4] = {
- {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
- {-1, -1, -1},},/*WHITEBALNACE OFF*/
- {{0x13, 0xf7}, {0x15, 0x00}, {-1, -1, -1},
- {-1, -1, -1},}, /*WHITEBALNACE AUTO*/
+ {{-1, -1, -1, -1 , -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},},/*WHITEBALNACE OFF*/
+ {{0x13, 0xf7}, {0x15, 0x00}, {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},}, /*WHITEBALNACE AUTO*/
{{0x13, 0xf5}, {0x01, 0x56}, {0x02, 0x50},
{0x15, 0x00},}, /*WHITEBALNACE CUSTOM*/
{{0x13, 0xf5}, {0x01, 0x66}, {0x02, 0x40},
{0x15, 0x00},}, /*INCANDISCENT*/
- {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
- {-1, -1, -1},}, /*FLOURESECT NOT SUPPORTED */
+ {{-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1},}, /*FLOURESECT NOT SUPPORTED */
{{0x13, 0xf5}, {0x01, 0x43}, {0x02, 0x5d},
{0x15, 0x00},}, /*DAYLIGHT*/
{{0x13, 0xf5}, {0x01, 0x48}, {0x02, 0x63},
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 05f3c4a..715b4e7 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -19,6 +19,7 @@
#include "msm_sensor.h"
#include "msm_actuator.h"
#include "msm_vfe32.h"
+#include "msm_csi_register.h"
#ifdef CONFIG_MSM_CAMERA_DEBUG
#define D(fmt, args...) pr_debug("msm: " fmt, ##args)
@@ -95,6 +96,19 @@
return -EINVAL;
}
+void msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle,
+ struct video_device *pvdev)
+{
+ v4l2_fh_init(eventHandle, pvdev);
+ v4l2_fh_add(eventHandle);
+}
+
+void msm_destroy_v4l2_event_queue(struct v4l2_fh *eventHandle)
+{
+ v4l2_fh_del(eventHandle);
+ v4l2_fh_exit(eventHandle);
+}
+
uint32_t msm_cam_server_get_mctl_handle(void)
{
uint32_t i;
@@ -422,6 +436,7 @@
plane_info.buffer_type = pfmt->type;
plane_info.ext_mode = pcam->dev_inst[idx]->image_mode;
plane_info.num_planes = 1;
+ plane_info.inst_handle = pcam->dev_inst[idx]->inst_handle;
D("%s: %d, %d, 0x%x\n", __func__,
pfmt->fmt.pix.width, pfmt->fmt.pix.height,
pfmt->fmt.pix.pixelformat);
@@ -478,6 +493,8 @@
plane_info.buffer_type = pfmt->type;
plane_info.ext_mode = pcam->dev_inst[idx]->image_mode;
plane_info.num_planes = pix_mp->num_planes;
+ plane_info.inst_handle = pcam->dev_inst[idx]->inst_handle;
+
if (plane_info.num_planes <= 0 ||
plane_info.num_planes > VIDEO_MAX_PLANES) {
pr_err("%s Invalid number of planes set %d", __func__,
@@ -880,7 +897,6 @@
struct msm_cam_v4l2_device *pcam)
{
int rc = 0;
- struct msm_cam_media_controller *pmctl;
D("%s\n", __func__);
@@ -906,17 +922,6 @@
/* initialization the media controller module*/
msm_mctl_init(pcam);
- /*for single VFE msms (8660, 8960v1), just populate the session
- with our VFE devices that registered*/
- pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
- if (pmctl == NULL) {
- pr_err("%s: cannot find mctl\n", __func__);
- msm_mctl_free(pcam);
- atomic_dec(&ps->number_pcam_active);
- return -ENODEV;
- }
- pmctl->axi_sdev = ps->axi_device[0];
- pmctl->isp_sdev = ps->isp_subdev[0];
return rc;
}
@@ -940,6 +945,50 @@
return rc;
}
+static int map_imem_addresses(struct msm_cam_media_controller *mctl)
+{
+ int rc = 0;
+ rc = msm_iommu_map_contig_buffer(
+ (unsigned long)IMEM_Y_PING_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+ ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
+ SZ_4K, IOMMU_WRITE | IOMMU_READ,
+ (unsigned long *)&mctl->ping_imem_y);
+ mctl->ping_imem_cbcr = mctl->ping_imem_y + IMEM_Y_SIZE;
+ if (rc < 0) {
+ pr_err("%s: ping iommu mapping returned error %d\n",
+ __func__, rc);
+ mctl->ping_imem_y = 0;
+ mctl->ping_imem_cbcr = 0;
+ }
+ msm_iommu_map_contig_buffer(
+ (unsigned long)IMEM_Y_PONG_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+ ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
+ SZ_4K, IOMMU_WRITE | IOMMU_READ,
+ (unsigned long *)&mctl->pong_imem_y);
+ mctl->pong_imem_cbcr = mctl->pong_imem_y + IMEM_Y_SIZE;
+ if (rc < 0) {
+ pr_err("%s: pong iommu mapping returned error %d\n",
+ __func__, rc);
+ mctl->pong_imem_y = 0;
+ mctl->pong_imem_cbcr = 0;
+ }
+ return rc;
+}
+
+static void unmap_imem_addresses(struct msm_cam_media_controller *mctl)
+{
+ msm_iommu_unmap_contig_buffer(mctl->ping_imem_y,
+ CAMERA_DOMAIN, GEN_POOL,
+ ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
+ msm_iommu_unmap_contig_buffer(mctl->pong_imem_y,
+ CAMERA_DOMAIN, GEN_POOL,
+ ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
+ mctl->ping_imem_y = 0;
+ mctl->ping_imem_cbcr = 0;
+ mctl->pong_imem_y = 0;
+ mctl->pong_imem_cbcr = 0;
+}
+
static long msm_ioctl_server(struct file *file, void *fh,
bool valid_prio, int cmd, void *arg)
{
@@ -1283,6 +1332,7 @@
{
int rc = -EINVAL, ges_evt;
struct msm_cam_server_queue *queue;
+ struct msm_cam_media_controller *pmctl;
if (!pcam) {
pr_err("%s pcam passed is null ", __func__);
@@ -1301,7 +1351,6 @@
msm_queue_init(&queue->ctrl_q, "control");
msm_queue_init(&queue->eventData_q, "eventdata");
queue->queue_active = 1;
-
rc = msm_cam_server_open_session(&g_server_dev, pcam);
if (rc < 0) {
pr_err("%s: cam_server_open_session failed %d\n",
@@ -1309,6 +1358,17 @@
goto error;
}
+ pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
+ if (!pmctl) {
+ pr_err("%s: invalid mctl controller", __func__);
+ goto error;
+ }
+ rc = map_imem_addresses(pmctl);
+ if (rc < 0) {
+ pr_err("%sFailed to map imem addresses %d\n", __func__, rc);
+ goto error;
+ }
+
return rc;
error:
ges_evt = MSM_V4L2_GES_CAM_CLOSE;
@@ -1328,6 +1388,7 @@
{
int rc = -EINVAL, ges_evt;
struct msm_cam_server_queue *queue;
+ struct msm_cam_media_controller *pmctl;
mutex_lock(&g_server_dev.server_queue_lock);
queue = &g_server_dev.server_queue[pcam->server_queue_idx];
@@ -1338,6 +1399,13 @@
msm_drain_eventq(&queue->eventData_q);
mutex_unlock(&g_server_dev.server_queue_lock);
+ pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
+ if (!pmctl) {
+ pr_err("%s: invalid mctl controller", __func__);
+ return -EINVAL;
+ }
+ unmap_imem_addresses(pmctl);
+
rc = msm_cam_server_close_session(&g_server_dev, pcam);
if (rc < 0)
pr_err("msm_cam_server_close_session fails %d\n", rc);
@@ -1374,6 +1442,7 @@
struct msm_camera_sensor_info *sinfo;
struct msm_camera_device_platform_data *camdev;
uint8_t csid_core = 0;
+ struct msm_cam_media_controller *p_mctl;
if (notification == NOTIFY_PCLK_CHANGE ||
notification == NOTIFY_CSIPHY_CFG ||
@@ -1384,7 +1453,14 @@
camdev = sinfo->pdata;
csid_core = camdev->csid_core;
}
-
+ if (notification != NOTIFY_GESTURE_CAM_EVT) {
+ p_mctl = v4l2_get_subdev_hostdata(sd);
+ if (p_mctl == NULL) {
+ pr_err("%s: cannot find mctl, %d\n",
+ __func__, notification);
+ return;
+ }
+ }
switch (notification) {
case NOTIFY_ISP_MSG_EVT:
case NOTIFY_VFE_MSG_OUT:
@@ -1393,10 +1469,10 @@
case NOTIFY_VFE_BUF_EVT:
case NOTIFY_VFE_BUF_FREE_EVT:
if (g_server_dev.isp_subdev[0] &&
- g_server_dev.isp_subdev[0]->isp_notify) {
+ g_server_dev.isp_subdev[0]->isp_notify
+ && p_mctl->isp_sdev->sd)
rc = g_server_dev.isp_subdev[0]->isp_notify(
- g_server_dev.vfe_device[0], notification, arg);
- }
+ p_mctl->isp_sdev->sd, notification, arg);
break;
case NOTIFY_VFE_IRQ:{
struct msm_vfe_cfg_cmd cfg_cmd;
@@ -1404,32 +1480,32 @@
cfg_cmd.cmd_type = CMD_VFE_PROCESS_IRQ;
vfe_params.vfe_cfg = &cfg_cmd;
vfe_params.data = arg;
- rc = v4l2_subdev_call(g_server_dev.vfe_device[0],
+ rc = v4l2_subdev_call(p_mctl->isp_sdev->sd,
core, ioctl, 0, &vfe_params);
}
break;
case NOTIFY_AXI_IRQ:
- rc = v4l2_subdev_call(g_server_dev.axi_device[0],
+ rc = v4l2_subdev_call(p_mctl->axi_sdev,
core, ioctl, VIDIOC_MSM_AXI_IRQ, arg);
break;
case NOTIFY_PCLK_CHANGE:
- if (g_server_dev.axi_device[0])
- rc = v4l2_subdev_call(g_server_dev.axi_device[0], video,
+ if (p_mctl->axi_sdev)
+ rc = v4l2_subdev_call(p_mctl->axi_sdev, video,
s_crystal_freq, *(uint32_t *)arg, 0);
else
- rc = v4l2_subdev_call(g_server_dev.vfe_device[0], video,
+ rc = v4l2_subdev_call(p_mctl->isp_sdev->sd, video,
s_crystal_freq, *(uint32_t *)arg, 0);
break;
case NOTIFY_CSIPHY_CFG:
- rc = v4l2_subdev_call(g_server_dev.csiphy_device[csid_core],
+ rc = v4l2_subdev_call(p_mctl->csiphy_sdev,
core, ioctl, VIDIOC_MSM_CSIPHY_CFG, arg);
break;
case NOTIFY_CSID_CFG:
- rc = v4l2_subdev_call(g_server_dev.csid_device[csid_core],
+ rc = v4l2_subdev_call(p_mctl->csid_sdev,
core, ioctl, VIDIOC_MSM_CSID_CFG, arg);
break;
case NOTIFY_CSIC_CFG:
- rc = v4l2_subdev_call(g_server_dev.csic_device[csid_core],
+ rc = v4l2_subdev_call(p_mctl->csic_sdev,
core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
break;
case NOTIFY_GESTURE_EVT:
@@ -1471,6 +1547,33 @@
return -EINVAL;
}
+static struct v4l2_subdev *msm_cam_find_subdev_node(
+ struct v4l2_subdev **sd_list, u32 revision_num)
+{
+ int i = 0;
+ for (i = 0; sd_list[i] != NULL; i++) {
+ if (sd_list[i]->entity.revision == revision_num) {
+ return sd_list[i];
+ break;
+ }
+ }
+ return NULL;
+}
+
+int msm_mctl_find_sensor_subdevs(struct msm_cam_media_controller *p_mctl,
+ int core_index)
+{
+ int rc = -ENODEV;
+
+ v4l2_set_subdev_hostdata(p_mctl->sensor_sdev, p_mctl);
+
+ rc = msm_csi_register_subdevs(p_mctl, core_index, &g_server_dev);
+ if (rc < 0)
+ pr_err("%s: Could not find sensor subdevs\n", __func__);
+
+ return rc;
+}
+
static irqreturn_t msm_camera_server_parse_irq(int irq_num, void *data)
{
unsigned long flags;
@@ -1703,10 +1806,10 @@
sizeof(struct intr_table_entry));
D("%s Saving Entry %d %d %d %p",
__func__,
- ind_irq_tbl[irq_req->cam_hw_idx].irq_num,
- ind_irq_tbl[irq_req->cam_hw_idx].cam_hw_idx,
- ind_irq_tbl[irq_req->cam_hw_idx].is_composite,
- ind_irq_tbl[irq_req->cam_hw_idx].subdev_list[0]);
+ ind_irq_tbl[irq_req->irq_idx].irq_num,
+ ind_irq_tbl[irq_req->irq_idx].cam_hw_idx,
+ ind_irq_tbl[irq_req->irq_idx].is_composite,
+ ind_irq_tbl[irq_req->irq_idx].subdev_list[0]);
spin_unlock_irqrestore(&g_server_dev.intr_table_lock,
flags);
@@ -1825,6 +1928,15 @@
index = sd_info->sd_index;
switch (sdev_type) {
+ case SENSOR_DEV:
+ if (index >= MAX_NUM_SENSOR_DEV) {
+ pr_err("%s Invalid sensor idx %d", __func__, index);
+ err = -EINVAL;
+ break;
+ }
+ g_server_dev.sensor_device[index] = sd;
+ break;
+
case CSIPHY_DEV:
if (index >= MAX_NUM_CSIPHY_DEV) {
pr_err("%s Invalid CSIPHY idx %d", __func__, index);
@@ -1859,10 +1971,16 @@
break;
case ISPIF_DEV:
- g_server_dev.ispif_device = sd;
+ if (index >= MAX_NUM_ISPIF_DEV) {
+ pr_err("%s Invalid ISPIF idx %d", __func__, index);
+ err = -EINVAL;
+ break;
+ }
+ cam_hw_idx = MSM_CAM_HW_ISPIF + index;
+ g_server_dev.ispif_device[index] = sd;
if (g_server_dev.irqr_device) {
g_server_dev.subdev_table[cam_hw_idx] = sd;
- err = msm_cam_server_fill_sdev_irqnum(MSM_CAM_HW_ISPIF,
+ err = msm_cam_server_fill_sdev_irqnum(cam_hw_idx,
sd_info->irq_num);
}
break;
@@ -1875,6 +1993,7 @@
}
cam_hw_idx = MSM_CAM_HW_VFE0 + index;
g_server_dev.vfe_device[index] = sd;
+ g_server_dev.isp_subdev[index]->sd = sd;
if (g_server_dev.irqr_device) {
g_server_dev.subdev_table[cam_hw_idx] = sd;
err = msm_cam_server_fill_sdev_irqnum(cam_hw_idx,
@@ -1954,19 +2073,25 @@
g_server_dev.video_dev->ioctl_ops = &msm_ioctl_ops_server;
g_server_dev.video_dev->release = video_device_release;
g_server_dev.video_dev->minor = 100;
- g_server_dev.video_dev->vfl_type = 1;
+ g_server_dev.video_dev->vfl_type = VFL_TYPE_GRABBER;
video_set_drvdata(g_server_dev.video_dev, &g_server_dev);
- strlcpy(g_server_dev.media_dev.model, "qcamera",
+ strlcpy(g_server_dev.media_dev.model, QCAMERA_SERVER_NAME,
sizeof(g_server_dev.media_dev.model));
g_server_dev.media_dev.dev = &pdev->dev;
rc = media_device_register(&g_server_dev.media_dev);
g_server_dev.v4l2_dev.mdev = &g_server_dev.media_dev;
+ media_entity_init(&g_server_dev.video_dev->entity, 0, NULL, 0);
+ g_server_dev.video_dev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+ g_server_dev.video_dev->entity.group_id = QCAMERA_VNODE_GROUP_ID;
rc = video_register_device(g_server_dev.video_dev,
VFL_TYPE_GRABBER, 100);
+ g_server_dev.video_dev->entity.name =
+ video_device_node_name(g_server_dev.video_dev);
+
mutex_init(&g_server_dev.server_lock);
mutex_init(&g_server_dev.server_queue_lock);
spin_lock_init(&g_server_dev.intr_table_lock);
@@ -1980,16 +2105,10 @@
/*initialize fake video device and event queue*/
g_server_dev.server_command_queue.pvdev = g_server_dev.video_dev;
- rc = msm_setup_v4l2_event_queue(
+ msm_setup_v4l2_event_queue(
&g_server_dev.server_command_queue.eventHandle,
g_server_dev.server_command_queue.pvdev);
- if (rc < 0) {
- pr_err("%s failed to initialize event queue\n", __func__);
- video_device_release(g_server_dev.server_command_queue.pvdev);
- return rc;
- }
-
for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
struct msm_cam_server_queue *queue;
queue = &g_server_dev.server_queue[i];
@@ -2336,6 +2455,104 @@
return rc;
}
+static struct msm_isp_ops *find_isp_op(struct v4l2_subdev *sdev)
+{
+ int i;
+ for (i = 0; i < g_server_dev.config_info.num_config_nodes; i++) {
+ if (g_server_dev.isp_subdev[i]->sd == sdev)
+ return g_server_dev.isp_subdev[i];
+ }
+ return NULL;
+}
+
+static int msm_set_mctl_subdev(struct msm_cam_media_controller *pmctl,
+ struct msm_mctl_set_sdev_data *set_data)
+{
+ int rc = 0;
+ struct v4l2_subdev *vfe_sdev = NULL;
+ struct v4l2_subdev *temp_sdev = NULL;
+ switch (set_data->sdev_type) {
+ case CSIPHY_DEV:
+ pmctl->csiphy_sdev = msm_cam_find_subdev_node
+ (&g_server_dev.csiphy_device[0], set_data->revision);
+ temp_sdev = pmctl->csiphy_sdev;
+ break;
+ case CSID_DEV:
+ pmctl->csid_sdev = msm_cam_find_subdev_node
+ (&g_server_dev.csid_device[0], set_data->revision);
+ temp_sdev = pmctl->csid_sdev;
+ break;
+ case CSIC_DEV:
+ pmctl->csic_sdev = msm_cam_find_subdev_node
+ (&g_server_dev.csic_device[0], set_data->revision);
+ temp_sdev = pmctl->csic_sdev;
+ break;
+ case ISPIF_DEV:
+ pmctl->ispif_sdev = msm_cam_find_subdev_node
+ (&g_server_dev.ispif_device[0], set_data->revision);
+ temp_sdev = pmctl->ispif_sdev;
+ break;
+ case VFE_DEV:
+ vfe_sdev = msm_cam_find_subdev_node
+ (&g_server_dev.vfe_device[0], set_data->revision);
+ temp_sdev = vfe_sdev;
+ pmctl->isp_sdev = find_isp_op(vfe_sdev);
+ pmctl->isp_sdev->sd = vfe_sdev;
+ break;
+ case AXI_DEV:
+ pmctl->axi_sdev = msm_cam_find_subdev_node
+ (&g_server_dev.axi_device[0], set_data->revision);
+ temp_sdev = pmctl->axi_sdev;
+ break;
+ case VPE_DEV:
+ pmctl->vpe_sdev = msm_cam_find_subdev_node
+ (&g_server_dev.vpe_device[0], set_data->revision);
+ temp_sdev = pmctl->vpe_sdev;
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+ if (temp_sdev != NULL)
+ v4l2_set_subdev_hostdata(temp_sdev, pmctl);
+ else
+ pr_err("%s: Could not find subdev\n", __func__);
+ return rc;
+}
+
+static int msm_unset_mctl_subdev(struct msm_cam_media_controller *pmctl,
+ struct msm_mctl_set_sdev_data *set_data)
+{
+ int rc = 0;
+ switch (set_data->sdev_type) {
+ case CSIPHY_DEV:
+ pmctl->csiphy_sdev = NULL;
+ break;
+ case CSID_DEV:
+ pmctl->csid_sdev = NULL;
+ break;
+ case CSIC_DEV:
+ pmctl->csic_sdev = NULL;
+ break;
+ case ISPIF_DEV:
+ pmctl->ispif_sdev = NULL;
+ break;
+ case VFE_DEV:
+ pmctl->isp_sdev = NULL;
+ break;
+ case AXI_DEV:
+ pmctl->axi_sdev = NULL;
+ break;
+ case VPE_DEV:
+ pmctl->vpe_sdev = NULL;
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
static long msm_ioctl_config(struct file *fp, unsigned int cmd,
unsigned long arg)
{
@@ -2491,6 +2708,30 @@
rc = -EINVAL;
break;
+ case MSM_CAM_IOCTL_SET_MCTL_SDEV:{
+ struct msm_mctl_set_sdev_data set_data;
+ if (copy_from_user(&set_data, (void __user *)arg,
+ sizeof(struct msm_mctl_set_sdev_data))) {
+ ERR_COPY_FROM_USER();
+ rc = -EINVAL;
+ break;
+ }
+ rc = msm_set_mctl_subdev(config_cam->p_mctl, &set_data);
+ break;
+ }
+
+ case MSM_CAM_IOCTL_UNSET_MCTL_SDEV:{
+ struct msm_mctl_set_sdev_data set_data;
+ if (copy_from_user(&set_data, (void __user *)arg,
+ sizeof(struct msm_mctl_set_sdev_data))) {
+ ERR_COPY_FROM_USER();
+ rc = -EINVAL;
+ break;
+ }
+ rc = msm_unset_mctl_subdev(config_cam->p_mctl, &set_data);
+ break;
+ }
+
default:{
/* For the rest of config command, forward to media controller*/
struct msm_cam_media_controller *p_mctl = config_cam->p_mctl;
@@ -2597,14 +2838,12 @@
goto config_setup_fail;
}
- rc = msm_setup_v4l2_event_queue(
+ /* v4l2_fh support */
+ spin_lock_init(&config_cam->config_stat_event_queue.pvdev->fh_lock);
+ INIT_LIST_HEAD(&config_cam->config_stat_event_queue.pvdev->fh_list);
+ msm_setup_v4l2_event_queue(
&config_cam->config_stat_event_queue.eventHandle,
config_cam->config_stat_event_queue.pvdev);
- if (rc < 0) {
- pr_err("%s failed to initialize event queue\n", __func__);
- video_device_release(config_cam->config_stat_event_queue.pvdev);
- goto config_setup_fail;
- }
return rc;
@@ -2616,6 +2855,7 @@
static int __devinit msm_camera_probe(struct platform_device *pdev)
{
int rc = 0, i;
+ memset(&g_server_dev, 0, sizeof(struct msm_cam_server_dev));
/*for now just create a config 0 node
put logic here later to know how many configs to create*/
g_server_dev.config_info.num_config_nodes = 1;
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index 2913d74..76e3592 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -12,6 +12,7 @@
*/
#include <linux/slab.h>
+#include <mach/iommu_domains.h>
#include "msm_smem.h"
struct smem_client {
@@ -19,12 +20,44 @@
void *clnt;
};
+static int get_device_address(struct ion_client *clnt,
+ struct ion_handle *hndl, int domain_num, int partition_num,
+ unsigned long align, unsigned long *iova,
+ unsigned long *buffer_size, unsigned long flags)
+{
+ int rc;
+
+ if (!iova || !buffer_size || !hndl || !clnt) {
+ pr_err("Invalid params: %p, %p, %p, %p\n",
+ clnt, hndl, iova, buffer_size);
+ return -EINVAL;
+ }
+ if (align < 4096)
+ align = 4096;
+ flags |= UNCACHED;
+ rc = ion_map_iommu(clnt, hndl, domain_num, partition_num, align,
+ 0, iova, buffer_size, flags, 0);
+ if (rc)
+ pr_err("ion_map_iommu failed(%d).domain: %d,partition: %d\n",
+ rc, domain_num, partition_num);
+
+ return rc;
+}
+
+static void put_device_address(struct ion_client *clnt,
+ struct ion_handle *hndl, int domain_num)
+{
+ ion_unmap_iommu(clnt, hndl, domain_num, 0);
+}
+
static int ion_user_to_kernel(struct smem_client *client,
- int fd, u32 offset, struct msm_smem *mem)
+ int fd, u32 offset, int domain, int partition,
+ struct msm_smem *mem)
{
struct ion_handle *hndl;
unsigned long ionflag;
- size_t len;
+ unsigned long iova = 0;
+ unsigned long buffer_size = 0;
int rc = 0;
hndl = ion_import_dma_buf(client->clnt, fd);
if (IS_ERR_OR_NULL(hndl)) {
@@ -38,25 +71,29 @@
pr_err("Failed to get ion flags: %d", rc);
goto fail_map;
}
- rc = ion_phys(client->clnt, hndl, &mem->paddr, &len);
- if (rc) {
- pr_err("Failed to get physical address\n");
- goto fail_map;
- }
mem->kvaddr = ion_map_kernel(client->clnt, hndl, ionflag);
if (!mem->kvaddr) {
pr_err("Failed to map shared mem in kernel\n");
rc = -EIO;
goto fail_map;
}
+ mem->domain = domain;
+ mem->partition_num = partition;
+ rc = get_device_address(client->clnt, hndl, mem->domain,
+ mem->partition_num, 4096, &iova, &buffer_size, UNCACHED);
+ if (rc) {
+ pr_err("Failed to get device address: %d\n", rc);
+ goto fail_device_address;
+ }
mem->kvaddr += offset;
- mem->paddr += offset;
mem->mem_type = client->mem_type;
mem->smem_priv = hndl;
- mem->device_addr = mem->paddr;
- mem->size = len;
+ mem->device_addr = iova + offset;
+ mem->size = buffer_size;
return rc;
+fail_device_address:
+ ion_unmap_kernel(client->clnt, hndl);
fail_map:
ion_free(client->clnt, hndl);
fail_import_fd:
@@ -64,14 +101,19 @@
}
static int alloc_ion_mem(struct smem_client *client, size_t size,
- u32 align, u32 flags, struct msm_smem *mem)
+ u32 align, u32 flags, int domain, int partition,
+ struct msm_smem *mem)
{
struct ion_handle *hndl;
- size_t len;
+ unsigned long iova = 0;
+ unsigned long buffer_size = 0;
int rc = 0;
if (size == 0)
goto skip_mem_alloc;
flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
+ if (align < 4096)
+ align = 4096;
+ size = (size + 4095) & (~4095);
hndl = ion_alloc(client->clnt, size, align, flags);
if (IS_ERR_OR_NULL(hndl)) {
pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
@@ -81,20 +123,27 @@
}
mem->mem_type = client->mem_type;
mem->smem_priv = hndl;
- if (ion_phys(client->clnt, hndl, &mem->paddr, &len)) {
- pr_err("Failed to get physical address\n");
- rc = -EIO;
- goto fail_map;
- }
- mem->device_addr = mem->paddr;
- mem->size = size;
+ mem->domain = domain;
+ mem->partition_num = partition;
mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
if (!mem->kvaddr) {
pr_err("Failed to map shared mem in kernel\n");
rc = -EIO;
goto fail_map;
}
+ rc = get_device_address(client->clnt, hndl, mem->domain,
+ mem->partition_num, align, &iova, &buffer_size, UNCACHED);
+ if (rc) {
+ pr_err("Failed to get device address: %d\n", rc);
+ goto fail_device_address;
+ }
+ mem->device_addr = iova;
+ pr_err("device_address = 0x%lx, kvaddr = 0x%p\n",
+ mem->device_addr, mem->kvaddr);
+ mem->size = size;
return rc;
+fail_device_address:
+ ion_unmap_kernel(client->clnt, hndl);
fail_map:
ion_free(client->clnt, hndl);
fail_shared_mem_alloc:
@@ -104,6 +153,8 @@
static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
{
+ put_device_address(client->clnt,
+ mem->smem_priv, mem->domain);
ion_unmap_kernel(client->clnt, mem->smem_priv);
ion_free(client->clnt, mem->smem_priv);
}
@@ -122,7 +173,8 @@
ion_client_destroy(client->clnt);
}
-struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset)
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
+ int domain, int partition)
{
struct smem_client *client = clt;
int rc = 0;
@@ -138,7 +190,8 @@
}
switch (client->mem_type) {
case SMEM_ION:
- rc = ion_user_to_kernel(clt, fd, offset, mem);
+ rc = ion_user_to_kernel(clt, fd, offset,
+ domain, partition, mem);
break;
default:
pr_err("Mem type not supported\n");
@@ -177,7 +230,8 @@
return client;
};
-struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags)
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
+ int domain, int partition)
{
struct smem_client *client;
int rc = 0;
@@ -195,7 +249,8 @@
}
switch (client->mem_type) {
case SMEM_ION:
- rc = alloc_ion_mem(client, size, align, flags, mem);
+ rc = alloc_ion_mem(client, size, align, flags,
+ domain, partition, mem);
break;
default:
pr_err("Mem type not supported\n");
diff --git a/drivers/media/video/msm_vidc/msm_smem.h b/drivers/media/video/msm_vidc/msm_smem.h
index 84d12cc..b742c79 100644
--- a/drivers/media/video/msm_vidc/msm_smem.h
+++ b/drivers/media/video/msm_vidc/msm_smem.h
@@ -24,15 +24,17 @@
int mem_type;
size_t size;
void *kvaddr;
- unsigned long paddr;
unsigned long device_addr;
- /*Device address and others to follow*/
+ int domain;
+ int partition_num;
void *smem_priv;
};
void *msm_smem_new_client(enum smem_type mtype);
-struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags);
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
+ int domain, int partition);
void msm_smem_free(void *clt, struct msm_smem *mem);
void msm_smem_delete_client(void *clt);
-struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset);
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, int
+ domain, int partition);
#endif
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 6cd9e6b..e1a71ce 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -21,7 +21,9 @@
#include <linux/debugfs.h>
#include <linux/version.h>
#include <linux/slab.h>
-
+#include <linux/of.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
#include <media/msm_vidc.h>
#include "msm_vidc_internal.h"
#include "vidc_hal_api.h"
@@ -277,8 +279,10 @@
goto exit;
}
handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1]);
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ vidc_inst->core->resources.io_map[NS_MAP].domain,
+ 0);
if (!handle) {
pr_err("Failed to get device buffer address\n");
kfree(binfo);
@@ -420,11 +424,92 @@
{
}
+static size_t read_u32_array(struct platform_device *pdev,
+ char *name, u32 *arr, size_t size)
+{
+ int len;
+ size_t sz = 0;
+ struct device_node *np = pdev->dev.of_node;
+ if (!of_get_property(np, name, &len)) {
+ pr_err("Failed to read %s from device tree\n",
+ name);
+ goto fail_read;
+ }
+ sz = len / sizeof(u32);
+ if (sz <= 0) {
+ pr_err("%s not specified in device tree\n", name);
+ goto fail_read;
+ }
+ if (sz > size) {
+ pr_err("Not enough memory to store %s values\n", name);
+ goto fail_read;
+ }
+ if (of_property_read_u32_array(np, name, arr, sz)) {
+ pr_err("error while reading %s from device tree\n",
+ name);
+ goto fail_read;
+ }
+ return sz;
+fail_read:
+ sz = 0;
+ return sz;
+}
+
+static int register_iommu_domains(struct platform_device *pdev,
+ struct msm_vidc_core *core)
+{
+ size_t len;
+ struct msm_iova_partition partition;
+ struct msm_iova_layout layout;
+ int rc = 0;
+ int i;
+ struct iommu_info *io_map = core->resources.io_map;
+ strlcpy(io_map[CP_MAP].name, "vidc-cp-map",
+ sizeof(io_map[CP_MAP].name));
+ strlcpy(io_map[CP_MAP].ctx, "venus_cp",
+ sizeof(io_map[CP_MAP].ctx));
+ strlcpy(io_map[NS_MAP].name, "vidc-ns-map",
+ sizeof(io_map[NS_MAP].name));
+ strlcpy(io_map[NS_MAP].ctx, "venus_ns",
+ sizeof(io_map[NS_MAP].ctx));
+
+ for (i = 0; i < MAX_MAP; i++) {
+ len = read_u32_array(pdev, io_map[i].name,
+ io_map[i].addr_range,
+ (sizeof(io_map[i].addr_range)/sizeof(u32)));
+ if (!len) {
+ pr_err("Error in reading cp address range\n");
+ rc = -EINVAL;
+ break;
+ }
+ partition.start = io_map[i].addr_range[0];
+ partition.size = io_map[i].addr_range[1];
+ layout.partitions = &partition;
+ layout.npartitions = 1;
+ layout.client_name = io_map[i].name;
+ layout.domain_flags = 0;
+ pr_debug("Registering domain with: %lx, %lx, %s\n",
+ partition.start, partition.size, layout.client_name);
+ io_map[i].domain = msm_register_domain(&layout);
+ if (io_map[i].domain < 0) {
+ pr_err("Failed to register cp domain\n");
+ rc = -EINVAL;
+ break;
+ }
+ }
+ /* There is no api provided as msm_unregister_domain, so
+ * we are not able to unregister the previously
+ * registered domains if any domain registration fails.*/
+ BUG_ON(i < MAX_MAP);
+ return rc;
+}
+
static int msm_vidc_initialize_core(struct platform_device *pdev,
struct msm_vidc_core *core)
{
struct resource *res;
int i = 0;
+ int rc = 0;
if (!core)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -443,13 +528,19 @@
INIT_LIST_HEAD(&core->instances);
mutex_init(&core->sync_lock);
spin_lock_init(&core->lock);
- core->base_addr = 0x14f00000;
+ core->base_addr = 0x0;
core->state = VIDC_CORE_UNINIT;
for (i = SYS_MSG_INDEX(SYS_MSG_START);
i <= SYS_MSG_INDEX(SYS_MSG_END); i++) {
init_completion(&core->completions[i]);
}
- return 0;
+ rc = register_iommu_domains(pdev, core);
+ if (rc) {
+ pr_err("Failed to register iommu domains: %d\n", rc);
+ goto fail_domain_register;
+ }
+fail_domain_register:
+ return rc;
}
static int __devinit msm_vidc_probe(struct platform_device *pdev)
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 09c7215..a8c6428 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -22,6 +22,8 @@
#define MAX_PLANES 1
#define DEFAULT_HEIGHT 720
#define DEFAULT_WIDTH 1280
+#define MAX_SUPPORTED_WIDTH 4096
+#define MAX_SUPPORTED_HEIGHT 2160
#define MIN_NUM_OUTPUT_BUFFERS 2
#define MAX_NUM_OUTPUT_BUFFERS 6
@@ -154,7 +156,11 @@
static u32 get_frame_size_nv12(int plane,
u32 height, u32 width)
{
- return (ALIGN(height, 32) * ALIGN(width, 32) * 3) / 2;
+ int luma_stride = ALIGN(width, 32);
+ int luma_slice = ALIGN(height, 32);
+ int chroma_stride = ALIGN(roundup(width, 2)/2, 32);
+ int chroma_slice = ALIGN(roundup(height, 2)/2, 32);
+ return (luma_stride * luma_slice) + (chroma_stride * chroma_slice) * 2;
}
static u32 get_frame_size_nv21(int plane,
u32 height, u32 width)
@@ -165,7 +171,7 @@
static u32 get_frame_size_compressed(int plane,
u32 height, u32 width)
{
- return 0x500000;
+ return (MAX_SUPPORTED_WIDTH * MAX_SUPPORTED_HEIGHT * 3/2)/2;
}
static const struct msm_vidc_format vdec_formats[] = {
@@ -218,6 +224,14 @@
.type = OUTPUT_PORT,
},
{
+ .name = "VP8",
+ .description = "VP8 compressed format",
+ .fourcc = V4L2_PIX_FMT_VP8,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
.name = "YCrCb Semiplanar 4:2:0",
.description = "Y/CrCb 4:2:0",
.fourcc = V4L2_PIX_FMT_NV21,
@@ -295,8 +309,21 @@
buffer_info.num_buffers = 1;
buffer_info.align_device_addr =
b->m.planes[i].m.userptr;
- buffer_info.extradata_size = 0;
- buffer_info.extradata_addr = 0;
+ if (!inst->extradata_handle) {
+ inst->extradata_handle =
+ msm_smem_alloc(inst->mem_client,
+ 4096 * 1024, 1, 0,
+ inst->core->resources.io_map[NS_MAP].domain,
+ 0);
+ if (!inst->extradata_handle) {
+ pr_err("Failed to allocate extradta memory\n");
+ rc = -ENOMEM;
+ break;
+ }
+ }
+ buffer_info.extradata_addr =
+ inst->extradata_handle->device_addr;
+ buffer_info.extradata_size = 4096 * 1024;
rc = vidc_hal_session_set_buffers((void *)inst->session,
&buffer_info);
if (rc) {
@@ -332,7 +359,8 @@
buffer_info.num_buffers = 1;
buffer_info.align_device_addr =
b->m.planes[i].m.userptr;
- buffer_info.extradata_addr = 0;
+ buffer_info.extradata_addr =
+ inst->extradata_handle->device_addr;
rc = vidc_hal_session_release_buffers(
(void *)inst->session, &buffer_info);
if (rc)
@@ -607,96 +635,20 @@
unsigned long flags;
struct vb2_buf_entry *temp;
struct list_head *ptr, *next;
- struct v4l2_control control;
- struct hal_nal_stream_format_supported stream_format;
- struct hal_enable_picture enable_picture;
- struct hal_enable hal_property;
- u32 control_idx = 0;
- enum hal_property property_id = 0;
- u32 property_val = 0;
- void *pdata;
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ pr_err("Failed to get buffer requirements : %d\n", rc);
+ goto fail_start;
+ }
rc = msm_comm_set_scratch_buffers(inst);
if (rc) {
pr_err("Failed to set scratch buffers: %d\n", rc);
goto fail_start;
}
- for (; control_idx < NUM_CTRLS; control_idx++) {
- control.id = msm_vdec_ctrls[control_idx].id;
- rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
- if (rc) {
- pr_err("Failed to get control value for ID=%d\n",
- msm_vdec_ctrls[control_idx].id);
- } else {
- property_id = 0;
- switch (control.id) {
- case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
- property_id =
- HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
- stream_format.nal_stream_format_supported =
- (0x00000001 << control.value);
- pdata = &stream_format;
- break;
- case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER:
- property_id = HAL_PARAM_VDEC_OUTPUT_ORDER;
- property_val = control.value;
- pdata = &property_val;
- break;
- case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE:
- property_id =
- HAL_PARAM_VDEC_PICTURE_TYPE_DECODE;
- enable_picture.picture_type = control.value;
- pdata = &enable_picture;
- break;
- case V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO:
- property_id =
- HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
- hal_property.enable = control.value;
- pdata = &hal_property;
- break;
- case V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE:
- property_id =
- HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
- hal_property.enable = control.value;
- pdata = &hal_property;
- break;
- case V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT:
- property_id = HAL_PARAM_DIVX_FORMAT;
- property_val = control.value;
- pdata = &property_val;
- break;
- case V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING:
- property_id =
- HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
- hal_property.enable = control.value;
- pdata = &hal_property;
- break;
- case V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER:
- property_id =
- HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
- hal_property.enable = control.value;
- pdata = &hal_property;
- break;
- default:
- break;
- }
- if (property_id) {
- pr_err("Control: HAL property=%x,ctrl_id=%x,ctrl_value=%d\n",
- property_id,
- msm_vdec_ctrls[control_idx].id,
- control.value);
- rc = vidc_hal_session_set_property((void *)
- inst->session, property_id,
- pdata);
- }
- if (rc)
- pr_err("Failed to set hal property for framesize\n");
- }
- }
-
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
pr_err("Failed to move inst: %p to start done state\n",
- inst);
+ inst);
goto fail_start;
}
spin_lock_irqsave(&inst->lock, flags);
@@ -812,7 +764,94 @@
static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
{
- return 0;
+ int rc = 0;
+ struct v4l2_control control;
+ struct hal_nal_stream_format_supported stream_format;
+ struct hal_enable_picture enable_picture;
+ struct hal_enable hal_property;/*, prop;*/
+ u32 control_idx = 0;
+ enum hal_property property_id = 0;
+ u32 property_val = 0;
+ void *pdata;
+ struct msm_vidc_inst *inst = container_of(ctrl->handler,
+ struct msm_vidc_inst, ctrl_handler);
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+
+ if (rc) {
+ pr_err("Failed to move inst: %p to start done state\n",
+ inst);
+ goto failed_open_done;
+ }
+
+ control.id = ctrl->id;
+ control.value = ctrl->val;
+
+ switch (control.id) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
+ property_id =
+ HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
+ stream_format.nal_stream_format_supported =
+ (0x00000001 << control.value);
+ pdata = &stream_format;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER:
+ property_id = HAL_PARAM_VDEC_OUTPUT_ORDER;
+ property_val = control.value;
+ pdata = &property_val;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE:
+ property_id =
+ HAL_PARAM_VDEC_PICTURE_TYPE_DECODE;
+ enable_picture.picture_type = control.value;
+ pdata = &enable_picture;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO:
+ property_id =
+ HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE:
+ property_id =
+ HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT:
+ property_id = HAL_PARAM_DIVX_FORMAT;
+ property_val = control.value;
+ pdata = &property_val;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING:
+ property_id =
+ HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER:
+ property_id =
+ HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ default:
+ break;
+ }
+ if (property_id) {
+ pr_debug("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+ property_id,
+ msm_vdec_ctrls[control_idx].id,
+ control.value);
+ rc = vidc_hal_session_set_property((void *)
+ inst->session, property_id,
+ pdata);
+ }
+ if (rc)
+ pr_err("Failed to set hal property for framesize\n");
+
+failed_open_done:
+
+ return rc;
}
static int msm_vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index e835aaa..72c6685 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -23,12 +23,13 @@
#define MIN_NUM_OUTPUT_BUFFERS 2
#define MAX_NUM_OUTPUT_BUFFERS 8
#define MIN_BIT_RATE 64
-#define MAX_BIT_RATE 20000
+#define MAX_BIT_RATE 160000
#define DEFAULT_BIT_RATE 64
#define BIT_RATE_STEP 1
#define MIN_FRAME_RATE 1
-#define MAX_FRAME_RATE 120
+#define MAX_FRAME_RATE 240
#define DEFAULT_FRAME_RATE 30
+#define DEFAULT_IR_MBS 30
#define MAX_SLICE_BYTE_SIZE 1024
#define MIN_SLICE_BYTE_SIZE 1024
#define MAX_SLICE_MB_SIZE 300
@@ -62,6 +63,30 @@
"Model 2",
NULL
};
+
+static const char *const h263_level[] = {
+ "1.0",
+ "2.0",
+ "3.0",
+ "4.0",
+ "4.5",
+ "5.0",
+ "6.0",
+ "7.0",
+};
+
+static const char *const h263_profile[] = {
+ "Baseline",
+ "H320 Coding",
+ "Backward Compatible",
+ "ISWV2",
+ "ISWV3",
+ "High Compression",
+ "Internet",
+ "Interlace",
+ "High Latency",
+};
+
static const struct msm_vidc_ctrl msm_venc_ctrls[] = {
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
@@ -211,10 +236,48 @@
.minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
- .step = 1,
+ .step = 0,
.menu_skip_mask = 0,
},
{
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
+ .name = "H263 Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY)
+ ),
+ .qmenu = h263_profile,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
+ .name = "H263 Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0)
+ ),
+ .qmenu = h263_level,
+ },
+ {
.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
.name = "Rotation",
.type = V4L2_CTRL_TYPE_MENU,
@@ -409,14 +472,20 @@
venc_h264_profile_level = {HAL_H264_PROFILE_BASELINE,
HAL_H264_LEVEL_1};
static struct hal_profile_level
- venc_mpeg4_profile_level = {HAL_H264_PROFILE_BASELINE,
- HAL_H264_LEVEL_1};
+ venc_mpeg4_profile_level = {HAL_MPEG4_PROFILE_SIMPLE,
+ HAL_MPEG4_LEVEL_0};
+static struct hal_profile_level
+ venc_h263_profile_level = {HAL_H263_PROFILE_BASELINE,
+ HAL_H263_LEVEL_10};
static struct hal_h264_entropy_control
venc_h264_entropy_control = {HAL_H264_ENTROPY_CAVLC,
HAL_H264_CABAC_MODEL_0};
static struct hal_multi_slice_control
venc_multi_slice_control = {HAL_MULTI_SLICE_OFF ,
0};
+static struct hal_intra_refresh
+ venc_intra_refresh = {HAL_INTRA_REFRESH_NONE ,
+ DEFAULT_IR_MBS, DEFAULT_IR_MBS, DEFAULT_IR_MBS};
static const struct msm_vidc_format venc_formats[] = {
{
@@ -452,6 +521,14 @@
.type = CAPTURE_PORT,
},
{
+ .name = "VP8",
+ .description = "VP8 compressed format",
+ .fourcc = V4L2_PIX_FMT_VP8,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
.name = "YCrCb Semiplanar 4:2:0",
.description = "Y/CrCb 4:2:0",
.fourcc = V4L2_PIX_FMT_NV21,
@@ -892,6 +969,84 @@
pr_debug("\nLevel: %d\n",
profile_level.level);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+
+ switch (control.value) {
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE:
+ control.value = HAL_H263_PROFILE_BASELINE;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING:
+ control.value = HAL_H263_PROFILE_H320CODING;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE:
+ control.value = HAL_H263_PROFILE_BACKWARDCOMPATIBLE;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2:
+ control.value = HAL_H263_PROFILE_ISWV2;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3:
+ control.value = HAL_H263_PROFILE_ISWV3;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION:
+ control.value = HAL_H263_PROFILE_HIGHCOMPRESSION;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET:
+ control.value = HAL_H263_PROFILE_INTERNET;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE:
+ control.value = HAL_H263_PROFILE_INTERLACE;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY:
+ control.value = HAL_H263_PROFILE_HIGHLATENCY;
+ break;
+ default:
+ break;
+ }
+ profile_level.profile = control.value;
+ venc_h263_profile_level.profile = control.value;
+ profile_level.level = venc_h263_profile_level.level;
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+
+ switch (control.value) {
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0:
+ control.value = HAL_H263_LEVEL_10;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0:
+ control.value = HAL_H263_LEVEL_20;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0:
+ control.value = HAL_H263_LEVEL_30;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0:
+ control.value = HAL_H263_LEVEL_40;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5:
+ control.value = HAL_H263_LEVEL_45;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0:
+ control.value = HAL_H263_LEVEL_50;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0:
+ control.value = HAL_H263_LEVEL_60;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0:
+ control.value = HAL_H263_LEVEL_70;
+ break;
+ default:
+ break;
+ }
+
+ profile_level.level = control.value;
+ venc_h263_profile_level.level = control.value;
+ profile_level.profile = venc_h263_profile_level.profile;
+ pdata = &profile_level;
+ break;
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
property_id =
HAL_CONFIG_VPE_OPERATIONS;
@@ -948,24 +1103,40 @@
property_id =
HAL_PARAM_VENC_INTRA_REFRESH;
intra_refresh.mode = control.value;
+ intra_refresh.air_mbs = venc_intra_refresh.air_mbs;
+ intra_refresh.air_ref = venc_intra_refresh.air_ref;
+ intra_refresh.cir_mbs = venc_intra_refresh.cir_mbs;
+ venc_intra_refresh.mode = intra_refresh.mode;
pdata = &intra_refresh;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS:
property_id =
HAL_PARAM_VENC_INTRA_REFRESH;
intra_refresh.air_mbs = control.value;
+ intra_refresh.mode = venc_intra_refresh.mode;
+ intra_refresh.air_ref = venc_intra_refresh.air_ref;
+ intra_refresh.cir_mbs = venc_intra_refresh.cir_mbs;
+ venc_intra_refresh.air_mbs = control.value;
pdata = &intra_refresh;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF:
property_id =
HAL_PARAM_VENC_INTRA_REFRESH;
intra_refresh.air_ref = control.value;
+ intra_refresh.air_mbs = venc_intra_refresh.air_mbs;
+ intra_refresh.mode = venc_intra_refresh.mode;
+ intra_refresh.cir_mbs = venc_intra_refresh.cir_mbs;
+ venc_intra_refresh.air_ref = control.value;
pdata = &intra_refresh;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS:
property_id =
HAL_PARAM_VENC_INTRA_REFRESH;
intra_refresh.cir_mbs = control.value;
+ intra_refresh.air_mbs = venc_intra_refresh.air_mbs;
+ intra_refresh.air_ref = venc_intra_refresh.air_ref;
+ intra_refresh.mode = venc_intra_refresh.mode;
+ venc_intra_refresh.cir_mbs = control.value;
pdata = &intra_refresh;
break;
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 11fbcf4..4d4cec5 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -29,19 +29,16 @@
struct vb2_buffer *out_vb = NULL;
struct vb2_buffer *cap_vb = NULL;
unsigned long flags;
- poll_wait(filp, &inst->event_handler.wait, wait);
- if (v4l2_event_pending(&inst->event_handler))
- return POLLPRI;
if (!outq->streaming && !capq->streaming) {
pr_err("Returning POLLERR from here: %d, %d\n",
outq->streaming, capq->streaming);
return POLLERR;
}
poll_wait(filp, &inst->event_handler.wait, wait);
- if (v4l2_event_pending(&inst->event_handler))
- return POLLPRI;
poll_wait(filp, &capq->done_wq, wait);
poll_wait(filp, &outq->done_wq, wait);
+ if (v4l2_event_pending(&inst->event_handler))
+ rc |= POLLPRI;
spin_lock_irqsave(&capq->done_lock, flags);
if (!list_empty(&capq->done_list))
cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
@@ -319,6 +316,8 @@
kfree(buf);
}
}
+ if (inst->extradata_handle)
+ msm_smem_free(inst->mem_client, inst->extradata_handle);
spin_unlock_irqrestore(&inst->lock, flags);
msm_smem_delete_client(inst->mem_client);
}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index a5cff9c..cd330316 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -13,6 +13,10 @@
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/iommu.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/peripheral-loader.h>
#include "msm_vidc_common.h"
#include "vidc_hal_api.h"
@@ -52,6 +56,60 @@
return NULL;
}
+static int msm_comm_iommu_attach(struct msm_vidc_core *core)
+{
+ int rc;
+ struct iommu_domain *domain;
+ int i;
+ struct iommu_info *io_map;
+ struct device *dev;
+ for (i = 0; i < MAX_MAP; i++) {
+ io_map = &core->resources.io_map[i];
+ dev = msm_iommu_get_ctx(io_map->ctx);
+ domain = msm_get_iommu_domain(io_map->domain);
+ if (IS_ERR_OR_NULL(domain)) {
+ pr_err("Failed to get domain: %s\n", io_map->name);
+ rc = PTR_ERR(domain);
+ break;
+ }
+ rc = iommu_attach_device(domain, dev);
+ if (rc) {
+ pr_err("IOMMU attach failed: %s\n", io_map->name);
+ break;
+ }
+ }
+ if (i < MAX_MAP) {
+ i--;
+ for (; i >= 0; i--) {
+ io_map = &core->resources.io_map[i];
+ dev = msm_iommu_get_ctx(io_map->ctx);
+ domain = msm_get_iommu_domain(io_map->domain);
+ if (dev && domain)
+ iommu_detach_device(domain, dev);
+ }
+ }
+ return rc;
+}
+
+static void msm_comm_iommu_detach(struct msm_vidc_core *core)
+{
+ struct device *dev;
+ struct iommu_domain *domain;
+ struct iommu_info *io_map;
+ int i;
+ if (!core) {
+ pr_err("Invalid paramter: %p\n", core);
+ return;
+ }
+ for (i = 0; i < MAX_MAP; i++) {
+ io_map = &core->resources.io_map[i];
+ dev = msm_iommu_get_ctx(io_map->ctx);
+ domain = msm_get_iommu_domain(io_map->domain);
+ if (dev && domain)
+ iommu_detach_device(domain, dev);
+ }
+}
+
const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
const struct msm_vidc_format fmt[], int size, int index, int fmt_type)
{
@@ -454,6 +512,47 @@
break;
}
}
+static int msm_comm_load_fw(struct msm_vidc_core *core)
+{
+ int rc = 0;
+ if (!core) {
+ pr_err("Invalid paramter: %p\n", core);
+ return -EINVAL;
+ }
+
+ if (!core->resources.fw.cookie)
+ core->resources.fw.cookie = pil_get("venus");
+
+ if (IS_ERR_OR_NULL(core->resources.fw.cookie)) {
+ pr_err("Failed to download firmware\n");
+ rc = -ENOMEM;
+ goto fail_pil_get;
+ }
+ rc = msm_comm_iommu_attach(core);
+ if (rc) {
+ pr_err("Failed to attach iommu");
+ goto fail_iommu_attach;
+ }
+ return rc;
+fail_iommu_attach:
+ pil_put(core->resources.fw.cookie);
+ core->resources.fw.cookie = NULL;
+fail_pil_get:
+ return rc;
+}
+
+static void msm_comm_unload_fw(struct msm_vidc_core *core)
+{
+ if (!core) {
+ pr_err("Invalid paramter: %p\n", core);
+ return;
+ }
+ if (core->resources.fw.cookie) {
+ pil_put(core->resources.fw.cookie);
+ core->resources.fw.cookie = NULL;
+ msm_comm_iommu_detach(core);
+ }
+}
static int msm_comm_init_core_done(struct msm_vidc_inst *inst)
{
@@ -499,18 +598,28 @@
core->id, core->state);
goto core_already_inited;
}
+ rc = msm_comm_load_fw(core);
+ if (rc) {
+ pr_err("Failed to load video firmware\n");
+ goto fail_fw_download;
+ }
init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
- rc = vidc_hal_core_init(core->device);
+ rc = vidc_hal_core_init(core->device,
+ core->resources.io_map[NS_MAP].domain);
if (rc) {
pr_err("Failed to init core, id = %d\n", core->id);
- goto exit;
+ goto fail_core_init;
}
spin_lock_irqsave(&core->lock, flags);
core->state = VIDC_CORE_INIT;
spin_unlock_irqrestore(&core->lock, flags);
core_already_inited:
change_inst_state(inst, MSM_VIDC_CORE_INIT);
-exit:
+ mutex_unlock(&core->sync_lock);
+ return rc;
+fail_core_init:
+ msm_comm_unload_fw(core);
+fail_fw_download:
mutex_unlock(&core->sync_lock);
return rc;
}
@@ -536,6 +645,7 @@
spin_lock_irqsave(&core->lock, flags);
core->state = VIDC_CORE_UNINIT;
spin_unlock_irqrestore(&core->lock, flags);
+ msm_comm_unload_fw(core);
}
core_already_uninited:
change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
@@ -587,6 +697,9 @@
case V4L2_PIX_FMT_VC1_ANNEX_L:
codec = HAL_VIDEO_CODEC_VC1;
break;
+ case V4L2_PIX_FMT_VP8:
+ codec = HAL_VIDEO_CODEC_VP8;
+ break;
case V4L2_PIX_FMT_DIVX_311:
codec = HAL_VIDEO_CODEC_DIVX_311;
break;
@@ -596,8 +709,7 @@
/*HAL_VIDEO_CODEC_MVC
HAL_VIDEO_CODEC_SPARK
HAL_VIDEO_CODEC_VP6
- HAL_VIDEO_CODEC_VP7
- HAL_VIDEO_CODEC_VP8*/
+ HAL_VIDEO_CODEC_VP7*/
default:
pr_err("Wrong codec: %d\n", fourcc);
codec = HAL_UNUSED_CODEC;
@@ -887,9 +999,16 @@
} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
frame_data.filled_len = 0;
frame_data.buffer_type = HAL_BUFFER_OUTPUT;
- frame_data.extradata_addr = 0;
- pr_debug("Sending ftb to hal..: Alloc: %d :filled: %d\n",
+ if (inst->extradata_handle) {
+ frame_data.extradata_addr =
+ inst->extradata_handle->device_addr;
+ } else {
+ frame_data.extradata_addr = 0;
+ }
+ pr_debug("Sending ftb to hal..: Alloc: %d :filled: %d",
frame_data.alloc_len, frame_data.filled_len);
+ pr_debug(" extradata_addr: %d\n",
+ frame_data.extradata_addr);
rc = vidc_hal_session_ftb((void *) inst->session,
&frame_data);
} else {
@@ -933,12 +1052,56 @@
{
int rc = 0;
struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+ bool ip_flush = false,
+ op_flush = false;
+
mutex_lock(&inst->sync_lock);
- if (dec->cmd != V4L2_DEC_CMD_STOP)
- return -EINVAL;
- rc = vidc_hal_session_flush((void *)inst->session, HAL_FLUSH_OUTPUT);
+
+ switch (dec->cmd) {
+ case V4L2_DEC_QCOM_CMD_FLUSH:
+ ip_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT;
+ op_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE;
+ /* Only support flush on decoder (for now)*/
+ if (inst->session_type == MSM_VIDC_ENCODER) {
+ pr_err("Buffer flushing not supported for encoder\n");
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ /* Certain types of flushes aren't supported such as: */
+ /* 1) Input only flush */
+ if (ip_flush && !op_flush) {
+ pr_err("Input only flush not supported\n");
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ /* 2) Output only flush when in reconfig */
+ if (!ip_flush && op_flush && !inst->in_reconfig) {
+ pr_err("Output only flush only supported when reconfiguring\n");
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ /* Finally flush */
+ if (op_flush && ip_flush)
+ rc = vidc_hal_session_flush(inst->session,
+ HAL_FLUSH_ALL);
+ else if (ip_flush)
+ rc = vidc_hal_session_flush(inst->session,
+ HAL_FLUSH_INPUT);
+ else if (op_flush)
+ rc = vidc_hal_session_flush(inst->session,
+ HAL_FLUSH_OUTPUT);
+
+ break;
+ default:
+ rc = -ENOTSUPP;
+ goto exit;
+ }
+
if (rc) {
- pr_err("Failed to get property\n");
+ pr_err("Failed to exec decoder cmd %d\n", dec->cmd);
goto exit;
}
exit:
@@ -974,7 +1137,8 @@
for (i = 0; i < inst->buff_req.buffer[6].buffer_count_actual;
i++) {
handle = msm_smem_alloc(inst->mem_client,
- inst->buff_req.buffer[6].buffer_size, 1, 0);
+ inst->buff_req.buffer[6].buffer_size, 1, 0,
+ inst->core->resources.io_map[NS_MAP].domain, 0);
if (!handle) {
pr_err("Failed to allocate scratch memory\n");
rc = -ENOMEM;
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index fb8fbc4..151fb21 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -106,6 +106,29 @@
struct video_device vdev;
};
+struct msm_vidc_fw {
+ void *cookie;
+};
+
+struct iommu_info {
+ u32 addr_range[2];
+ char name[64];
+ char ctx[64];
+ int domain;
+ int partition;
+};
+
+enum io_maps {
+ CP_MAP,
+ NS_MAP,
+ MAX_MAP
+};
+
+struct msm_vidc_resources {
+ struct msm_vidc_fw fw;
+ struct iommu_info io_map[MAX_MAP];
+};
+
struct msm_vidc_core {
struct list_head list;
struct mutex sync_lock;
@@ -121,6 +144,7 @@
u32 register_size;
u32 irq;
enum vidc_core_state state;
+ struct msm_vidc_resources resources;
struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
};
@@ -146,6 +170,7 @@
bool in_reconfig;
u32 reconfig_width;
u32 reconfig_height;
+ struct msm_smem *extradata_handle;
};
extern struct msm_vidc_drv *vidc_driver;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 85e984d..9052a63 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -23,7 +23,7 @@
#define REG_ADDR_OFFSET_BITMASK 0x000FFFFF
/*Workaround for virtio */
-#define HFI_VIRTIO_FW_BIAS 0x14f00000
+#define HFI_VIRTIO_FW_BIAS 0x0
struct hal_device_data hal_ctxt;
@@ -300,7 +300,8 @@
return 0;
}
-static int vidc_hal_alloc(void *mem, void *clnt, u32 size, u32 align, u32 flags)
+static int vidc_hal_alloc(void *mem, void *clnt, u32 size, u32 align, u32 flags,
+ int domain)
{
struct vidc_mem_addr *vmem;
struct msm_smem *alloc;
@@ -312,7 +313,7 @@
vmem = (struct vidc_mem_addr *)mem;
HAL_MSG_HIGH("start to alloc: size:%d, Flags: %d", size, flags);
- alloc = msm_smem_alloc(clnt, size, align, flags);
+ alloc = msm_smem_alloc(clnt, size, align, flags, domain, 0);
HAL_MSG_LOW("Alloc done");
if (!alloc) {
HAL_MSG_HIGH("Alloc fail in %s", __func__);
@@ -503,7 +504,7 @@
device->hal_client = NULL;
}
-static int vidc_hal_interface_queues_init(struct hal_device *dev)
+static int vidc_hal_interface_queues_init(struct hal_device *dev, int domain)
{
struct hfi_queue_table_header *q_tbl_hdr;
struct hfi_queue_header *q_hdr;
@@ -513,7 +514,7 @@
rc = vidc_hal_alloc((void *) &dev->iface_q_table,
dev->hal_client,
- VIDC_IFACEQ_TABLE_SIZE, 1, 0);
+ VIDC_IFACEQ_TABLE_SIZE, 1, 0, domain);
if (rc) {
HAL_MSG_ERROR("%s:iface_q_table_alloc_fail", __func__);
return -ENOMEM;
@@ -533,7 +534,7 @@
iface_q = &dev->iface_queues[i];
rc = vidc_hal_alloc((void *) &iface_q->q_array,
dev->hal_client, VIDC_IFACEQ_QUEUE_SIZE,
- 1, 0);
+ 1, 0, domain);
if (rc) {
HAL_MSG_ERROR("%s:iface_q_table_alloc[%d]_fail",
__func__, i);
@@ -592,7 +593,7 @@
return rc;
}
-int vidc_hal_core_init(void *device)
+int vidc_hal_core_init(void *device, int domain)
{
struct hfi_cmd_sys_init_packet pkt;
int rc = 0;
@@ -619,10 +620,10 @@
HAL_MSG_ERROR("Device_Virt_Address : 0x%x,"
"Register_Virt_Addr: 0x%x",
- (u32) dev->hal_data->device_base_addr,
+ dev->hal_data->device_base_addr,
(u32) dev->hal_data->register_base_addr);
- rc = vidc_hal_interface_queues_init(dev);
+ rc = vidc_hal_interface_queues_init(dev, domain);
if (rc) {
HAL_MSG_ERROR("failed to init queues");
rc = -ENOMEM;
@@ -665,6 +666,8 @@
}
write_register(dev->hal_data->register_base_addr,
VIDC_CPU_CS_SCIACMDARG3, 0, 0);
+ disable_irq_nosync(dev->hal_data->irq);
+ vidc_hal_interface_queues_release(dev);
HAL_MSG_INFO("\nHAL exited\n");
return 0;
}
@@ -1118,6 +1121,7 @@
case HAL_CONFIG_VENC_REQUEST_IFRAME:
pkt->rg_property_data[0] =
HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME;
+ pkt->size += sizeof(u32);
break;
case HAL_PARAM_VENC_MPEG4_SHORT_HEADER:
break;
@@ -1272,18 +1276,6 @@
sizeof(struct hfi_h264_db_control);
break;
}
- case HAL_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF:
- {
- struct hfi_temporal_spatial_tradeoff *hfi;
- pkt->rg_property_data[0] =
- HFI_PROPERTY_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF;
- hfi = (struct hfi_temporal_spatial_tradeoff *)
- &pkt->rg_property_data[1];
- hfi->ts_factor = ((struct hfi_temporal_spatial_tradeoff *)
- pdata)->ts_factor;
- pkt->size += sizeof(u32) * 2;
- break;
- }
case HAL_PARAM_VENC_SESSION_QP:
{
struct hfi_quantization *hfi;
@@ -1505,8 +1497,6 @@
break;
case HAL_PARAM_VENC_H264_DEBLOCK_CONTROL:
break;
- case HAL_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF:
- break;
case HAL_PARAM_VENC_SESSION_QP:
break;
case HAL_CONFIG_VENC_INTRA_PERIOD:
@@ -2000,11 +1990,11 @@
list_for_each_safe(curr, next, &core.dev_head) {
device = list_entry(curr, struct hal_device, list);
if (device && device->hal_data->irq == irq &&
- (CONTAINS((u32)device->hal_data->
+ (CONTAINS(device->hal_data->
device_base_addr,
FIRMWARE_SIZE, fw_addr) ||
CONTAINS(fw_addr, FIRMWARE_SIZE,
- (u32)device->hal_data->
+ device->hal_data->
device_base_addr) ||
CONTAINS((u32)device->hal_data->
register_base_addr,
@@ -2018,12 +2008,12 @@
OVERLAPS(reg_addr, reg_size,
(u32)device->hal_data->
register_base_addr, reg_size) ||
- OVERLAPS((u32)device->hal_data->
+ OVERLAPS(device->hal_data->
device_base_addr,
FIRMWARE_SIZE, fw_addr,
FIRMWARE_SIZE) ||
OVERLAPS(fw_addr, FIRMWARE_SIZE,
- (u32)device->hal_data->
+ device->hal_data->
device_base_addr,
FIRMWARE_SIZE))) {
return 0;
@@ -2073,7 +2063,7 @@
struct hal_data *hal = NULL;
int rc = 0;
- if (device_id || !fw_base_addr || !reg_base || !reg_size ||
+ if (device_id || !reg_base || !reg_size ||
!irq || !callback) {
HAL_MSG_ERROR("Invalid Paramters");
return NULL;
@@ -2091,13 +2081,7 @@
return NULL;
}
hal->irq = irq;
- hal->device_base_addr =
- ioremap_nocache(fw_base_addr, FIRMWARE_SIZE);
- if (!hal->device_base_addr) {
- HAL_MSG_ERROR("could not map fw addr %d of size %d",
- fw_base_addr, FIRMWARE_SIZE);
- goto err_map;
- }
+ hal->device_base_addr = fw_base_addr;
hal->register_base_addr =
ioremap_nocache(reg_base, reg_size);
if (!hal->register_base_addr) {
diff --git a/drivers/media/video/msm_vidc/vidc_hal.h b/drivers/media/video/msm_vidc/vidc_hal.h
index a36d7f3..8e7c3d3 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.h
+++ b/drivers/media/video/msm_vidc/vidc_hal.h
@@ -155,6 +155,7 @@
#define HFI_EXTRADATA_VC1_SEQDISP 0x00000004
#define HFI_EXTRADATA_TIMESTAMP 0x00000005
#define HFI_EXTRADATA_S3D_FRAME_PACKING 0x00000006
+#define HFI_EXTRADATA_EOSNAL_DETECTED 0x00000007
#define HFI_EXTRADATA_MULTISLICE_INFO 0x7F100000
#define HFI_EXTRADATA_NUM_CONCEALED_MB 0x7F100001
#define HFI_EXTRADATA_INDEX 0x7F100002
@@ -164,6 +165,11 @@
#define HFI_INDEX_EXTRADATA_DIGITAL_ZOOM 0x07000010
#define HFI_INDEX_EXTRADATA_ASPECT_RATIO 0x7F100003
+struct HFI_INDEX_EXTRADATA_CONFIG_TYPE {
+ int enable;
+ u32 index_extra_data_id;
+};
+
struct hfi_extradata_header {
u32 size;
u32 version;
@@ -196,7 +202,7 @@
(HFI_PROPERTY_PARAM_OX_START + 0x004)
#define HFI_PROPERTY_PARAM_EXTRA_DATA_HEADER_CONFIG \
(HFI_PROPERTY_PARAM_OX_START + 0x005)
-#define HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE \
+#define HFI_PROPERTY_PARAM_INDEX_EXTRADATA \
(HFI_PROPERTY_PARAM_OX_START + 0x006)
#define HFI_PROPERTY_PARAM_DIVX_FORMAT \
(HFI_PROPERTY_PARAM_OX_START + 0x007)
@@ -244,6 +250,10 @@
#define HFI_PROPERTY_PARAM_VENC_OX_START \
(HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x5000)
+#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO \
+ (HFI_PROPERTY_PARAM_VENC_OX_START + 0x001)
+#define HFI_PROPERTY_PARAM_VENC_H264_IDR_S3D_FRAME_PACKING_NAL \
+ (HFI_PROPERTY_PARAM_VENC_OX_START + 0x002)
#define HFI_PROPERTY_CONFIG_VENC_OX_START \
(HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x6000)
@@ -285,10 +295,6 @@
u8 rg_data[1];
};
-struct hfi_seq_header_info {
- u32 max_header_len;
-};
-
struct hfi_enable_picture {
u32 picture_type;
};
@@ -828,7 +834,7 @@
struct hal_data {
u32 irq;
- u8 *device_base_addr;
+ u32 device_base_addr;
u8 *register_base_addr;
};
@@ -861,6 +867,14 @@
int dev_count;
};
+struct hfi_index_extradata_aspect_ratio_payload {
+ u32 size;
+ u32 version;
+ u32 port_index;
+ u32 saspect_width;
+ u32 saspect_height;
+};
+
extern struct hal_device_data hal_ctxt;
int vidc_hal_iface_msgq_read(struct hal_device *device, void *pkt);
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index 332bbac..c77ae12 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -943,7 +943,7 @@
};
/* VIDC_HAL CORE API's */
-int vidc_hal_core_init(void *device);
+int vidc_hal_core_init(void *device, int domain);
int vidc_hal_core_release(void *device);
int vidc_hal_core_pc_prep(void *device);
int vidc_hal_core_set_resource(void *device,
diff --git a/drivers/media/video/msm_vidc/vidc_hal_helper.h b/drivers/media/video/msm_vidc/vidc_hal_helper.h
index d4e2619..43995eb 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_helper.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_helper.h
@@ -68,8 +68,8 @@
#define HFI_VIDEO_DOMAIN_ENCODER (HFI_COMMON_BASE + 0x1)
#define HFI_VIDEO_DOMAIN_DECODER (HFI_COMMON_BASE + 0x2)
-#define HFI_VIDEO_DOMAIN_VPE (HFI_COMMON_BASE + 0x3)
-#define HFI_VIDEO_DOMAIN_MBI (HFI_COMMON_BASE + 0x4)
+#define HFI_VIDEO_DOMAIN_VPE (HFI_COMMON_BASE + 0x4)
+#define HFI_VIDEO_DOMAIN_MBI (HFI_COMMON_BASE + 0x8)
#define HFI_DOMAIN_BASE_COMMON (HFI_COMMON_BASE + 0)
#define HFI_DOMAIN_BASE_VDEC (HFI_COMMON_BASE + 0x01000000)
@@ -131,6 +131,7 @@
#define HFI_H264_PROFILE_STEREO_HIGH 0x00000008
#define HFI_H264_PROFILE_MULTIVIEW_HIGH 0x00000010
#define HFI_H264_PROFILE_CONSTRAINED_HIGH 0x00000020
+#define HFI_H264_PROFILE_CONSTRAINED_BASE 0x00000040
#define HFI_H264_LEVEL_1 0x00000001
#define HFI_H264_LEVEL_1b 0x00000002
@@ -261,6 +262,10 @@
(HFI_PROPERTY_PARAM_COMMON_START + 0x00B)
#define HFI_PROPERTY_PARAM_MULTI_VIEW_FORMAT \
(HFI_PROPERTY_PARAM_COMMON_START + 0x00C)
+#define HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x00D)
+#define HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x00E)
#define HFI_PROPERTY_CONFIG_COMMON_START \
(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x2000)
@@ -271,6 +276,8 @@
(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x3000)
#define HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM \
(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR \
+ (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x002)
#define HFI_PROPERTY_CONFIG_VDEC_COMMON_START \
(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x4000)
@@ -285,15 +292,13 @@
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x003)
#define HFI_PROPERTY_PARAM_VENC_RATE_CONTROL \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x004)
-#define HFI_PROPERTY_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF \
+#define HFI_PROPERTY_PARAM_VENC_H264_PICORDER_CNT_TYPE \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x005)
-#define HFI_PROPERTY_PARAM_VENC_QUALITY_VS_SPEED \
- (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x010)
#define HFI_PROPERTY_PARAM_VENC_SESSION_QP \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x006)
#define HFI_PROPERTY_PARAM_VENC_MPEG4_AC_PREDICTION \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x007)
-#define HFI_PROPERTY_PARAM_VENC_MPEG4_DATA_PARTITIONING \
+#define HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x008)
#define HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x009)
@@ -301,22 +306,26 @@
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00A)
#define HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00B)
-#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO \
+#define HFI_PROPERTY_PARAM_VENC_OPEN_GOP \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00C)
#define HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00D)
#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00E)
-#define HFI_PROPERTY_PARAM_VENC_VBVBUFFER_SIZE \
+#define HFI_PROPERTY_PARAM_VENC_VBV_HRD_BUF_SIZE \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00F)
+#define HFI_PROPERTY_PARAM_VENC_QUALITY_VS_SPEED \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x010)
#define HFI_PROPERTY_PARAM_VENC_MPEG4_QPEL \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x011)
#define HFI_PROPERTY_PARAM_VENC_ADVANCED \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x012)
#define HFI_PROPERTY_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x013)
-#define HFI_PROPERTY_PARAM_VENC_H264_IDR_S3D_FRAME_PACKING_NAL \
+#define HFI_PROPERTY_PARAM_VENC_H264_SPS_ID \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x014)
+#define HFI_PROPERTY_PARAM_VENC_H264_PPS_ID \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x015)
#define HFI_PROPERTY_CONFIG_VENC_COMMON_START \
(HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x6000)
@@ -328,7 +337,7 @@
(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x003)
#define HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME \
(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x004)
-#define HFI_PROPERTY_CONFIG_VENC_TIMESTAMP_SCALE \
+#define HFI_PROPERTY_CONFIG_VENC_SLICE_SIZE \
(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x005)
#define HFI_PROPERTY_CONFIG_VENC_FRAME_QP \
(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x006)
@@ -357,6 +366,8 @@
#define HFI_CAPABILITY_SCALE_X (HFI_COMMON_BASE + 0x6)
#define HFI_CAPABILITY_SCALE_Y (HFI_COMMON_BASE + 0x7)
#define HFI_CAPABILITY_BITRATE (HFI_COMMON_BASE + 0x8)
+#define HFI_CAPABILITY_BFRAME (HFI_COMMON_BASE + 0x9)
+#define HFI_CAPABILITY_HIERARCHICAL_P_LAYERS (HFI_COMMON_BASE + 0x10)
struct hfi_capability_supported {
u32 capability_type;
@@ -433,10 +444,6 @@
u32 bframes;
};
-struct hfi_timestamp_scale {
- u32 time_stamp_scale;
-};
-
struct hfi_mpeg4_header_extension {
u32 header_extension;
};
@@ -492,6 +499,10 @@
struct hfi_profile_level rg_profile_level[1];
};
+struct hfi_quality_vs_speed {
+ u32 quality_vs_speed;
+};
+
struct hfi_quantization {
u32 qp_i;
u32 qp_p;
@@ -499,8 +510,10 @@
u32 layer_id;
};
-struct hfi_temporal_spatial_tradeoff {
- u32 ts_factor;
+struct hfi_quantization_range {
+ u32 min_qp;
+ u32 max_qp;
+ u32 layer_id;
};
struct hfi_frame_size {
@@ -605,6 +618,8 @@
u8 pipe2d;
u8 hw_mode;
u8 low_delay_enforce;
+ u8 worker_vppsg_delay;
+ int close_gop;
int h264_constrain_intra_pred;
int h264_transform_8x8_flag;
int mpeg4_qpel_enable;
@@ -613,6 +628,9 @@
u8 vpp_info_packet_mode;
u8 ref_tile_mode;
u8 bitstream_flush_mode;
+ u32 vppsg_vspap_fb_sync_delay;
+ u32 rc_initial_delay;
+ u32 peak_bitrate_constraint;
u32 ds_display_frame_width;
u32 ds_display_frame_height;
u32 perf_tune_param_ptr;
@@ -624,6 +642,19 @@
u32 h264_num_ref_frames;
};
+struct hfi_vbv_hrd_bufsize {
+ u32 buffer_size;
+};
+
+struct hfi_codec_mask_supported {
+ u32 codecs;
+ u32 video_domains;
+};
+
+struct hfi_seq_header_info {
+ u32 max_hader_len;
+};
+
#define HFI_CMD_SYS_COMMON_START \
(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x0000)
#define HFI_CMD_SYS_INIT (HFI_CMD_SYS_COMMON_START + 0x001)
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 0a033ae..98e2fd9 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -303,6 +303,105 @@
cd->set_vp_o = false;
}
+/* VCAP Internal QBUF and DQBUF for VC + VP */
+int vcvp_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+ struct vb2_buffer *vb;
+
+ if (q->fileio) {
+ dprintk(1, "%s: file io in progress\n", __func__);
+ return -EBUSY;
+ }
+
+ if (b->type != q->type) {
+ dprintk(1, "%s: invalid buffer type\n", __func__);
+ return -EINVAL;
+ }
+
+ if (b->index >= q->num_buffers) {
+ dprintk(1, "%s: buffer index out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ vb = q->bufs[b->index];
+ if (NULL == vb) {
+ dprintk(1, "%s: buffer is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (b->memory != q->memory) {
+ dprintk(1, "%s: invalid memory type\n", __func__);
+ return -EINVAL;
+ }
+
+ if (vb->state != VB2_BUF_STATE_DEQUEUED &&
+ vb->state != VB2_BUF_STATE_PREPARED) {
+ dprintk(1, "%s: buffer already in use\n", __func__);
+ return -EINVAL;
+ }
+
+ list_add_tail(&vb->queued_entry, &q->queued_list);
+ vb->state = VB2_BUF_STATE_QUEUED;
+
+ if (q->streaming) {
+ vb->state = VB2_BUF_STATE_ACTIVE;
+ atomic_inc(&q->queued_count);
+ q->ops->buf_queue(vb);
+ }
+ return 0;
+}
+
+int vcvp_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+ struct vb2_buffer *vb = NULL;
+ unsigned long flags;
+
+ if (q->fileio) {
+ dprintk(1, "%s: file io in progress\n", __func__);
+ return -EBUSY;
+ }
+
+ if (b->type != q->type) {
+ dprintk(1, "%s: invalid buffer type\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!q->streaming) {
+ dprintk(1, "Streaming off, will not wait for buffers\n");
+ return -EINVAL;
+ }
+
+ if (!list_empty(&q->done_list)) {
+ spin_lock_irqsave(&q->done_lock, flags);
+ vb = list_first_entry(&q->done_list, struct vb2_buffer,
+ done_entry);
+ list_del(&vb->done_entry);
+ spin_unlock_irqrestore(&q->done_lock, flags);
+
+ switch (vb->state) {
+ case VB2_BUF_STATE_DONE:
+ dprintk(3, "%s: Returning done buffer\n", __func__);
+ break;
+ case VB2_BUF_STATE_ERROR:
+ dprintk(3, "%s: Ret done buf with err\n", __func__);
+ break;
+ default:
+ dprintk(1, "%s: Invalid buffer state\n", __func__);
+ return -EINVAL;
+ }
+
+ memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
+
+ list_del(&vb->queued_entry);
+
+ vb->state = VB2_BUF_STATE_DEQUEUED;
+ return 0;
+ }
+
+ dprintk(1, "No buffers to dequeue\n");
+ return -EAGAIN;
+}
+
int get_phys_addr(struct vcap_dev *dev, struct vb2_queue *q,
struct v4l2_buffer *b)
{
@@ -889,6 +988,14 @@
dprintk(1, "qbuf: buffer already in use\n");
return -EINVAL;
}
+ rc = get_phys_addr(c_data->dev, &c_data->vc_vidq, p);
+ if (rc < 0)
+ return rc;
+ rc = vcvp_qbuf(&c_data->vc_vidq, p);
+ if (rc < 0)
+ free_ion_handle(c_data->dev,
+ &c_data->vc_vidq, p);
+ return rc;
}
rc = get_phys_addr(c_data->dev, &c_data->vc_vidq, p);
if (rc < 0)
@@ -1009,6 +1116,7 @@
unsigned long flags;
int rc;
unsigned long rate;
+ long rate_rc;
dprintk(3, "In Stream ON\n");
if (determine_mode(c_data) != c_data->op_mode) {
@@ -1035,12 +1143,13 @@
}
rate = c_data->vc_format.clk_freq;
- rate = clk_round_rate(dev->vcap_clk, rate);
- if (rate <= 0) {
+ rate_rc = clk_round_rate(dev->vcap_clk, rate);
+ if (rate_rc <= 0) {
pr_err("%s: Failed core rnd_rate\n", __func__);
rc = -EINVAL;
goto free_res;
}
+ rate = (unsigned long)rate_rc;
rc = clk_set_rate(dev->vcap_clk, rate);
if (rc < 0)
goto free_res;
@@ -1064,6 +1173,7 @@
goto free_res;
config_vc_format(c_data);
+ c_data->streaming = 1;
rc = vb2_streamon(&c_data->vc_vidq, i);
if (rc < 0)
goto free_res;
@@ -1080,12 +1190,13 @@
c_data->dev->vp_client = c_data;
rate = 160000000;
- rate = clk_round_rate(dev->vcap_clk, rate);
- if (rate <= 0) {
+ rate_rc = clk_round_rate(dev->vcap_clk, rate);
+ if (rate_rc <= 0) {
pr_err("%s: Failed core rnd_rate\n", __func__);
rc = -EINVAL;
goto free_res;
}
+ rate = (unsigned long)rate_rc;
rc = clk_set_rate(dev->vcap_clk, rate);
if (rc < 0)
goto free_res;
@@ -1148,12 +1259,13 @@
}
rate = c_data->vc_format.clk_freq;
- rate = clk_round_rate(dev->vcap_clk, rate);
- if (rate <= 0) {
+ rate_rc = clk_round_rate(dev->vcap_clk, rate);
+ if (rate_rc <= 0) {
pr_err("%s: Failed core rnd_rate\n", __func__);
rc = -EINVAL;
goto free_res;
}
+ rate = (unsigned long)rate_rc;
rc = clk_set_rate(dev->vcap_clk, rate);
if (rc < 0)
goto free_res;
@@ -1266,13 +1378,11 @@
return 0;
}
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+int streamoff_work(struct vcap_client_data *c_data)
{
- struct vcap_client_data *c_data = to_client_data(file->private_data);
struct vcap_dev *dev = c_data->dev;
unsigned long flags;
int rc;
-
switch (c_data->op_mode) {
case VC_VCAP_OP:
if (c_data != dev->vc_client) {
@@ -1288,9 +1398,12 @@
}
dev->vc_resource = 0;
spin_unlock_irqrestore(&dev->dev_slock, flags);
- rc = vb2_streamoff(&c_data->vc_vidq, i);
- if (rc >= 0)
+ rc = vb2_streamoff(&c_data->vc_vidq,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (rc >= 0) {
+ c_data->streaming = 0;
atomic_set(&c_data->dev->vc_enabled, 0);
+ }
return rc;
case VP_VCAP_OP:
if (c_data != dev->vp_client) {
@@ -1383,7 +1496,12 @@
pr_err("VCAP Error: %s: Unknown Operation mode", __func__);
return -ENOTRECOVERABLE;
}
- return 0;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct vcap_client_data *c_data = to_client_data(file->private_data);
+ return streamoff_work(c_data);
}
static int vidioc_subscribe_event(struct v4l2_fh *fh,
@@ -1539,6 +1657,9 @@
if (c_data == NULL)
return 0;
+ if (c_data->streaming)
+ streamoff_work(c_data);
+
spin_lock_irqsave(&dev->dev_slock, flags);
atomic_dec(&dev->open_clients);
ret = atomic_read(&dev->open_clients);
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index ad0718e..62cc306 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -62,19 +62,19 @@
struct vcap_buffer *buf_vp;
int rc;
- p.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
p.memory = V4L2_MEMORY_USERPTR;
while (1) {
+ p.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (!vp_work->cd->streaming)
return;
- rc = vb2_dqbuf(&vp_work->cd->vc_vidq, &p, O_NONBLOCK);
+ rc = vcvp_dqbuf(&vp_work->cd->vc_vidq, &p);
if (rc < 0)
return;
vb_vc = vp_work->cd->vc_vidq.bufs[p.index];
if (NULL == vb_vc) {
dprintk(1, "%s: buffer is NULL\n", __func__);
- vb2_qbuf(&vp_work->cd->vc_vidq, &p);
+ vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
return;
}
buf_vc = container_of(vb_vc, struct vcap_buffer, vb);
@@ -82,7 +82,7 @@
vb_vp = vp_work->cd->vp_in_vidq.bufs[p.index];
if (NULL == vb_vp) {
dprintk(1, "%s: buffer is NULL\n", __func__);
- vb2_qbuf(&vp_work->cd->vc_vidq, &p);
+ vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
return;
}
buf_vp = container_of(vb_vp, struct vcap_buffer, vb);
@@ -94,7 +94,7 @@
p.type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
/* This call should not fail */
- rc = vb2_qbuf(&vp_work->cd->vp_in_vidq, &p);
+ rc = vcvp_qbuf(&vp_work->cd->vp_in_vidq, &p);
if (rc < 0) {
pr_err("%s: qbuf to vp_in failed\n", __func__);
buf_vc->ion_handle = buf_vp->ion_handle;
@@ -102,7 +102,7 @@
buf_vp->ion_handle = NULL;
buf_vp->paddr = 0;
p.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- vb2_qbuf(&vp_work->cd->vc_vidq, &p);
+ vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
}
}
}
diff --git a/drivers/media/video/vcap_vc.h b/drivers/media/video/vcap_vc.h
index 57d13cd..792fb14 100644
--- a/drivers/media/video/vcap_vc.h
+++ b/drivers/media/video/vcap_vc.h
@@ -69,11 +69,6 @@
#define VC_BUFFER_WRITTEN (0x3 << 1)
-struct vc_reg_data {
- unsigned data;
- unsigned addr;
-};
-
int vc_start_capture(struct vcap_client_data *c_data);
int vc_hw_kick_off(struct vcap_client_data *c_data);
void vc_stop_capture(struct vcap_client_data *c_data);
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index 1b503ba..be1b4ff 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -117,21 +117,21 @@
struct vcap_buffer *buf_vp;
int rc;
- p.type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
p.memory = V4L2_MEMORY_USERPTR;
/* This loop exits when there is no more buffers left */
while (1) {
+ p.type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
if (!vp_work->cd->streaming)
return;
- rc = vb2_dqbuf(&vp_work->cd->vp_in_vidq, &p, O_NONBLOCK);
+ rc = vcvp_dqbuf(&vp_work->cd->vp_in_vidq, &p);
if (rc < 0)
return;
vb_vc = vp_work->cd->vc_vidq.bufs[p.index];
if (NULL == vb_vc) {
dprintk(1, "%s: buffer is NULL\n", __func__);
- vb2_qbuf(&vp_work->cd->vp_in_vidq, &p);
+ vcvp_qbuf(&vp_work->cd->vp_in_vidq, &p);
return;
}
buf_vc = container_of(vb_vc, struct vcap_buffer, vb);
@@ -139,7 +139,7 @@
vb_vp = vp_work->cd->vp_in_vidq.bufs[p.index];
if (NULL == vb_vp) {
dprintk(1, "%s: buffer is NULL\n", __func__);
- vb2_qbuf(&vp_work->cd->vp_in_vidq, &p);
+ vcvp_qbuf(&vp_work->cd->vp_in_vidq, &p);
return;
}
buf_vp = container_of(vb_vp, struct vcap_buffer, vb);
@@ -150,7 +150,7 @@
p.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* This call should not fail */
- rc = vb2_qbuf(&vp_work->cd->vc_vidq, &p);
+ rc = vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
if (rc < 0) {
dprintk(1, "%s: qbuf to vc failed\n", __func__);
buf_vp->ion_handle = buf_vc->ion_handle;
@@ -158,7 +158,7 @@
buf_vc->ion_handle = NULL;
buf_vc->paddr = 0;
p.type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
- vb2_qbuf(&vp_work->cd->vp_in_vidq, &p);
+ vcvp_qbuf(&vp_work->cd->vp_in_vidq, &p);
}
}
}
@@ -180,12 +180,13 @@
return;
vp_act = &dev->vp_client->vid_vp_action;
- irq = vp_work->irq;
rc = readl_relaxed(VCAP_OFFSET(0x048));
while (!(rc & 0x00000100))
rc = readl_relaxed(VCAP_OFFSET(0x048));
+ irq = readl_relaxed(VCAP_VP_INT_STATUS);
+
writel_relaxed(0x00000000, VCAP_VP_BAL_VMOTION_STATE);
writel_relaxed(0x40000000, VCAP_VP_REDUCT_AVG_MOTION2);
@@ -283,7 +284,7 @@
}
dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
- if (!(irq & VP_PIC_DONE)) {
+ if (!(irq & (VP_PIC_DONE || VP_MODE_CHANGE))) {
writel_relaxed(irq, VCAP_VP_INT_CLEAR);
pr_err("VP IRQ shows some error\n");
return IRQ_HANDLED;
@@ -307,7 +308,6 @@
INIT_WORK(&dev->vp_work.work, vp_wq_fnc);
dev->vp_work.cd = c_data;
- dev->vp_work.irq = irq;
rc = queue_work(dev->vcap_wq, &dev->vp_work.work);
disable_irq_nosync(dev->vpirq->start);
@@ -411,7 +411,7 @@
void *buf;
if (!c_data->vid_vp_action.bufMotion) {
- dprintk(1, "Motion buffer has not been created");
+ pr_err("Motion buffer has not been created");
return;
}
@@ -556,7 +556,7 @@
if (c_data->vp_out_fmt.pixfmt == V4L2_PIX_FMT_NV16)
chroma_fmt = 1;
- writel_relaxed((c_data->vp_in_fmt.width / 16) << 20 |
+ writel_relaxed((c_data->vp_out_fmt.width / 16) << 20 |
chroma_fmt << 11 | 0x1 << 4, VCAP_VP_OUT_CONFIG);
/* Enable Interrupt */
diff --git a/drivers/media/video/vcap_vp.h b/drivers/media/video/vcap_vp.h
index 47ad8d4..5415e54 100644
--- a/drivers/media/video/vcap_vp.h
+++ b/drivers/media/video/vcap_vp.h
@@ -89,6 +89,7 @@
#define VCAP_VP_NR_T2_C_BASE_ADDR (VCAP_BASE + 0x4B8)
#define VP_PIC_DONE (0x1 << 0)
+#define VP_MODE_CHANGE (0x1 << 8)
irqreturn_t vp_handler(struct vcap_dev *dev);
int config_vp_format(struct vcap_client_data *c_data);
diff --git a/drivers/mfd/pm8xxx-spk.c b/drivers/mfd/pm8xxx-spk.c
index 297ddfa..2de70f4 100644
--- a/drivers/mfd/pm8xxx-spk.c
+++ b/drivers/mfd/pm8xxx-spk.c
@@ -162,7 +162,10 @@
val = pm8xxx_spk_read(PM8XXX_SPK_CTL1_REG_OFF);
if (val < 0)
return val;
- val |= (enable << 3);
+ if (enable)
+ val |= (1 << 3);
+ else
+ val &= ~(1 << 3);
ret = pm8xxx_spk_write(PM8XXX_SPK_CTL1_REG_OFF, val);
if (!ret)
ret = pm8xxx_spk_bank_write(addr, 6, PWM_EN_MASK);
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 021dcf1..2256f67 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -297,7 +297,6 @@
static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx, int irq)
{
int ret;
- u8 idbyte_0, idbyte_1, idbyte_2, idbyte_3;
struct mfd_cell *wcd9xxx_dev = NULL;
int wcd9xxx_dev_size = 0;
@@ -321,49 +320,26 @@
goto err;
}
- idbyte_0 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0);
- idbyte_1 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_1);
- idbyte_2 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2);
- idbyte_3 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_3);
+ wcd9xxx->idbyte_0 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0);
+ wcd9xxx->idbyte_1 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_1);
+ wcd9xxx->idbyte_2 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2);
+ wcd9xxx->idbyte_3 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_3);
wcd9xxx->version = wcd9xxx_reg_read(wcd9xxx,
WCD9XXX_A_CHIP_VERSION) & 0x1F;
pr_info("%s : Codec version %u initialized\n",
__func__, wcd9xxx->version);
- pr_info("idbyte_0[%08x] idbyte_1[%08x] idbyte_2[%08x] idbyte_3[%08x]\n",
- idbyte_0, idbyte_1, idbyte_2, idbyte_3);
- if (wcd9xxx->slim != NULL) {
- if (!strncmp(wcd9xxx->slim->name, "tabla", 5)) {
- if (TABLA_IS_1_X(wcd9xxx->version)) {
- wcd9xxx_dev = tabla1x_devs;
- wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
- } else {
- wcd9xxx_dev = tabla_devs;
- wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
- }
- } else {
- wcd9xxx_dev = sitar_devs;
- wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
- }
- } else {
- /* Need to add here check for Tabla.
- * For now the read of version takes
- * care of now only tabla.
- */
- pr_debug("%s : Read codec version using I2C\n", __func__);
- if (!strncmp(wcd9xxx_modules[0].client->name, "sitar", 5)) {
- wcd9xxx_dev = sitar_devs;
- wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
- } else if (TABLA_IS_1_X(wcd9xxx->version)) {
- wcd9xxx_dev = tabla1x_devs;
- wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
- } else if (TABLA_IS_2_0(wcd9xxx->version)) {
- wcd9xxx_dev = tabla_devs;
- wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
- }
+ if (wcd9xxx->idbyte_0 == 0x2) {
+ wcd9xxx_dev = tabla_devs;
+ wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
+ } else if (wcd9xxx->idbyte_0 == 0x1) {
+ wcd9xxx_dev = tabla1x_devs;
+ wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
+ } else if (wcd9xxx->idbyte_0 == 0x0) {
+ wcd9xxx_dev = sitar_devs;
+ wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
}
-
ret = mfd_add_devices(wcd9xxx->dev, -1,
wcd9xxx_dev, wcd9xxx_dev_size,
NULL, 0);
@@ -766,21 +742,22 @@
wcd9xxx->irq = pdata->irq;
wcd9xxx->irq_base = pdata->irq_base;
- /*read the tabla status before initializing the device type*/
- ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
- if (!strncmp(wcd9xxx_modules[0].client->name, "sitar", 5))
- i2c_mode = SITAR_I2C_MODE;
- else if (!strncmp(wcd9xxx_modules[0].client->name, "tabla", 5))
- i2c_mode = TABLA_I2C_MODE;
-
- if ((ret < 0) || (val != i2c_mode))
- pr_err("failed to read the wcd9xxx status ret = %d\n", ret);
-
ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
if (ret) {
pr_err("%s: error, initializing device failed\n", __func__);
goto err_device_init;
}
+
+ if ((wcd9xxx->idbyte_0 == 0x2) || (wcd9xxx->idbyte_0 == 0x1))
+ i2c_mode = TABLA_I2C_MODE;
+ else if (wcd9xxx->idbyte_0 == 0x0)
+ i2c_mode = SITAR_I2C_MODE;
+
+ ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
+
+ if ((ret < 0) || (val != i2c_mode))
+ pr_err("failed to read the wcd9xxx status ret = %d\n", ret);
+
wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_I2C;
return ret;
@@ -1127,15 +1104,6 @@
};
MODULE_DEVICE_TABLE(i2c, tabla_id_table);
-static struct i2c_device_id sitar_id_table[] = {
- {"sitar top level", WCD9XXX_I2C_TOP_LEVEL},
- {"sitar analog", WCD9XXX_I2C_ANALOG},
- {"sitar digital1", WCD9XXX_I2C_DIGITAL_1},
- {"sitar digital2", WCD9XXX_I2C_DIGITAL_2},
- {}
-};
-MODULE_DEVICE_TABLE(i2c, tabla_id_table);
-
static struct i2c_driver tabla_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
@@ -1148,21 +1116,9 @@
.suspend = wcd9xxx_i2c_suspend,
};
-static struct i2c_driver sitar_i2c_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "sitar-i2c-core",
- },
- .id_table = sitar_id_table,
- .probe = wcd9xxx_i2c_probe,
- .remove = __devexit_p(wcd9xxx_i2c_remove),
- .resume = wcd9xxx_i2c_resume,
- .suspend = wcd9xxx_i2c_suspend,
-};
-
static int __init wcd9xxx_init(void)
{
- int ret1, ret2, ret3, ret4, ret5, ret6;
+ int ret1, ret2, ret3, ret4, ret5;
ret1 = slim_driver_register(&tabla_slim_driver);
if (ret1 != 0)
@@ -1184,11 +1140,7 @@
if (ret5 != 0)
pr_err("Failed to register sitar SB driver: %d\n", ret5);
- ret6 = i2c_add_driver(&sitar_i2c_driver);
- if (ret6 != 0)
- pr_err("failed to add the I2C driver\n");
-
- return (ret1 && ret2 && ret3 && ret4 && ret5 && ret6) ? -1 : 0;
+ return (ret1 && ret2 && ret3 && ret4 && ret5) ? -1 : 0;
}
module_init(wcd9xxx_init);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index d4eb6e0..8354aa8 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -609,10 +609,24 @@
return -EINVAL;
}
- if (resp.result == QSEOS_RESULT_FAILURE)
- return 0;
- else
- return resp.data;
+ if (resp.result == QSEOS_RESULT_FAILURE) {
+ return 0;
+ } else {
+ switch (resp.resp_type) {
+ /*qsee returned listener type response */
+ case QSEOS_LISTENER_ID:
+ pr_err("resp type is of listener type instead of app");
+ return -EINVAL;
+ break;
+ case QSEOS_APP_ID:
+ return resp.data;
+ default:
+ pr_err("invalid resp type (%d) from qsee",
+ resp.resp_type);
+ return -ENODEV;
+ break;
+ }
+ }
}
static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
@@ -627,6 +641,8 @@
uint32_t len;
struct qseecom_command_scm_resp resp;
struct qseecom_check_app_ireq req;
+ struct qseecom_load_app_ireq load_req;
+
/* Copy the relevant information needed for loading the image */
if (__copy_from_user(&load_img_req,
(void __user *)argp,
@@ -642,108 +658,86 @@
req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
- ret = __qseecom_check_app_exists(req);
- if (ret < 0)
- return ret;
- else
- app_id = ret;
-
- if (app_id) {
- pr_warn("App id %d (%s) already exists\n", app_id,
+ pr_warn("App (%s) does not exist, loading apps for first time\n",
(char *)(req.app_name));
- spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
- list_for_each_entry(entry,
- &qseecom.registered_app_list_head, list){
- if (entry->app_id == app_id) {
- entry->ref_cnt++;
- break;
- }
- }
- spin_unlock_irqrestore(
- &qseecom.registered_app_list_lock, flags);
- } else {
- struct qseecom_load_app_ireq load_req;
-
- pr_warn("App (%s) does not exist, loading apps for first time\n",
- (char *)(req.app_name));
- /* Get the handle of the shared fd */
- ihandle = ion_import_dma_buf(qseecom.ion_clnt,
+ /* Get the handle of the shared fd */
+ ihandle = ion_import_dma_buf(qseecom.ion_clnt,
load_img_req.ifd_data_fd);
- if (IS_ERR_OR_NULL(ihandle)) {
- pr_err("Ion client could not retrieve the handle\n");
- qsee_disable_clock_vote(CLK_SFPB);
- return -ENOMEM;
- }
+ if (IS_ERR_OR_NULL(ihandle)) {
+ pr_err("Ion client could not retrieve the handle\n");
+ qsee_disable_clock_vote(CLK_SFPB);
+ return -ENOMEM;
+ }
- /* Get the physical address of the ION BUF */
- ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
+ /* Get the physical address of the ION BUF */
+ ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
- /* Populate the structure for sending scm call to load image */
- load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
- load_req.mdt_len = load_img_req.mdt_len;
- load_req.img_len = load_img_req.img_len;
- load_req.phy_addr = pa;
+ /* Populate the structure for sending scm call to load image */
+ load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
+ load_req.mdt_len = load_img_req.mdt_len;
+ load_req.img_len = load_img_req.img_len;
+ load_req.phy_addr = pa;
- /* SCM_CALL to load the app and get the app_id back */
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
- sizeof(struct qseecom_load_app_ireq),
- &resp, sizeof(resp));
- if (ret) {
- pr_err("scm_call to load app failed\n");
- return -EINVAL;
- }
+ /* SCM_CALL to load the app and get the app_id back */
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
+ sizeof(struct qseecom_load_app_ireq),
+ &resp, sizeof(resp));
+ if (ret) {
+ pr_err("scm_call to load app failed\n");
+ return -EINVAL;
+ }
- if (resp.result == QSEOS_RESULT_FAILURE) {
- pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
- if (!IS_ERR_OR_NULL(ihandle))
- ion_free(qseecom.ion_clnt, ihandle);
- qsee_disable_clock_vote(CLK_SFPB);
- return -EFAULT;
- }
-
- if (resp.result == QSEOS_RESULT_INCOMPLETE) {
- ret = __qseecom_process_incomplete_cmd(data, &resp);
- if (ret) {
- pr_err("process_incomplete_cmd failed err: %d\n",
- ret);
- if (!IS_ERR_OR_NULL(ihandle))
- ion_free(qseecom.ion_clnt, ihandle);
- qsee_disable_clock_vote(CLK_SFPB);
- return ret;
- }
- }
- if (resp.result != QSEOS_RESULT_SUCCESS) {
- pr_err("scm_call failed resp.result unknown, %d\n",
- resp.result);
- if (!IS_ERR_OR_NULL(ihandle))
- ion_free(qseecom.ion_clnt, ihandle);
- qsee_disable_clock_vote(CLK_SFPB);
- return -EFAULT;
- }
-
- app_id = resp.data;
-
- entry = kmalloc(sizeof(*entry), GFP_KERNEL);
- if (!entry) {
- pr_err("kmalloc failed\n");
- qsee_disable_clock_vote(CLK_SFPB);
- return -ENOMEM;
- }
- entry->app_id = app_id;
- entry->ref_cnt = 1;
-
- /* Deallocate the handle */
+ if (resp.result == QSEOS_RESULT_FAILURE) {
+ pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
-
- spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
- list_add_tail(&entry->list, &qseecom.registered_app_list_head);
- spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
- flags);
-
- pr_warn("App with id %d (%s) now loaded\n", app_id,
- (char *)(req.app_name));
+ qsee_disable_clock_vote(CLK_SFPB);
+ return -EFAULT;
}
+
+ if (resp.result == QSEOS_RESULT_INCOMPLETE) {
+ ret = __qseecom_process_incomplete_cmd(data, &resp);
+ if (ret) {
+ pr_err("process_incomplete_cmd failed err: %d\n",
+ ret);
+ if (!IS_ERR_OR_NULL(ihandle))
+ ion_free(qseecom.ion_clnt, ihandle);
+ qsee_disable_clock_vote(CLK_SFPB);
+ return ret;
+ }
+ }
+
+ if (resp.result != QSEOS_RESULT_SUCCESS) {
+ pr_err("scm_call failed resp.result unknown, %d\n",
+ resp.result);
+ if (!IS_ERR_OR_NULL(ihandle))
+ ion_free(qseecom.ion_clnt, ihandle);
+ qsee_disable_clock_vote(CLK_SFPB);
+ return -EFAULT;
+ }
+
+ app_id = resp.data;
+
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ pr_err("kmalloc failed\n");
+ qsee_disable_clock_vote(CLK_SFPB);
+ return -ENOMEM;
+ }
+ entry->app_id = app_id;
+ entry->ref_cnt = 1;
+
+ /* Deallocate the handle */
+ if (!IS_ERR_OR_NULL(ihandle))
+ ion_free(qseecom.ion_clnt, ihandle);
+
+ spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+ list_add_tail(&entry->list, &qseecom.registered_app_list_head);
+ spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags);
+
+ pr_warn("App with id %d (%s) now loaded\n", app_id,
+ (char *)(req.app_name));
+
data->client.app_id = app_id;
load_img_req.app_id = app_id;
if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
@@ -1432,6 +1426,8 @@
int32_t ret;
struct qseecom_qseos_app_load_query query_req;
struct qseecom_check_app_ireq req;
+ struct qseecom_registered_app_list *entry = NULL;
+ unsigned long flags = 0;
/* Copy the relevant information needed for loading the image */
if (__copy_from_user(&query_req,
@@ -1445,11 +1441,30 @@
memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
ret = __qseecom_check_app_exists(req);
- if (ret == -EINVAL) {
+
+ if ((ret == -EINVAL) || (ret == -ENODEV)) {
pr_err(" scm call to check if app is loaded failed");
return ret; /* scm call failed */
} else if (ret > 0) {
- pr_err("app is already loaded in QSEE");
+ pr_warn("App id %d (%s) already exists\n", ret,
+ (char *)(req.app_name));
+ spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+ list_for_each_entry(entry,
+ &qseecom.registered_app_list_head, list){
+ if (entry->app_id == ret) {
+ entry->ref_cnt++;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(
+ &qseecom.registered_app_list_lock, flags);
+ data->client.app_id = ret;
+ query_req.app_id = ret;
+
+ if (copy_to_user(argp, &query_req, sizeof(query_req))) {
+ pr_err("copy_to_user failed\n");
+ return -EFAULT;
+ }
return -EEXIST; /* app already loaded */
} else {
return 0; /* app not loaded */
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 4d7553e..cc65929 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -1818,11 +1818,12 @@
goto err_bam;
}
- if (device->tsif_pclk && clk_enable(device->tsif_pclk) != 0) {
+ if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
dev_err(&pdev->dev, "Can't start pclk");
goto err_pclk;
}
- if (device->tsif_ref_clk && clk_enable(device->tsif_ref_clk) != 0) {
+ if (device->tsif_ref_clk &&
+ clk_prepare_enable(device->tsif_ref_clk) != 0) {
dev_err(&pdev->dev, "Can't start ref clk");
goto err_refclk;
}
@@ -1849,7 +1850,7 @@
err_refclk:
if (device->tsif_pclk)
- clk_disable(device->tsif_pclk);
+ clk_disable_unprepare(device->tsif_pclk);
err_pclk:
sps_deregister_bam_device(device->bam_handle);
err_bam:
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index 0ace608..871675c 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.c
@@ -33,11 +33,16 @@
#define PACKED_HDR_RW_MASK 0x0000FF00
#define PACKED_HDR_NUM_REQS_MASK 0x00FF0000
#define PACKED_HDR_BITS_16_TO_29_SET 0x3FFF0000
+#define SECTOR_SIZE 512
+#define NUM_OF_SECTORS_PER_BIO ((BIO_U32_SIZE * 4) / SECTOR_SIZE)
+#define BIO_TO_SECTOR(x) (x * NUM_OF_SECTORS_PER_BIO)
#define test_pr_debug(fmt, args...) pr_debug("%s: "fmt"\n", MODULE_NAME, args)
#define test_pr_info(fmt, args...) pr_info("%s: "fmt"\n", MODULE_NAME, args)
#define test_pr_err(fmt, args...) pr_err("%s: "fmt"\n", MODULE_NAME, args)
+#define SANITIZE_TEST_TIMEOUT 240000
+
enum is_random {
NON_RANDOM_TEST,
RANDOM_TEST,
@@ -83,6 +88,27 @@
TEST_CMD23_BITS_16TO29_SET,
TEST_CMD23_HDR_BLK_NOT_IN_COUNT,
INVALID_CMD_MAX_TESTCASE = TEST_CMD23_HDR_BLK_NOT_IN_COUNT,
+
+ /*
+ * Start of packing control test group.
+ * in these next testcases the abbreviation FB = followed by
+ */
+ PACKING_CONTROL_MIN_TESTCASE,
+ TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ =
+ PACKING_CONTROL_MIN_TESTCASE,
+ TEST_PACKING_EXP_N_OVER_TRIGGER,
+ TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ,
+ TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N,
+ TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER,
+ TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS,
+ TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS,
+ TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER,
+ TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER,
+ TEST_PACK_MIX_PACKED_NO_PACKED_PACKED,
+ TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED,
+ PACKING_CONTROL_MAX_TESTCASE = TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED,
+
+ TEST_WRITE_DISCARD_SANITIZE_READ,
};
enum mmc_block_test_group {
@@ -91,6 +117,7 @@
TEST_SEND_WRITE_PACKING_GROUP,
TEST_ERR_CHECK_GROUP,
TEST_SEND_INVALID_GROUP,
+ TEST_PACKING_CONTROL_GROUP,
};
struct mmc_block_test_debug {
@@ -98,6 +125,8 @@
struct dentry *err_check_test;
struct dentry *send_invalid_packed_test;
struct dentry *random_test_seed;
+ struct dentry *packing_control_test;
+ struct dentry *discard_sanitize_test;
};
struct mmc_block_test_data {
@@ -454,6 +483,30 @@
return "Test invalid - cmd23 bits [16-29] set";
case TEST_CMD23_HDR_BLK_NOT_IN_COUNT:
return "Test invalid - cmd23 header block not in count";
+ case TEST_PACKING_EXP_N_OVER_TRIGGER:
+ return "\nTest packing control - pack n";
+ case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
+ return "\nTest packing control - pack n followed by read";
+ case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
+ return "\nTest packing control - pack n followed by flush";
+ case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
+ return "\nTest packing control - pack one followed by read";
+ case TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER:
+ return "\nTest packing control - pack threshold";
+ case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
+ return "\nTest packing control - no packing";
+ case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
+ return "\nTest packing control - no packing, trigger requests";
+ case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
+ return "\nTest packing control - no pack, trigger-read-trigger";
+ case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
+ return "\nTest packing control- no pack, trigger-flush-trigger";
+ case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
+ return "\nTest packing control - mix: pack -> no pack -> pack";
+ case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
+ return "\nTest packing control - mix: no pack->pack->no pack";
+ case TEST_WRITE_DISCARD_SANITIZE_READ:
+ return "\nTest write, discard, sanitize";
default:
return "Unknown testcase";
}
@@ -505,7 +558,7 @@
stop_reason = mmc_packed_stats->pack_stop_reason;
- for (i = 1 ; i <= max_packed_reqs ; ++i) {
+ for (i = 1; i <= max_packed_reqs; ++i) {
if (mmc_packed_stats->packing_events[i] !=
expected_stats.packing_events[i]) {
test_pr_err(
@@ -710,7 +763,7 @@
test_pr_info("%s: Adding %d write requests, first req_id=%d", __func__,
num_requests, td->wr_rd_next_req_id);
- for (i = 1 ; i <= num_requests ; i++) {
+ for (i = 1; i <= num_requests; i++) {
start_sec = td->start_sector + 4096 * td->num_of_write_bios;
if (is_random)
pseudo_rnd_num_of_bios(bio_seed, &num_bios);
@@ -826,6 +879,185 @@
}
/*
+ * Prepare the write, read and flush requests for the packing control
+ * testcases
+ */
+static int prepare_packed_control_tests_requests(struct test_data *td,
+ int is_err_expected, int num_requests, int is_random)
+{
+ int ret = 0;
+ struct mmc_queue *mq;
+ int max_packed_reqs;
+ int temp_num_req = num_requests;
+ struct request_queue *req_q;
+ int test_packed_trigger;
+ int num_packed_reqs;
+
+ if (!td) {
+ test_pr_err("%s: NULL td\n", __func__);
+ return -EINVAL;
+ }
+
+ req_q = td->req_q;
+
+ if (!req_q) {
+ test_pr_err("%s: NULL request queue\n", __func__);
+ return -EINVAL;
+ }
+
+ mq = req_q->queuedata;
+ if (!mq) {
+ test_pr_err("%s: NULL mq", __func__);
+ return -EINVAL;
+ }
+
+ max_packed_reqs = mq->card->ext_csd.max_packed_writes;
+ test_packed_trigger = mq->num_wr_reqs_to_start_packing;
+ num_packed_reqs = num_requests - test_packed_trigger;
+
+ if (mbtd->random_test_seed == 0) {
+ mbtd->random_test_seed =
+ (unsigned int)(get_jiffies_64() & 0xFFFF);
+ test_pr_info("%s: got seed from jiffies %d",
+ __func__, mbtd->random_test_seed);
+ }
+
+ mmc_blk_init_packed_statistics(mq->card);
+
+ if (td->test_info.testcase ==
+ TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED) {
+ temp_num_req = num_requests;
+ num_requests = test_packed_trigger - 1;
+ }
+
+ /* Verify that the packing is disabled before starting the test */
+ mq->wr_packing_enabled = false;
+ mq->num_of_potential_packed_wr_reqs = 0;
+
+ if (td->test_info.testcase == TEST_PACK_MIX_PACKED_NO_PACKED_PACKED) {
+ mq->num_of_potential_packed_wr_reqs = test_packed_trigger + 1;
+ mq->wr_packing_enabled = true;
+ num_requests = test_packed_trigger + 2;
+ }
+
+ ret = prepare_request_add_write_reqs(td, num_requests, is_err_expected,
+ is_random);
+ if (ret)
+ goto exit;
+
+ if (td->test_info.testcase == TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED)
+ num_requests = temp_num_req;
+
+ memset((void *)mbtd->exp_packed_stats.pack_stop_reason, 0,
+ sizeof(mbtd->exp_packed_stats.pack_stop_reason));
+ memset(mbtd->exp_packed_stats.packing_events, 0,
+ (max_packed_reqs + 1) * sizeof(u32));
+
+ switch (td->test_info.testcase) {
+ case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
+ case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
+ ret = prepare_request_add_read(td);
+ if (ret)
+ goto exit;
+
+ mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
+ mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
+ break;
+ case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
+ ret = prepare_request_add_flush(td);
+ if (ret)
+ goto exit;
+
+ ret = prepare_request_add_write_reqs(td, num_packed_reqs,
+ is_err_expected, is_random);
+ if (ret)
+ goto exit;
+
+ mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
+ mbtd->exp_packed_stats.pack_stop_reason[FLUSH_OR_DISCARD] = 1;
+ mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 2;
+ break;
+ case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
+ ret = prepare_request_add_read(td);
+ if (ret)
+ goto exit;
+
+ ret = prepare_request_add_write_reqs(td, test_packed_trigger,
+ is_err_expected, is_random);
+ if (ret)
+ goto exit;
+
+ mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
+ break;
+ case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
+ ret = prepare_request_add_flush(td);
+ if (ret)
+ goto exit;
+
+ ret = prepare_request_add_write_reqs(td, test_packed_trigger,
+ is_err_expected, is_random);
+ if (ret)
+ goto exit;
+
+ mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
+ break;
+ case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
+ ret = prepare_request_add_read(td);
+ if (ret)
+ goto exit;
+
+ ret = prepare_request_add_write_reqs(td, test_packed_trigger-1,
+ is_err_expected, is_random);
+ if (ret)
+ goto exit;
+
+ ret = prepare_request_add_write_reqs(td, num_requests,
+ is_err_expected, is_random);
+ if (ret)
+ goto exit;
+
+ mbtd->exp_packed_stats.packing_events[num_requests] = 1;
+ mbtd->exp_packed_stats.packing_events[num_requests-1] = 1;
+ mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
+ mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
+ break;
+ case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
+ ret = prepare_request_add_read(td);
+ if (ret)
+ goto exit;
+
+ ret = prepare_request_add_write_reqs(td, num_requests,
+ is_err_expected, is_random);
+ if (ret)
+ goto exit;
+
+ ret = prepare_request_add_read(td);
+ if (ret)
+ goto exit;
+
+ ret = prepare_request_add_write_reqs(td, test_packed_trigger-1,
+ is_err_expected, is_random);
+ if (ret)
+ goto exit;
+
+ mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
+ mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
+ break;
+ case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
+ case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
+ mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
+ break;
+ default:
+ mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
+ mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
+ }
+ mbtd->num_requests = num_requests;
+
+exit:
+ return ret;
+}
+
+/*
* Prepare requests for the TEST_RET_PARTIAL_FOLLOWED_BY_ABORT testcase.
* In this testcase we have mixed error expectations from different
* write requests, hence the special prepare function.
@@ -848,13 +1080,14 @@
mmc_blk_init_packed_statistics(mq->card);
- for (i = 1 ; i <= num_requests ; i++) {
+ for (i = 1; i <= num_requests; i++) {
if (i > (num_requests / 2))
is_err_expected = 1;
- start_address = td->start_sector + 4096*td->num_of_write_bios;
+ start_address = td->start_sector + 4096 * td->num_of_write_bios;
ret = test_iosched_add_wr_rd_test_req(is_err_expected, WRITE,
- start_address, (i%5)+1, TEST_PATTERN_5A, NULL);
+ start_address, (i % 5) + 1, TEST_PATTERN_5A,
+ NULL);
if (ret) {
test_pr_err("%s: failed to add a write request",
__func__);
@@ -888,6 +1121,8 @@
int num_requests;
int min_num_requests = 2;
int is_random = mbtd->is_random;
+ int max_for_double;
+ int test_packed_trigger;
req_q = test_iosched_get_req_queue();
if (req_q)
@@ -904,16 +1139,52 @@
max_num_requests = mq->card->ext_csd.max_packed_writes;
num_requests = max_num_requests - 2;
+ test_packed_trigger = mq->num_wr_reqs_to_start_packing;
+
+ /*
+ * Here max_for_double is intended for packed control testcases
+ * in which we issue many write requests. It's purpose is to prevent
+ * exceeding max number of req_queue requests.
+ */
+ max_for_double = max_num_requests - 10;
+
+ if (td->test_info.testcase ==
+ TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
+ /* Don't expect packing, so issue up to trigger-1 reqs */
+ num_requests = test_packed_trigger - 1;
if (is_random) {
if (td->test_info.testcase ==
TEST_RET_PARTIAL_FOLLOWED_BY_ABORT)
+ /*
+ * Here we don't want num_requests to be less than 1
+ * as a consequence of division by 2.
+ */
min_num_requests = 3;
+ if (td->test_info.testcase ==
+ TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
+ /* Don't expect packing, so issue up to trigger reqs */
+ max_num_requests = test_packed_trigger;
+
num_requests = pseudo_random_seed(seed, min_num_requests,
max_num_requests - 1);
}
+ if (td->test_info.testcase ==
+ TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
+ num_requests -= test_packed_trigger;
+
+ if (td->test_info.testcase == TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N)
+ num_requests =
+ num_requests > max_for_double ? max_for_double : num_requests;
+
+ if (mbtd->test_group == TEST_PACKING_CONTROL_GROUP)
+ num_requests += test_packed_trigger;
+
+ if (td->test_info.testcase == TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS)
+ num_requests = test_packed_trigger;
+
return num_requests;
}
@@ -929,6 +1200,7 @@
int num_requests = 0;
int ret = 0;
int is_random = mbtd->is_random;
+ int test_packed_trigger = mq->num_wr_reqs_to_start_packing;
if (!mq) {
test_pr_err("%s: NULL mq", __func__);
@@ -997,6 +1269,33 @@
case TEST_HDR_CMD23_PACKED_BIT_SET:
ret = prepare_packed_requests(td, 1, num_requests, is_random);
break;
+ case TEST_PACKING_EXP_N_OVER_TRIGGER:
+ case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
+ case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
+ case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
+ case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
+ case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
+ ret = prepare_packed_control_tests_requests(td, 0, num_requests,
+ is_random);
+ break;
+ case TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER:
+ ret = prepare_packed_control_tests_requests(td, 0,
+ max_num_requests, is_random);
+ break;
+ case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
+ ret = prepare_packed_control_tests_requests(td, 0,
+ test_packed_trigger + 1,
+ is_random);
+ break;
+ case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
+ ret = prepare_packed_control_tests_requests(td, 0, num_requests,
+ is_random);
+ break;
+ case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
+ case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
+ ret = prepare_packed_control_tests_requests(td, 0,
+ test_packed_trigger, is_random);
+ break;
default:
test_pr_info("%s: Invalid test case...", __func__);
return -EINVAL;
@@ -1084,6 +1383,9 @@
/* disable the packing control */
host->caps2 &= ~MMC_CAP2_PACKED_WR_CONTROL;
break;
+ case TEST_PACKING_CONTROL_GROUP:
+ host->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
+ break;
default:
break;
}
@@ -1091,6 +1393,63 @@
return 0;
}
+static void pseudo_rnd_sector_and_size(unsigned int *seed,
+ unsigned int min_start_sector,
+ unsigned int *start_sector,
+ unsigned int *num_of_bios)
+{
+ unsigned int max_sec = min_start_sector + TEST_MAX_SECTOR_RANGE;
+ do {
+ *start_sector = pseudo_random_seed(seed,
+ 1, max_sec);
+ *num_of_bios = pseudo_random_seed(seed,
+ 1, TEST_MAX_BIOS_PER_REQ);
+ if (!(*num_of_bios))
+ *num_of_bios = 1;
+ } while ((*start_sector < min_start_sector) ||
+ (*start_sector + (*num_of_bios * BIO_U32_SIZE * 4)) > max_sec);
+}
+
+/* sanitize test functions */
+static int prepare_write_discard_sanitize_read(struct test_data *td)
+{
+ unsigned int start_sector;
+ unsigned int num_of_bios = 0;
+ static unsigned int total_bios;
+ unsigned int *num_bios_seed;
+ int i = 0;
+
+ if (mbtd->random_test_seed == 0) {
+ mbtd->random_test_seed =
+ (unsigned int)(get_jiffies_64() & 0xFFFF);
+ test_pr_info("%s: got seed from jiffies %d",
+ __func__, mbtd->random_test_seed);
+ }
+ num_bios_seed = &mbtd->random_test_seed;
+
+ do {
+ pseudo_rnd_sector_and_size(num_bios_seed, td->start_sector,
+ &start_sector, &num_of_bios);
+
+ /* DISCARD */
+ total_bios += num_of_bios;
+ test_pr_info("%s: discard req: id=%d, startSec=%d, NumBios=%d",
+ __func__, td->unique_next_req_id, start_sector,
+ num_of_bios);
+ test_iosched_add_unique_test_req(0, REQ_UNIQUE_DISCARD,
+ start_sector, BIO_TO_SECTOR(num_of_bios),
+ NULL);
+
+ } while (++i < (BLKDEV_MAX_RQ-10));
+
+ test_pr_info("%s: total discard bios = %d", __func__, total_bios);
+
+ test_pr_info("%s: add sanitize req", __func__);
+ test_iosched_add_unique_test_req(0, REQ_UNIQUE_SANITIZE, 0, 0, NULL);
+
+ return 0;
+}
+
static bool message_repeat;
static int test_open(struct inode *inode, struct file *file)
{
@@ -1135,12 +1494,12 @@
mbtd->test_info.get_test_case_str_fn = get_test_case_str;
mbtd->test_info.post_test_fn = post_test;
- for (i = 0 ; i < number ; ++i) {
+ for (i = 0; i < number; ++i) {
test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
test_pr_info("%s: ====================", __func__);
- for (j = SEND_WRITE_PACKING_MIN_TESTCASE ;
- j <= SEND_WRITE_PACKING_MAX_TESTCASE ; j++) {
+ for (j = SEND_WRITE_PACKING_MIN_TESTCASE;
+ j <= SEND_WRITE_PACKING_MAX_TESTCASE; j++) {
mbtd->test_info.testcase = j;
mbtd->is_random = RANDOM_TEST;
@@ -1233,7 +1592,7 @@
mbtd->test_info.get_test_case_str_fn = get_test_case_str;
mbtd->test_info.post_test_fn = post_test;
- for (i = 0 ; i < number ; ++i) {
+ for (i = 0; i < number; ++i) {
test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
test_pr_info("%s: ====================", __func__);
@@ -1332,7 +1691,7 @@
mbtd->test_info.get_test_case_str_fn = get_test_case_str;
mbtd->test_info.post_test_fn = post_test;
- for (i = 0 ; i < number ; ++i) {
+ for (i = 0; i < number; ++i) {
test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
test_pr_info("%s: ====================", __func__);
@@ -1408,12 +1767,167 @@
.read = send_invalid_packed_test_read,
};
+/* packing_control TEST */
+static ssize_t write_packing_control_test_write(struct file *file,
+ const char __user *buf,
+ size_t count,
+ loff_t *ppos)
+{
+ int ret = 0;
+ int i = 0;
+ int number = -1;
+ int j = 0;
+ struct mmc_queue *mq = test_iosched_get_req_queue()->queuedata;
+ int max_num_requests = mq->card->ext_csd.max_packed_writes;
+ int test_successful = 1;
+
+ test_pr_info("%s: -- write_packing_control TEST --", __func__);
+
+ sscanf(buf, "%d", &number);
+
+ if (number <= 0)
+ number = 1;
+
+ test_pr_info("%s: max_num_requests = %d ", __func__,
+ max_num_requests);
+
+ memset(&mbtd->test_info, 0, sizeof(struct test_info));
+ mbtd->test_group = TEST_PACKING_CONTROL_GROUP;
+
+ if (validate_packed_commands_settings())
+ return count;
+
+ mbtd->test_info.data = mbtd;
+ mbtd->test_info.prepare_test_fn = prepare_test;
+ mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
+ mbtd->test_info.get_test_case_str_fn = get_test_case_str;
+
+ for (i = 0; i < number; ++i) {
+ test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
+ test_pr_info("%s: ====================", __func__);
+
+ for (j = PACKING_CONTROL_MIN_TESTCASE;
+ j <= PACKING_CONTROL_MAX_TESTCASE; j++) {
+
+ test_successful = 1;
+ mbtd->test_info.testcase = j;
+ mbtd->is_random = RANDOM_TEST;
+ ret = test_iosched_start_test(&mbtd->test_info);
+ if (ret) {
+ test_successful = 0;
+ break;
+ }
+ /* Allow FS requests to be dispatched */
+ msleep(1000);
+
+ mbtd->test_info.testcase = j;
+ mbtd->is_random = NON_RANDOM_TEST;
+ ret = test_iosched_start_test(&mbtd->test_info);
+ if (ret) {
+ test_successful = 0;
+ break;
+ }
+ /* Allow FS requests to be dispatched */
+ msleep(1000);
+ }
+
+ if (!test_successful)
+ break;
+ }
+
+ test_pr_info("%s: Completed all the test cases.", __func__);
+
+ return count;
+}
+
+static ssize_t write_packing_control_test_read(struct file *file,
+ char __user *buffer,
+ size_t count,
+ loff_t *offset)
+{
+ memset((void *)buffer, 0, count);
+
+ snprintf(buffer, count,
+ "\nwrite_packing_control_test\n"
+ "=========\n"
+ "Description:\n"
+ "This test checks the following scenarios\n"
+ "- Packing expected - one over trigger\n"
+ "- Packing expected - N over trigger\n"
+ "- Packing expected - N over trigger followed by read\n"
+ "- Packing expected - N over trigger followed by flush\n"
+ "- Packing expected - threshold over trigger FB by flush\n"
+ "- Packing not expected - less than trigger\n"
+ "- Packing not expected - trigger requests\n"
+ "- Packing not expected - trigger, read, trigger\n"
+ "- Mixed state - packing -> no packing -> packing\n"
+ "- Mixed state - no packing -> packing -> no packing\n");
+
+ if (message_repeat == 1) {
+ message_repeat = 0;
+ return strnlen(buffer, count);
+ } else {
+ return 0;
+ }
+}
+
+const struct file_operations write_packing_control_test_ops = {
+ .open = test_open,
+ .write = write_packing_control_test_write,
+ .read = write_packing_control_test_read,
+};
+
+static ssize_t write_discard_sanitize_test_write(struct file *file,
+ const char __user *buf,
+ size_t count,
+ loff_t *ppos)
+{
+ int ret = 0;
+ int i = 0;
+ int number = -1;
+
+ sscanf(buf, "%d", &number);
+ if (number <= 0)
+ number = 1;
+
+ test_pr_info("%s: -- write_discard_sanitize TEST --\n", __func__);
+
+ memset(&mbtd->test_info, 0, sizeof(struct test_info));
+
+ mbtd->test_group = TEST_GENERAL_GROUP;
+
+ mbtd->test_info.data = mbtd;
+ mbtd->test_info.prepare_test_fn = prepare_write_discard_sanitize_read;
+ mbtd->test_info.get_test_case_str_fn = get_test_case_str;
+ mbtd->test_info.timeout_msec = SANITIZE_TEST_TIMEOUT;
+
+ for (i = 0 ; i < number ; ++i) {
+ test_pr_info("%s: Cycle # %d / %d\n", __func__, i+1, number);
+ test_pr_info("%s: ===================", __func__);
+
+ mbtd->test_info.testcase = TEST_WRITE_DISCARD_SANITIZE_READ;
+ ret = test_iosched_start_test(&mbtd->test_info);
+
+ if (ret)
+ break;
+ }
+
+ return count;
+}
+
+const struct file_operations write_discard_sanitize_test_ops = {
+ .open = test_open,
+ .write = write_discard_sanitize_test_write,
+};
+
static void mmc_block_test_debugfs_cleanup(void)
{
debugfs_remove(mbtd->debug.random_test_seed);
debugfs_remove(mbtd->debug.send_write_packing_test);
debugfs_remove(mbtd->debug.err_check_test);
debugfs_remove(mbtd->debug.send_invalid_packed_test);
+ debugfs_remove(mbtd->debug.packing_control_test);
+ debugfs_remove(mbtd->debug.discard_sanitize_test);
}
static int mmc_block_test_debugfs_init(void)
@@ -1465,6 +1979,27 @@
if (!mbtd->debug.send_invalid_packed_test)
goto err_nomem;
+ mbtd->debug.packing_control_test = debugfs_create_file(
+ "packing_control_test",
+ S_IRUGO | S_IWUGO,
+ tests_root,
+ NULL,
+ &write_packing_control_test_ops);
+
+ if (!mbtd->debug.packing_control_test)
+ goto err_nomem;
+
+ mbtd->debug.discard_sanitize_test =
+ debugfs_create_file("write_discard_sanitize_test",
+ S_IRUGO | S_IWUGO,
+ tests_root,
+ NULL,
+ &write_discard_sanitize_test_ops);
+ if (!mbtd->debug.discard_sanitize_test) {
+ mmc_block_test_debugfs_cleanup();
+ return -ENOMEM;
+ }
+
return 0;
err_nomem:
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index a4af6c9..98507de 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -20,6 +20,7 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -236,6 +237,14 @@
pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
mmc_hostname(host->mmc), rc);
+ if (host->sps.reset_device) {
+ rc = sps_device_reset(host->sps.bam_handle);
+ if (rc)
+ pr_err("%s: sps_device_reset error=%d\n",
+ mmc_hostname(host->mmc), rc);
+ host->sps.reset_device = false;
+ }
+
/* Restore all BAM pipes connections */
rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
if (rc)
@@ -2521,6 +2530,12 @@
curr = host->plat->pin_data->gpio_data;
for (i = 0; i < curr->size; i++) {
+ if (!gpio_is_valid(curr->gpio[i].no)) {
+ rc = -EINVAL;
+ pr_err("%s: Invalid gpio = %d\n",
+ mmc_hostname(host->mmc), curr->gpio[i].no);
+ goto free_gpios;
+ }
if (enable) {
if (curr->gpio[i].is_always_on &&
curr->gpio[i].is_enabled)
@@ -2545,7 +2560,7 @@
goto out;
free_gpios:
- for (; i >= 0; i--) {
+ for (i--; i >= 0; i--) {
gpio_free(curr->gpio[i].no);
curr->gpio[i].is_enabled = false;
}
@@ -4323,6 +4338,96 @@
}
/**
+ * Handle BAM device's global error condition
+ *
+ * This is an error handler for the SDCC bam device
+ *
+ * This function is registered as a callback with SPS-BAM
+ * driver and will called in case there are an errors for
+ * the SDCC BAM deivce. Any error conditions in the BAM
+ * device are global and will be result in this function
+ * being called once per device.
+ *
+ * This function will be called from the sps driver's
+ * interrupt context.
+ *
+ * @sps_cb_case - indicates what error it is
+ * @user - Pointer to sdcc host structure
+ */
+static void
+msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
+{
+ struct msmsdcc_host *host = (struct msmsdcc_host *)user;
+ struct mmc_request *mrq;
+ unsigned long flags;
+ int32_t error = 0;
+
+ BUG_ON(!host);
+ BUG_ON(!is_sps_mode(host));
+
+ if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
+ /**
+ * Reset the all endpoints along with reseting the sps device.
+ */
+ host->sps.pipe_reset_pending = true;
+ host->sps.reset_device = true;
+
+ pr_err("%s: BAM Global ERROR IRQ happened\n",
+ mmc_hostname(host->mmc));
+ error = EAGAIN;
+ } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
+ /**
+ * This means that there was an AHB access error and
+ * the address we are trying to read/write is something
+ * we dont have priviliges to do so.
+ */
+ pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
+ mmc_hostname(host->mmc));
+ error = EACCES;
+ } else {
+ /**
+ * This should not have happened ideally. If this happens
+ * there is some seriously wrong.
+ */
+ pr_err("%s: BAM global IRQ callback received, type:%d\n",
+ mmc_hostname(host->mmc), (u32) sps_cb_case);
+ error = EIO;
+ }
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ mrq = host->curr.mrq;
+
+ if (mrq && mrq->cmd) {
+ msmsdcc_dump_sdcc_state(host);
+
+ if (!mrq->cmd->error)
+ mrq->cmd->error = -error;
+ if (host->curr.data) {
+ if (mrq->data && !mrq->data->error)
+ mrq->data->error = -error;
+ host->curr.data_xfered = 0;
+ if (host->sps.sg && is_sps_mode(host)) {
+ /* Stop current SPS transfer */
+ msmsdcc_sps_exit_curr_xfer(host);
+ } else {
+ /* this condition should not have happened */
+ pr_err("%s: something is seriously wrong. "\
+ "Funtion: %s, line: %d\n",
+ mmc_hostname(host->mmc),
+ __func__, __LINE__);
+ }
+ } else {
+ /* this condition should not have happened */
+ pr_err("%s: something is seriously wrong. Funtion: "\
+ "%s, line: %d\n", mmc_hostname(host->mmc),
+ __func__, __LINE__);
+ }
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/**
* Initialize SPS HW connected with SDCC core
*
* This function register BAM HW resources with
@@ -4371,6 +4476,8 @@
/* SPS driver wll handle the SDCC BAM IRQ */
bam.irq = (u32)host->bam_irqres->start;
bam.manage = SPS_BAM_MGR_LOCAL;
+ bam.callback = msmsdcc_sps_bam_global_irq_cb;
+ bam.user = (void *)host;
pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
(u32)bam.phys_addr);
@@ -4505,6 +4612,35 @@
return count;
}
+static ssize_t
+show_idle_timeout(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mmc_host *mmc = dev_get_drvdata(dev);
+ struct msmsdcc_host *host = mmc_priv(mmc);
+
+ return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
+ host->idle_tout_ms / 1000);
+}
+
+static ssize_t
+store_idle_timeout(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mmc_host *mmc = dev_get_drvdata(dev);
+ struct msmsdcc_host *host = mmc_priv(mmc);
+ unsigned int long flags;
+ int timeout; /* in secs */
+
+ if (!kstrtou32(buf, 0, &timeout)
+ && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
+ spin_lock_irqsave(&host->lock, flags);
+ host->idle_tout_ms = timeout * 1000;
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+ return count;
+}
+
#ifdef CONFIG_HAS_EARLYSUSPEND
static void msmsdcc_early_suspend(struct early_suspend *h)
{
@@ -4649,6 +4785,298 @@
spin_unlock_irqrestore(&host->lock, flags);
}
+/*
+ * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
+ *
+ * @dev: device node from which the property value is to be read.
+ * @prop_name: name of the property to be searched.
+ * @out_array: filled array returned to caller
+ * @len: filled array size returned to caller
+ * @size: expected size of the array
+ *
+ * If expected "size" doesn't match with "len" an error is returned. If
+ * expected size is zero, the length of actual array is returned provided
+ * return value is zero.
+ *
+ * RETURNS:
+ * zero on success, negative error if failed.
+ */
+static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
+ u32 **out_array, int *len, int size)
+{
+ int ret = 0;
+ u32 *array = NULL;
+ struct device_node *np = dev->of_node;
+
+ if (of_get_property(np, prop_name, len)) {
+ size_t sz;
+ sz = *len = *len / sizeof(*array);
+
+ if (sz > 0 && !(size > 0 && (sz != size))) {
+ array = devm_kzalloc(dev, sz * sizeof(*array),
+ GFP_KERNEL);
+ if (!array) {
+ dev_err(dev, "%s: no memory\n", prop_name);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = of_property_read_u32_array(np, prop_name,
+ array, sz);
+ if (ret < 0) {
+ dev_err(dev, "%s: error reading array %d\n",
+ prop_name, ret);
+ goto out;
+ }
+ } else {
+ dev_err(dev, "%s invalid size\n", prop_name);
+ ret = -EINVAL;
+ goto out;
+ }
+ } else {
+ dev_err(dev, "%s not specified\n", prop_name);
+ ret = -EINVAL;
+ goto out;
+ }
+ *out_array = array;
+out:
+ if (ret)
+ *len = 0;
+ return ret;
+}
+
+static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
+ struct msm_mmc_pad_pull_data **pad_pull_data)
+{
+ int ret = 0, base = 0, len, i;
+ u32 *tmp;
+ struct msm_mmc_pad_pull_data *pull_data;
+ struct msm_mmc_pad_pull *pull;
+
+ switch (id) {
+ case 1:
+ base = TLMM_PULL_SDC1_CLK;
+ break;
+ case 2:
+ base = TLMM_PULL_SDC2_CLK;
+ break;
+ case 3:
+ base = TLMM_PULL_SDC3_CLK;
+ break;
+ case 4:
+ base = TLMM_PULL_SDC4_CLK;
+ break;
+ default:
+ dev_err(dev, "%s: Invalid slot id\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
+ GFP_KERNEL);
+ if (!pull_data) {
+ dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ pull_data->size = 3; /* array size for clk, cmd, data */
+
+ /* Allocate on, off configs for clk, cmd, data */
+ pull = devm_kzalloc(dev, 2 * pull_data->size *\
+ sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
+ if (!pull) {
+ dev_err(dev, "No memory for msm_mmc_pad_pull\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ pull_data->on = pull;
+ pull_data->off = pull + pull_data->size;
+
+ ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
+ &tmp, &len, pull_data->size);
+ if (!ret) {
+ for (i = 0; i < len; i++) {
+ pull_data->on[i].no = base + i;
+ pull_data->on[i].val = tmp[i];
+ dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+ i, pull_data->on[i].val);
+ }
+ } else {
+ goto err;
+ }
+
+ ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
+ &tmp, &len, pull_data->size);
+ if (!ret) {
+ for (i = 0; i < len; i++) {
+ pull_data->off[i].no = base + i;
+ pull_data->off[i].val = tmp[i];
+ dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+ i, pull_data->off[i].val);
+ }
+ } else {
+ goto err;
+ }
+
+ *pad_pull_data = pull_data;
+err:
+ return ret;
+}
+
+static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
+ struct msm_mmc_pad_drv_data **pad_drv_data)
+{
+ int ret = 0, base = 0, len, i;
+ u32 *tmp;
+ struct msm_mmc_pad_drv_data *drv_data;
+ struct msm_mmc_pad_drv *drv;
+
+ switch (id) {
+ case 1:
+ base = TLMM_HDRV_SDC1_CLK;
+ break;
+ case 2:
+ base = TLMM_HDRV_SDC2_CLK;
+ break;
+ case 3:
+ base = TLMM_HDRV_SDC3_CLK;
+ break;
+ case 4:
+ base = TLMM_HDRV_SDC4_CLK;
+ break;
+ default:
+ dev_err(dev, "%s: Invalid slot id\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
+ GFP_KERNEL);
+ if (!drv_data) {
+ dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ drv_data->size = 3; /* array size for clk, cmd, data */
+
+ /* Allocate on, off configs for clk, cmd, data */
+ drv = devm_kzalloc(dev, 2 * drv_data->size *\
+ sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
+ if (!drv) {
+ dev_err(dev, "No memory msm_mmc_pad_drv\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ drv_data->on = drv;
+ drv_data->off = drv + drv_data->size;
+
+ ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
+ &tmp, &len, drv_data->size);
+ if (!ret) {
+ for (i = 0; i < len; i++) {
+ drv_data->on[i].no = base + i;
+ drv_data->on[i].val = tmp[i];
+ dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+ i, drv_data->on[i].val);
+ }
+ } else {
+ goto err;
+ }
+
+ ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
+ &tmp, &len, drv_data->size);
+ if (!ret) {
+ for (i = 0; i < len; i++) {
+ drv_data->off[i].no = base + i;
+ drv_data->off[i].val = tmp[i];
+ dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+ i, drv_data->off[i].val);
+ }
+ } else {
+ goto err;
+ }
+
+ *pad_drv_data = drv_data;
+err:
+ return ret;
+}
+
+static int msmsdcc_dt_parse_gpio_info(struct device *dev,
+ struct mmc_platform_data *pdata)
+{
+ int ret = 0, id = 0, cnt, i;
+ struct msm_mmc_pin_data *pin_data;
+ struct device_node *np = dev->of_node;
+
+ pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
+ if (!pin_data) {
+ dev_err(dev, "No memory for pin_data\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ cnt = of_gpio_count(np);
+ if (cnt > 0) {
+ pin_data->is_gpio = true;
+
+ pin_data->gpio_data = devm_kzalloc(dev,
+ sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
+ if (!pin_data->gpio_data) {
+ dev_err(dev, "No memory for gpio_data\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ pin_data->gpio_data->size = cnt;
+ pin_data->gpio_data->gpio = devm_kzalloc(dev,
+ cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
+ if (!pin_data->gpio_data->gpio) {
+ dev_err(dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ const char *name = NULL;
+ char result[32];
+ pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
+ of_property_read_string_index(np,
+ "qcom,sdcc-gpio-names", i, &name);
+
+ snprintf(result, 32, "%s-%s",
+ dev_name(dev), name ? name : "?");
+ pin_data->gpio_data->gpio[i].name = result;
+ dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
+ pin_data->gpio_data->gpio[i].name,
+ pin_data->gpio_data->gpio[i].no);
+ }
+ } else {
+ pin_data->pad_data = devm_kzalloc(dev,
+ sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
+ if (!pin_data->pad_data) {
+ dev_err(dev, "No memory for pin_data->pad_data\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ of_property_read_u32(np, "cell-index", &id);
+
+ ret = msmsdcc_dt_get_pad_pull_info(dev, id,
+ &pin_data->pad_data->pull);
+ if (ret)
+ goto err;
+ ret = msmsdcc_dt_get_pad_drv_info(dev, id,
+ &pin_data->pad_data->drv);
+ if (ret)
+ goto err;
+ }
+
+ pdata->pin_data = pin_data;
+err:
+ if (ret)
+ dev_err(dev, "%s failed with err %d\n", __func__, ret);
+ return ret;
+}
+
#define MAX_PROP_SIZE 32
static int msmsdcc_dt_parse_vreg_info(struct device *dev,
struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
@@ -4738,29 +5166,10 @@
pdata->mmc_bus_width = 0;
}
- if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
- size_t sz;
- sz = sup_volt_len / sizeof(*sup_voltages);
- if (sz > 0) {
- sup_voltages = devm_kzalloc(dev,
- sz * sizeof(*sup_voltages), GFP_KERNEL);
- if (!sup_voltages) {
- dev_err(dev, "No memory for supported voltage\n");
- goto err;
- }
-
- ret = of_property_read_u32_array(np,
- "qcom,sdcc-sup-voltages", sup_voltages, sz);
- if (ret < 0) {
- dev_err(dev, "error while reading voltage"
- "ranges %d\n", ret);
- goto err;
- }
- } else {
- dev_err(dev, "No supported voltages\n");
- goto err;
- }
- for (i = 0; i < sz; i += 2) {
+ ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
+ &sup_voltages, &sup_volt_len, 0);
+ if (!ret) {
+ for (i = 0; i < sup_volt_len; i += 2) {
u32 mask;
mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
@@ -4770,37 +5179,13 @@
pdata->ocr_mask |= mask;
}
dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
- } else {
- dev_err(dev, "Supported voltage range not specified\n");
}
- if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
- size_t sz;
- sz = clk_table_len / sizeof(*clk_table);
-
- if (sz > 0) {
- clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
- GFP_KERNEL);
- if (!clk_table) {
- dev_err(dev, "No memory for clock table\n");
- goto err;
- }
-
- ret = of_property_read_u32_array(np,
- "qcom,sdcc-clk-rates", clk_table, sz);
- if (ret < 0) {
- dev_err(dev, "error while reading clk"
- "table %d\n", ret);
- goto err;
- }
- } else {
- dev_err(dev, "clk_table not specified\n");
- goto err;
- }
+ ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
+ &clk_table, &clk_table_len, 0);
+ if (!ret) {
pdata->sup_clk_table = clk_table;
- pdata->sup_clk_cnt = sz;
- } else {
- dev_err(dev, "Supported clock rates not specified\n");
+ pdata->sup_clk_cnt = clk_table_len;
}
pdata->vreg_data = devm_kzalloc(dev,
@@ -4818,6 +5203,9 @@
&pdata->vreg_data->vdd_io_data, "vdd-io"))
goto err;
+ if (msmsdcc_dt_parse_gpio_info(dev, pdata))
+ goto err;
+
len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
for (i = 0; i < len; i++) {
@@ -5321,6 +5709,7 @@
pm_runtime_enable(&(pdev)->dev);
}
#endif
+ host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
(unsigned long)host);
@@ -5392,8 +5781,19 @@
if (ret)
goto remove_max_bus_bw_file;
}
+ host->idle_timeout.show = show_idle_timeout;
+ host->idle_timeout.store = store_idle_timeout;
+ sysfs_attr_init(&host->idle_timeout.attr);
+ host->idle_timeout.attr.name = "idle_timeout";
+ host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(&pdev->dev, &host->idle_timeout);
+ if (ret)
+ goto remove_polling_file;
return 0;
+ remove_polling_file:
+ if (!plat->status_irq)
+ device_remove_file(&pdev->dev, &host->polling);
remove_max_bus_bw_file:
device_remove_file(&pdev->dev, &host->max_bus_bw);
platform_irq_free:
@@ -5474,6 +5874,7 @@
device_remove_file(&pdev->dev, &host->max_bus_bw);
if (!plat->status_irq)
device_remove_file(&pdev->dev, &host->polling);
+ device_remove_file(&pdev->dev, &host->idle_timeout);
del_timer_sync(&host->req_tout_timer);
tasklet_kill(&host->dma_tlet);
@@ -5771,7 +6172,7 @@
return 0;
/* Idle timeout is not configurable for now */
- pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
+ pm_schedule_suspend(dev, host->idle_tout_ms);
return -EAGAIN;
}
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index baeabd2..cc41c46 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -213,7 +213,7 @@
#define NR_SG 128
-#define MSM_MMC_IDLE_TIMEOUT 5000 /* msecs */
+#define MSM_MMC_DEFAULT_IDLE_TIMEOUT 5000 /* msecs */
#define MSM_MMC_CLK_GATE_DELAY 200 /* msecs */
/* Set the request timeout to 10secs */
@@ -321,6 +321,7 @@
unsigned int busy;
unsigned int xfer_req_cnt;
bool pipe_reset_pending;
+ bool reset_device;
struct tasklet_struct tlet;
};
@@ -410,9 +411,11 @@
bool sdio_wakeupirq_disabled;
struct mutex clk_mutex;
bool pending_resume;
+ unsigned int idle_tout_ms; /* Timeout in msecs */
struct msmsdcc_msm_bus_vote msm_bus_vote;
struct device_attribute max_bus_bw;
struct device_attribute polling;
+ struct device_attribute idle_timeout;
};
#define MSMSDCC_VERSION_MASK 0xFFFF
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index 55020a1..eb57693 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -558,6 +558,8 @@
udev = unet->udev;
+ usb_enable_autosuspend(udev);
+
/* allow modem to wake up suspended system */
device_set_wakeup_enable(&udev->dev, 1);
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 0c3d4ad..d75cac4 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -60,4 +60,11 @@
devices support Pulse Width Modulation output with user generated
patterns. They share a lookup table with size of 64 entries.
+config QPNP_POWER_ON
+ tristate "QPNP PMIC POWER-ON Driver"
+ depends on OF_SPMI && SPMI && MSM_QPNP_INT
+ help
+ This driver supports the power-on functionality on Qualcomm
+ PNP PMIC. It currently supports reporting the change in status of
+ the KPDPWR_N line (connected to the power-key).
endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 6deb6ee..2b6b806 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_USB_BAM) += usb_bam.o
obj-$(CONFIG_SPS) += sps/
obj-$(CONFIG_QPNP_PWM) += qpnp-pwm.o
+obj-$(CONFIG_QPNP_POWER_ON) += qpnp-power-on.o
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
new file mode 100644
index 0000000..d8bb884
--- /dev/null
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -0,0 +1,241 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+
+#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_CNTL_PULL_UP BIT(1)
+#define QPNP_PON_CNTL_TRIG_DELAY_MASK (0x7)
+#define QPNP_PON_KPDPWR_N_SET BIT(0)
+
+struct qpnp_pon {
+ struct spmi_device *spmi;
+ struct input_dev *pon_input;
+ u32 key_status_irq;
+ u16 base;
+};
+
+static irqreturn_t qpnp_pon_key_irq(int irq, void *_pon)
+{
+ u8 pon_rt_sts;
+ int rc;
+ struct qpnp_pon *pon = _pon;
+
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
+ return IRQ_HANDLED;
+ }
+
+ input_report_key(pon->pon_input, KEY_POWER,
+ !(pon_rt_sts & QPNP_PON_KPDPWR_N_SET));
+ input_sync(pon->pon_input);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit qpnp_pon_key_init(struct qpnp_pon *pon)
+{
+ int rc = 0;
+ u32 pullup, delay;
+ u8 pon_cntl;
+
+ pon->key_status_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "power-key");
+ if (pon->key_status_irq < 0) {
+ dev_err(&pon->spmi->dev, "Unable to get pon key irq\n");
+ return -ENXIO;
+ }
+
+ rc = of_property_read_u32(pon->spmi->dev.of_node,
+ "qcom,pon-key-dbc-delay", &delay);
+ if (rc) {
+ delay = (delay << 6) / USEC_PER_SEC;
+ delay = ilog2(delay);
+
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
+ QPNP_PON_DBC_CTL(pon->base));
+ return rc;
+ }
+ pon_cntl &= ~QPNP_PON_CNTL_TRIG_DELAY_MASK;
+ pon_cntl |= (delay & QPNP_PON_CNTL_TRIG_DELAY_MASK);
+ rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "spmi write addre=%x failed\n",
+ QPNP_PON_DBC_CTL(pon->base));
+ return rc;
+ }
+ }
+
+ rc = of_property_read_u32(pon->spmi->dev.of_node,
+ "qcom,pon-key-pull-up", &pullup);
+ if (!rc) {
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
+ QPNP_PON_PULL_CTL(pon->base));
+ return rc;
+ }
+ if (pullup)
+ pon_cntl |= QPNP_PON_CNTL_PULL_UP;
+ else
+ pon_cntl &= ~QPNP_PON_CNTL_PULL_UP;
+
+ rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "spmi write addr=%x failed\n",
+ QPNP_PON_PULL_CTL(pon->base));
+ return rc;
+ }
+ }
+
+ pon->pon_input = input_allocate_device();
+ if (!pon->pon_input) {
+ dev_err(&pon->spmi->dev, "Can't allocate pon button\n");
+ return -ENOMEM;
+ }
+
+ input_set_capability(pon->pon_input, EV_KEY, KEY_POWER);
+ pon->pon_input->name = "qpnp_pon_key";
+ pon->pon_input->phys = "qpnp_pon_key/input0";
+
+ rc = input_register_device(pon->pon_input);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Can't register pon key: %d\n", rc);
+ goto free_input_dev;
+ }
+
+ rc = request_any_context_irq(pon->key_status_irq, qpnp_pon_key_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "qpnp_pon_key_status", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev, "Can't request %d IRQ for pon: %d\n",
+ pon->key_status_irq, rc);
+ goto unreg_input_dev;
+ }
+
+ device_init_wakeup(&pon->spmi->dev, 1);
+ enable_irq_wake(pon->key_status_irq);
+
+ return rc;
+
+unreg_input_dev:
+ input_unregister_device(pon->pon_input);
+free_input_dev:
+ input_free_device(pon->pon_input);
+ return rc;
+}
+
+static int __devinit qpnp_pon_probe(struct spmi_device *spmi)
+{
+ struct qpnp_pon *pon;
+ struct resource *pon_resource;
+ u32 pon_key_enable = 0;
+ int rc = 0;
+
+ pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
+ GFP_KERNEL);
+ if (!pon) {
+ dev_err(&spmi->dev, "Can't allocate qpnp_pon\n");
+ return -ENOMEM;
+ }
+
+ pon->spmi = spmi;
+
+ pon_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+ if (!pon_resource) {
+ dev_err(&spmi->dev, "Unable to get PON base address\n");
+ return -ENXIO;
+ }
+ pon->base = pon_resource->start;
+
+ dev_set_drvdata(&spmi->dev, pon);
+
+ /* pon-key-enable property must be set to register pon key */
+ rc = of_property_read_u32(spmi->dev.of_node, "qcom,pon-key-enable",
+ &pon_key_enable);
+ if (rc && rc != -EINVAL) {
+ dev_err(&spmi->dev,
+ "Error reading 'pon-key-enable' property (%d)", rc);
+ return rc;
+ }
+
+ if (pon_key_enable) {
+ rc = qpnp_pon_key_init(pon);
+ if (rc < 0) {
+ dev_err(&spmi->dev, "Failed to register pon-key\n");
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static int qpnp_pon_remove(struct spmi_device *spmi)
+{
+ struct qpnp_pon *pon = dev_get_drvdata(&spmi->dev);
+
+ if (pon->pon_input) {
+ free_irq(pon->key_status_irq, pon);
+ input_unregister_device(pon->pon_input);
+ }
+
+ return 0;
+}
+
+static struct of_device_id spmi_match_table[] = {
+ { .compatible = "qcom,qpnp-power-on",
+ }
+};
+
+static struct spmi_driver qpnp_pon_driver = {
+ .driver = {
+ .name = "qcom,qpnp-power-on",
+ .of_match_table = spmi_match_table,
+ },
+ .probe = qpnp_pon_probe,
+ .remove = __devexit_p(qpnp_pon_remove),
+};
+
+static int __init qpnp_pon_init(void)
+{
+ return spmi_driver_register(&qpnp_pon_driver);
+}
+module_init(qpnp_pon_init);
+
+static void __exit qpnp_pon_exit(void)
+{
+ return spmi_driver_unregister(&qpnp_pon_driver);
+}
+module_exit(qpnp_pon_exit);
+
+MODULE_DESCRIPTION("QPNP PMIC POWER-ON driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 1329f6c..0371f5a 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -2028,30 +2028,30 @@
goto device_create_err;
}
- if (!d_type) {
- sps->dfab_clk = clk_get(sps->dev, "dfab_clk");
- if (IS_ERR(sps->dfab_clk)) {
- SPS_ERR("sps:fail to get dfab_clk.");
+ sps->dfab_clk = clk_get(sps->dev, "dfab_clk");
+ if (IS_ERR(sps->dfab_clk)) {
+ SPS_ERR("sps:fail to get dfab_clk.");
+ goto clk_err;
+ } else {
+ ret = clk_set_rate(sps->dfab_clk, 64000000);
+ if (ret) {
+ SPS_ERR("sps:failed to set dfab_clk rate.");
+ clk_put(sps->dfab_clk);
goto clk_err;
- } else {
- ret = clk_set_rate(sps->dfab_clk, 64000000);
- if (ret) {
- SPS_ERR("sps:failed to set dfab_clk rate.");
- clk_put(sps->dfab_clk);
- goto clk_err;
- }
}
}
- sps->pmem_clk = clk_get(sps->dev, "mem_clk");
- if (IS_ERR(sps->pmem_clk)) {
- SPS_ERR("sps:fail to get pmem_clk.");
- goto clk_err;
- } else {
- ret = clk_prepare_enable(sps->pmem_clk);
- if (ret) {
- SPS_ERR("sps:failed to enable pmem_clk. ret=%d", ret);
+ if (!d_type) {
+ sps->pmem_clk = clk_get(sps->dev, "mem_clk");
+ if (IS_ERR(sps->pmem_clk)) {
+ SPS_ERR("sps:fail to get pmem_clk.");
goto clk_err;
+ } else {
+ ret = clk_prepare_enable(sps->pmem_clk);
+ if (ret) {
+ SPS_ERR("sps:failed to enable pmem_clk.");
+ goto clk_err;
+ }
}
}
@@ -2068,26 +2068,22 @@
}
}
- if (!d_type) {
- ret = clk_prepare_enable(sps->dfab_clk);
- if (ret) {
- SPS_ERR("sps:failed to enable dfab_clk. ret=%d", ret);
- goto clk_err;
- }
+ ret = clk_prepare_enable(sps->dfab_clk);
+ if (ret) {
+ SPS_ERR("sps:failed to enable dfab_clk. ret=%d", ret);
+ goto clk_err;
}
#endif
ret = sps_device_init();
if (ret) {
SPS_ERR("sps:sps_device_init err.");
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
- if (!d_type)
- clk_disable_unprepare(sps->dfab_clk);
+ clk_disable_unprepare(sps->dfab_clk);
#endif
goto sps_device_init_err;
}
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
- if (!d_type)
- clk_disable_unprepare(sps->dfab_clk);
+ clk_disable_unprepare(sps->dfab_clk);
#endif
sps->is_ready = true;
@@ -2114,9 +2110,9 @@
class_destroy(sps->dev_class);
sps_device_de_init();
+ clk_put(sps->dfab_clk);
if (!d_type)
- clk_put(sps->dfab_clk);
- clk_put(sps->pmem_clk);
+ clk_put(sps->pmem_clk);
clk_put(sps->bamdma_clk);
return 0;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index fc0d02a..1849118 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1169,4 +1169,13 @@
This driver can also be built as a module. If so, the module
will be called rtc-ls1x.
+config RTC_DRV_QPNP
+ tristate "Qualcomm QPNP PMIC RTC"
+ depends on SPMI && OF_SPMI && MSM_QPNP_INT
+ help
+ Say Y here if you want to support the Qualcomm QPNP PMIC RTC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called qpnp-rtc.
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 8a3cecd..295f927 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -88,6 +88,7 @@
obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
+obj-$(CONFIG_RTC_DRV_QPNP) += qpnp-rtc.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
diff --git a/drivers/rtc/qpnp-rtc.c b/drivers/rtc/qpnp-rtc.c
new file mode 100644
index 0000000..5650e74
--- /dev/null
+++ b/drivers/rtc/qpnp-rtc.c
@@ -0,0 +1,641 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/of_device.h>
+#include <linux/spmi.h>
+#include <linux/spinlock.h>
+#include <linux/spmi.h>
+
+/* RTC/ALARM Register offsets */
+#define REG_OFFSET_ALARM_RW 0x40
+#define REG_OFFSET_ALARM_CTRL1 0x46
+#define REG_OFFSET_ALARM_CTRL2 0x48
+#define REG_OFFSET_RTC_WRITE 0x40
+#define REG_OFFSET_RTC_CTRL 0x46
+#define REG_OFFSET_RTC_READ 0x48
+#define REG_OFFSET_PERP_SUBTYPE 0x05
+
+/* RTC_CTRL register bit fields */
+#define BIT_RTC_ENABLE BIT(7)
+#define BIT_RTC_ALARM_ENABLE BIT(7)
+#define BIT_RTC_ABORT_ENABLE BIT(0)
+#define BIT_RTC_ALARM_CLEAR BIT(0)
+
+/* RTC/ALARM peripheral subtype values */
+#define RTC_PERPH_SUBTYPE 0x1
+#define ALARM_PERPH_SUBTYPE 0x3
+
+#define NUM_8_BIT_RTC_REGS 0x4
+
+#define TO_SECS(arr) (arr[0] | (arr[1] << 8) | (arr[2] << 16) | \
+ (arr[3] << 24))
+
+/* rtc driver internal structure */
+struct qpnp_rtc {
+ u8 rtc_ctrl_reg;
+ u8 alarm_ctrl_reg1;
+ u16 rtc_base;
+ u16 alarm_base;
+ u32 rtc_write_enable;
+ u32 rtc_alarm_powerup;
+ int rtc_alarm_irq;
+ struct device *rtc_dev;
+ struct rtc_device *rtc;
+ struct spmi_device *spmi;
+ spinlock_t alarm_ctrl_lock;
+};
+
+static int qpnp_read_wrapper(struct qpnp_rtc *rtc_dd, u8 *rtc_val,
+ u16 base, int count)
+{
+ int rc;
+ struct spmi_device *spmi = rtc_dd->spmi;
+
+ rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, base, rtc_val,
+ count);
+ if (rc) {
+ dev_err(rtc_dd->rtc_dev, "SPMI read failed\n");
+ return rc;
+ }
+ return 0;
+}
+
+static int qpnp_write_wrapper(struct qpnp_rtc *rtc_dd, u8 *rtc_val,
+ u16 base, int count)
+{
+ int rc;
+ struct spmi_device *spmi = rtc_dd->spmi;
+
+ rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, base, rtc_val,
+ count);
+ if (rc) {
+ dev_err(rtc_dd->rtc_dev, "SPMI write failed\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static int
+qpnp_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ int rc;
+ unsigned long secs, irq_flags;
+ u8 value[4], reg = 0, alarm_enabled = 0, ctrl_reg;
+ struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
+
+ rtc_tm_to_time(tm, &secs);
+
+ value[0] = secs & 0xFF;
+ value[1] = (secs >> 8) & 0xFF;
+ value[2] = (secs >> 16) & 0xFF;
+ value[3] = (secs >> 24) & 0xFF;
+
+ dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
+
+ spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);
+ ctrl_reg = rtc_dd->alarm_ctrl_reg1;
+
+ if (ctrl_reg & BIT_RTC_ALARM_ENABLE) {
+ alarm_enabled = 1;
+ ctrl_reg &= ~BIT_RTC_ALARM_ENABLE;
+ rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
+ rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+ if (rc) {
+ dev_err(dev, "Write to ALARM ctrl reg failed\n");
+ goto rtc_rw_fail;
+ }
+ } else
+ spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+
+ /*
+ * 32 bit seconds value is coverted to four 8 bit values
+ * |<------ 32 bit time value in seconds ------>|
+ * <- 8 bit ->|<- 8 bit ->|<- 8 bit ->|<- 8 bit ->|
+ * ----------------------------------------------
+ * | BYTE[3] | BYTE[2] | BYTE[1] | BYTE[0] |
+ * ----------------------------------------------
+ *
+ * RTC has four 8 bit registers for writting time in seconds:
+ * WDATA[3], WDATA[2], WDATA[1], WDATA[0]
+ *
+ * Write to the RTC registers should be done in following order
+ * Clear WDATA[0] register
+ *
+ * Write BYTE[1], BYTE[2] and BYTE[3] of time to
+ * RTC WDATA[3], WDATA[2], WDATA[1] registers
+ *
+ * Write BYTE[0] of time to RTC WDATA[0] register
+ *
+ * Clearing BYTE[0] and writting in the end will prevent any
+ * unintentional overflow from WDATA[0] to higher bytes during the
+ * write operation
+ */
+
+ /* Clear WDATA[0] */
+ reg = 0x0;
+ rc = qpnp_write_wrapper(rtc_dd, ®,
+ rtc_dd->rtc_base + REG_OFFSET_RTC_WRITE, 1);
+ if (rc) {
+ dev_err(dev, "Write to RTC reg failed\n");
+ goto rtc_rw_fail;
+ }
+
+ /* Write to WDATA[3], WDATA[2] and WDATA[1] */
+ rc = qpnp_write_wrapper(rtc_dd, &value[1],
+ rtc_dd->rtc_base + REG_OFFSET_RTC_WRITE + 1, 3);
+ if (rc) {
+ dev_err(dev, "Write to RTC reg failed\n");
+ goto rtc_rw_fail;
+ }
+
+ /* Write to WDATA[0] */
+ rc = qpnp_write_wrapper(rtc_dd, value,
+ rtc_dd->rtc_base + REG_OFFSET_RTC_WRITE, 1);
+ if (rc) {
+ dev_err(dev, "Write to RTC reg failed\n");
+ goto rtc_rw_fail;
+ }
+
+ if (alarm_enabled) {
+ ctrl_reg |= BIT_RTC_ALARM_ENABLE;
+ rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
+ rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+ if (rc) {
+ dev_err(dev, "Write to ALARM ctrl reg failed\n");
+ goto rtc_rw_fail;
+ }
+ }
+
+ rtc_dd->alarm_ctrl_reg1 = ctrl_reg;
+
+rtc_rw_fail:
+ if (alarm_enabled)
+ spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+
+ return rc;
+}
+
+static int
+qpnp_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ int rc;
+ u8 value[4], reg;
+ unsigned long secs;
+ struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
+
+ rc = qpnp_read_wrapper(rtc_dd, value,
+ rtc_dd->rtc_base + REG_OFFSET_RTC_READ,
+ NUM_8_BIT_RTC_REGS);
+ if (rc) {
+ dev_err(dev, "Read from RTC reg failed\n");
+ return rc;
+ }
+
+ /*
+ * Read the LSB again and check if there has been a carry over
+ * If there is, redo the read operation
+ */
+ rc = qpnp_read_wrapper(rtc_dd, ®,
+ rtc_dd->rtc_base + REG_OFFSET_RTC_READ, 1);
+ if (rc) {
+ dev_err(dev, "Read from RTC reg failed\n");
+ return rc;
+ }
+
+ if (reg < value[0]) {
+ rc = qpnp_read_wrapper(rtc_dd, value,
+ rtc_dd->rtc_base + REG_OFFSET_RTC_READ,
+ NUM_8_BIT_RTC_REGS);
+ if (rc) {
+ dev_err(dev, "Read from RTC reg failed\n");
+ return rc;
+ }
+ }
+
+ secs = TO_SECS(value);
+
+ rtc_time_to_tm(secs, tm);
+
+ rc = rtc_valid_tm(tm);
+ if (rc) {
+ dev_err(dev, "Invalid time read from RTC\n");
+ return rc;
+ }
+
+ dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n",
+ secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
+ tm->tm_mday, tm->tm_mon, tm->tm_year);
+
+ return 0;
+}
+
+static int
+qpnp_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ int rc;
+ u8 value[4], ctrl_reg;
+ unsigned long secs, secs_rtc, irq_flags;
+ struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
+ struct rtc_time rtc_tm;
+
+ rtc_tm_to_time(&alarm->time, &secs);
+
+ /*
+ * Read the current RTC time and verify if the alarm time is in the
+ * past. If yes, return invalid
+ */
+ rc = qpnp_rtc_read_time(dev, &rtc_tm);
+ if (rc) {
+ dev_err(dev, "Unable to read RTC time\n");
+ return -EINVAL;
+ }
+
+ rtc_tm_to_time(&rtc_tm, &secs_rtc);
+ if (secs < secs_rtc) {
+ dev_err(dev, "Trying to set alarm in the past\n");
+ return -EINVAL;
+ }
+
+ value[0] = secs & 0xFF;
+ value[1] = (secs >> 8) & 0xFF;
+ value[2] = (secs >> 16) & 0xFF;
+ value[3] = (secs >> 24) & 0xFF;
+
+ spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);
+
+ rc = qpnp_write_wrapper(rtc_dd, value,
+ rtc_dd->alarm_base + REG_OFFSET_ALARM_RW,
+ NUM_8_BIT_RTC_REGS);
+ if (rc) {
+ dev_err(dev, "Write to ALARM reg failed\n");
+ goto rtc_rw_fail;
+ }
+
+ ctrl_reg = (alarm->enabled) ?
+ (rtc_dd->alarm_ctrl_reg1 | BIT_RTC_ALARM_ENABLE) :
+ (rtc_dd->alarm_ctrl_reg1 & ~BIT_RTC_ALARM_ENABLE);
+
+ rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
+ rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+ if (rc) {
+ dev_err(dev, "Write to ALARM cntrol reg failed\n");
+ goto rtc_rw_fail;
+ }
+
+ rtc_dd->alarm_ctrl_reg1 = ctrl_reg;
+
+ dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
+ alarm->time.tm_hour, alarm->time.tm_min,
+ alarm->time.tm_sec, alarm->time.tm_mday,
+ alarm->time.tm_mon, alarm->time.tm_year);
+rtc_rw_fail:
+ spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+ return rc;
+}
+
+static int
+qpnp_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ int rc;
+ u8 value[4];
+ unsigned long secs;
+ struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
+
+ rc = qpnp_read_wrapper(rtc_dd, value,
+ rtc_dd->alarm_base + REG_OFFSET_ALARM_RW,
+ NUM_8_BIT_RTC_REGS);
+ if (rc) {
+ dev_err(dev, "Read from ALARM reg failed\n");
+ return rc;
+ }
+
+ secs = TO_SECS(value);
+ rtc_time_to_tm(secs, &alarm->time);
+
+ rc = rtc_valid_tm(&alarm->time);
+ if (rc) {
+ dev_err(dev, "Invalid time read from RTC\n");
+ return rc;
+ }
+
+ dev_dbg(dev, "Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
+ alarm->time.tm_hour, alarm->time.tm_min,
+ alarm->time.tm_sec, alarm->time.tm_mday,
+ alarm->time.tm_mon, alarm->time.tm_year);
+
+ return 0;
+}
+
+
+static int
+qpnp_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ int rc;
+ unsigned long irq_flags;
+ struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
+ u8 ctrl_reg;
+
+ spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);
+ ctrl_reg = rtc_dd->alarm_ctrl_reg1;
+ ctrl_reg = enabled ? (ctrl_reg | BIT_RTC_ALARM_ENABLE) :
+ (ctrl_reg & ~BIT_RTC_ALARM_ENABLE);
+
+ rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
+ rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+ if (rc) {
+ dev_err(dev, "Write to ALARM control reg failed\n");
+ goto rtc_rw_fail;
+ }
+
+ rtc_dd->alarm_ctrl_reg1 = ctrl_reg;
+
+rtc_rw_fail:
+ spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+ return rc;
+}
+
+static struct rtc_class_ops qpnp_rtc_ops = {
+ .read_time = qpnp_rtc_read_time,
+ .set_alarm = qpnp_rtc_set_alarm,
+ .read_alarm = qpnp_rtc_read_alarm,
+ .alarm_irq_enable = qpnp_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t qpnp_alarm_trigger(int irq, void *dev_id)
+{
+ struct qpnp_rtc *rtc_dd = dev_id;
+ u8 ctrl_reg;
+ int rc;
+ unsigned long irq_flags;
+
+ rtc_update_irq(rtc_dd->rtc, 1, RTC_IRQF | RTC_AF);
+
+ spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);
+
+ /* Clear the alarm enable bit */
+ ctrl_reg = rtc_dd->alarm_ctrl_reg1;
+ ctrl_reg &= ~BIT_RTC_ALARM_ENABLE;
+
+ rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
+ rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+ if (rc) {
+ spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+ dev_err(rtc_dd->rtc_dev,
+ "Write to ALARM control reg failed\n");
+ goto rtc_alarm_handled;
+ }
+
+ rtc_dd->alarm_ctrl_reg1 = ctrl_reg;
+ spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+
+ /* Set ALARM_CLR bit */
+ ctrl_reg = 0x1;
+ rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
+ rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL2, 1);
+ if (rc)
+ dev_err(rtc_dd->rtc_dev,
+ "Write to ALARM control reg failed\n");
+
+rtc_alarm_handled:
+ return IRQ_HANDLED;
+}
+
+static int __devinit qpnp_rtc_probe(struct spmi_device *spmi)
+{
+ int rc;
+ u8 subtype;
+ struct qpnp_rtc *rtc_dd;
+ struct resource *resource;
+ struct spmi_resource *spmi_resource;
+
+ rtc_dd = devm_kzalloc(&spmi->dev, sizeof(*rtc_dd), GFP_KERNEL);
+ if (rtc_dd == NULL) {
+ dev_err(&spmi->dev, "Unable to allocate memory!\n");
+ return -ENOMEM;
+ }
+
+ /* Get the rtc write property */
+ rc = of_property_read_u32(spmi->dev.of_node, "qcom,qpnp-rtc-write",
+ &rtc_dd->rtc_write_enable);
+ if (rc && rc != -EINVAL) {
+ dev_err(&spmi->dev,
+ "Error reading rtc_write_enable property %d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(spmi->dev.of_node,
+ "qcom,qpnp-rtc-alarm-pwrup",
+ &rtc_dd->rtc_alarm_powerup);
+ if (rc && rc != -EINVAL) {
+ dev_err(&spmi->dev,
+ "Error reading rtc_alarm_powerup property %d\n", rc);
+ return rc;
+ }
+
+ /* Initialise spinlock to protect RTC control register */
+ spin_lock_init(&rtc_dd->alarm_ctrl_lock);
+
+ rtc_dd->rtc_dev = &(spmi->dev);
+ rtc_dd->spmi = spmi;
+
+ /* Get RTC/ALARM resources */
+ spmi_for_each_container_dev(spmi_resource, spmi) {
+ if (!spmi_resource) {
+ dev_err(&spmi->dev,
+ "%s: rtc_alarm: spmi resource absent!\n",
+ __func__);
+ rc = -ENXIO;
+ goto fail_rtc_enable;
+ }
+
+ resource = spmi_get_resource(spmi, spmi_resource,
+ IORESOURCE_MEM, 0);
+ if (!(resource && resource->start)) {
+ dev_err(&spmi->dev,
+ "%s: node %s IO resource absent!\n",
+ __func__, spmi->dev.of_node->full_name);
+ rc = -ENXIO;
+ goto fail_rtc_enable;
+ }
+
+ rc = qpnp_read_wrapper(rtc_dd, &subtype,
+ resource->start + REG_OFFSET_PERP_SUBTYPE, 1);
+ if (rc) {
+ dev_err(&spmi->dev,
+ "Peripheral subtype read failed\n");
+ goto fail_rtc_enable;
+ }
+
+ switch (subtype) {
+ case RTC_PERPH_SUBTYPE:
+ rtc_dd->rtc_base = resource->start;
+ break;
+ case ALARM_PERPH_SUBTYPE:
+ rtc_dd->alarm_base = resource->start;
+ rtc_dd->rtc_alarm_irq =
+ spmi_get_irq(spmi, spmi_resource, 0);
+ if (rtc_dd->rtc_alarm_irq < 0) {
+ dev_err(&spmi->dev, "ALARM IRQ absent\n");
+ rc = -ENXIO;
+ goto fail_rtc_enable;
+ }
+ break;
+ default:
+ dev_err(&spmi->dev, "Invalid peripheral subtype\n");
+ rc = -EINVAL;
+ goto fail_rtc_enable;
+ }
+ }
+
+ rtc_dd->rtc_ctrl_reg = BIT_RTC_ENABLE;
+ rc = qpnp_write_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");
+ goto fail_rtc_enable;
+ }
+
+ /* Enable abort enable feature */
+ rtc_dd->alarm_ctrl_reg1 = BIT_RTC_ABORT_ENABLE;
+ rc = qpnp_write_wrapper(rtc_dd, &rtc_dd->alarm_ctrl_reg1,
+ rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+ if (rc) {
+ dev_err(&spmi->dev, "SPMI write failed!\n");
+ goto fail_rtc_enable;
+ }
+
+ if (rtc_dd->rtc_write_enable == true)
+ qpnp_rtc_ops.set_time = qpnp_rtc_set_time;
+
+ dev_set_drvdata(&spmi->dev, rtc_dd);
+
+ /* Register the RTC device */
+ rtc_dd->rtc = rtc_device_register("qpnp_rtc", &spmi->dev,
+ &qpnp_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc_dd->rtc)) {
+ dev_err(&spmi->dev, "%s: RTC registration failed (%ld)\n",
+ __func__, PTR_ERR(rtc_dd->rtc));
+ rc = PTR_ERR(rtc_dd->rtc);
+ goto fail_rtc_enable;
+ }
+
+ /* Request the alarm IRQ */
+ rc = request_any_context_irq(rtc_dd->rtc_alarm_irq,
+ qpnp_alarm_trigger, IRQF_TRIGGER_RISING,
+ "qpnp_rtc_alarm", rtc_dd);
+ if (rc) {
+ dev_err(&spmi->dev, "Request IRQ failed (%d)\n", rc);
+ goto fail_req_irq;
+ }
+
+ device_init_wakeup(&spmi->dev, 1);
+ enable_irq_wake(rtc_dd->rtc_alarm_irq);
+
+ dev_dbg(&spmi->dev, "Probe success !!\n");
+
+ return 0;
+
+fail_req_irq:
+ rtc_device_unregister(rtc_dd->rtc);
+fail_rtc_enable:
+ dev_set_drvdata(&spmi->dev, NULL);
+
+ return rc;
+}
+
+static int __devexit qpnp_rtc_remove(struct spmi_device *spmi)
+{
+ struct qpnp_rtc *rtc_dd = dev_get_drvdata(&spmi->dev);
+
+ device_init_wakeup(&spmi->dev, 0);
+ free_irq(rtc_dd->rtc_alarm_irq, rtc_dd);
+ rtc_device_unregister(rtc_dd->rtc);
+ dev_set_drvdata(&spmi->dev, NULL);
+
+ return 0;
+}
+
+static void qpnp_rtc_shutdown(struct spmi_device *spmi)
+{
+ u8 value[4] = {0};
+ u8 reg;
+ int rc;
+ unsigned long irq_flags;
+ struct qpnp_rtc *rtc_dd = dev_get_drvdata(&spmi->dev);
+ bool rtc_alarm_powerup = rtc_dd->rtc_alarm_powerup;
+
+ if (!rtc_alarm_powerup) {
+ spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);
+ dev_dbg(&spmi->dev, "Disabling alarm interrupts\n");
+
+ /* Disable RTC alarms */
+ reg = rtc_dd->alarm_ctrl_reg1;
+ reg &= ~BIT_RTC_ALARM_ENABLE;
+ rc = qpnp_write_wrapper(rtc_dd, ®,
+ rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+ if (rc) {
+ dev_err(rtc_dd->rtc_dev, "SPMI write failed\n");
+ goto fail_alarm_disable;
+ }
+
+ /* Clear Alarm register */
+ rc = qpnp_write_wrapper(rtc_dd, value,
+ rtc_dd->alarm_base + REG_OFFSET_ALARM_RW,
+ NUM_8_BIT_RTC_REGS);
+ if (rc)
+ dev_err(rtc_dd->rtc_dev, "SPMI write failed\n");
+
+fail_alarm_disable:
+ spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
+ }
+}
+
+static struct of_device_id spmi_match_table[] = {
+ {
+ .compatible = "qcom,qpnp-rtc",
+ },
+ {}
+};
+
+static struct spmi_driver qpnp_rtc_driver = {
+ .probe = qpnp_rtc_probe,
+ .remove = __devexit_p(qpnp_rtc_remove),
+ .shutdown = qpnp_rtc_shutdown,
+ .driver = {
+ .name = "qcom,qpnp-rtc",
+ .owner = THIS_MODULE,
+ .of_match_table = spmi_match_table,
+ },
+};
+
+static int __init qpnp_rtc_init(void)
+{
+ return spmi_driver_register(&qpnp_rtc_driver);
+}
+module_init(qpnp_rtc_init);
+
+static void __exit qpnp_rtc_exit(void)
+{
+ spmi_driver_unregister(&qpnp_rtc_driver);
+}
+module_exit(qpnp_rtc_exit);
+
+MODULE_DESCRIPTION("SMPI PMIC RTC driver");
+MODULE_LICENSE("GPL V2");
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index d99a02a..b2d2f74 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -52,6 +52,16 @@
Also able to set threshold temperature for both hot and cold and update
when a threshold is reached.
+config THERMAL_TSENS8974
+ tristate "Qualcomm 8974 TSENS Temperature driver"
+ depends on THERMAL
+ help
+ This enables the thermal sysfs driver for the TSENS device. It shows
+ up in Sysfs as a thermal zone with multiple trip points. Also able
+ to set threshold temperature for both warm and cool and update
+ thermal userspace client when a threshold is reached. Warm/Cool
+ temperature thresholds can be set independently for each sensor.
+
config THERMAL_PM8XXX
tristate "Qualcomm PMIC PM8xxx Temperature Alarm"
depends on THERMAL
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 275a692..f7e7cc6 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -8,4 +8,5 @@
obj-$(CONFIG_THERMAL_TSENS8960) += msm8960_tsens.o
obj-$(CONFIG_THERMAL_PM8XXX) += pm8xxx-tm.o
obj-$(CONFIG_THERMAL_MONITOR) += msm_thermal.o
-obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
\ No newline at end of file
+obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
+obj-$(CONFIG_THERMAL_TSENS8974) += msm8974-tsens.o
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
new file mode 100644
index 0000000..6628b79
--- /dev/null
+++ b/drivers/thermal/msm8974-tsens.c
@@ -0,0 +1,870 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/msm_tsens.h>
+#include <linux/err.h>
+#include <linux/of.h>
+
+#include <mach/msm_iomap.h>
+
+#define TSENS_DRIVER_NAME "msm-tsens"
+/* TSENS register info */
+#define TSENS_UPPER_LOWER_INTERRUPT_CTRL(n) ((n) + 0x1000)
+#define TSENS_INTERRUPT_EN BIT(0)
+
+#define TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(n) ((n) + 0x1004)
+#define TSENS_UPPER_STATUS_CLR BIT(21)
+#define TSENS_LOWER_STATUS_CLR BIT(20)
+#define TSENS_UPPER_THRESHOLD_MASK 0xffc00
+#define TSENS_LOWER_THRESHOLD_MASK 0x3ff
+#define TSENS_UPPER_THRESHOLD_SHIFT 10
+
+#define TSENS_S0_STATUS_ADDR(n) ((n) + 0x1030)
+#define TSENS_SN_ADDR_OFFSET 0x4
+#define TSENS_SN_STATUS_TEMP_MASK 0x3ff
+#define TSENS_SN_STATUS_LOWER_STATUS BIT(11)
+#define TSENS_SN_STATUS_UPPER_STATUS BIT(12)
+#define TSENS_STATUS_ADDR_OFFSET 2
+
+#define TSENS_TRDY_ADDR(n) ((n) + 0x105c)
+#define TSENS_TRDY_MASK BIT(0)
+
+#define TSENS_CTRL_ADDR(n) (n)
+#define TSENS_SW_RST BIT(1)
+#define TSENS_SN_MIN_MAX_STATUS_CTRL(n) ((n) + 4)
+#define TSENS_GLOBAL_CONFIG(n) ((n) + 0x34)
+#define TSENS_S0_MAIN_CONFIG(n) ((n) + 0x38)
+#define TSENS_SN_REMOTE_CONFIG(n) ((n) + 0x3c)
+
+/* TSENS calibration Mask data */
+#define TSENS_BASE1_MASK 0xff
+#define TSENS0_POINT1_MASK 0x3f00
+#define TSENS1_POINT1_MASK 0xfc000
+#define TSENS2_POINT1_MASK 0x3f00000
+#define TSENS3_POINT1_MASK 0xfc000000
+#define TSENS4_POINT1_MASK 0x3f
+#define TSENS5_POINT1_MASK 0xfc00
+#define TSENS6_POINT1_MASK 0x3f000
+#define TSENS7_POINT1_MASK 0xfc0000
+#define TSENS8_POINT1_MASK 0x3f000000
+#define TSENS9_POINT1_MASK 0x3f
+#define TSENS10_POINT1_MASK 0xfc00
+#define TSENS_CAL_SEL_0_1 0xc0000000
+#define TSENS_CAL_SEL_2 BIT(30)
+#define TSENS_CAL_SEL_SHIFT 30
+#define TSENS_CAL_SEL_SHIFT_2 28
+#define TSENS_ONE_POINT_CALIB 0x3
+#define TSENS_TWO_POINT_CALIB 0x2
+
+#define TSENS_BASE2_MASK 0xff000
+#define TSENS0_POINT2_MASK 0x3f00000
+#define TSENS1_POINT2_MASK 0xfc000000
+#define TSENS2_POINT2_MASK 0x3f
+#define TSENS3_POINT2_MASK 0xfc00
+#define TSENS4_POINT2_MASK 0x3f000
+#define TSENS5_POINT2_MASK 0xfc0000
+#define TSENS6_POINT2_MASK 0x3f000000
+#define TSENS7_POINT2_MASK 0x3f
+#define TSENS8_POINT2_MASK 0xfc00
+#define TSENS9_POINT2_MASK 0x3f000
+#define TSENS10_POINT2_MASK 0xfc0000
+
+#define TSENS_BIT_APPEND 0x3
+#define TSENS_CAL_DEGC_POINT1 30
+#define TSENS_CAL_DEGC_POINT2 120
+#define TSENS_SLOPE_FACTOR 1000
+
+/* TSENS register data */
+#define TSENS_TRDY_RDY_MIN_TIME 2000
+#define TSENS_TRDY_RDY_MAX_TIME 2100
+#define TSENS_THRESHOLD_MAX_CODE 0x3ff
+#define TSENS_THRESHOLD_MIN_CODE 0x0
+
+#define TSENS_CTRL_INIT_DATA1 0x3fffff9
+#define TSENS_GLOBAL_INIT_DATA 0x20013
+#define TSENS_S0_MAIN_CFG_INIT_DATA 0x1ba
+#define TSENS_SN_MIN_MAX_STATUS_CTRL_DATA 0x3ffc00
+#define TSENS_SN_REMOTE_CFG_DATA 0xdba
+
+/* Trips: warm and cool */
+enum tsens_trip_type {
+ TSENS_TRIP_WARM = 0,
+ TSENS_TRIP_COOL,
+ TSENS_TRIP_NUM,
+};
+
+struct tsens_tm_device_sensor {
+ struct thermal_zone_device *tz_dev;
+ enum thermal_device_mode mode;
+ unsigned int sensor_num;
+ struct work_struct work;
+ int offset;
+ int calib_data_point1;
+ int calib_data_point2;
+ uint32_t slope_mul_tsens_factor;
+};
+
+struct tsens_tm_device {
+ struct platform_device *pdev;
+ bool prev_reading_avail;
+ int tsens_factor;
+ uint32_t tsens_num_sensor;
+ int tsens_irq;
+ void *tsens_addr;
+ void *tsens_calib_addr;
+ int tsens_len;
+ int calib_len;
+ struct resource *res_tsens_mem;
+ struct resource *res_calib_mem;
+ struct tsens_tm_device_sensor sensor[0];
+};
+
+struct tsens_tm_device *tmdev;
+
+static int tsens_tz_code_to_degc(int adc_code, int sensor_num)
+{
+ int degcbeforefactor, degc;
+ degcbeforefactor = (adc_code *
+ tmdev->sensor[sensor_num].slope_mul_tsens_factor
+ + tmdev->sensor[sensor_num].offset);
+
+ if (degcbeforefactor == 0)
+ degc = degcbeforefactor;
+ else if (degcbeforefactor > 0)
+ degc = (degcbeforefactor + tmdev->tsens_factor/2)
+ / tmdev->tsens_factor;
+ else
+ degc = (degcbeforefactor - tmdev->tsens_factor/2)
+ / tmdev->tsens_factor;
+ return degc;
+}
+
+static int tsens_tz_degc_to_code(int degc, int sensor_num)
+{
+ int code = (degc * tmdev->tsens_factor -
+ tmdev->sensor[sensor_num].offset
+ + tmdev->sensor[sensor_num].slope_mul_tsens_factor/2)
+ / tmdev->sensor[sensor_num].slope_mul_tsens_factor;
+
+ if (code > TSENS_THRESHOLD_MAX_CODE)
+ code = TSENS_THRESHOLD_MAX_CODE;
+ else if (code < TSENS_THRESHOLD_MIN_CODE)
+ code = TSENS_THRESHOLD_MIN_CODE;
+ return code;
+}
+
+static void msm_tsens_get_temp(int sensor_num, unsigned long *temp)
+{
+ unsigned int code, sensor_addr;
+
+ if (!tmdev->prev_reading_avail) {
+ while (!(readl_relaxed(TSENS_TRDY_ADDR(tmdev->tsens_addr))
+ & TSENS_TRDY_MASK))
+ usleep_range(TSENS_TRDY_RDY_MIN_TIME,
+ TSENS_TRDY_RDY_MAX_TIME);
+ tmdev->prev_reading_avail = true;
+ }
+
+ sensor_addr =
+ (unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
+ code = readl_relaxed(sensor_addr +
+ (sensor_num << TSENS_STATUS_ADDR_OFFSET));
+ *temp = tsens_tz_code_to_degc((code & TSENS_SN_STATUS_TEMP_MASK),
+ sensor_num);
+}
+
+static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
+
+ if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
+ return -EINVAL;
+
+ msm_tsens_get_temp(tm_sensor->sensor_num, temp);
+
+ return 0;
+}
+
+int tsens_get_temp(struct tsens_device *device, unsigned long *temp)
+{
+ if (!tmdev)
+ return -ENODEV;
+
+ msm_tsens_get_temp(device->sensor_num, temp);
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_tsens_get_temp);
+
+static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
+ enum thermal_device_mode *mode)
+{
+ struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
+
+ if (!tm_sensor || !mode)
+ return -EINVAL;
+
+ *mode = tm_sensor->mode;
+
+ return 0;
+}
+
+static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
+ int trip, enum thermal_trip_type *type)
+{
+ struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
+
+ if (!tm_sensor || trip < 0 || !type)
+ return -EINVAL;
+
+ switch (trip) {
+ case TSENS_TRIP_WARM:
+ *type = THERMAL_TRIP_CONFIGURABLE_HI;
+ break;
+ case TSENS_TRIP_COOL:
+ *type = THERMAL_TRIP_CONFIGURABLE_LOW;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
+ int trip, enum thermal_trip_activation_mode mode)
+{
+ struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
+ unsigned int reg_cntl, code, hi_code, lo_code, mask;
+
+ if (!tm_sensor || trip < 0)
+ return -EINVAL;
+
+ lo_code = TSENS_THRESHOLD_MIN_CODE;
+ hi_code = TSENS_THRESHOLD_MAX_CODE;
+
+ reg_cntl = readl_relaxed((TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+ (tmdev->tsens_addr) +
+ (tm_sensor->sensor_num * 4)));
+ switch (trip) {
+ case TSENS_TRIP_WARM:
+ code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+ >> TSENS_UPPER_THRESHOLD_SHIFT;
+ mask = TSENS_UPPER_STATUS_CLR;
+
+ if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
+ lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+ break;
+ case TSENS_TRIP_COOL:
+ code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+ mask = TSENS_LOWER_STATUS_CLR;
+
+ if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
+ hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+ >> TSENS_UPPER_THRESHOLD_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
+ writel_relaxed(reg_cntl | mask,
+ (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+ (tmdev->tsens_addr) +
+ (tm_sensor->sensor_num * 4)));
+ else {
+ if (code < lo_code || code > hi_code) {
+ pr_err("%s with invalid code %x\n", __func__, code);
+ return -EINVAL;
+ }
+ writel_relaxed(reg_cntl & ~mask,
+ (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_addr) +
+ (tm_sensor->sensor_num * 4)));
+ }
+ mb();
+ return 0;
+}
+
+static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
+ int trip, unsigned long *temp)
+{
+ struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
+ unsigned int reg;
+
+ if (!tm_sensor || trip < 0 || !temp)
+ return -EINVAL;
+
+ reg = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+ (tmdev->tsens_addr) +
+ (tm_sensor->sensor_num * TSENS_SN_ADDR_OFFSET));
+ switch (trip) {
+ case TSENS_TRIP_WARM:
+ reg = (reg & TSENS_UPPER_THRESHOLD_MASK) >>
+ TSENS_UPPER_THRESHOLD_SHIFT;
+ break;
+ case TSENS_TRIP_COOL:
+ reg = (reg & TSENS_LOWER_THRESHOLD_MASK);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *temp = tsens_tz_code_to_degc(reg, tm_sensor->sensor_num);
+
+ return 0;
+}
+
+static int tsens_tz_notify(struct thermal_zone_device *thermal,
+ int count, enum thermal_trip_type type)
+{
+ /* TSENS driver does not shutdown the device.
+ All Thermal notification are sent to the
+ thermal daemon to take appropriate action */
+ pr_debug("%s debug\n", __func__);
+ return 1;
+}
+
+static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
+ int trip, long temp)
+{
+ struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
+ unsigned int reg_cntl;
+ int code, hi_code, lo_code, code_err_chk;
+
+ code_err_chk = code = tsens_tz_degc_to_code(temp,
+ tm_sensor->sensor_num);
+ if (!tm_sensor || trip < 0)
+ return -EINVAL;
+
+ lo_code = TSENS_THRESHOLD_MIN_CODE;
+ hi_code = TSENS_THRESHOLD_MAX_CODE;
+
+ reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+ (tmdev->tsens_addr) +
+ (tm_sensor->sensor_num * TSENS_SN_ADDR_OFFSET));
+ switch (trip) {
+ case TSENS_TRIP_WARM:
+ code <<= TSENS_UPPER_THRESHOLD_SHIFT;
+ reg_cntl &= ~TSENS_UPPER_THRESHOLD_MASK;
+ if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
+ lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+ break;
+ case TSENS_TRIP_COOL:
+ reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK;
+ if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
+ hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+ >> TSENS_UPPER_THRESHOLD_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (code_err_chk < lo_code || code_err_chk > hi_code)
+ return -EINVAL;
+
+ writel_relaxed(reg_cntl | code, (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+ (tmdev->tsens_addr) +
+ (tm_sensor->sensor_num *
+ TSENS_SN_ADDR_OFFSET)));
+ mb();
+ return 0;
+}
+
+static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
+ .get_temp = tsens_tz_get_temp,
+ .get_mode = tsens_tz_get_mode,
+ .get_trip_type = tsens_tz_get_trip_type,
+ .activate_trip_type = tsens_tz_activate_trip_type,
+ .get_trip_temp = tsens_tz_get_trip_temp,
+ .set_trip_temp = tsens_tz_set_trip_temp,
+ .notify = tsens_tz_notify,
+};
+
+static void notify_uspace_tsens_fn(struct work_struct *work)
+{
+ struct tsens_tm_device_sensor *tm = container_of(work,
+ struct tsens_tm_device_sensor, work);
+
+ sysfs_notify(&tm->tz_dev->device.kobj,
+ NULL, "type");
+}
+
+static irqreturn_t tsens_isr(int irq, void *data)
+{
+ struct tsens_tm_device *tm = data;
+ unsigned int i, status, threshold;
+ unsigned int sensor_status_addr, sensor_status_ctrl_addr;
+
+ sensor_status_addr =
+ (unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
+ sensor_status_ctrl_addr =
+ (unsigned int)TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+ (tmdev->tsens_addr);
+ for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+ bool upper_thr = false, lower_thr = false;
+ status = readl_relaxed(sensor_status_addr);
+ threshold = readl_relaxed(sensor_status_ctrl_addr);
+ if (status & TSENS_SN_STATUS_UPPER_STATUS) {
+ writel_relaxed(threshold | TSENS_UPPER_STATUS_CLR,
+ sensor_status_ctrl_addr);
+ upper_thr = true;
+ }
+ if (status & TSENS_SN_STATUS_LOWER_STATUS) {
+ writel_relaxed(threshold | TSENS_LOWER_STATUS_CLR,
+ sensor_status_ctrl_addr);
+ lower_thr = true;
+ }
+ if (upper_thr || lower_thr) {
+ /* Notify user space */
+ schedule_work(&tm->sensor[i].work);
+ pr_debug("sensor:%d trigger temp (%d degC)\n", i,
+ tsens_tz_code_to_degc((status &
+ TSENS_SN_STATUS_TEMP_MASK), i));
+ }
+ sensor_status_addr += TSENS_SN_ADDR_OFFSET;
+ sensor_status_ctrl_addr += TSENS_SN_ADDR_OFFSET;
+ }
+ mb();
+ return IRQ_HANDLED;
+}
+
+static void tsens_hw_init(void)
+{
+ unsigned int reg_cntl = 0;
+ unsigned int i;
+
+ reg_cntl = readl_relaxed(TSENS_CTRL_ADDR(tmdev->tsens_addr));
+ writel_relaxed(reg_cntl | TSENS_SW_RST,
+ TSENS_CTRL_ADDR(tmdev->tsens_addr));
+ writel_relaxed(TSENS_CTRL_INIT_DATA1,
+ TSENS_CTRL_ADDR(tmdev->tsens_addr));
+ writel_relaxed(TSENS_GLOBAL_INIT_DATA,
+ TSENS_GLOBAL_CONFIG(tmdev->tsens_addr));
+ writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
+ TSENS_S0_MAIN_CONFIG(tmdev->tsens_addr));
+ for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+ writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
+ TSENS_SN_MIN_MAX_STATUS_CTRL(tmdev->tsens_addr)
+ + (i * TSENS_SN_ADDR_OFFSET));
+ writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
+ TSENS_SN_REMOTE_CONFIG(tmdev->tsens_addr)
+ + (i * TSENS_SN_ADDR_OFFSET));
+ }
+ writel_relaxed(TSENS_INTERRUPT_EN,
+ TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
+}
+
+static int tsens_calib_sensors(void)
+{
+ int i, tsens_base1_data, tsens0_point1, tsens1_point1;
+ int tsens2_point1, tsens3_point1, tsens4_point1, tsens5_point1;
+ int tsens6_point1, tsens7_point1, tsens8_point1, tsens9_point1;
+ int tsens10_point1, tsens0_point2, tsens1_point2, tsens2_point2;
+ int tsens3_point2, tsens4_point2, tsens5_point2, tsens6_point2;
+ int tsens7_point2, tsens8_point2, tsens9_point2, tsens10_point2;
+ int tsens_base2_data, tsens_calibration_mode, temp;
+ uint32_t calib_data[5];
+
+ for (i = 0; i < 5; i++)
+ calib_data[i] = readl_relaxed(tmdev->tsens_calib_addr
+ + (i * TSENS_SN_ADDR_OFFSET));
+
+ tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1
+ >> TSENS_CAL_SEL_SHIFT);
+ temp = (calib_data[3] & TSENS_CAL_SEL_2
+ >> TSENS_CAL_SEL_SHIFT_2);
+ tsens_calibration_mode |= temp;
+ /* Remove this after bringup */
+ tsens_calibration_mode = TSENS_ONE_POINT_CALIB;
+
+ if (!tsens_calibration_mode) {
+ pr_err("TSENS not calibrated\n");
+ return -ENODEV;
+ } else if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
+ TSENS_TWO_POINT_CALIB) {
+ tsens_base1_data = calib_data[0] & TSENS_BASE1_MASK;
+ tsens0_point1 = calib_data[0] & TSENS0_POINT1_MASK;
+ tsens1_point1 = calib_data[0] & TSENS1_POINT1_MASK;
+ tsens2_point1 = calib_data[0] & TSENS2_POINT1_MASK;
+ tsens3_point1 = calib_data[0] & TSENS3_POINT1_MASK;
+ tsens4_point1 = calib_data[1] & TSENS4_POINT1_MASK;
+ tsens5_point1 = calib_data[1] & TSENS5_POINT1_MASK;
+ tsens6_point1 = calib_data[1] & TSENS6_POINT1_MASK;
+ tsens7_point1 = calib_data[1] & TSENS7_POINT1_MASK;
+ tsens8_point1 = calib_data[1] & TSENS8_POINT1_MASK;
+ tsens9_point1 = calib_data[2] & TSENS9_POINT1_MASK;
+ tsens10_point1 = calib_data[2] & TSENS10_POINT1_MASK;
+ } else if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+ tsens_base2_data = calib_data[2] & TSENS_BASE2_MASK;
+ tsens0_point2 = calib_data[2] & TSENS0_POINT2_MASK;
+ tsens1_point2 = calib_data[2] & TSENS1_POINT2_MASK;
+ tsens2_point2 = calib_data[3] & TSENS2_POINT2_MASK;
+ tsens3_point2 = calib_data[3] & TSENS3_POINT2_MASK;
+ tsens4_point2 = calib_data[3] & TSENS4_POINT2_MASK;
+ tsens5_point2 = calib_data[3] & TSENS5_POINT2_MASK;
+ tsens6_point2 = calib_data[3] & TSENS6_POINT2_MASK;
+ tsens7_point2 = calib_data[4] & TSENS7_POINT2_MASK;
+ tsens8_point2 = calib_data[4] & TSENS8_POINT2_MASK;
+ tsens9_point2 = calib_data[4] & TSENS9_POINT2_MASK;
+ tsens10_point2 = calib_data[4] & TSENS10_POINT2_MASK;
+ } else
+ pr_debug("Calibration mode is unknown: %d\n",
+ tsens_calibration_mode);
+
+ tmdev->sensor[0].calib_data_point1 =
+ (((tsens_base1_data + tsens0_point1) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[0].calib_data_point2 =
+ (((tsens_base2_data + tsens0_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[1].calib_data_point1 =
+ (((tsens_base1_data + tsens1_point1) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[1].calib_data_point2 =
+ (((tsens_base2_data + tsens1_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[2].calib_data_point1 =
+ (((tsens_base1_data + tsens2_point1) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[2].calib_data_point2 =
+ (((tsens_base2_data + tsens2_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[3].calib_data_point1 =
+ (((tsens_base1_data + tsens3_point1) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[3].calib_data_point2 =
+ (((tsens_base2_data + tsens3_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[4].calib_data_point1 =
+ (((tsens_base1_data + tsens4_point1) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[4].calib_data_point2 =
+ (((tsens_base2_data + tsens4_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[5].calib_data_point1 =
+ (((tsens_base1_data + tsens5_point1) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[5].calib_data_point2 =
+ (((tsens_base2_data + tsens5_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[6].calib_data_point1 =
+ (((tsens_base1_data + tsens6_point1) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[6].calib_data_point2 =
+ (((tsens_base2_data + tsens6_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[7].calib_data_point1 =
+ (((tsens_base1_data + tsens7_point1) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[7].calib_data_point2 =
+ (((tsens_base2_data + tsens7_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[8].calib_data_point1 =
+ (((tsens_base1_data + tsens8_point1) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[8].calib_data_point2 =
+ (((tsens_base2_data + tsens8_point2) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[9].calib_data_point1 =
+ (((tsens_base1_data + tsens9_point1) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[9].calib_data_point2 =
+ (((tsens_base2_data + tsens9_point2) < 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[10].calib_data_point1 =
+ (((tsens_base1_data + tsens10_point1) << 2) | TSENS_BIT_APPEND);
+ tmdev->sensor[10].calib_data_point2 =
+ (((tsens_base2_data + tsens10_point2) << 2) | TSENS_BIT_APPEND);
+
+ for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+ int32_t num = 0, den = 0;
+ num = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT2;
+ den = tmdev->sensor[i].calib_data_point2 -
+ tmdev->sensor[i].calib_data_point1;
+ num *= tmdev->tsens_factor;
+ if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)
+ tmdev->sensor[i].slope_mul_tsens_factor = num/den;
+ tmdev->sensor[i].offset = (TSENS_CAL_DEGC_POINT1 *
+ tmdev->tsens_factor)
+ - (tmdev->sensor[i].calib_data_point1 *
+ tmdev->sensor[i].slope_mul_tsens_factor);
+ INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
+ tmdev->prev_reading_avail = false;
+ }
+
+ return 0;
+}
+
+static int get_device_tree_data(struct platform_device *pdev)
+{
+ const struct device_node *of_node = pdev->dev.of_node;
+ struct resource *res_mem = NULL;
+ u32 *tsens_slope_data;
+ u32 rc = 0, i, tsens_num_sensors;
+
+ rc = of_property_read_u32(of_node,
+ "qcom,sensors", &tsens_num_sensors);
+ if (rc) {
+ dev_err(&pdev->dev, "missing sensor number\n");
+ return -ENODEV;
+ }
+
+ tsens_slope_data = devm_kzalloc(&pdev->dev,
+ tsens_num_sensors, GFP_KERNEL);
+ if (!tsens_slope_data) {
+ dev_err(&pdev->dev, "can not allocate slope data\n");
+ return -ENOMEM;
+ }
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,slope", tsens_slope_data, tsens_num_sensors/sizeof(u32));
+ if (rc) {
+ dev_err(&pdev->dev, "invalid or missing property: tsens-slope\n");
+ return rc;
+ };
+
+ tmdev = devm_kzalloc(&pdev->dev,
+ sizeof(struct tsens_tm_device) +
+ tsens_num_sensors *
+ sizeof(struct tsens_tm_device_sensor),
+ GFP_KERNEL);
+ if (tmdev == NULL) {
+ pr_err("%s: kzalloc() failed.\n", __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < tsens_num_sensors; i++)
+ tmdev->sensor[i].slope_mul_tsens_factor = tsens_slope_data[i];
+ tmdev->tsens_factor = TSENS_SLOPE_FACTOR;
+ tmdev->tsens_num_sensor = tsens_num_sensors;
+
+ tmdev->tsens_irq = platform_get_irq(pdev, 0);
+ if (tmdev->tsens_irq < 0) {
+ pr_err("Invalid get irq\n");
+ return tmdev->tsens_irq;
+ }
+
+ tmdev->res_tsens_mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "tsens_physical");
+ if (!tmdev->res_tsens_mem) {
+ pr_err("Could not get tsens physical address resource\n");
+ rc = -EINVAL;
+ goto fail_free_irq;
+ }
+
+ tmdev->tsens_len = tmdev->res_tsens_mem->end -
+ tmdev->res_tsens_mem->start + 1;
+
+ res_mem = request_mem_region(tmdev->res_tsens_mem->start,
+ tmdev->tsens_len, tmdev->res_tsens_mem->name);
+ if (!res_mem) {
+ pr_err("Request tsens physical memory region failed\n");
+ rc = -EINVAL;
+ goto fail_free_irq;
+ }
+
+ tmdev->tsens_addr = ioremap(res_mem->start, tmdev->tsens_len);
+ if (!tmdev->tsens_addr) {
+ pr_err("Failed to IO map TSENS registers.\n");
+ rc = -EINVAL;
+ goto fail_unmap_tsens_region;
+ }
+
+ tmdev->res_calib_mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "tsens_eeprom_physical");
+ if (!tmdev->res_calib_mem) {
+ pr_err("Could not get qfprom physical address resource\n");
+ rc = -EINVAL;
+ goto fail_unmap_tsens;
+ }
+
+ tmdev->calib_len = tmdev->res_calib_mem->end -
+ tmdev->res_calib_mem->start + 1;
+
+ res_mem = request_mem_region(tmdev->res_calib_mem->start,
+ tmdev->calib_len, tmdev->res_calib_mem->name);
+ if (!res_mem) {
+ pr_err("Request calibration memory region failed\n");
+ rc = -EINVAL;
+ goto fail_unmap_tsens;
+ }
+
+ tmdev->tsens_calib_addr = ioremap(res_mem->start,
+ tmdev->calib_len);
+ if (!tmdev->tsens_calib_addr) {
+ pr_err("Failed to IO map EEPROM registers.\n");
+ rc = -EINVAL;
+ goto fail_unmap_calib_region;
+ }
+
+ return 0;
+
+fail_unmap_calib_region:
+ if (tmdev->res_calib_mem)
+ release_mem_region(tmdev->res_calib_mem->start,
+ tmdev->calib_len);
+fail_unmap_tsens:
+ if (tmdev->tsens_addr)
+ iounmap(tmdev->tsens_addr);
+fail_unmap_tsens_region:
+ if (tmdev->res_tsens_mem)
+ release_mem_region(tmdev->res_tsens_mem->start,
+ tmdev->tsens_len);
+fail_free_irq:
+ free_irq(tmdev->tsens_irq, tmdev);
+
+ return rc;
+}
+
+static int __devinit tsens_tm_probe(struct platform_device *pdev)
+{
+ int rc;
+
+ if (tmdev) {
+ pr_err("TSENS device already in use\n");
+ return -EBUSY;
+ }
+
+ if (pdev->dev.of_node)
+ rc = get_device_tree_data(pdev);
+ else
+ return -ENODEV;
+
+ tmdev->pdev = pdev;
+ rc = tsens_calib_sensors();
+ if (rc < 0)
+ goto fail;
+
+ tsens_hw_init();
+ tmdev->prev_reading_avail = true;
+
+ platform_set_drvdata(pdev, tmdev);
+
+ return 0;
+fail:
+ if (tmdev->tsens_calib_addr)
+ iounmap(tmdev->tsens_calib_addr);
+ if (tmdev->res_calib_mem)
+ release_mem_region(tmdev->res_calib_mem->start,
+ tmdev->calib_len);
+ if (tmdev->tsens_addr)
+ iounmap(tmdev->tsens_addr);
+ if (tmdev->res_tsens_mem)
+ release_mem_region(tmdev->res_tsens_mem->start,
+ tmdev->tsens_len);
+ free_irq(tmdev->tsens_irq, tmdev);
+ kfree(tmdev);
+
+ return rc;
+}
+
+static int __devinit _tsens_register_thermal(void)
+{
+ struct platform_device *pdev = tmdev->pdev;
+ int rc, i;
+
+ if (!tmdev) {
+ pr_err("%s: TSENS early init not done\n", __func__);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+ char name[18];
+ snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
+ tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
+ tmdev->sensor[i].sensor_num = i;
+ tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
+ TSENS_TRIP_NUM, &tmdev->sensor[i],
+ &tsens_thermal_zone_ops, 0, 0, 0, 0);
+ if (IS_ERR(tmdev->sensor[i].tz_dev)) {
+ pr_err("%s: thermal_zone_device_register() failed.\n",
+ __func__);
+ rc = -ENODEV;
+ goto fail;
+ }
+ }
+ rc = request_irq(tmdev->tsens_irq, tsens_isr,
+ IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
+ if (rc < 0) {
+ pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
+ for (i = 0; i < tmdev->tsens_num_sensor; i++)
+ thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
+ goto fail;
+ }
+ platform_set_drvdata(pdev, tmdev);
+
+ return 0;
+fail:
+ if (tmdev->tsens_calib_addr)
+ iounmap(tmdev->tsens_calib_addr);
+ if (tmdev->res_calib_mem)
+ release_mem_region(tmdev->res_calib_mem->start,
+ tmdev->calib_len);
+ if (tmdev->tsens_addr)
+ iounmap(tmdev->tsens_addr);
+ if (tmdev->res_tsens_mem)
+ release_mem_region(tmdev->res_tsens_mem->start,
+ tmdev->tsens_len);
+ kfree(tmdev);
+
+ return rc;
+}
+
+static int __devexit tsens_tm_remove(struct platform_device *pdev)
+{
+ struct tsens_tm_device *tmdev = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < tmdev->tsens_num_sensor; i++)
+ thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
+ if (tmdev->tsens_calib_addr)
+ iounmap(tmdev->tsens_calib_addr);
+ if (tmdev->res_calib_mem)
+ release_mem_region(tmdev->res_calib_mem->start,
+ tmdev->calib_len);
+ if (tmdev->tsens_addr)
+ iounmap(tmdev->tsens_addr);
+ if (tmdev->res_tsens_mem)
+ release_mem_region(tmdev->res_tsens_mem->start,
+ tmdev->tsens_len);
+ free_irq(tmdev->tsens_irq, tmdev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(tmdev);
+
+ return 0;
+}
+
+static struct of_device_id tsens_match[] = {
+ { .compatible = "qcom,msm-tsens",
+ },
+ {}
+};
+
+static struct platform_driver tsens_tm_driver = {
+ .probe = tsens_tm_probe,
+ .remove = tsens_tm_remove,
+ .driver = {
+ .name = "msm-tsens",
+ .owner = THIS_MODULE,
+ .of_match_table = tsens_match,
+ },
+};
+
+static int __init tsens_tm_init_driver(void)
+{
+ return platform_driver_register(&tsens_tm_driver);
+}
+arch_initcall(tsens_tm_init_driver);
+
+static int __init tsens_thermal_register(void)
+{
+ return _tsens_register_thermal();
+}
+module_init(tsens_thermal_register);
+
+static void __exit _tsens_tm_remove(void)
+{
+ platform_driver_unregister(&tsens_tm_driver);
+}
+module_exit(_tsens_tm_remove);
+
+MODULE_ALIAS("platform:" TSENS_DRIVER_NAME);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 083ed19..1904706 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -174,7 +174,7 @@
#define UARTDM_TX_BUF_SIZE UART_XMIT_SIZE
#define UARTDM_RX_BUF_SIZE 512
#define RETRY_TIMEOUT 5
-#define UARTDM_NR 2
+#define UARTDM_NR 5
static struct dentry *debug_base;
static struct msm_hs_port q_uart_port[UARTDM_NR];
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 1fbfdd8..54ea85d 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -373,6 +373,17 @@
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
/*
+ * The default value of GUCTL[31:22] should be 0x8. But on cores
+ * revision < 2.30a, the default value is mistakenly overridden
+ * with 0x0. Restore the correct default value.
+ */
+ if (dwc->revision < DWC3_REVISION_230A) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
+ reg &= ~DWC3_GUCTL_REFCLKPER;
+ reg |= 0x8 << __ffs(DWC3_GUCTL_REFCLKPER);
+ dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
+ }
+ /*
* Currently, the default and the recommended value for GUSB3PIPECTL
* [21:19] in the RTL is 3'b100 or 32 consecutive errors. Based on
* analysis and experiments in the lab, it is found that there is a
@@ -395,6 +406,11 @@
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
reg &= ~DWC3_GUSB3PIPECTL_DELAY_P1P2P3;
reg |= 1 << __ffs(DWC3_GUSB3PIPECTL_DELAY_P1P2P3);
+ /*
+ * Receiver Detection in U3/Rx.Det is mistakenly disabled in
+ * cores < 2.30a. Fix it here.
+ */
+ reg &= ~DWC3_GUSB3PIPECTL_DIS_RXDET_U3_RXDET;
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
}
@@ -506,9 +522,9 @@
if (of_get_property(node, "tx-fifo-resize", NULL))
dwc->needs_fifo_resize = true;
+ pm_runtime_no_callbacks(dev);
+ pm_runtime_set_active(dev);
pm_runtime_enable(dev);
- pm_runtime_get_sync(dev);
- pm_runtime_forbid(dev);
ret = dwc3_core_init(dwc);
if (ret) {
@@ -570,8 +586,6 @@
goto err2;
}
- pm_runtime_allow(dev);
-
return 0;
err2:
@@ -605,7 +619,6 @@
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
dwc3_debugfs_exit(dwc);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 98adff7..92e28f5 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -180,6 +180,9 @@
#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
+/* Global User Control Register */
+#define DWC3_GUCTL_REFCLKPER (0x3FF << 22)
+
/* Global USB2 PHY Configuration Register */
#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
@@ -188,6 +191,7 @@
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
#define DWC3_GUSB3PIPECTL_DELAY_P1P2P3 (7 << 19)
+#define DWC3_GUSB3PIPECTL_DIS_RXDET_U3_RXDET (1 << 22)
/* Global TX Fifo Size Register */
#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 05f1a60..136c6d9 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -16,6 +16,8 @@
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/clk.h>
#include <linux/io.h>
@@ -24,6 +26,8 @@
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/list.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/msm_hsusb.h>
@@ -124,6 +128,12 @@
struct regulator *ssusb_vddcx;
enum usb_vdd_type ss_vdd_type;
enum usb_vdd_type hs_vdd_type;
+ struct dwc3_ext_xceiv ext_xceiv;
+ bool resume_pending;
+ atomic_t pm_suspended;
+ atomic_t in_lpm;
+ struct delayed_work resume_work;
+ struct wake_lock wlock;
struct dwc3_charger charger;
struct usb_phy *otg_xceiv;
struct delayed_work chg_work;
@@ -1213,6 +1223,159 @@
queue_delayed_work(system_nrt_wq, &mdwc->chg_work, 0);
}
+static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
+{
+ dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
+
+ if (atomic_read(&mdwc->in_lpm)) {
+ dev_dbg(mdwc->dev, "%s: Already suspended\n", __func__);
+ return 0;
+ }
+
+ clk_disable_unprepare(mdwc->core_clk);
+ dwc3_hsusb_ldo_enable(0);
+ dwc3_ssusb_ldo_enable(0);
+ wake_unlock(&mdwc->wlock);
+
+ atomic_set(&mdwc->in_lpm, 1);
+ dev_info(mdwc->dev, "DWC3 in low power mode\n");
+
+ return 0;
+}
+
+static int dwc3_msm_resume(struct dwc3_msm *mdwc)
+{
+ dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
+
+ if (!atomic_read(&mdwc->in_lpm)) {
+ dev_dbg(mdwc->dev, "%s: Already resumed\n", __func__);
+ return 0;
+ }
+
+ wake_lock(&mdwc->wlock);
+ clk_prepare_enable(mdwc->core_clk);
+ dwc3_hsusb_ldo_enable(1);
+ dwc3_ssusb_ldo_enable(1);
+
+ atomic_set(&mdwc->in_lpm, 0);
+ dev_info(mdwc->dev, "DWC3 exited from low power mode\n");
+
+ return 0;
+}
+
+static void dwc3_resume_work(struct work_struct *w)
+{
+ struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
+ resume_work.work);
+
+ dev_dbg(mdwc->dev, "%s: dwc3 resume work\n", __func__);
+ /* handle any event that was queued while work was already running */
+ if (!atomic_read(&mdwc->in_lpm)) {
+ dev_dbg(mdwc->dev, "%s: notifying xceiv event\n", __func__);
+ if (mdwc->otg_xceiv)
+ mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
+ DWC3_EVENT_XCEIV_STATE);
+ return;
+ }
+
+ /* bail out if system resume in process, else initiate RESUME */
+ if (atomic_read(&mdwc->pm_suspended)) {
+ mdwc->resume_pending = true;
+ } else {
+ pm_runtime_get_sync(mdwc->dev);
+ if (mdwc->otg_xceiv)
+ mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
+ DWC3_EVENT_PHY_RESUME);
+ pm_runtime_put_sync(mdwc->dev);
+ }
+}
+
+static bool debug_id, debug_bsv, debug_connect;
+
+static int dwc3_connect_show(struct seq_file *s, void *unused)
+{
+ if (debug_connect)
+ seq_printf(s, "true\n");
+ else
+ seq_printf(s, "false\n");
+
+ return 0;
+}
+
+static int dwc3_connect_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dwc3_connect_show, inode->i_private);
+}
+
+static ssize_t dwc3_connect_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *s = file->private_data;
+ struct dwc3_msm *mdwc = s->private;
+ char buf[8];
+
+ memset(buf, 0x00, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (!strncmp(buf, "enable", 6) || !strncmp(buf, "true", 4)) {
+ debug_connect = true;
+ } else {
+ debug_connect = debug_bsv = false;
+ debug_id = true;
+ }
+
+ mdwc->ext_xceiv.bsv = debug_bsv;
+ mdwc->ext_xceiv.id = debug_id ? DWC3_ID_FLOAT : DWC3_ID_GROUND;
+
+ if (atomic_read(&mdwc->in_lpm)) {
+ dev_dbg(mdwc->dev, "%s: calling resume_work\n", __func__);
+ dwc3_resume_work(&mdwc->resume_work.work);
+ } else {
+ dev_dbg(mdwc->dev, "%s: notifying xceiv event\n", __func__);
+ if (mdwc->otg_xceiv)
+ mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
+ DWC3_EVENT_XCEIV_STATE);
+ }
+
+ return count;
+}
+
+const struct file_operations dwc3_connect_fops = {
+ .open = dwc3_connect_open,
+ .read = seq_read,
+ .write = dwc3_connect_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *dwc3_debugfs_root;
+
+static void dwc3_debugfs_init(struct dwc3_msm *mdwc)
+{
+ dwc3_debugfs_root = debugfs_create_dir("msm_dwc3", NULL);
+
+ if (!dwc3_debugfs_root || IS_ERR(dwc3_debugfs_root))
+ return;
+
+ if (!debugfs_create_bool("id", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
+ (u32 *)&debug_id))
+ goto error;
+
+ if (!debugfs_create_bool("bsv", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
+ (u32 *)&debug_bsv))
+ goto error;
+
+ if (!debugfs_create_file("connect", S_IRUGO | S_IWUSR,
+ dwc3_debugfs_root, mdwc, &dwc3_connect_fops))
+ goto error;
+
+ return;
+
+error:
+ debugfs_remove_recursive(dwc3_debugfs_root);
+}
static int __devinit dwc3_msm_probe(struct platform_device *pdev)
{
@@ -1234,6 +1397,7 @@
INIT_LIST_HEAD(&msm->req_complete_list);
INIT_DELAYED_WORK(&msm->chg_work, dwc3_chg_detect_work);
+ INIT_DELAYED_WORK(&msm->resume_work, dwc3_resume_work);
/*
* DWC3 Core requires its CORE CLK (aka master / bus clk) to
@@ -1354,6 +1518,9 @@
msm->resource_size = resource_size(res);
msm->dwc3 = dwc3;
+ pm_runtime_set_active(msm->dev);
+ pm_runtime_enable(msm->dev);
+
if (of_property_read_u32(node, "qcom,dwc-usb3-msm-dbm-eps",
&msm->dbm_num_eps)) {
dev_err(&pdev->dev,
@@ -1395,10 +1562,21 @@
ret);
goto put_xcvr;
}
+
+ ret = dwc3_set_ext_xceiv(msm->otg_xceiv->otg, &msm->ext_xceiv);
+ if (ret || !msm->ext_xceiv.notify_ext_events) {
+ dev_err(&pdev->dev, "failed to register xceiver: %d\n",
+ ret);
+ goto put_xcvr;
+ }
} else {
dev_err(&pdev->dev, "%s: No OTG transceiver found\n", __func__);
}
+ wake_lock_init(&msm->wlock, WAKE_LOCK_SUSPEND, "msm_dwc3");
+ wake_lock(&msm->wlock);
+ dwc3_debugfs_init(msm);
+
return 0;
put_xcvr:
@@ -1432,11 +1610,15 @@
{
struct dwc3_msm *msm = platform_get_drvdata(pdev);
+ if (dwc3_debugfs_root)
+ debugfs_remove_recursive(dwc3_debugfs_root);
if (msm->otg_xceiv) {
dwc3_start_chg_det(&msm->charger, false);
usb_put_transceiver(msm->otg_xceiv);
}
+ pm_runtime_disable(msm->dev);
platform_device_unregister(msm->dwc3);
+ wake_lock_destroy(&msm->wlock);
dwc3_hsusb_ldo_enable(0);
dwc3_hsusb_ldo_init(0);
@@ -1451,6 +1633,77 @@
return 0;
}
+static int dwc3_msm_pm_suspend(struct device *dev)
+{
+ int ret = 0;
+ struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "dwc3-msm PM suspend\n");
+
+ ret = dwc3_msm_suspend(mdwc);
+ if (!ret)
+ atomic_set(&mdwc->pm_suspended, 1);
+
+ return ret;
+}
+
+static int dwc3_msm_pm_resume(struct device *dev)
+{
+ int ret = 0;
+ struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "dwc3-msm PM resume\n");
+
+ atomic_set(&mdwc->pm_suspended, 0);
+ if (mdwc->resume_pending) {
+ mdwc->resume_pending = false;
+
+ ret = dwc3_msm_resume(mdwc);
+ /* Update runtime PM status */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ /* Let OTG know about resume event and update pm_count */
+ if (mdwc->otg_xceiv)
+ mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
+ DWC3_EVENT_PHY_RESUME);
+ }
+
+ return ret;
+}
+
+static int dwc3_msm_runtime_idle(struct device *dev)
+{
+ dev_dbg(dev, "DWC3-msm runtime idle\n");
+
+ return 0;
+}
+
+static int dwc3_msm_runtime_suspend(struct device *dev)
+{
+ struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "DWC3-msm runtime suspend\n");
+
+ return dwc3_msm_suspend(mdwc);
+}
+
+static int dwc3_msm_runtime_resume(struct device *dev)
+{
+ struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "DWC3-msm runtime resume\n");
+
+ return dwc3_msm_resume(mdwc);
+}
+
+static const struct dev_pm_ops dwc3_msm_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(dwc3_msm_pm_suspend, dwc3_msm_pm_resume)
+ SET_RUNTIME_PM_OPS(dwc3_msm_runtime_suspend, dwc3_msm_runtime_resume,
+ dwc3_msm_runtime_idle)
+};
+
static const struct of_device_id of_dwc3_matach[] = {
{
.compatible = "qcom,dwc-usb3-msm",
@@ -1464,6 +1717,7 @@
.remove = __devexit_p(dwc3_msm_remove),
.driver = {
.name = "msm-dwc3",
+ .pm = &dwc3_msm_dev_pm_ops,
.of_match_table = of_dwc3_matach,
},
};
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 23b582d..4a37f03 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -271,6 +271,61 @@
return 0;
}
+/**
+ * dwc3_ext_event_notify - callback to handle events from external transceiver
+ * @otg: Pointer to the otg transceiver structure
+ * @event: Event reported by transceiver
+ *
+ * Returns 0 on success
+ */
+static void dwc3_ext_event_notify(struct usb_otg *otg,
+ enum dwc3_ext_events event)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+ struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
+ struct usb_phy *phy = dotg->otg.phy;
+
+ if (event == DWC3_EVENT_PHY_RESUME) {
+ if (!pm_runtime_status_suspended(phy->dev)) {
+ dev_warn(phy->dev, "PHY_RESUME event out of LPM!!!!\n");
+ } else {
+ dev_dbg(phy->dev, "ext PHY_RESUME event received\n");
+ /* ext_xceiver would have taken h/w out of LPM by now */
+ pm_runtime_get(phy->dev);
+ }
+ }
+
+ if (ext_xceiv->id == DWC3_ID_FLOAT)
+ set_bit(ID, &dotg->inputs);
+ else
+ clear_bit(ID, &dotg->inputs);
+
+ if (ext_xceiv->bsv)
+ set_bit(B_SESS_VLD, &dotg->inputs);
+ else
+ clear_bit(B_SESS_VLD, &dotg->inputs);
+
+ schedule_work(&dotg->sm_work);
+}
+
+/**
+ * dwc3_set_ext_xceiv - bind/unbind external transceiver driver
+ * @otg: Pointer to the otg transceiver structure
+ * @ext_xceiv: Pointer to the external transceiver struccture
+ *
+ * Returns 0 on success
+ */
+int dwc3_set_ext_xceiv(struct usb_otg *otg, struct dwc3_ext_xceiv *ext_xceiv)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ dotg->ext_xceiv = ext_xceiv;
+ if (ext_xceiv)
+ ext_xceiv->notify_ext_events = dwc3_ext_event_notify;
+
+ return 0;
+}
+
/* IRQs which OTG driver is interested in handling */
#define DWC3_OEVT_MASK (DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT | \
DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)
@@ -284,10 +339,21 @@
static irqreturn_t dwc3_otg_interrupt(int irq, void *_dotg)
{
struct dwc3_otg *dotg = (struct dwc3_otg *)_dotg;
+ struct usb_phy *phy = dotg->otg.phy;
u32 osts, oevt_reg;
int ret = IRQ_NONE;
int handled_irqs = 0;
+ /*
+ * If PHY is in retention mode then this interrupt would not be fired.
+ * ext_xcvr (parent) is responsible for bringing h/w out of LPM.
+ * OTG driver just need to increment power count and can safely
+ * assume that h/w is out of low power state now.
+ * TODO: explicitly disable OEVTEN interrupts if ext_xceiv is present
+ */
+ if (pm_runtime_status_suspended(phy->dev))
+ pm_runtime_get(phy->dev);
+
oevt_reg = dwc3_readl(dotg->regs, DWC3_OEVT);
if (!(oevt_reg & DWC3_OEVT_MASK))
@@ -371,6 +437,7 @@
struct dwc3_charger *charger = dotg->charger;
bool work = 0;
+ pm_runtime_resume(phy->dev);
dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state));
/* Check OTG state */
@@ -388,7 +455,8 @@
work = 1;
} else {
phy->state = OTG_STATE_B_IDLE;
- /* TODO: Enter low power state */
+ dev_dbg(phy->dev, "No device, trying to suspend\n");
+ pm_runtime_put_sync(phy->dev);
}
break;
@@ -411,7 +479,8 @@
/* Has charger been detected? If no detect it */
switch (charger->chg_type) {
case DWC3_DCP_CHARGER:
- /* TODO: initiate LPM */
+ dev_dbg(phy->dev, "lpm, DCP charger\n");
+ pm_runtime_put_sync(phy->dev);
break;
case DWC3_CDP_CHARGER:
dwc3_otg_start_peripheral(&dotg->otg,
@@ -438,9 +507,10 @@
* yet. We will re-try as soon as it
* will be called
*/
- dev_err(phy->dev,
+ dev_err(phy->dev, "enter lpm as\n"
"unable to start B-device\n");
phy->state = OTG_STATE_UNDEFINED;
+ pm_runtime_put_sync(phy->dev);
return;
}
}
@@ -453,7 +523,8 @@
charger->chg_type =
DWC3_INVALID_CHARGER;
}
- /* TODO: Enter low power state */
+ dev_dbg(phy->dev, "No device, trying to suspend\n");
+ pm_runtime_put_sync(phy->dev);
}
break;
@@ -481,9 +552,10 @@
* Probably set_host was not called yet.
* We will re-try as soon as it will be called
*/
- dev_dbg(phy->dev,
+ dev_dbg(phy->dev, "enter lpm as\n"
"unable to start A-device\n");
phy->state = OTG_STATE_UNDEFINED;
+ pm_runtime_put_sync(phy->dev);
return;
}
phy->state = OTG_STATE_A_HOST;
@@ -628,6 +700,8 @@
goto err3;
}
+ pm_runtime_get(dwc->dev);
+
return 0;
err3:
@@ -658,6 +732,7 @@
dotg->charger->start_detection(dotg->charger, false);
cancel_work_sync(&dotg->sm_work);
usb_set_transceiver(NULL);
+ pm_runtime_put(dwc->dev);
free_irq(dotg->irq, dotg);
kfree(dotg->otg.phy);
kfree(dotg);
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index 0d8b61b..b60b42a 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -35,8 +35,9 @@
struct usb_otg otg;
int irq;
void __iomem *regs;
- struct work_struct sm_work;
- struct dwc3_charger *charger;
+ struct work_struct sm_work;
+ struct dwc3_charger *charger;
+ struct dwc3_ext_xceiv *ext_xceiv;
#define ID 0
#define B_SESS_VLD 1
unsigned long inputs;
@@ -73,4 +74,29 @@
/* for external charger driver */
extern int dwc3_set_charger(struct usb_otg *otg, struct dwc3_charger *charger);
+enum dwc3_ext_events {
+ DWC3_EVENT_NONE = 0, /* no change event */
+ DWC3_EVENT_PHY_RESUME, /* PHY has come out of LPM */
+ DWC3_EVENT_XCEIV_STATE, /* XCEIV state (id/bsv) has changed */
+};
+
+enum dwc3_id_state {
+ DWC3_ID_GROUND = 0,
+ DWC3_ID_FLOAT,
+};
+
+/* external transceiver that can perform connect/disconnect monitoring in LPM */
+struct dwc3_ext_xceiv {
+ enum dwc3_id_state id;
+ bool bsv;
+
+ /* to notify OTG about LPM exit event, provided by OTG */
+ void (*notify_ext_events)(struct usb_otg *otg,
+ enum dwc3_ext_events ext_event);
+};
+
+/* for external transceiver driver */
+extern int dwc3_set_ext_xceiv(struct usb_otg *otg,
+ struct dwc3_ext_xceiv *ext_xceiv);
+
#endif /* __LINUX_USB_DWC3_OTG_H */
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 060144f..a3f6e58 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2425,6 +2425,11 @@
dev_err(dwc->dev, "failed to set peripheral to otg\n");
goto err7;
}
+ } else {
+ pm_runtime_no_callbacks(&dwc->gadget.dev);
+ pm_runtime_set_active(&dwc->gadget.dev);
+ pm_runtime_enable(&dwc->gadget.dev);
+ pm_runtime_get(&dwc->gadget.dev);
}
return 0;
@@ -2462,6 +2467,11 @@
{
int irq;
+ if (dwc->dotg) {
+ pm_runtime_put(&dwc->gadget.dev);
+ pm_runtime_disable(&dwc->gadget.dev);
+ }
+
usb_del_gadget_udc(&dwc->gadget);
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index a13b5da..9339800 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -83,6 +83,8 @@
#define VENDOR_ID 0x18D1
#define PRODUCT_ID 0x0001
+#define ANDROID_DEVICE_NODE_NAME_LENGTH 11
+
struct android_usb_function {
char *name;
void *config;
@@ -94,6 +96,8 @@
/* for android_dev.enabled_functions */
struct list_head enabled_list;
+ struct android_dev *android_dev;
+
/* Optional: initialization during gadget bind */
int (*init)(struct android_usb_function *, struct usb_composite_dev *);
/* Optional: cleanup during gadget unbind */
@@ -132,12 +136,18 @@
char pm_qos[5];
struct pm_qos_request pm_qos_req_dma;
struct work_struct work;
+
+ struct list_head list_item;
+
+ struct usb_configuration config;
};
static struct class *android_class;
-static struct android_dev *_android_dev;
+static struct list_head android_dev_list;
+static int android_dev_count;
static int android_bind_config(struct usb_configuration *c);
static void android_unbind_config(struct usb_configuration *c);
+static struct android_dev *cdev_to_android_dev(struct usb_composite_dev *cdev);
/* string IDs are assigned dynamically */
#define STRING_MANUFACTURER_IDX 0
@@ -189,12 +199,6 @@
NULL,
};
-static struct usb_configuration android_config_driver = {
- .label = "android",
- .unbind = android_unbind_config,
- .bConfigurationValue = 1,
-};
-
enum android_device_state {
USB_DISCONNECTED,
USB_CONNECTED,
@@ -291,7 +295,7 @@
return;
if (--dev->disable_depth == 0) {
- usb_add_config(cdev, &android_config_driver,
+ usb_add_config(cdev, &dev->config,
android_bind_config);
usb_gadget_connect(cdev->gadget);
}
@@ -305,7 +309,7 @@
usb_gadget_disconnect(cdev->gadget);
/* Cancel pending control requests */
usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
- usb_remove_config(cdev, &android_config_driver);
+ usb_remove_config(cdev, &dev->config);
}
}
@@ -343,7 +347,7 @@
static void adb_android_function_enable(struct android_usb_function *f)
{
- struct android_dev *dev = _android_dev;
+ struct android_dev *dev = f->android_dev;
struct adb_data *data = f->config;
data->enabled = true;
@@ -355,7 +359,7 @@
static void adb_android_function_disable(struct android_usb_function *f)
{
- struct android_dev *dev = _android_dev;
+ struct android_dev *dev = f->android_dev;
struct adb_data *data = f->config;
data->enabled = false;
@@ -376,32 +380,30 @@
static void adb_ready_callback(void)
{
- struct android_dev *dev = _android_dev;
+ struct android_dev *dev = adb_function.android_dev;
struct adb_data *data = adb_function.config;
- mutex_lock(&dev->mutex);
-
data->opened = true;
- if (data->enabled)
+ if (data->enabled && dev) {
+ mutex_lock(&dev->mutex);
android_enable(dev);
-
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->mutex);
+ }
}
static void adb_closed_callback(void)
{
- struct android_dev *dev = _android_dev;
+ struct android_dev *dev = adb_function.android_dev;
struct adb_data *data = adb_function.config;
- mutex_lock(&dev->mutex);
-
data->opened = false;
- if (data->enabled)
+ if (data->enabled) {
+ mutex_lock(&dev->mutex);
android_disable(dev);
-
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->mutex);
+ }
}
@@ -609,6 +611,7 @@
char buf[32], *b;
int once = 0, err = -1;
int (*notify)(uint32_t, const char *);
+ struct android_dev *dev = cdev_to_android_dev(c->cdev);
strlcpy(buf, diag_clients, sizeof(buf));
b = strim(buf);
@@ -617,8 +620,8 @@
notify = NULL;
name = strsep(&b, ",");
/* Allow only first diag channel to update pid and serial no */
- if (_android_dev->pdata && !once++)
- notify = _android_dev->pdata->update_pid_and_serial_num;
+ if (dev->pdata && !once++)
+ notify = dev->pdata->update_pid_and_serial_num;
if (name) {
err = diag_function_add(c, name, notify);
@@ -1065,9 +1068,12 @@
static int mass_storage_function_init(struct android_usb_function *f,
struct usb_composite_dev *cdev)
{
+ struct android_dev *dev = cdev_to_android_dev(cdev);
struct mass_storage_function_config *config;
struct fsg_common *common;
int err;
+ int i;
+ const char *name[2];
config = kzalloc(sizeof(struct mass_storage_function_config),
GFP_KERNEL);
@@ -1075,6 +1081,15 @@
return -ENOMEM;
config->fsg.nluns = 1;
+ name[0] = "lun";
+ if (dev->pdata && dev->pdata->cdrom) {
+ config->fsg.nluns = 2;
+ config->fsg.luns[1].cdrom = 1;
+ config->fsg.luns[1].ro = 1;
+ config->fsg.luns[1].removable = 1;
+ name[1] = "lun0";
+ }
+
config->fsg.luns[0].removable = 1;
common = fsg_common_init(NULL, cdev, &config->fsg);
@@ -1083,18 +1098,24 @@
return PTR_ERR(common);
}
- err = sysfs_create_link(&f->dev->kobj,
- &common->luns[0].dev.kobj,
- "lun");
- if (err) {
- fsg_common_release(&common->ref);
- kfree(config);
- return err;
+ for (i = 0; i < config->fsg.nluns; i++) {
+ err = sysfs_create_link(&f->dev->kobj,
+ &common->luns[i].dev.kobj,
+ name[i]);
+ if (err)
+ goto error;
}
config->common = common;
f->config = config;
return 0;
+error:
+ for (; i > 0 ; i--)
+ sysfs_remove_link(&f->dev->kobj, name[i-1]);
+
+ fsg_common_release(&common->ref);
+ kfree(config);
+ return err;
}
static void mass_storage_function_cleanup(struct android_usb_function *f)
@@ -1229,7 +1250,7 @@
static int android_init_functions(struct android_usb_function **functions,
struct usb_composite_dev *cdev)
{
- struct android_dev *dev = _android_dev;
+ struct android_dev *dev = cdev_to_android_dev(cdev);
struct android_usb_function *f;
struct device_attribute **attrs;
struct device_attribute *attr;
@@ -1238,6 +1259,7 @@
for (; (f = *functions++); index++) {
f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name);
+ f->android_dev = NULL;
if (!f->dev_name) {
err = -ENOMEM;
goto err_out;
@@ -1324,9 +1346,15 @@
struct android_usb_function *f;
while ((f = *functions++)) {
if (!strcmp(name, f->name)) {
- list_add_tail(&f->enabled_list,
- &dev->enabled_functions);
- return 0;
+ if (f->android_dev)
+ pr_err("%s cannot be enabled on two devices\n",
+ f->name);
+ else {
+ list_add_tail(&f->enabled_list,
+ &dev->enabled_functions);
+ f->android_dev = dev;
+ return 0;
+ }
}
}
return -EINVAL;
@@ -1338,14 +1366,17 @@
static ssize_t remote_wakeup_show(struct device *pdev,
struct device_attribute *attr, char *buf)
{
+ struct android_dev *dev = dev_get_drvdata(pdev);
+
return snprintf(buf, PAGE_SIZE, "%d\n",
- !!(android_config_driver.bmAttributes &
+ !!(dev->config.bmAttributes &
USB_CONFIG_ATT_WAKEUP));
}
static ssize_t remote_wakeup_store(struct device *pdev,
struct device_attribute *attr, const char *buff, size_t size)
{
+ struct android_dev *dev = dev_get_drvdata(pdev);
int enable = 0;
sscanf(buff, "%d", &enable);
@@ -1354,9 +1385,9 @@
enable ? "enabling" : "disabling");
if (enable)
- android_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ dev->config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
else
- android_config_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
+ dev->config.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
return size;
}
@@ -1385,6 +1416,7 @@
const char *buff, size_t size)
{
struct android_dev *dev = dev_get_drvdata(pdev);
+ struct android_usb_function *f;
char *name;
char buf[256], *b;
int err;
@@ -1396,6 +1428,10 @@
return -EBUSY;
}
+ /* Clear previous enabled list */
+ list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
+ f->android_dev = NULL;
+ }
INIT_LIST_HEAD(&dev->enabled_functions);
strlcpy(buf, buff, sizeof(buf));
@@ -1594,7 +1630,7 @@
static int android_bind_config(struct usb_configuration *c)
{
- struct android_dev *dev = _android_dev;
+ struct android_dev *dev = cdev_to_android_dev(c->cdev);
int ret = 0;
ret = android_bind_enabled_functions(dev, c);
@@ -1606,26 +1642,34 @@
static void android_unbind_config(struct usb_configuration *c)
{
- struct android_dev *dev = _android_dev;
+ struct android_dev *dev = cdev_to_android_dev(c->cdev);
android_unbind_enabled_functions(dev, c);
}
static int android_bind(struct usb_composite_dev *cdev)
{
- struct android_dev *dev = _android_dev;
+ struct android_dev *dev;
struct usb_gadget *gadget = cdev->gadget;
int gcnum, id, ret;
+ /* Bind to the last android_dev that was probed */
+ dev = list_entry(android_dev_list.prev, struct android_dev, list_item);
+
+ dev->cdev = cdev;
+
/*
* Start disconnected. Userspace will connect the gadget once
* it is done configuring the functions.
*/
usb_gadget_disconnect(gadget);
- ret = android_init_functions(dev->functions, cdev);
- if (ret)
- return ret;
+ /* Init the supported functions only once, on the first android_dev */
+ if (android_dev_count == 1) {
+ ret = android_init_functions(dev->functions, cdev);
+ if (ret)
+ return ret;
+ }
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
@@ -1655,7 +1699,7 @@
device_desc.iSerialNumber = id;
if (gadget_is_otg(cdev->gadget))
- android_config_driver.descriptors = otg_desc;
+ dev->config.descriptors = otg_desc;
gcnum = usb_gadget_controller_number(gadget);
if (gcnum >= 0)
@@ -1666,14 +1710,12 @@
device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
}
- dev->cdev = cdev;
-
return 0;
}
static int android_usb_unbind(struct usb_composite_dev *cdev)
{
- struct android_dev *dev = _android_dev;
+ struct android_dev *dev = cdev_to_android_dev(cdev);
manufacturer_string[0] = '\0';
product_string[0] = '\0';
@@ -1694,8 +1736,8 @@
static int
android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c)
{
- struct android_dev *dev = _android_dev;
struct usb_composite_dev *cdev = get_gadget_data(gadget);
+ struct android_dev *dev = cdev_to_android_dev(cdev);
struct usb_request *req = cdev->req;
struct android_usb_function *f;
int value = -EOPNOTSUPP;
@@ -1738,8 +1780,8 @@
static void android_disconnect(struct usb_gadget *gadget)
{
- struct android_dev *dev = _android_dev;
struct usb_composite_dev *cdev = get_gadget_data(gadget);
+ struct android_dev *dev = cdev_to_android_dev(cdev);
unsigned long flags;
composite_disconnect(gadget);
@@ -1750,14 +1792,21 @@
spin_unlock_irqrestore(&cdev->lock, flags);
}
-static int android_create_device(struct android_dev *dev)
+static int android_create_device(struct android_dev *dev, u8 usb_core_id)
{
struct device_attribute **attrs = android_usb_attributes;
struct device_attribute *attr;
+ char device_node_name[ANDROID_DEVICE_NODE_NAME_LENGTH];
int err;
+ /*
+ * The primary usb core should always have usb_core_id=0, since
+ * Android user space is currently interested in android0 events.
+ */
+ snprintf(device_node_name, ANDROID_DEVICE_NODE_NAME_LENGTH,
+ "android%d", usb_core_id);
dev->dev = device_create(android_class, NULL,
- MKDEV(0, 0), NULL, "android0");
+ MKDEV(0, 0), NULL, device_node_name);
if (IS_ERR(dev->dev))
return PTR_ERR(dev->dev);
@@ -1783,27 +1832,64 @@
device_destroy(android_class, dev->dev->devt);
}
+static struct android_dev *cdev_to_android_dev(struct usb_composite_dev *cdev)
+{
+ struct android_dev *dev = NULL;
+
+ /* Find the android dev from the list */
+ list_for_each_entry(dev, &android_dev_list, list_item) {
+ if (dev->cdev == cdev)
+ break;
+ }
+
+ return dev;
+}
+
static int __devinit android_probe(struct platform_device *pdev)
{
struct android_usb_platform_data *pdata = pdev->dev.platform_data;
- struct android_dev *dev = _android_dev;
+ struct android_dev *android_dev;
int ret = 0;
- dev->pdata = pdata;
+ if (!android_class) {
+ android_class = class_create(THIS_MODULE, "android_usb");
+ if (IS_ERR(android_class))
+ return PTR_ERR(android_class);
+ }
- android_class = class_create(THIS_MODULE, "android_usb");
- if (IS_ERR(android_class))
- return PTR_ERR(android_class);
+ android_dev = kzalloc(sizeof(*android_dev), GFP_KERNEL);
+ if (!android_dev) {
+ pr_err("%s(): Failed to alloc memory for android_dev\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
- ret = android_create_device(dev);
+ android_dev->config.label = pdev->name;
+ android_dev->config.unbind = android_unbind_config;
+ android_dev->config.bConfigurationValue = 1;
+ android_dev->disable_depth = 1;
+ android_dev->functions = supported_functions;
+ INIT_LIST_HEAD(&android_dev->enabled_functions);
+ INIT_WORK(&android_dev->work, android_work);
+ mutex_init(&android_dev->mutex);
+
+ android_dev->pdata = pdata;
+
+ list_add_tail(&android_dev->list_item, &android_dev_list);
+ android_dev_count++;
+
+ if (pdata)
+ composite_driver.usb_core_id = pdata->usb_core_id;
+ else
+ composite_driver.usb_core_id = 0; /*To backward compatibility*/
+
+ ret = android_create_device(android_dev, composite_driver.usb_core_id);
if (ret) {
pr_err("%s(): android_create_device failed\n", __func__);
goto err_dev;
}
- if (pdata)
- composite_driver.usb_core_id = pdata->usb_core_id;
-
ret = usb_composite_probe(&android_usb_driver, android_bind);
if (ret) {
pr_err("%s(): Failed to register android "
@@ -1813,67 +1899,91 @@
/* pm qos request to prevent apps idle power collapse */
if (pdata && pdata->swfi_latency)
- pm_qos_add_request(&dev->pm_qos_req_dma,
+ pm_qos_add_request(&android_dev->pm_qos_req_dma,
PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
- strlcpy(dev->pm_qos, "high", sizeof(dev->pm_qos));
+ strlcpy(android_dev->pm_qos, "high", sizeof(android_dev->pm_qos));
return ret;
err_probe:
- android_destroy_device(dev);
+ android_destroy_device(android_dev);
err_dev:
- class_destroy(android_class);
+ list_del(&android_dev->list_item);
+ android_dev_count--;
+ kfree(android_dev);
+err_alloc:
+ if (list_empty(&android_dev_list)) {
+ class_destroy(android_class);
+ android_class = NULL;
+ }
return ret;
}
static int android_remove(struct platform_device *pdev)
{
- struct android_dev *dev = _android_dev;
+ struct android_dev *dev = NULL;
struct android_usb_platform_data *pdata = pdev->dev.platform_data;
+ int usb_core_id = 0;
- android_destroy_device(dev);
- class_destroy(android_class);
- usb_composite_unregister(&android_usb_driver);
- if (pdata && pdata->swfi_latency)
- pm_qos_remove_request(&dev->pm_qos_req_dma);
+ if (pdata)
+ usb_core_id = pdata->usb_core_id;
+
+ /* Find the android dev from the list */
+ list_for_each_entry(dev, &android_dev_list, list_item) {
+ if (!dev->pdata)
+ break; /*To backward compatibility*/
+ if (dev->pdata->usb_core_id == usb_core_id)
+ break;
+ }
+
+ if (dev) {
+ android_destroy_device(dev);
+ if (pdata && pdata->swfi_latency)
+ pm_qos_remove_request(&dev->pm_qos_req_dma);
+ list_del(&dev->list_item);
+ android_dev_count--;
+ kfree(dev);
+ }
+
+ if (list_empty(&android_dev_list)) {
+ class_destroy(android_class);
+ android_class = NULL;
+ usb_composite_unregister(&android_usb_driver);
+ }
return 0;
}
+static const struct platform_device_id android_id_table[] __devinitconst = {
+ {
+ .name = "android_usb",
+ },
+ {
+ .name = "android_usb_hsic",
+ },
+};
+
static struct platform_driver android_platform_driver = {
.driver = { .name = "android_usb"},
.probe = android_probe,
.remove = android_remove,
+ .id_table = android_id_table,
};
static int __init init(void)
{
- struct android_dev *dev;
int ret;
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- pr_err("%s(): Failed to alloc memory for android_dev\n",
- __func__);
- return -ENOMEM;
- }
-
- dev->disable_depth = 1;
- dev->functions = supported_functions;
- INIT_LIST_HEAD(&dev->enabled_functions);
- INIT_WORK(&dev->work, android_work);
- mutex_init(&dev->mutex);
-
- _android_dev = dev;
-
/* Override composite driver functions */
composite_driver.setup = android_setup;
composite_driver.disconnect = android_disconnect;
+ INIT_LIST_HEAD(&android_dev_list);
+ android_dev_count = 0;
+
ret = platform_driver_register(&android_platform_driver);
if (ret) {
pr_err("%s(): Failed to register android"
"platform driver\n", __func__);
- kfree(dev);
}
return ret;
@@ -1883,7 +1993,5 @@
static void __exit cleanup(void)
{
platform_driver_unregister(&android_platform_driver);
- kfree(_android_dev);
- _android_dev = NULL;
}
module_exit(cleanup);
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index d35d861..86c0e73 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1625,7 +1625,7 @@
{
int retval;
- if (!driver || !driver->dev || !bind || composite)
+ if (!driver || !driver->dev || !bind)
return -EINVAL;
if (!driver->name)
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 278e04e..1ea3982 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2865,15 +2865,6 @@
common->ep0req = cdev->req;
common->cdev = cdev;
- /* Maybe allocate device-global string IDs, and patch descriptors */
- if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
- rc = usb_string_id(cdev);
- if (unlikely(rc < 0))
- goto error_release;
- fsg_strings[FSG_STRING_INTERFACE].id = rc;
- fsg_intf_desc.iInterface = rc;
- }
-
/*
* Create the LUNs, open their backing files, and register the
* LUN devices in sysfs.
@@ -3194,6 +3185,15 @@
struct fsg_dev *fsg;
int rc;
+ /* Maybe allocate device-global string IDs, and patch descriptors */
+ if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
+ rc = usb_string_id(cdev);
+ if (unlikely(rc < 0))
+ return rc;
+ fsg_strings[FSG_STRING_INTERFACE].id = rc;
+ fsg_intf_desc.iInterface = rc;
+ }
+
fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
if (unlikely(!fsg))
return -ENOMEM;
diff --git a/drivers/usb/gadget/f_tcm.c b/drivers/usb/gadget/f_tcm.c
new file mode 100644
index 0000000..d944745
--- /dev/null
+++ b/drivers/usb/gadget/f_tcm.c
@@ -0,0 +1,2434 @@
+/* Target based USB-Gadget Function
+ *
+ * UAS protocol handling, target callbacks, configfs handling,
+ * BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling.
+ *
+ * Author: Sebastian Andrzej Siewior <bigeasy at linutronix dot de>
+ * License: GPLv2 as published by FSF.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/storage.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+#include <asm/unaligned.h>
+
+#include "f_tcm.h"
+
+static struct target_fabric_configfs *usbg_fabric_configfs;
+static int (*usbg_connect_cb) (bool connect);
+
+static inline struct f_uas *to_f_uas(struct usb_function *f)
+{
+ return container_of(f, struct f_uas, function);
+}
+
+static void usbg_cmd_release(struct kref *);
+
+static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd)
+{
+ kref_put(&cmd->ref, usbg_cmd_release);
+}
+
+/* Start bot.c code */
+
+static int bot_enqueue_cmd_cbw(struct f_uas *fu)
+{
+ int ret;
+
+ if (fu->flags & USBG_BOT_CMD_PEND)
+ return 0;
+
+ ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC);
+ if (!ret)
+ fu->flags |= USBG_BOT_CMD_PEND;
+ return ret;
+}
+
+static void bot_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct f_uas *fu = cmd->fu;
+
+ usbg_cleanup_cmd(cmd);
+ if (req->status < 0) {
+ pr_err("ERR %s(%d)\n", __func__, __LINE__);
+ return;
+ }
+
+ /* CSW completed, wait for next CBW */
+ bot_enqueue_cmd_cbw(fu);
+}
+
+static void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd)
+{
+ struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+ int ret;
+ u8 *sense;
+ unsigned int csw_stat;
+
+ csw_stat = cmd->csw_code;
+
+ /*
+ * We can't send SENSE as a response. So we take ASC & ASCQ from our
+ * sense buffer and queue it and hope the host sends a REQUEST_SENSE
+ * command where it learns why we failed.
+ */
+ sense = cmd->sense_iu.sense;
+
+ csw->Tag = cmd->bot_tag;
+ csw->Status = csw_stat;
+ fu->bot_status.req->context = cmd;
+ ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+}
+
+static void bot_err_compl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct f_uas *fu = cmd->fu;
+
+ if (req->status < 0)
+ pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+ if (cmd->data_len) {
+ if (cmd->data_len > ep->maxpacket) {
+ req->length = ep->maxpacket;
+ cmd->data_len -= ep->maxpacket;
+ } else {
+ req->length = cmd->data_len;
+ cmd->data_len = 0;
+ }
+
+ usb_ep_queue(ep, req, GFP_ATOMIC);
+ return ;
+ }
+ bot_enqueue_sense_code(fu, cmd);
+}
+
+static void bot_send_bad_status(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+ struct usb_request *req;
+ struct usb_ep *ep;
+
+ csw->Residue = cpu_to_le32(cmd->data_len);
+
+ if (cmd->data_len) {
+ if (cmd->is_read) {
+ ep = fu->ep_in;
+ req = fu->bot_req_in;
+ } else {
+ ep = fu->ep_out;
+ req = fu->bot_req_out;
+ }
+
+ if (cmd->data_len > fu->ep_in->maxpacket) {
+ req->length = ep->maxpacket;
+ cmd->data_len -= ep->maxpacket;
+ } else {
+ req->length = cmd->data_len;
+ cmd->data_len = 0;
+ }
+ req->complete = bot_err_compl;
+ req->context = cmd;
+ req->buf = fu->cmd.buf;
+ usb_ep_queue(ep, req, GFP_KERNEL);
+ } else {
+ bot_enqueue_sense_code(fu, cmd);
+ }
+}
+
+static int bot_send_status(struct usbg_cmd *cmd, bool moved_data)
+{
+ struct f_uas *fu = cmd->fu;
+ struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+ int ret;
+
+ if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) {
+ if (!moved_data && cmd->data_len) {
+ /*
+ * the host wants to move data, we don't. Fill / empty
+ * the pipe and then send the csw with reside set.
+ */
+ cmd->csw_code = US_BULK_STAT_OK;
+ bot_send_bad_status(cmd);
+ return 0;
+ }
+
+ csw->Tag = cmd->bot_tag;
+ csw->Residue = cpu_to_le32(0);
+ csw->Status = US_BULK_STAT_OK;
+ fu->bot_status.req->context = cmd;
+
+ ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL);
+ if (ret)
+ pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+ } else {
+ cmd->csw_code = US_BULK_STAT_FAIL;
+ bot_send_bad_status(cmd);
+ }
+ return 0;
+}
+
+/*
+ * Called after command (no data transfer) or after the write (to device)
+ * operation is completed
+ */
+static int bot_send_status_response(struct usbg_cmd *cmd)
+{
+ bool moved_data = false;
+
+ if (!cmd->is_read)
+ moved_data = true;
+ return bot_send_status(cmd, moved_data);
+}
+
+/* Read request completed, now we have to send the CSW */
+static void bot_read_compl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+
+ if (req->status < 0)
+ pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+ bot_send_status(cmd, true);
+}
+
+static int bot_send_read_response(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+ int ret;
+
+ if (!cmd->data_len) {
+ cmd->csw_code = US_BULK_STAT_PHASE;
+ bot_send_bad_status(cmd);
+ return 0;
+ }
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ sg_copy_to_buffer(se_cmd->t_data_sg,
+ se_cmd->t_data_nents,
+ cmd->data_buf,
+ se_cmd->data_length);
+
+ fu->bot_req_in->buf = cmd->data_buf;
+ } else {
+ fu->bot_req_in->buf = NULL;
+ fu->bot_req_in->num_sgs = se_cmd->t_data_nents;
+ fu->bot_req_in->sg = se_cmd->t_data_sg;
+ }
+
+ fu->bot_req_in->complete = bot_read_compl;
+ fu->bot_req_in->length = se_cmd->data_length;
+ fu->bot_req_in->context = cmd;
+ ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+ return 0;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *);
+static int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *);
+
+static int bot_send_write_request(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+ int ret;
+
+ init_completion(&cmd->write_complete);
+ cmd->fu = fu;
+
+ if (!cmd->data_len) {
+ cmd->csw_code = US_BULK_STAT_PHASE;
+ return -EINVAL;
+ }
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ fu->bot_req_out->buf = cmd->data_buf;
+ } else {
+ fu->bot_req_out->buf = NULL;
+ fu->bot_req_out->num_sgs = se_cmd->t_data_nents;
+ fu->bot_req_out->sg = se_cmd->t_data_sg;
+ }
+
+ fu->bot_req_out->complete = usbg_data_write_cmpl;
+ fu->bot_req_out->length = se_cmd->data_length;
+ fu->bot_req_out->context = cmd;
+
+ ret = usbg_prepare_w_request(cmd, fu->bot_req_out);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+
+ wait_for_completion(&cmd->write_complete);
+ transport_generic_process_write(se_cmd);
+cleanup:
+ return ret;
+}
+
+static int bot_submit_command(struct f_uas *, void *, unsigned int);
+
+static void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_uas *fu = req->context;
+ int ret;
+
+ fu->flags &= ~USBG_BOT_CMD_PEND;
+
+ if (req->status < 0)
+ return;
+
+ ret = bot_submit_command(fu, req->buf, req->actual);
+ if (ret)
+ pr_err("%s(%d): %d\n", __func__, __LINE__, ret);
+}
+
+static int bot_prepare_reqs(struct f_uas *fu)
+{
+ int ret;
+
+ fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+ if (!fu->bot_req_in)
+ goto err;
+
+ fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+ if (!fu->bot_req_out)
+ goto err_out;
+
+ fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+ if (!fu->cmd.req)
+ goto err_cmd;
+
+ fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+ if (!fu->bot_status.req)
+ goto err_sts;
+
+ fu->bot_status.req->buf = &fu->bot_status.csw;
+ fu->bot_status.req->length = US_BULK_CS_WRAP_LEN;
+ fu->bot_status.req->complete = bot_status_complete;
+ fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN);
+
+ fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL);
+ if (!fu->cmd.buf)
+ goto err_buf;
+
+ fu->cmd.req->complete = bot_cmd_complete;
+ fu->cmd.req->buf = fu->cmd.buf;
+ fu->cmd.req->length = fu->ep_out->maxpacket;
+ fu->cmd.req->context = fu;
+
+ ret = bot_enqueue_cmd_cbw(fu);
+ if (ret)
+ goto err_queue;
+ return 0;
+err_queue:
+ kfree(fu->cmd.buf);
+ fu->cmd.buf = NULL;
+err_buf:
+ usb_ep_free_request(fu->ep_in, fu->bot_status.req);
+err_sts:
+ usb_ep_free_request(fu->ep_out, fu->cmd.req);
+ fu->cmd.req = NULL;
+err_cmd:
+ usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+ fu->bot_req_out = NULL;
+err_out:
+ usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+ fu->bot_req_in = NULL;
+err:
+ pr_err("BOT: endpoint setup failed\n");
+ return -ENOMEM;
+}
+
+void bot_cleanup_old_alt(struct f_uas *fu)
+{
+ if (!(fu->flags & USBG_ENABLED))
+ return;
+
+ usb_ep_disable(fu->ep_in);
+ usb_ep_disable(fu->ep_out);
+
+ if (!fu->bot_req_in)
+ return;
+
+ usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+ usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+ usb_ep_free_request(fu->ep_out, fu->cmd.req);
+ usb_ep_free_request(fu->ep_out, fu->bot_status.req);
+
+ kfree(fu->cmd.buf);
+
+ fu->bot_req_in = NULL;
+ fu->bot_req_out = NULL;
+ fu->cmd.req = NULL;
+ fu->bot_status.req = NULL;
+ fu->cmd.buf = NULL;
+}
+
+static void bot_set_alt(struct f_uas *fu)
+{
+ struct usb_function *f = &fu->function;
+ struct usb_gadget *gadget = f->config->cdev->gadget;
+ int ret;
+
+ fu->flags = USBG_IS_BOT;
+
+ config_ep_by_speed(gadget, f, fu->ep_in);
+ ret = usb_ep_enable(fu->ep_in);
+ if (ret)
+ goto err_b_in;
+
+ config_ep_by_speed(gadget, f, fu->ep_out);
+ ret = usb_ep_enable(fu->ep_out);
+ if (ret)
+ goto err_b_out;
+
+ ret = bot_prepare_reqs(fu);
+ if (ret)
+ goto err_wq;
+ fu->flags |= USBG_ENABLED;
+ pr_info("Using the BOT protocol\n");
+ return;
+err_wq:
+ usb_ep_disable(fu->ep_out);
+err_b_out:
+ usb_ep_disable(fu->ep_in);
+err_b_in:
+ fu->flags = USBG_IS_BOT;
+}
+
+static int usbg_bot_setup(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct f_uas *fu = to_f_uas(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+ int luns;
+ u8 *ret_lun;
+
+ switch (ctrl->bRequest) {
+ case US_BULK_GET_MAX_LUN:
+ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE))
+ return -ENOTSUPP;
+
+ if (w_length < 1)
+ return -EINVAL;
+ if (w_value != 0)
+ return -EINVAL;
+ luns = atomic_read(&fu->tpg->tpg_port_count);
+ if (!luns) {
+ pr_err("No LUNs configured?\n");
+ return -EINVAL;
+ }
+ /*
+ * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be
+ * accessed. The upper limit is 0xf
+ */
+ luns--;
+ if (luns > 0xf) {
+ pr_info_once("Limiting the number of luns to 16\n");
+ luns = 0xf;
+ }
+ ret_lun = cdev->req->buf;
+ *ret_lun = luns;
+ cdev->req->length = 1;
+ return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
+ break;
+
+ case US_BULK_RESET_REQUEST:
+ /* XXX maybe we should remove previous requests for IN + OUT */
+ bot_enqueue_cmd_cbw(fu);
+ return 0;
+ break;
+ };
+ return -ENOTSUPP;
+}
+
+/* Start uas.c code */
+
+static void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream)
+{
+ /* We have either all three allocated or none */
+ if (!stream->req_in)
+ return;
+
+ usb_ep_free_request(fu->ep_in, stream->req_in);
+ usb_ep_free_request(fu->ep_out, stream->req_out);
+ usb_ep_free_request(fu->ep_status, stream->req_status);
+
+ stream->req_in = NULL;
+ stream->req_out = NULL;
+ stream->req_status = NULL;
+}
+
+static void uasp_free_cmdreq(struct f_uas *fu)
+{
+ usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+ kfree(fu->cmd.buf);
+ fu->cmd.req = NULL;
+ fu->cmd.buf = NULL;
+}
+
+static void uasp_cleanup_old_alt(struct f_uas *fu)
+{
+ int i;
+
+ if (!(fu->flags & USBG_ENABLED))
+ return;
+
+ usb_ep_disable(fu->ep_in);
+ usb_ep_disable(fu->ep_out);
+ usb_ep_disable(fu->ep_status);
+ usb_ep_disable(fu->ep_cmd);
+
+ for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++)
+ uasp_cleanup_one_stream(fu, &fu->stream[i]);
+ uasp_free_cmdreq(fu);
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req);
+
+static int uasp_prepare_r_request(struct usbg_cmd *cmd)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct f_uas *fu = cmd->fu;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+ struct uas_stream *stream = cmd->stream;
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ sg_copy_to_buffer(se_cmd->t_data_sg,
+ se_cmd->t_data_nents,
+ cmd->data_buf,
+ se_cmd->data_length);
+
+ stream->req_in->buf = cmd->data_buf;
+ } else {
+ stream->req_in->buf = NULL;
+ stream->req_in->num_sgs = se_cmd->t_data_nents;
+ stream->req_in->sg = se_cmd->t_data_sg;
+ }
+
+ stream->req_in->complete = uasp_status_data_cmpl;
+ stream->req_in->length = se_cmd->data_length;
+ stream->req_in->context = cmd;
+
+ cmd->state = UASP_SEND_STATUS;
+ return 0;
+}
+
+static void uasp_prepare_status(struct usbg_cmd *cmd)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct sense_iu *iu = &cmd->sense_iu;
+ struct uas_stream *stream = cmd->stream;
+
+ cmd->state = UASP_QUEUE_COMMAND;
+ iu->iu_id = IU_ID_STATUS;
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ /*
+ * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?);
+ */
+ iu->len = cpu_to_be16(se_cmd->scsi_sense_length);
+ iu->status = se_cmd->scsi_status;
+ stream->req_status->context = cmd;
+ stream->req_status->length = se_cmd->scsi_sense_length + 16;
+ stream->req_status->buf = iu;
+ stream->req_status->complete = uasp_status_data_cmpl;
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct uas_stream *stream = cmd->stream;
+ struct f_uas *fu = cmd->fu;
+ int ret;
+
+ if (req->status < 0)
+ goto cleanup;
+
+ switch (cmd->state) {
+ case UASP_SEND_DATA:
+ ret = uasp_prepare_r_request(cmd);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ break;
+
+ case UASP_RECEIVE_DATA:
+ ret = usbg_prepare_w_request(cmd, stream->req_out);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ break;
+
+ case UASP_SEND_STATUS:
+ uasp_prepare_status(cmd);
+ ret = usb_ep_queue(fu->ep_status, stream->req_status,
+ GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ break;
+
+ case UASP_QUEUE_COMMAND:
+ usbg_cleanup_cmd(cmd);
+ usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+ break;
+
+ default:
+ BUG();
+ };
+ return;
+
+cleanup:
+ usbg_cleanup_cmd(cmd);
+}
+
+static int uasp_send_status_response(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct uas_stream *stream = cmd->stream;
+ struct sense_iu *iu = &cmd->sense_iu;
+
+ iu->tag = cpu_to_be16(cmd->tag);
+ stream->req_status->complete = uasp_status_data_cmpl;
+ stream->req_status->context = cmd;
+ cmd->fu = fu;
+ uasp_prepare_status(cmd);
+ return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC);
+}
+
+static int uasp_send_read_response(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct uas_stream *stream = cmd->stream;
+ struct sense_iu *iu = &cmd->sense_iu;
+ int ret;
+
+ cmd->fu = fu;
+
+ iu->tag = cpu_to_be16(cmd->tag);
+ if (fu->flags & USBG_USE_STREAMS) {
+
+ ret = uasp_prepare_r_request(cmd);
+ if (ret)
+ goto out;
+ ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+ if (ret) {
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ kfree(cmd->data_buf);
+ cmd->data_buf = NULL;
+ }
+
+ } else {
+
+ iu->iu_id = IU_ID_READ_READY;
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ stream->req_status->complete = uasp_status_data_cmpl;
+ stream->req_status->context = cmd;
+
+ cmd->state = UASP_SEND_DATA;
+ stream->req_status->buf = iu;
+ stream->req_status->length = sizeof(struct iu);
+
+ ret = usb_ep_queue(fu->ep_status, stream->req_status,
+ GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ }
+out:
+ return ret;
+}
+
+static int uasp_send_write_request(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct uas_stream *stream = cmd->stream;
+ struct sense_iu *iu = &cmd->sense_iu;
+ int ret;
+
+ init_completion(&cmd->write_complete);
+ cmd->fu = fu;
+
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ if (fu->flags & USBG_USE_STREAMS) {
+
+ ret = usbg_prepare_w_request(cmd, stream->req_out);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+
+ } else {
+
+ iu->iu_id = IU_ID_WRITE_READY;
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ stream->req_status->complete = uasp_status_data_cmpl;
+ stream->req_status->context = cmd;
+
+ cmd->state = UASP_RECEIVE_DATA;
+ stream->req_status->buf = iu;
+ stream->req_status->length = sizeof(struct iu);
+
+ ret = usb_ep_queue(fu->ep_status, stream->req_status,
+ GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+ }
+
+ wait_for_completion(&cmd->write_complete);
+ transport_generic_process_write(se_cmd);
+cleanup:
+ return ret;
+}
+
+static int usbg_submit_command(struct f_uas *, void *, unsigned int);
+
+static void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_uas *fu = req->context;
+ int ret;
+
+ if (req->status < 0)
+ return;
+
+ ret = usbg_submit_command(fu, req->buf, req->actual);
+ /*
+ * Once we tune for performance enqueue the command req here again so
+ * we can receive a second command while we processing this one. Pay
+ * attention to properly sync STAUS endpoint with DATA IN + OUT so you
+ * don't break HS.
+ */
+ if (!ret)
+ return;
+ usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+}
+
+static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
+{
+ stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+ if (!stream->req_in)
+ goto out;
+
+ stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+ if (!stream->req_out)
+ goto err_out;
+
+ stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL);
+ if (!stream->req_status)
+ goto err_sts;
+
+ return 0;
+err_sts:
+ usb_ep_free_request(fu->ep_status, stream->req_status);
+ stream->req_status = NULL;
+err_out:
+ usb_ep_free_request(fu->ep_out, stream->req_out);
+ stream->req_out = NULL;
+out:
+ return -ENOMEM;
+}
+
+static int uasp_alloc_cmd(struct f_uas *fu)
+{
+ fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL);
+ if (!fu->cmd.req)
+ goto err;
+
+ fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL);
+ if (!fu->cmd.buf)
+ goto err_buf;
+
+ fu->cmd.req->complete = uasp_cmd_complete;
+ fu->cmd.req->buf = fu->cmd.buf;
+ fu->cmd.req->length = fu->ep_cmd->maxpacket;
+ fu->cmd.req->context = fu;
+ return 0;
+
+err_buf:
+ usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+err:
+ return -ENOMEM;
+}
+
+static void uasp_setup_stream_res(struct f_uas *fu, int max_streams)
+{
+ int i;
+
+ for (i = 0; i < max_streams; i++) {
+ struct uas_stream *s = &fu->stream[i];
+
+ s->req_in->stream_id = i + 1;
+ s->req_out->stream_id = i + 1;
+ s->req_status->stream_id = i + 1;
+ }
+}
+
+static int uasp_prepare_reqs(struct f_uas *fu)
+{
+ int ret;
+ int i;
+ int max_streams;
+
+ if (fu->flags & USBG_USE_STREAMS)
+ max_streams = UASP_SS_EP_COMP_NUM_STREAMS;
+ else
+ max_streams = 1;
+
+ for (i = 0; i < max_streams; i++) {
+ ret = uasp_alloc_stream_res(fu, &fu->stream[i]);
+ if (ret)
+ goto err_cleanup;
+ }
+
+ ret = uasp_alloc_cmd(fu);
+ if (ret)
+ goto err_free_stream;
+ uasp_setup_stream_res(fu, max_streams);
+
+ ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+ if (ret)
+ goto err_free_stream;
+
+ return 0;
+
+err_free_stream:
+ uasp_free_cmdreq(fu);
+
+err_cleanup:
+ if (i) {
+ do {
+ uasp_cleanup_one_stream(fu, &fu->stream[i - 1]);
+ i--;
+ } while (i);
+ }
+ pr_err("UASP: endpoint setup failed\n");
+ return ret;
+}
+
+static void uasp_set_alt(struct f_uas *fu)
+{
+ struct usb_function *f = &fu->function;
+ struct usb_gadget *gadget = f->config->cdev->gadget;
+ int ret;
+
+ fu->flags = USBG_IS_UAS;
+
+ if (gadget->speed == USB_SPEED_SUPER)
+ fu->flags |= USBG_USE_STREAMS;
+
+ config_ep_by_speed(gadget, f, fu->ep_in);
+ ret = usb_ep_enable(fu->ep_in);
+ if (ret)
+ goto err_b_in;
+
+ config_ep_by_speed(gadget, f, fu->ep_out);
+ ret = usb_ep_enable(fu->ep_out);
+ if (ret)
+ goto err_b_out;
+
+ config_ep_by_speed(gadget, f, fu->ep_cmd);
+ ret = usb_ep_enable(fu->ep_cmd);
+ if (ret)
+ goto err_cmd;
+ config_ep_by_speed(gadget, f, fu->ep_status);
+ ret = usb_ep_enable(fu->ep_status);
+ if (ret)
+ goto err_status;
+
+ ret = uasp_prepare_reqs(fu);
+ if (ret)
+ goto err_wq;
+ fu->flags |= USBG_ENABLED;
+
+ pr_info("Using the UAS protocol\n");
+ return;
+err_wq:
+ usb_ep_disable(fu->ep_status);
+err_status:
+ usb_ep_disable(fu->ep_cmd);
+err_cmd:
+ usb_ep_disable(fu->ep_out);
+err_b_out:
+ usb_ep_disable(fu->ep_in);
+err_b_in:
+ fu->flags = 0;
+}
+
+static int get_cmd_dir(const unsigned char *cdb)
+{
+ int ret;
+
+ switch (cdb[0]) {
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ case READ_16:
+ case INQUIRY:
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ case SERVICE_ACTION_IN:
+ case MAINTENANCE_IN:
+ case PERSISTENT_RESERVE_IN:
+ case SECURITY_PROTOCOL_IN:
+ case ACCESS_CONTROL_IN:
+ case REPORT_LUNS:
+ case READ_BLOCK_LIMITS:
+ case READ_POSITION:
+ case READ_CAPACITY:
+ case READ_TOC:
+ case READ_FORMAT_CAPACITIES:
+ case REQUEST_SENSE:
+ ret = DMA_FROM_DEVICE;
+ break;
+
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
+ case MODE_SELECT:
+ case MODE_SELECT_10:
+ case WRITE_VERIFY:
+ case WRITE_VERIFY_12:
+ case PERSISTENT_RESERVE_OUT:
+ case MAINTENANCE_OUT:
+ case SECURITY_PROTOCOL_OUT:
+ case ACCESS_CONTROL_OUT:
+ ret = DMA_TO_DEVICE;
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ case TEST_UNIT_READY:
+ case SYNCHRONIZE_CACHE:
+ case START_STOP:
+ case ERASE:
+ case REZERO_UNIT:
+ case SEEK_10:
+ case SPACE:
+ case VERIFY:
+ case WRITE_FILEMARKS:
+ ret = DMA_NONE;
+ break;
+ default:
+ pr_warn("target: Unknown data direction for SCSI Opcode "
+ "0x%02x\n", cdb[0]);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+
+ if (req->status < 0) {
+ pr_err("%s() state %d transfer failed\n", __func__, cmd->state);
+ goto cleanup;
+ }
+
+ if (req->num_sgs == 0) {
+ sg_copy_from_buffer(se_cmd->t_data_sg,
+ se_cmd->t_data_nents,
+ cmd->data_buf,
+ se_cmd->data_length);
+ }
+
+ complete(&cmd->write_complete);
+ return;
+
+cleanup:
+ usbg_cleanup_cmd(cmd);
+}
+
+static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct f_uas *fu = cmd->fu;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ req->buf = cmd->data_buf;
+ } else {
+ req->buf = NULL;
+ req->num_sgs = se_cmd->t_data_nents;
+ req->sg = se_cmd->t_data_sg;
+ }
+
+ req->complete = usbg_data_write_cmpl;
+ req->length = se_cmd->data_length;
+ req->context = cmd;
+ return 0;
+}
+
+static int usbg_send_status_response(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return bot_send_status_response(cmd);
+ else
+ return uasp_send_status_response(cmd);
+}
+
+static int usbg_send_write_request(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return bot_send_write_request(cmd);
+ else
+ return uasp_send_write_request(cmd);
+}
+
+static int usbg_send_read_response(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return bot_send_read_response(cmd);
+ else
+ return uasp_send_read_response(cmd);
+}
+
+static void usbg_cmd_work(struct work_struct *work)
+{
+ struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ struct usbg_tpg *tpg;
+ int dir;
+
+ se_cmd = &cmd->se_cmd;
+ tpg = cmd->fu->tpg;
+ tv_nexus = tpg->tpg_nexus;
+ dir = get_cmd_dir(cmd->cmd_buf);
+ if (dir < 0) {
+ transport_init_se_cmd(se_cmd,
+ tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+ tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+ cmd->prio_attr, cmd->sense_iu.sense);
+
+ transport_send_check_condition_and_sense(se_cmd,
+ TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+ usbg_cleanup_cmd(cmd);
+ return;
+ }
+
+ target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+ cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+ 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE);
+}
+
+static int usbg_submit_command(struct f_uas *fu,
+ void *cmdbuf, unsigned int len)
+{
+ struct command_iu *cmd_iu = cmdbuf;
+ struct usbg_cmd *cmd;
+ struct usbg_tpg *tpg;
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ u32 cmd_len;
+ int ret;
+
+ if (cmd_iu->iu_id != IU_ID_COMMAND) {
+ pr_err("Unsupported type %d\n", cmd_iu->iu_id);
+ return -EINVAL;
+ }
+
+ cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->fu = fu;
+
+ /* XXX until I figure out why I can't free in on complete */
+ kref_init(&cmd->ref);
+ kref_get(&cmd->ref);
+
+ tpg = fu->tpg;
+ cmd_len = (cmd_iu->len & ~0x3) + 16;
+ if (cmd_len > USBG_MAX_CMD)
+ goto err;
+
+ memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len);
+
+ cmd->tag = be16_to_cpup(&cmd_iu->tag);
+ if (fu->flags & USBG_USE_STREAMS) {
+ if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS)
+ goto err;
+ if (!cmd->tag)
+ cmd->stream = &fu->stream[0];
+ else
+ cmd->stream = &fu->stream[cmd->tag - 1];
+ } else {
+ cmd->stream = &fu->stream[0];
+ }
+
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ pr_err("Missing nexus, ignoring command\n");
+ goto err;
+ }
+
+ switch (cmd_iu->prio_attr & 0x7) {
+ case UAS_HEAD_TAG:
+ cmd->prio_attr = MSG_HEAD_TAG;
+ break;
+ case UAS_ORDERED_TAG:
+ cmd->prio_attr = MSG_ORDERED_TAG;
+ break;
+ case UAS_ACA:
+ cmd->prio_attr = MSG_ACA_TAG;
+ break;
+ default:
+ pr_debug_once("Unsupported prio_attr: %02x.\n",
+ cmd_iu->prio_attr);
+ case UAS_SIMPLE_TAG:
+ cmd->prio_attr = MSG_SIMPLE_TAG;
+ break;
+ }
+
+ se_cmd = &cmd->se_cmd;
+ cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun);
+
+ INIT_WORK(&cmd->work, usbg_cmd_work);
+ ret = queue_work(tpg->workqueue, &cmd->work);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+err:
+ kfree(cmd);
+ return -EINVAL;
+}
+
+static void bot_cmd_work(struct work_struct *work)
+{
+ struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ struct usbg_tpg *tpg;
+ int dir;
+
+ se_cmd = &cmd->se_cmd;
+ tpg = cmd->fu->tpg;
+ tv_nexus = tpg->tpg_nexus;
+ dir = get_cmd_dir(cmd->cmd_buf);
+ if (dir < 0) {
+ transport_init_se_cmd(se_cmd,
+ tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+ tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+ cmd->prio_attr, cmd->sense_iu.sense);
+
+ transport_send_check_condition_and_sense(se_cmd,
+ TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+ usbg_cleanup_cmd(cmd);
+ return;
+ }
+
+ target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+ cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+ cmd->data_len, cmd->prio_attr, dir, 0);
+}
+
+static int bot_submit_command(struct f_uas *fu,
+ void *cmdbuf, unsigned int len)
+{
+ struct bulk_cb_wrap *cbw = cmdbuf;
+ struct usbg_cmd *cmd;
+ struct usbg_tpg *tpg;
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ u32 cmd_len;
+ int ret;
+
+ if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) {
+ pr_err("Wrong signature on CBW\n");
+ return -EINVAL;
+ }
+ if (len != 31) {
+ pr_err("Wrong length for CBW\n");
+ return -EINVAL;
+ }
+
+ cmd_len = cbw->Length;
+ if (cmd_len < 1 || cmd_len > 16)
+ return -EINVAL;
+
+ cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->fu = fu;
+
+ /* XXX until I figure out why I can't free in on complete */
+ kref_init(&cmd->ref);
+ kref_get(&cmd->ref);
+
+ tpg = fu->tpg;
+
+ memcpy(cmd->cmd_buf, cbw->CDB, cmd_len);
+
+ cmd->bot_tag = cbw->Tag;
+
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ pr_err("Missing nexus, ignoring command\n");
+ goto err;
+ }
+
+ cmd->prio_attr = MSG_SIMPLE_TAG;
+ se_cmd = &cmd->se_cmd;
+ cmd->unpacked_lun = cbw->Lun;
+ cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0;
+ cmd->data_len = le32_to_cpu(cbw->DataTransferLength);
+
+ INIT_WORK(&cmd->work, bot_cmd_work);
+ ret = queue_work(tpg->workqueue, &cmd->work);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+err:
+ kfree(cmd);
+ return -EINVAL;
+}
+
+/* Start fabric.c code */
+
+static int usbg_check_true(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int usbg_check_false(struct se_portal_group *se_tpg)
+{
+ return 0;
+}
+
+static char *usbg_get_fabric_name(void)
+{
+ return "usb_gadget";
+}
+
+static u8 usbg_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+ u8 proto_id;
+
+ switch (tport->tport_proto_id) {
+ case SCSI_PROTOCOL_SAS:
+ default:
+ proto_id = sas_get_fabric_proto_ident(se_tpg);
+ break;
+ }
+
+ return proto_id;
+}
+
+static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+
+ return &tport->tport_name[0];
+}
+
+static u16 usbg_get_tag(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ return tpg->tport_tpgt;
+}
+
+static u32 usbg_get_default_depth(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static u32 usbg_get_pr_transport_id(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code,
+ unsigned char *buf)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+ int ret = 0;
+
+ switch (tport->tport_proto_id) {
+ case SCSI_PROTOCOL_SAS:
+ default:
+ ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+ format_code, buf);
+ break;
+ }
+
+ return ret;
+}
+
+static u32 usbg_get_pr_transport_id_len(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+ int ret = 0;
+
+ switch (tport->tport_proto_id) {
+ case SCSI_PROTOCOL_SAS:
+ default:
+ ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+ format_code);
+ break;
+ }
+
+ return ret;
+}
+
+static char *usbg_parse_pr_out_transport_id(
+ struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+ char *tid = NULL;
+
+ switch (tport->tport_proto_id) {
+ case SCSI_PROTOCOL_SAS:
+ default:
+ tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+ port_nexus_ptr);
+ }
+
+ return tid;
+}
+
+static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+ struct usbg_nacl *nacl;
+
+ nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL);
+ if (!nacl) {
+ printk(KERN_ERR "Unable to alocate struct usbg_nacl\n");
+ return NULL;
+ }
+
+ return &nacl->se_node_acl;
+}
+
+static void usbg_release_fabric_acl(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl)
+{
+ struct usbg_nacl *nacl = container_of(se_nacl,
+ struct usbg_nacl, se_node_acl);
+ kfree(nacl);
+}
+
+static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int usbg_new_cmd(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ int ret;
+
+ ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf);
+ if (ret)
+ return ret;
+
+ return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0);
+}
+
+static void usbg_cmd_release(struct kref *ref)
+{
+ struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd,
+ ref);
+
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
+}
+
+static void usbg_release_cmd(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ kfree(cmd->data_buf);
+ kfree(cmd);
+ return;
+}
+
+static int usbg_shutdown_session(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static void usbg_close_session(struct se_session *se_sess)
+{
+ return;
+}
+
+static u32 usbg_sess_get_index(struct se_session *se_sess)
+{
+ return 0;
+}
+
+/*
+ * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be
+ */
+static int usbg_write_pending_status(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static void usbg_set_default_node_attrs(struct se_node_acl *nacl)
+{
+ return;
+}
+
+static u32 usbg_get_task_tag(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return le32_to_cpu(cmd->bot_tag);
+ else
+ return cmd->tag;
+}
+
+static int usbg_get_cmd_state(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static int usbg_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static u16 usbg_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
+{
+ return 0;
+}
+
+static u16 usbg_get_fabric_sense_len(void)
+{
+ return 0;
+}
+
+static const char *usbg_check_wwn(const char *name)
+{
+ const char *n;
+ unsigned int len;
+
+ n = strstr(name, "naa.");
+ if (!n)
+ return NULL;
+ n += 4;
+ len = strlen(n);
+ if (len == 0 || len > USBG_NAMELEN - 1)
+ return NULL;
+ return n;
+}
+
+static struct se_node_acl *usbg_make_nodeacl(
+ struct se_portal_group *se_tpg,
+ struct config_group *group,
+ const char *name)
+{
+ struct se_node_acl *se_nacl, *se_nacl_new;
+ struct usbg_nacl *nacl;
+ u64 wwpn = 0;
+ u32 nexus_depth;
+ const char *wnn_name;
+
+ wnn_name = usbg_check_wwn(name);
+ if (!wnn_name)
+ return ERR_PTR(-EINVAL);
+ se_nacl_new = usbg_alloc_fabric_acl(se_tpg);
+ if (!(se_nacl_new))
+ return ERR_PTR(-ENOMEM);
+
+ nexus_depth = 1;
+ /*
+ * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+ * when converting a NodeACL from demo mode -> explict
+ */
+ se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+ name, nexus_depth);
+ if (IS_ERR(se_nacl)) {
+ usbg_release_fabric_acl(se_tpg, se_nacl_new);
+ return se_nacl;
+ }
+ /*
+ * Locate our struct usbg_nacl and set the FC Nport WWPN
+ */
+ nacl = container_of(se_nacl, struct usbg_nacl, se_node_acl);
+ nacl->iport_wwpn = wwpn;
+ snprintf(nacl->iport_name, sizeof(nacl->iport_name), "%s", name);
+ return se_nacl;
+}
+
+static void usbg_drop_nodeacl(struct se_node_acl *se_acl)
+{
+ struct usbg_nacl *nacl = container_of(se_acl,
+ struct usbg_nacl, se_node_acl);
+ core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+ kfree(nacl);
+}
+
+struct usbg_tpg *the_only_tpg_I_currently_have;
+
+static struct se_portal_group *usbg_make_tpg(
+ struct se_wwn *wwn,
+ struct config_group *group,
+ const char *name)
+{
+ struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
+ tport_wwn);
+ struct usbg_tpg *tpg;
+ unsigned long tpgt;
+ int ret;
+
+ if (strstr(name, "tpgt_") != name)
+ return ERR_PTR(-EINVAL);
+ if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
+ return ERR_PTR(-EINVAL);
+ if (the_only_tpg_I_currently_have) {
+ pr_err("Until the gadget framework can't handle multiple\n");
+ pr_err("gadgets, you can't do this here.\n");
+ return ERR_PTR(-EBUSY);
+ }
+
+ tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
+ if (!tpg) {
+ printk(KERN_ERR "Unable to allocate struct usbg_tpg");
+ return ERR_PTR(-ENOMEM);
+ }
+ mutex_init(&tpg->tpg_mutex);
+ atomic_set(&tpg->tpg_port_count, 0);
+ tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1);
+ if (!tpg->workqueue) {
+ kfree(tpg);
+ return NULL;
+ }
+
+ tpg->tport = tport;
+ tpg->tport_tpgt = tpgt;
+
+ ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn,
+ &tpg->se_tpg, tpg,
+ TRANSPORT_TPG_TYPE_NORMAL);
+ if (ret < 0) {
+ destroy_workqueue(tpg->workqueue);
+ kfree(tpg);
+ return NULL;
+ }
+ the_only_tpg_I_currently_have = tpg;
+ return &tpg->se_tpg;
+}
+
+static void usbg_drop_tpg(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+
+ core_tpg_deregister(se_tpg);
+ destroy_workqueue(tpg->workqueue);
+ kfree(tpg);
+ the_only_tpg_I_currently_have = NULL;
+}
+
+static struct se_wwn *usbg_make_tport(
+ struct target_fabric_configfs *tf,
+ struct config_group *group,
+ const char *name)
+{
+ struct usbg_tport *tport;
+ const char *wnn_name;
+ u64 wwpn = 0;
+
+ wnn_name = usbg_check_wwn(name);
+ if (!wnn_name)
+ return ERR_PTR(-EINVAL);
+
+ tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL);
+ if (!(tport)) {
+ printk(KERN_ERR "Unable to allocate struct usbg_tport");
+ return ERR_PTR(-ENOMEM);
+ }
+ tport->tport_wwpn = wwpn;
+ snprintf(tport->tport_name, sizeof(tport->tport_name), wnn_name);
+ return &tport->tport_wwn;
+}
+
+static void usbg_drop_tport(struct se_wwn *wwn)
+{
+ struct usbg_tport *tport = container_of(wwn,
+ struct usbg_tport, tport_wwn);
+ kfree(tport);
+}
+
+/*
+ * If somebody feels like dropping the version property, go ahead.
+ */
+static ssize_t usbg_wwn_show_attr_version(
+ struct target_fabric_configfs *tf,
+ char *page)
+{
+ return sprintf(page, "usb-gadget fabric module\n");
+}
+TF_WWN_ATTR_RO(usbg, version);
+
+static struct configfs_attribute *usbg_wwn_attrs[] = {
+ &usbg_wwn_version.attr,
+ NULL,
+};
+
+static ssize_t tcm_usbg_tpg_show_enable(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+ return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect);
+}
+
+static int usbg_attach(struct usbg_tpg *tpg)
+{
+ return usbg_connect_cb(true);
+}
+
+static void usbg_detach(struct usbg_tpg *tpg)
+{
+ usbg_connect_cb(false);
+}
+
+static ssize_t tcm_usbg_tpg_store_enable(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+ unsigned long op;
+ ssize_t ret;
+
+ ret = kstrtoul(page, 0, &op);
+ if (ret < 0)
+ return -EINVAL;
+ if (op > 1)
+ return -EINVAL;
+
+ if (op && tpg->gadget_connect)
+ goto out;
+ if (!op && !tpg->gadget_connect)
+ goto out;
+
+ if (op) {
+ ret = usbg_attach(tpg);
+ if (ret)
+ goto out;
+ } else {
+ usbg_detach(tpg);
+ }
+ tpg->gadget_connect = op;
+out:
+ return count;
+}
+TF_TPG_BASE_ATTR(tcm_usbg, enable, S_IRUGO | S_IWUSR);
+
+static ssize_t tcm_usbg_tpg_show_nexus(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+ struct tcm_usbg_nexus *tv_nexus;
+ ssize_t ret;
+
+ mutex_lock(&tpg->tpg_mutex);
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ ret = -ENODEV;
+ goto out;
+ }
+ ret = snprintf(page, PAGE_SIZE, "%s\n",
+ tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+out:
+ mutex_unlock(&tpg->tpg_mutex);
+ return ret;
+}
+
+static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
+{
+ struct se_portal_group *se_tpg;
+ struct tcm_usbg_nexus *tv_nexus;
+ int ret;
+
+ mutex_lock(&tpg->tpg_mutex);
+ if (tpg->tpg_nexus) {
+ ret = -EEXIST;
+ pr_debug("tpg->tpg_nexus already exists\n");
+ goto err_unlock;
+ }
+ se_tpg = &tpg->se_tpg;
+
+ ret = -ENOMEM;
+ tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
+ if (!tv_nexus) {
+ pr_err("Unable to allocate struct tcm_vhost_nexus\n");
+ goto err_unlock;
+ }
+ tv_nexus->tvn_se_sess = transport_init_session();
+ if (IS_ERR(tv_nexus->tvn_se_sess))
+ goto err_free;
+
+ /*
+ * Since we are running in 'demo mode' this call with generate a
+ * struct se_node_acl for the tcm_vhost struct se_portal_group with
+ * the SCSI Initiator port name of the passed configfs group 'name'.
+ */
+ tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
+ se_tpg, name);
+ if (!tv_nexus->tvn_se_sess->se_node_acl) {
+ pr_debug("core_tpg_check_initiator_node_acl() failed"
+ " for %s\n", name);
+ goto err_session;
+ }
+ /*
+ * Now register the TCM vHost virtual I_T Nexus as active with the
+ * call to __transport_register_session()
+ */
+ __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+ tv_nexus->tvn_se_sess, tv_nexus);
+ tpg->tpg_nexus = tv_nexus;
+ mutex_unlock(&tpg->tpg_mutex);
+ return 0;
+
+err_session:
+ transport_free_session(tv_nexus->tvn_se_sess);
+err_free:
+ kfree(tv_nexus);
+err_unlock:
+ mutex_unlock(&tpg->tpg_mutex);
+ return ret;
+}
+
+static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg)
+{
+ struct se_session *se_sess;
+ struct tcm_usbg_nexus *tv_nexus;
+ int ret = -ENODEV;
+
+ mutex_lock(&tpg->tpg_mutex);
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus)
+ goto out;
+
+ se_sess = tv_nexus->tvn_se_sess;
+ if (!se_sess)
+ goto out;
+
+ if (atomic_read(&tpg->tpg_port_count)) {
+ ret = -EPERM;
+ pr_err("Unable to remove Host I_T Nexus with"
+ " active TPG port count: %d\n",
+ atomic_read(&tpg->tpg_port_count));
+ goto out;
+ }
+
+ pr_debug("Removing I_T Nexus to Initiator Port: %s\n",
+ tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+ /*
+ * Release the SCSI I_T Nexus to the emulated vHost Target Port
+ */
+ transport_deregister_session(tv_nexus->tvn_se_sess);
+ tpg->tpg_nexus = NULL;
+
+ kfree(tv_nexus);
+out:
+ mutex_unlock(&tpg->tpg_mutex);
+ return 0;
+}
+
+static ssize_t tcm_usbg_tpg_store_nexus(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+ unsigned char i_port[USBG_NAMELEN], *ptr;
+ int ret;
+
+ if (!strncmp(page, "NULL", 4)) {
+ ret = tcm_usbg_drop_nexus(tpg);
+ return (!ret) ? count : ret;
+ }
+ if (strlen(page) > USBG_NAMELEN) {
+ pr_err("Emulated NAA Sas Address: %s, exceeds"
+ " max: %d\n", page, USBG_NAMELEN);
+ return -EINVAL;
+ }
+ snprintf(i_port, USBG_NAMELEN, "%s", page);
+
+ ptr = strstr(i_port, "naa.");
+ if (!ptr) {
+ pr_err("Missing 'naa.' prefix\n");
+ return -EINVAL;
+ }
+
+ if (i_port[strlen(i_port) - 1] == '\n')
+ i_port[strlen(i_port) - 1] = '\0';
+
+ ret = tcm_usbg_make_nexus(tpg, &i_port[4]);
+ if (ret < 0)
+ return ret;
+ return count;
+}
+TF_TPG_BASE_ATTR(tcm_usbg, nexus, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *usbg_base_attrs[] = {
+ &tcm_usbg_tpg_enable.attr,
+ &tcm_usbg_tpg_nexus.attr,
+ NULL,
+};
+
+static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+ atomic_inc(&tpg->tpg_port_count);
+ smp_mb__after_atomic_inc();
+ return 0;
+}
+
+static void usbg_port_unlink(struct se_portal_group *se_tpg,
+ struct se_lun *se_lun)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+ atomic_dec(&tpg->tpg_port_count);
+ smp_mb__after_atomic_dec();
+}
+
+static int usbg_check_stop_free(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+
+ kref_put(&cmd->ref, usbg_cmd_release);
+ return 1;
+}
+
+static struct target_core_fabric_ops usbg_ops = {
+ .get_fabric_name = usbg_get_fabric_name,
+ .get_fabric_proto_ident = usbg_get_fabric_proto_ident,
+ .tpg_get_wwn = usbg_get_fabric_wwn,
+ .tpg_get_tag = usbg_get_tag,
+ .tpg_get_default_depth = usbg_get_default_depth,
+ .tpg_get_pr_transport_id = usbg_get_pr_transport_id,
+ .tpg_get_pr_transport_id_len = usbg_get_pr_transport_id_len,
+ .tpg_parse_pr_out_transport_id = usbg_parse_pr_out_transport_id,
+ .tpg_check_demo_mode = usbg_check_true,
+ .tpg_check_demo_mode_cache = usbg_check_false,
+ .tpg_check_demo_mode_write_protect = usbg_check_false,
+ .tpg_check_prod_mode_write_protect = usbg_check_false,
+ .tpg_alloc_fabric_acl = usbg_alloc_fabric_acl,
+ .tpg_release_fabric_acl = usbg_release_fabric_acl,
+ .tpg_get_inst_index = usbg_tpg_get_inst_index,
+ .new_cmd_map = usbg_new_cmd,
+ .release_cmd = usbg_release_cmd,
+ .shutdown_session = usbg_shutdown_session,
+ .close_session = usbg_close_session,
+ .sess_get_index = usbg_sess_get_index,
+ .sess_get_initiator_sid = NULL,
+ .write_pending = usbg_send_write_request,
+ .write_pending_status = usbg_write_pending_status,
+ .set_default_node_attributes = usbg_set_default_node_attrs,
+ .get_task_tag = usbg_get_task_tag,
+ .get_cmd_state = usbg_get_cmd_state,
+ .queue_data_in = usbg_send_read_response,
+ .queue_status = usbg_send_status_response,
+ .queue_tm_rsp = usbg_queue_tm_rsp,
+ .get_fabric_sense_len = usbg_get_fabric_sense_len,
+ .set_fabric_sense_len = usbg_set_fabric_sense_len,
+ .check_stop_free = usbg_check_stop_free,
+
+ .fabric_make_wwn = usbg_make_tport,
+ .fabric_drop_wwn = usbg_drop_tport,
+ .fabric_make_tpg = usbg_make_tpg,
+ .fabric_drop_tpg = usbg_drop_tpg,
+ .fabric_post_link = usbg_port_link,
+ .fabric_pre_unlink = usbg_port_unlink,
+ .fabric_make_np = NULL,
+ .fabric_drop_np = NULL,
+ .fabric_make_nodeacl = usbg_make_nodeacl,
+ .fabric_drop_nodeacl = usbg_drop_nodeacl,
+};
+
+static int usbg_register_configfs(void)
+{
+ struct target_fabric_configfs *fabric;
+ int ret;
+
+ fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget");
+ if (IS_ERR(fabric)) {
+ printk(KERN_ERR "target_fabric_configfs_init() failed\n");
+ return PTR_ERR(fabric);
+ }
+
+ fabric->tf_ops = usbg_ops;
+ TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = usbg_wwn_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = usbg_base_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+ ret = target_fabric_configfs_register(fabric);
+ if (ret < 0) {
+ printk(KERN_ERR "target_fabric_configfs_register() failed"
+ " for usb-gadget\n");
+ return ret;
+ }
+ usbg_fabric_configfs = fabric;
+ return 0;
+};
+
+static void usbg_deregister_configfs(void)
+{
+ if (!(usbg_fabric_configfs))
+ return;
+
+ target_fabric_configfs_deregister(usbg_fabric_configfs);
+ usbg_fabric_configfs = NULL;
+};
+
+/* Start gadget.c code */
+
+static struct usb_interface_descriptor bot_intf_desc = {
+ .bLength = sizeof(bot_intf_desc),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 2,
+ .bAlternateSetting = USB_G_ALT_INT_BBB,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
+ .bInterfaceSubClass = USB_SC_SCSI,
+ .bInterfaceProtocol = USB_PR_BULK,
+ /* .iInterface = DYNAMIC */
+};
+
+static struct usb_interface_descriptor uasp_intf_desc = {
+ .bLength = sizeof(uasp_intf_desc),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 4,
+ .bAlternateSetting = USB_G_ALT_INT_UAS,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
+ .bInterfaceSubClass = USB_SC_SCSI,
+ .bInterfaceProtocol = USB_PR_UAS,
+ /* .iInterface = DYNAMIC */
+};
+
+static struct usb_endpoint_descriptor uasp_bi_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bi_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = {
+ .bLength = sizeof(uasp_bi_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = DATA_IN_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bi_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = {
+ .bLength = sizeof(uasp_bi_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 0,
+ .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
+ .wBytesPerInterval = 0,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = {
+ .bLength = sizeof(bot_bi_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 0,
+};
+
+static struct usb_endpoint_descriptor uasp_bo_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bo_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = {
+ .bLength = sizeof(uasp_bo_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = DATA_OUT_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bo_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(0x400),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = {
+ .bLength = sizeof(uasp_bo_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = {
+ .bLength = sizeof(bot_bo_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_endpoint_descriptor uasp_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_status_pipe_desc = {
+ .bLength = sizeof(uasp_status_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = STATUS_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = {
+ .bLength = sizeof(uasp_status_in_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_endpoint_descriptor uasp_cmd_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_cmd_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = {
+ .bLength = sizeof(uasp_cmd_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = CMD_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_cmd_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = {
+ .bLength = sizeof(uasp_cmd_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *uasp_fs_function_desc[] = {
+ (struct usb_descriptor_header *) &bot_intf_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bi_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bo_desc,
+
+ (struct usb_descriptor_header *) &uasp_intf_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bo_desc,
+ (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_fs_status_desc,
+ (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_fs_cmd_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+};
+
+static struct usb_descriptor_header *uasp_hs_function_desc[] = {
+ (struct usb_descriptor_header *) &bot_intf_desc,
+ (struct usb_descriptor_header *) &uasp_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bo_desc,
+
+ (struct usb_descriptor_header *) &uasp_intf_desc,
+ (struct usb_descriptor_header *) &uasp_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_bo_desc,
+ (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_status_desc,
+ (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+ NULL,
+};
+
+static struct usb_descriptor_header *uasp_ss_function_desc[] = {
+ (struct usb_descriptor_header *) &bot_intf_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bi_desc,
+ (struct usb_descriptor_header *) &bot_bi_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bo_desc,
+ (struct usb_descriptor_header *) &bot_bo_ep_comp_desc,
+
+ (struct usb_descriptor_header *) &uasp_intf_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bi_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bo_desc,
+ (struct usb_descriptor_header *) &uasp_bo_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_ss_status_desc,
+ (struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_ss_cmd_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_comp_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+ NULL,
+};
+
+static struct usb_string tcm_us_strings[] = {
+ [0].s = "Bulk Only Transport",
+ [1].s = "USB Attached SCSI",
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings tcm_stringtab = {
+ .language = 0x0409,
+ .strings = tcm_us_strings,
+};
+
+static struct usb_gadget_strings *tcm_strings[] = {
+ &tcm_stringtab,
+ NULL,
+};
+
+static void give_back_ep(struct usb_ep **pep)
+{
+ struct usb_ep *ep = *pep;
+ if (!ep)
+ return;
+ ep->driver_data = NULL;
+}
+
+static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_uas *fu = to_f_uas(f);
+ struct usb_gadget *gadget = c->cdev->gadget;
+ struct usb_ep *ep;
+ int iface;
+
+ iface = usb_interface_id(c, f);
+ if (iface < 0)
+ return iface;
+
+ bot_intf_desc.bInterfaceNumber = iface;
+ uasp_intf_desc.bInterfaceNumber = iface;
+ fu->iface = iface;
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc,
+ &uasp_bi_ep_comp_desc);
+ if (!ep)
+ goto ep_fail;
+
+ ep->driver_data = fu;
+ fu->ep_in = ep;
+
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
+ &uasp_bo_ep_comp_desc);
+ if (!ep)
+ goto ep_fail;
+ ep->driver_data = fu;
+ fu->ep_out = ep;
+
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
+ &uasp_status_in_ep_comp_desc);
+ if (!ep)
+ goto ep_fail;
+ ep->driver_data = fu;
+ fu->ep_status = ep;
+
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
+ &uasp_cmd_comp_desc);
+ if (!ep)
+ goto ep_fail;
+ ep->driver_data = fu;
+ fu->ep_cmd = ep;
+
+ /* Assume endpoint addresses are the same for both speeds */
+ uasp_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
+ uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+ uasp_status_desc.bEndpointAddress =
+ uasp_ss_status_desc.bEndpointAddress;
+ uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+ uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
+ uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+ uasp_fs_status_desc.bEndpointAddress =
+ uasp_ss_status_desc.bEndpointAddress;
+ uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+ return 0;
+ep_fail:
+ pr_err("Can't claim all required eps\n");
+
+ give_back_ep(&fu->ep_in);
+ give_back_ep(&fu->ep_out);
+ give_back_ep(&fu->ep_status);
+ give_back_ep(&fu->ep_cmd);
+ return -ENOTSUPP;
+}
+
+static void usbg_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ kfree(fu);
+}
+
+struct guas_setup_wq {
+ struct work_struct work;
+ struct f_uas *fu;
+ unsigned int alt;
+};
+
+static void usbg_delayed_set_alt(struct work_struct *wq)
+{
+ struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
+ work);
+ struct f_uas *fu = work->fu;
+ int alt = work->alt;
+
+ kfree(work);
+
+ if (fu->flags & USBG_IS_BOT)
+ bot_cleanup_old_alt(fu);
+ if (fu->flags & USBG_IS_UAS)
+ uasp_cleanup_old_alt(fu);
+
+ if (alt == USB_G_ALT_INT_BBB)
+ bot_set_alt(fu);
+ else if (alt == USB_G_ALT_INT_UAS)
+ uasp_set_alt(fu);
+ usb_composite_setup_continue(fu->function.config->cdev);
+}
+
+static int usbg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
+ struct guas_setup_wq *work;
+
+ work = kmalloc(sizeof(*work), GFP_ATOMIC);
+ if (!work)
+ return -ENOMEM;
+ INIT_WORK(&work->work, usbg_delayed_set_alt);
+ work->fu = fu;
+ work->alt = alt;
+ schedule_work(&work->work);
+ return USB_GADGET_DELAYED_STATUS;
+ }
+ return -EOPNOTSUPP;
+}
+
+static void usbg_disable(struct usb_function *f)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ if (fu->flags & USBG_IS_UAS)
+ uasp_cleanup_old_alt(fu);
+ else if (fu->flags & USBG_IS_BOT)
+ bot_cleanup_old_alt(fu);
+ fu->flags = 0;
+}
+
+static int usbg_setup(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ if (!(fu->flags & USBG_IS_BOT))
+ return -EOPNOTSUPP;
+
+ return usbg_bot_setup(f, ctrl);
+}
+
+static int tcm_bind_config(struct usb_configuration *c)
+{
+ struct f_uas *fu;
+ int ret;
+
+ fu = kzalloc(sizeof(*fu), GFP_KERNEL);
+ if (!fu)
+ return -ENOMEM;
+ fu->function.name = "Target Function";
+ fu->function.descriptors = uasp_fs_function_desc;
+ fu->function.hs_descriptors = uasp_hs_function_desc;
+ fu->function.ss_descriptors = uasp_ss_function_desc;
+ fu->function.strings = tcm_strings;
+ fu->function.bind = usbg_bind;
+ fu->function.unbind = usbg_unbind;
+ fu->function.set_alt = usbg_set_alt;
+ fu->function.setup = usbg_setup;
+ fu->function.disable = usbg_disable;
+ fu->tpg = the_only_tpg_I_currently_have;
+
+ /* BOT interface string */
+ ret = usb_string_id(c->cdev);
+ if (ret < 0)
+ goto err;
+ tcm_us_strings[0].id = ret;
+ bot_intf_desc.iInterface = ret;
+
+ /* data interface label */
+ ret = usb_string_id(c->cdev);
+ if (ret < 0)
+ goto err;
+ tcm_us_strings[1].id = ret;
+ uasp_intf_desc.iInterface = ret;
+
+ ret = usb_add_function(c, &fu->function);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ kfree(fu);
+ return ret;
+}
+
+static int f_tcm_init(int (*connect_cb)(bool connect))
+{
+ int ret;
+
+ usbg_connect_cb = connect_cb;
+ ret = usbg_register_configfs();
+ return ret;
+}
+
+static void f_tcm_exit(void)
+{
+ usbg_deregister_configfs();
+ usbg_connect_cb = NULL;
+}
diff --git a/drivers/usb/gadget/tcm_usb_gadget.h b/drivers/usb/gadget/f_tcm.h
similarity index 93%
rename from drivers/usb/gadget/tcm_usb_gadget.h
rename to drivers/usb/gadget/f_tcm.h
index bb18999..bed8435 100644
--- a/drivers/usb/gadget/tcm_usb_gadget.h
+++ b/drivers/usb/gadget/f_tcm.h
@@ -16,13 +16,6 @@
#define UASP_SS_EP_COMP_LOG_STREAMS 4
#define UASP_SS_EP_COMP_NUM_STREAMS (1 << UASP_SS_EP_COMP_LOG_STREAMS)
-#define USB_G_STR_MANUFACTOR 1
-#define USB_G_STR_PRODUCT 2
-#define USB_G_STR_SERIAL 3
-#define USB_G_STR_CONFIG 4
-#define USB_G_STR_INT_UAS 5
-#define USB_G_STR_INT_BBB 6
-
#define USB_G_ALT_INT_BBB 0
#define USB_G_ALT_INT_UAS 1
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 3e40552..297c183 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -190,6 +190,8 @@
/* max power requested by selected configuration */
unsigned b_max_pow;
unsigned chg_current;
+ unsigned chg_type_retry_cnt;
+ bool proprietary_chg;
struct delayed_work chg_det;
struct delayed_work chg_stop;
struct msm_hsusb_gadget_platform_data *pdata;
@@ -294,11 +296,18 @@
{
if ((readl(USB_PORTSC) & PORTSC_LS) == PORTSC_LS)
return USB_CHG_TYPE__WALLCHARGER;
- else
- return USB_CHG_TYPE__SDP;
+ else {
+ if (ui->gadget.speed == USB_SPEED_LOW ||
+ ui->gadget.speed == USB_SPEED_FULL ||
+ ui->gadget.speed == USB_SPEED_HIGH)
+ return USB_CHG_TYPE__SDP;
+ else
+ return USB_CHG_TYPE__INVALID;
+ }
}
#define USB_WALLCHARGER_CHG_CURRENT 1800
+#define USB_PROPRIETARY_CHG_CURRENT 500
static int usb_get_max_power(struct usb_info *ui)
{
struct msm_otg *otg = to_msm_otg(ui->xceiv);
@@ -321,8 +330,10 @@
if (temp == USB_CHG_TYPE__INVALID)
return -ENODEV;
- if (temp == USB_CHG_TYPE__WALLCHARGER)
+ if (temp == USB_CHG_TYPE__WALLCHARGER && !ui->proprietary_chg)
return USB_WALLCHARGER_CHG_CURRENT;
+ else
+ return USB_PROPRIETARY_CHG_CURRENT;
if (suspended || !configured)
return 0;
@@ -428,6 +439,17 @@
}
temp = usb_get_chg_type(ui);
+ if (temp != USB_CHG_TYPE__WALLCHARGER && temp != USB_CHG_TYPE__SDP
+ && !ui->chg_type_retry_cnt) {
+ schedule_delayed_work(&ui->chg_det, USB_CHG_DET_DELAY);
+ ui->chg_type_retry_cnt++;
+ spin_unlock_irqrestore(&ui->lock, flags);
+ return;
+ }
+ if (temp == USB_CHG_TYPE__INVALID) {
+ temp = USB_CHG_TYPE__WALLCHARGER;
+ ui->proprietary_chg = true;
+ }
spin_unlock_irqrestore(&ui->lock, flags);
atomic_set(&otg->chg_type, temp);
@@ -1737,6 +1759,8 @@
ui->gadget.speed = USB_SPEED_UNKNOWN;
ui->usb_state = USB_STATE_NOTATTACHED;
ui->flags |= USB_FLAG_VBUS_OFFLINE;
+ ui->chg_type_retry_cnt = 0;
+ ui->proprietary_chg = false;
}
if (in_interrupt()) {
schedule_work(&ui->work);
diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c
index c46439c..8787768 100644
--- a/drivers/usb/gadget/tcm_usb_gadget.c
+++ b/drivers/usb/gadget/tcm_usb_gadget.c
@@ -1,4 +1,4 @@
-/* Target based USB-Gadget
+/* Target based USB-Gadget Function
*
* UAS protocol handling, target callbacks, configfs handling,
* BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling.
@@ -6,2208 +6,28 @@
* Author: Sebastian Andrzej Siewior <bigeasy at linutronix dot de>
* License: GPLv2 as published by FSF.
*/
-#include <linux/kernel.h>
+
+#include <linux/init.h>
#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/configfs.h>
-#include <linux/ctype.h>
-#include <linux/usb/ch9.h>
+
#include <linux/usb/composite.h>
#include <linux/usb/gadget.h>
-#include <linux/usb/storage.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_tcq.h>
-#include <target/target_core_base.h>
-#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
-#include <target/target_core_configfs.h>
-#include <target/configfs_macros.h>
-#include <asm/unaligned.h>
#include "usbstring.c"
#include "epautoconf.c"
#include "config.c"
#include "composite.c"
-#include "tcm_usb_gadget.h"
-
-static struct target_fabric_configfs *usbg_fabric_configfs;
-
-static inline struct f_uas *to_f_uas(struct usb_function *f)
-{
- return container_of(f, struct f_uas, function);
-}
-
-static void usbg_cmd_release(struct kref *);
-
-static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd)
-{
- kref_put(&cmd->ref, usbg_cmd_release);
-}
-
-/* Start bot.c code */
-
-static int bot_enqueue_cmd_cbw(struct f_uas *fu)
-{
- int ret;
-
- if (fu->flags & USBG_BOT_CMD_PEND)
- return 0;
-
- ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC);
- if (!ret)
- fu->flags |= USBG_BOT_CMD_PEND;
- return ret;
-}
-
-static void bot_status_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct usbg_cmd *cmd = req->context;
- struct f_uas *fu = cmd->fu;
-
- usbg_cleanup_cmd(cmd);
- if (req->status < 0) {
- pr_err("ERR %s(%d)\n", __func__, __LINE__);
- return;
- }
-
- /* CSW completed, wait for next CBW */
- bot_enqueue_cmd_cbw(fu);
-}
-
-static void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd)
-{
- struct bulk_cs_wrap *csw = &fu->bot_status.csw;
- int ret;
- u8 *sense;
- unsigned int csw_stat;
-
- csw_stat = cmd->csw_code;
-
- /*
- * We can't send SENSE as a response. So we take ASC & ASCQ from our
- * sense buffer and queue it and hope the host sends a REQUEST_SENSE
- * command where it learns why we failed.
- */
- sense = cmd->sense_iu.sense;
-
- csw->Tag = cmd->bot_tag;
- csw->Status = csw_stat;
- fu->bot_status.req->context = cmd;
- ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
-}
-
-static void bot_err_compl(struct usb_ep *ep, struct usb_request *req)
-{
- struct usbg_cmd *cmd = req->context;
- struct f_uas *fu = cmd->fu;
-
- if (req->status < 0)
- pr_err("ERR %s(%d)\n", __func__, __LINE__);
-
- if (cmd->data_len) {
- if (cmd->data_len > ep->maxpacket) {
- req->length = ep->maxpacket;
- cmd->data_len -= ep->maxpacket;
- } else {
- req->length = cmd->data_len;
- cmd->data_len = 0;
- }
-
- usb_ep_queue(ep, req, GFP_ATOMIC);
- return ;
- }
- bot_enqueue_sense_code(fu, cmd);
-}
-
-static void bot_send_bad_status(struct usbg_cmd *cmd)
-{
- struct f_uas *fu = cmd->fu;
- struct bulk_cs_wrap *csw = &fu->bot_status.csw;
- struct usb_request *req;
- struct usb_ep *ep;
-
- csw->Residue = cpu_to_le32(cmd->data_len);
-
- if (cmd->data_len) {
- if (cmd->is_read) {
- ep = fu->ep_in;
- req = fu->bot_req_in;
- } else {
- ep = fu->ep_out;
- req = fu->bot_req_out;
- }
-
- if (cmd->data_len > fu->ep_in->maxpacket) {
- req->length = ep->maxpacket;
- cmd->data_len -= ep->maxpacket;
- } else {
- req->length = cmd->data_len;
- cmd->data_len = 0;
- }
- req->complete = bot_err_compl;
- req->context = cmd;
- req->buf = fu->cmd.buf;
- usb_ep_queue(ep, req, GFP_KERNEL);
- } else {
- bot_enqueue_sense_code(fu, cmd);
- }
-}
-
-static int bot_send_status(struct usbg_cmd *cmd, bool moved_data)
-{
- struct f_uas *fu = cmd->fu;
- struct bulk_cs_wrap *csw = &fu->bot_status.csw;
- int ret;
-
- if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) {
- if (!moved_data && cmd->data_len) {
- /*
- * the host wants to move data, we don't. Fill / empty
- * the pipe and then send the csw with reside set.
- */
- cmd->csw_code = US_BULK_STAT_OK;
- bot_send_bad_status(cmd);
- return 0;
- }
-
- csw->Tag = cmd->bot_tag;
- csw->Residue = cpu_to_le32(0);
- csw->Status = US_BULK_STAT_OK;
- fu->bot_status.req->context = cmd;
-
- ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL);
- if (ret)
- pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
- } else {
- cmd->csw_code = US_BULK_STAT_FAIL;
- bot_send_bad_status(cmd);
- }
- return 0;
-}
-
-/*
- * Called after command (no data transfer) or after the write (to device)
- * operation is completed
- */
-static int bot_send_status_response(struct usbg_cmd *cmd)
-{
- bool moved_data = false;
-
- if (!cmd->is_read)
- moved_data = true;
- return bot_send_status(cmd, moved_data);
-}
-
-/* Read request completed, now we have to send the CSW */
-static void bot_read_compl(struct usb_ep *ep, struct usb_request *req)
-{
- struct usbg_cmd *cmd = req->context;
-
- if (req->status < 0)
- pr_err("ERR %s(%d)\n", __func__, __LINE__);
-
- bot_send_status(cmd, true);
-}
-
-static int bot_send_read_response(struct usbg_cmd *cmd)
-{
- struct f_uas *fu = cmd->fu;
- struct se_cmd *se_cmd = &cmd->se_cmd;
- struct usb_gadget *gadget = fuas_to_gadget(fu);
- int ret;
-
- if (!cmd->data_len) {
- cmd->csw_code = US_BULK_STAT_PHASE;
- bot_send_bad_status(cmd);
- return 0;
- }
-
- if (!gadget->sg_supported) {
- cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
- if (!cmd->data_buf)
- return -ENOMEM;
-
- sg_copy_to_buffer(se_cmd->t_data_sg,
- se_cmd->t_data_nents,
- cmd->data_buf,
- se_cmd->data_length);
-
- fu->bot_req_in->buf = cmd->data_buf;
- } else {
- fu->bot_req_in->buf = NULL;
- fu->bot_req_in->num_sgs = se_cmd->t_data_nents;
- fu->bot_req_in->sg = se_cmd->t_data_sg;
- }
-
- fu->bot_req_in->complete = bot_read_compl;
- fu->bot_req_in->length = se_cmd->data_length;
- fu->bot_req_in->context = cmd;
- ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d)\n", __func__, __LINE__);
- return 0;
-}
-
-static void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *);
-static int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *);
-
-static int bot_send_write_request(struct usbg_cmd *cmd)
-{
- struct f_uas *fu = cmd->fu;
- struct se_cmd *se_cmd = &cmd->se_cmd;
- struct usb_gadget *gadget = fuas_to_gadget(fu);
- int ret;
-
- init_completion(&cmd->write_complete);
- cmd->fu = fu;
-
- if (!cmd->data_len) {
- cmd->csw_code = US_BULK_STAT_PHASE;
- return -EINVAL;
- }
-
- if (!gadget->sg_supported) {
- cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
- if (!cmd->data_buf)
- return -ENOMEM;
-
- fu->bot_req_out->buf = cmd->data_buf;
- } else {
- fu->bot_req_out->buf = NULL;
- fu->bot_req_out->num_sgs = se_cmd->t_data_nents;
- fu->bot_req_out->sg = se_cmd->t_data_sg;
- }
-
- fu->bot_req_out->complete = usbg_data_write_cmpl;
- fu->bot_req_out->length = se_cmd->data_length;
- fu->bot_req_out->context = cmd;
-
- ret = usbg_prepare_w_request(cmd, fu->bot_req_out);
- if (ret)
- goto cleanup;
- ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL);
- if (ret)
- pr_err("%s(%d)\n", __func__, __LINE__);
-
- wait_for_completion(&cmd->write_complete);
- transport_generic_process_write(se_cmd);
-cleanup:
- return ret;
-}
-
-static int bot_submit_command(struct f_uas *, void *, unsigned int);
-
-static void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct f_uas *fu = req->context;
- int ret;
-
- fu->flags &= ~USBG_BOT_CMD_PEND;
-
- if (req->status < 0)
- return;
-
- ret = bot_submit_command(fu, req->buf, req->actual);
- if (ret)
- pr_err("%s(%d): %d\n", __func__, __LINE__, ret);
-}
-
-static int bot_prepare_reqs(struct f_uas *fu)
-{
- int ret;
-
- fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
- if (!fu->bot_req_in)
- goto err;
-
- fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
- if (!fu->bot_req_out)
- goto err_out;
-
- fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
- if (!fu->cmd.req)
- goto err_cmd;
-
- fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
- if (!fu->bot_status.req)
- goto err_sts;
-
- fu->bot_status.req->buf = &fu->bot_status.csw;
- fu->bot_status.req->length = US_BULK_CS_WRAP_LEN;
- fu->bot_status.req->complete = bot_status_complete;
- fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN);
-
- fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL);
- if (!fu->cmd.buf)
- goto err_buf;
-
- fu->cmd.req->complete = bot_cmd_complete;
- fu->cmd.req->buf = fu->cmd.buf;
- fu->cmd.req->length = fu->ep_out->maxpacket;
- fu->cmd.req->context = fu;
-
- ret = bot_enqueue_cmd_cbw(fu);
- if (ret)
- goto err_queue;
- return 0;
-err_queue:
- kfree(fu->cmd.buf);
- fu->cmd.buf = NULL;
-err_buf:
- usb_ep_free_request(fu->ep_in, fu->bot_status.req);
-err_sts:
- usb_ep_free_request(fu->ep_out, fu->cmd.req);
- fu->cmd.req = NULL;
-err_cmd:
- usb_ep_free_request(fu->ep_out, fu->bot_req_out);
- fu->bot_req_out = NULL;
-err_out:
- usb_ep_free_request(fu->ep_in, fu->bot_req_in);
- fu->bot_req_in = NULL;
-err:
- pr_err("BOT: endpoint setup failed\n");
- return -ENOMEM;
-}
-
-void bot_cleanup_old_alt(struct f_uas *fu)
-{
- if (!(fu->flags & USBG_ENABLED))
- return;
-
- usb_ep_disable(fu->ep_in);
- usb_ep_disable(fu->ep_out);
-
- if (!fu->bot_req_in)
- return;
-
- usb_ep_free_request(fu->ep_in, fu->bot_req_in);
- usb_ep_free_request(fu->ep_out, fu->bot_req_out);
- usb_ep_free_request(fu->ep_out, fu->cmd.req);
- usb_ep_free_request(fu->ep_out, fu->bot_status.req);
-
- kfree(fu->cmd.buf);
-
- fu->bot_req_in = NULL;
- fu->bot_req_out = NULL;
- fu->cmd.req = NULL;
- fu->bot_status.req = NULL;
- fu->cmd.buf = NULL;
-}
-
-static void bot_set_alt(struct f_uas *fu)
-{
- struct usb_function *f = &fu->function;
- struct usb_gadget *gadget = f->config->cdev->gadget;
- int ret;
-
- fu->flags = USBG_IS_BOT;
-
- config_ep_by_speed(gadget, f, fu->ep_in);
- ret = usb_ep_enable(fu->ep_in);
- if (ret)
- goto err_b_in;
-
- config_ep_by_speed(gadget, f, fu->ep_out);
- ret = usb_ep_enable(fu->ep_out);
- if (ret)
- goto err_b_out;
-
- ret = bot_prepare_reqs(fu);
- if (ret)
- goto err_wq;
- fu->flags |= USBG_ENABLED;
- pr_info("Using the BOT protocol\n");
- return;
-err_wq:
- usb_ep_disable(fu->ep_out);
-err_b_out:
- usb_ep_disable(fu->ep_in);
-err_b_in:
- fu->flags = USBG_IS_BOT;
-}
-
-static int usbg_bot_setup(struct usb_function *f,
- const struct usb_ctrlrequest *ctrl)
-{
- struct f_uas *fu = to_f_uas(f);
- struct usb_composite_dev *cdev = f->config->cdev;
- u16 w_value = le16_to_cpu(ctrl->wValue);
- u16 w_length = le16_to_cpu(ctrl->wLength);
- int luns;
- u8 *ret_lun;
-
- switch (ctrl->bRequest) {
- case US_BULK_GET_MAX_LUN:
- if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS |
- USB_RECIP_INTERFACE))
- return -ENOTSUPP;
-
- if (w_length < 1)
- return -EINVAL;
- if (w_value != 0)
- return -EINVAL;
- luns = atomic_read(&fu->tpg->tpg_port_count);
- if (!luns) {
- pr_err("No LUNs configured?\n");
- return -EINVAL;
- }
- /*
- * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be
- * accessed. The upper limit is 0xf
- */
- luns--;
- if (luns > 0xf) {
- pr_info_once("Limiting the number of luns to 16\n");
- luns = 0xf;
- }
- ret_lun = cdev->req->buf;
- *ret_lun = luns;
- cdev->req->length = 1;
- return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
- break;
-
- case US_BULK_RESET_REQUEST:
- /* XXX maybe we should remove previous requests for IN + OUT */
- bot_enqueue_cmd_cbw(fu);
- return 0;
- break;
- };
- return -ENOTSUPP;
-}
-
-/* Start uas.c code */
-
-static void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream)
-{
- /* We have either all three allocated or none */
- if (!stream->req_in)
- return;
-
- usb_ep_free_request(fu->ep_in, stream->req_in);
- usb_ep_free_request(fu->ep_out, stream->req_out);
- usb_ep_free_request(fu->ep_status, stream->req_status);
-
- stream->req_in = NULL;
- stream->req_out = NULL;
- stream->req_status = NULL;
-}
-
-static void uasp_free_cmdreq(struct f_uas *fu)
-{
- usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
- kfree(fu->cmd.buf);
- fu->cmd.req = NULL;
- fu->cmd.buf = NULL;
-}
-
-static void uasp_cleanup_old_alt(struct f_uas *fu)
-{
- int i;
-
- if (!(fu->flags & USBG_ENABLED))
- return;
-
- usb_ep_disable(fu->ep_in);
- usb_ep_disable(fu->ep_out);
- usb_ep_disable(fu->ep_status);
- usb_ep_disable(fu->ep_cmd);
-
- for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++)
- uasp_cleanup_one_stream(fu, &fu->stream[i]);
- uasp_free_cmdreq(fu);
-}
-
-static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req);
-
-static int uasp_prepare_r_request(struct usbg_cmd *cmd)
-{
- struct se_cmd *se_cmd = &cmd->se_cmd;
- struct f_uas *fu = cmd->fu;
- struct usb_gadget *gadget = fuas_to_gadget(fu);
- struct uas_stream *stream = cmd->stream;
-
- if (!gadget->sg_supported) {
- cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
- if (!cmd->data_buf)
- return -ENOMEM;
-
- sg_copy_to_buffer(se_cmd->t_data_sg,
- se_cmd->t_data_nents,
- cmd->data_buf,
- se_cmd->data_length);
-
- stream->req_in->buf = cmd->data_buf;
- } else {
- stream->req_in->buf = NULL;
- stream->req_in->num_sgs = se_cmd->t_data_nents;
- stream->req_in->sg = se_cmd->t_data_sg;
- }
-
- stream->req_in->complete = uasp_status_data_cmpl;
- stream->req_in->length = se_cmd->data_length;
- stream->req_in->context = cmd;
-
- cmd->state = UASP_SEND_STATUS;
- return 0;
-}
-
-static void uasp_prepare_status(struct usbg_cmd *cmd)
-{
- struct se_cmd *se_cmd = &cmd->se_cmd;
- struct sense_iu *iu = &cmd->sense_iu;
- struct uas_stream *stream = cmd->stream;
-
- cmd->state = UASP_QUEUE_COMMAND;
- iu->iu_id = IU_ID_STATUS;
- iu->tag = cpu_to_be16(cmd->tag);
-
- /*
- * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?);
- */
- iu->len = cpu_to_be16(se_cmd->scsi_sense_length);
- iu->status = se_cmd->scsi_status;
- stream->req_status->context = cmd;
- stream->req_status->length = se_cmd->scsi_sense_length + 16;
- stream->req_status->buf = iu;
- stream->req_status->complete = uasp_status_data_cmpl;
-}
-
-static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
-{
- struct usbg_cmd *cmd = req->context;
- struct uas_stream *stream = cmd->stream;
- struct f_uas *fu = cmd->fu;
- int ret;
-
- if (req->status < 0)
- goto cleanup;
-
- switch (cmd->state) {
- case UASP_SEND_DATA:
- ret = uasp_prepare_r_request(cmd);
- if (ret)
- goto cleanup;
- ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
- break;
-
- case UASP_RECEIVE_DATA:
- ret = usbg_prepare_w_request(cmd, stream->req_out);
- if (ret)
- goto cleanup;
- ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
- break;
-
- case UASP_SEND_STATUS:
- uasp_prepare_status(cmd);
- ret = usb_ep_queue(fu->ep_status, stream->req_status,
- GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
- break;
-
- case UASP_QUEUE_COMMAND:
- usbg_cleanup_cmd(cmd);
- usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
- break;
-
- default:
- BUG();
- };
- return;
-
-cleanup:
- usbg_cleanup_cmd(cmd);
-}
-
-static int uasp_send_status_response(struct usbg_cmd *cmd)
-{
- struct f_uas *fu = cmd->fu;
- struct uas_stream *stream = cmd->stream;
- struct sense_iu *iu = &cmd->sense_iu;
-
- iu->tag = cpu_to_be16(cmd->tag);
- stream->req_status->complete = uasp_status_data_cmpl;
- stream->req_status->context = cmd;
- cmd->fu = fu;
- uasp_prepare_status(cmd);
- return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC);
-}
-
-static int uasp_send_read_response(struct usbg_cmd *cmd)
-{
- struct f_uas *fu = cmd->fu;
- struct uas_stream *stream = cmd->stream;
- struct sense_iu *iu = &cmd->sense_iu;
- int ret;
-
- cmd->fu = fu;
-
- iu->tag = cpu_to_be16(cmd->tag);
- if (fu->flags & USBG_USE_STREAMS) {
-
- ret = uasp_prepare_r_request(cmd);
- if (ret)
- goto out;
- ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
- if (ret) {
- pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
- kfree(cmd->data_buf);
- cmd->data_buf = NULL;
- }
-
- } else {
-
- iu->iu_id = IU_ID_READ_READY;
- iu->tag = cpu_to_be16(cmd->tag);
-
- stream->req_status->complete = uasp_status_data_cmpl;
- stream->req_status->context = cmd;
-
- cmd->state = UASP_SEND_DATA;
- stream->req_status->buf = iu;
- stream->req_status->length = sizeof(struct iu);
-
- ret = usb_ep_queue(fu->ep_status, stream->req_status,
- GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
- }
-out:
- return ret;
-}
-
-static int uasp_send_write_request(struct usbg_cmd *cmd)
-{
- struct f_uas *fu = cmd->fu;
- struct se_cmd *se_cmd = &cmd->se_cmd;
- struct uas_stream *stream = cmd->stream;
- struct sense_iu *iu = &cmd->sense_iu;
- int ret;
-
- init_completion(&cmd->write_complete);
- cmd->fu = fu;
-
- iu->tag = cpu_to_be16(cmd->tag);
-
- if (fu->flags & USBG_USE_STREAMS) {
-
- ret = usbg_prepare_w_request(cmd, stream->req_out);
- if (ret)
- goto cleanup;
- ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d)\n", __func__, __LINE__);
-
- } else {
-
- iu->iu_id = IU_ID_WRITE_READY;
- iu->tag = cpu_to_be16(cmd->tag);
-
- stream->req_status->complete = uasp_status_data_cmpl;
- stream->req_status->context = cmd;
-
- cmd->state = UASP_RECEIVE_DATA;
- stream->req_status->buf = iu;
- stream->req_status->length = sizeof(struct iu);
-
- ret = usb_ep_queue(fu->ep_status, stream->req_status,
- GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d)\n", __func__, __LINE__);
- }
-
- wait_for_completion(&cmd->write_complete);
- transport_generic_process_write(se_cmd);
-cleanup:
- return ret;
-}
-
-static int usbg_submit_command(struct f_uas *, void *, unsigned int);
-
-static void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct f_uas *fu = req->context;
- int ret;
-
- if (req->status < 0)
- return;
-
- ret = usbg_submit_command(fu, req->buf, req->actual);
- /*
- * Once we tune for performance enqueue the command req here again so
- * we can receive a second command while we processing this one. Pay
- * attention to properly sync STAUS endpoint with DATA IN + OUT so you
- * don't break HS.
- */
- if (!ret)
- return;
- usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
-}
-
-static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
-{
- stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
- if (!stream->req_in)
- goto out;
-
- stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
- if (!stream->req_out)
- goto err_out;
-
- stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL);
- if (!stream->req_status)
- goto err_sts;
-
- return 0;
-err_sts:
- usb_ep_free_request(fu->ep_status, stream->req_status);
- stream->req_status = NULL;
-err_out:
- usb_ep_free_request(fu->ep_out, stream->req_out);
- stream->req_out = NULL;
-out:
- return -ENOMEM;
-}
-
-static int uasp_alloc_cmd(struct f_uas *fu)
-{
- fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL);
- if (!fu->cmd.req)
- goto err;
-
- fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL);
- if (!fu->cmd.buf)
- goto err_buf;
-
- fu->cmd.req->complete = uasp_cmd_complete;
- fu->cmd.req->buf = fu->cmd.buf;
- fu->cmd.req->length = fu->ep_cmd->maxpacket;
- fu->cmd.req->context = fu;
- return 0;
-
-err_buf:
- usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
-err:
- return -ENOMEM;
-}
-
-static void uasp_setup_stream_res(struct f_uas *fu, int max_streams)
-{
- int i;
-
- for (i = 0; i < max_streams; i++) {
- struct uas_stream *s = &fu->stream[i];
-
- s->req_in->stream_id = i + 1;
- s->req_out->stream_id = i + 1;
- s->req_status->stream_id = i + 1;
- }
-}
-
-static int uasp_prepare_reqs(struct f_uas *fu)
-{
- int ret;
- int i;
- int max_streams;
-
- if (fu->flags & USBG_USE_STREAMS)
- max_streams = UASP_SS_EP_COMP_NUM_STREAMS;
- else
- max_streams = 1;
-
- for (i = 0; i < max_streams; i++) {
- ret = uasp_alloc_stream_res(fu, &fu->stream[i]);
- if (ret)
- goto err_cleanup;
- }
-
- ret = uasp_alloc_cmd(fu);
- if (ret)
- goto err_free_stream;
- uasp_setup_stream_res(fu, max_streams);
-
- ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
- if (ret)
- goto err_free_stream;
-
- return 0;
-
-err_free_stream:
- uasp_free_cmdreq(fu);
-
-err_cleanup:
- if (i) {
- do {
- uasp_cleanup_one_stream(fu, &fu->stream[i - 1]);
- i--;
- } while (i);
- }
- pr_err("UASP: endpoint setup failed\n");
- return ret;
-}
-
-static void uasp_set_alt(struct f_uas *fu)
-{
- struct usb_function *f = &fu->function;
- struct usb_gadget *gadget = f->config->cdev->gadget;
- int ret;
-
- fu->flags = USBG_IS_UAS;
-
- if (gadget->speed == USB_SPEED_SUPER)
- fu->flags |= USBG_USE_STREAMS;
-
- config_ep_by_speed(gadget, f, fu->ep_in);
- ret = usb_ep_enable(fu->ep_in);
- if (ret)
- goto err_b_in;
-
- config_ep_by_speed(gadget, f, fu->ep_out);
- ret = usb_ep_enable(fu->ep_out);
- if (ret)
- goto err_b_out;
-
- config_ep_by_speed(gadget, f, fu->ep_cmd);
- ret = usb_ep_enable(fu->ep_cmd);
- if (ret)
- goto err_cmd;
- config_ep_by_speed(gadget, f, fu->ep_status);
- ret = usb_ep_enable(fu->ep_status);
- if (ret)
- goto err_status;
-
- ret = uasp_prepare_reqs(fu);
- if (ret)
- goto err_wq;
- fu->flags |= USBG_ENABLED;
-
- pr_info("Using the UAS protocol\n");
- return;
-err_wq:
- usb_ep_disable(fu->ep_status);
-err_status:
- usb_ep_disable(fu->ep_cmd);
-err_cmd:
- usb_ep_disable(fu->ep_out);
-err_b_out:
- usb_ep_disable(fu->ep_in);
-err_b_in:
- fu->flags = 0;
-}
-
-static int get_cmd_dir(const unsigned char *cdb)
-{
- int ret;
-
- switch (cdb[0]) {
- case READ_6:
- case READ_10:
- case READ_12:
- case READ_16:
- case INQUIRY:
- case MODE_SENSE:
- case MODE_SENSE_10:
- case SERVICE_ACTION_IN:
- case MAINTENANCE_IN:
- case PERSISTENT_RESERVE_IN:
- case SECURITY_PROTOCOL_IN:
- case ACCESS_CONTROL_IN:
- case REPORT_LUNS:
- case READ_BLOCK_LIMITS:
- case READ_POSITION:
- case READ_CAPACITY:
- case READ_TOC:
- case READ_FORMAT_CAPACITIES:
- case REQUEST_SENSE:
- ret = DMA_FROM_DEVICE;
- break;
-
- case WRITE_6:
- case WRITE_10:
- case WRITE_12:
- case WRITE_16:
- case MODE_SELECT:
- case MODE_SELECT_10:
- case WRITE_VERIFY:
- case WRITE_VERIFY_12:
- case PERSISTENT_RESERVE_OUT:
- case MAINTENANCE_OUT:
- case SECURITY_PROTOCOL_OUT:
- case ACCESS_CONTROL_OUT:
- ret = DMA_TO_DEVICE;
- break;
- case ALLOW_MEDIUM_REMOVAL:
- case TEST_UNIT_READY:
- case SYNCHRONIZE_CACHE:
- case START_STOP:
- case ERASE:
- case REZERO_UNIT:
- case SEEK_10:
- case SPACE:
- case VERIFY:
- case WRITE_FILEMARKS:
- ret = DMA_NONE;
- break;
- default:
- pr_warn("target: Unknown data direction for SCSI Opcode "
- "0x%02x\n", cdb[0]);
- ret = -EINVAL;
- }
- return ret;
-}
-
-static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req)
-{
- struct usbg_cmd *cmd = req->context;
- struct se_cmd *se_cmd = &cmd->se_cmd;
-
- if (req->status < 0) {
- pr_err("%s() state %d transfer failed\n", __func__, cmd->state);
- goto cleanup;
- }
-
- if (req->num_sgs == 0) {
- sg_copy_from_buffer(se_cmd->t_data_sg,
- se_cmd->t_data_nents,
- cmd->data_buf,
- se_cmd->data_length);
- }
-
- complete(&cmd->write_complete);
- return;
-
-cleanup:
- usbg_cleanup_cmd(cmd);
-}
-
-static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req)
-{
- struct se_cmd *se_cmd = &cmd->se_cmd;
- struct f_uas *fu = cmd->fu;
- struct usb_gadget *gadget = fuas_to_gadget(fu);
-
- if (!gadget->sg_supported) {
- cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
- if (!cmd->data_buf)
- return -ENOMEM;
-
- req->buf = cmd->data_buf;
- } else {
- req->buf = NULL;
- req->num_sgs = se_cmd->t_data_nents;
- req->sg = se_cmd->t_data_sg;
- }
-
- req->complete = usbg_data_write_cmpl;
- req->length = se_cmd->data_length;
- req->context = cmd;
- return 0;
-}
-
-static int usbg_send_status_response(struct se_cmd *se_cmd)
-{
- struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
- se_cmd);
- struct f_uas *fu = cmd->fu;
-
- if (fu->flags & USBG_IS_BOT)
- return bot_send_status_response(cmd);
- else
- return uasp_send_status_response(cmd);
-}
-
-static int usbg_send_write_request(struct se_cmd *se_cmd)
-{
- struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
- se_cmd);
- struct f_uas *fu = cmd->fu;
-
- if (fu->flags & USBG_IS_BOT)
- return bot_send_write_request(cmd);
- else
- return uasp_send_write_request(cmd);
-}
-
-static int usbg_send_read_response(struct se_cmd *se_cmd)
-{
- struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
- se_cmd);
- struct f_uas *fu = cmd->fu;
-
- if (fu->flags & USBG_IS_BOT)
- return bot_send_read_response(cmd);
- else
- return uasp_send_read_response(cmd);
-}
-
-static void usbg_cmd_work(struct work_struct *work)
-{
- struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
- struct se_cmd *se_cmd;
- struct tcm_usbg_nexus *tv_nexus;
- struct usbg_tpg *tpg;
- int dir;
-
- se_cmd = &cmd->se_cmd;
- tpg = cmd->fu->tpg;
- tv_nexus = tpg->tpg_nexus;
- dir = get_cmd_dir(cmd->cmd_buf);
- if (dir < 0) {
- transport_init_se_cmd(se_cmd,
- tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
- tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
- cmd->prio_attr, cmd->sense_iu.sense);
-
- transport_send_check_condition_and_sense(se_cmd,
- TCM_UNSUPPORTED_SCSI_OPCODE, 1);
- usbg_cleanup_cmd(cmd);
- return;
- }
-
- target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
- cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
- 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE);
-}
-
-static int usbg_submit_command(struct f_uas *fu,
- void *cmdbuf, unsigned int len)
-{
- struct command_iu *cmd_iu = cmdbuf;
- struct usbg_cmd *cmd;
- struct usbg_tpg *tpg;
- struct se_cmd *se_cmd;
- struct tcm_usbg_nexus *tv_nexus;
- u32 cmd_len;
- int ret;
-
- if (cmd_iu->iu_id != IU_ID_COMMAND) {
- pr_err("Unsupported type %d\n", cmd_iu->iu_id);
- return -EINVAL;
- }
-
- cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
- if (!cmd)
- return -ENOMEM;
-
- cmd->fu = fu;
-
- /* XXX until I figure out why I can't free in on complete */
- kref_init(&cmd->ref);
- kref_get(&cmd->ref);
-
- tpg = fu->tpg;
- cmd_len = (cmd_iu->len & ~0x3) + 16;
- if (cmd_len > USBG_MAX_CMD)
- goto err;
-
- memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len);
-
- cmd->tag = be16_to_cpup(&cmd_iu->tag);
- if (fu->flags & USBG_USE_STREAMS) {
- if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS)
- goto err;
- if (!cmd->tag)
- cmd->stream = &fu->stream[0];
- else
- cmd->stream = &fu->stream[cmd->tag - 1];
- } else {
- cmd->stream = &fu->stream[0];
- }
-
- tv_nexus = tpg->tpg_nexus;
- if (!tv_nexus) {
- pr_err("Missing nexus, ignoring command\n");
- goto err;
- }
-
- switch (cmd_iu->prio_attr & 0x7) {
- case UAS_HEAD_TAG:
- cmd->prio_attr = MSG_HEAD_TAG;
- break;
- case UAS_ORDERED_TAG:
- cmd->prio_attr = MSG_ORDERED_TAG;
- break;
- case UAS_ACA:
- cmd->prio_attr = MSG_ACA_TAG;
- break;
- default:
- pr_debug_once("Unsupported prio_attr: %02x.\n",
- cmd_iu->prio_attr);
- case UAS_SIMPLE_TAG:
- cmd->prio_attr = MSG_SIMPLE_TAG;
- break;
- }
-
- se_cmd = &cmd->se_cmd;
- cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun);
-
- INIT_WORK(&cmd->work, usbg_cmd_work);
- ret = queue_work(tpg->workqueue, &cmd->work);
- if (ret < 0)
- goto err;
-
- return 0;
-err:
- kfree(cmd);
- return -EINVAL;
-}
-
-static void bot_cmd_work(struct work_struct *work)
-{
- struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
- struct se_cmd *se_cmd;
- struct tcm_usbg_nexus *tv_nexus;
- struct usbg_tpg *tpg;
- int dir;
-
- se_cmd = &cmd->se_cmd;
- tpg = cmd->fu->tpg;
- tv_nexus = tpg->tpg_nexus;
- dir = get_cmd_dir(cmd->cmd_buf);
- if (dir < 0) {
- transport_init_se_cmd(se_cmd,
- tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
- tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
- cmd->prio_attr, cmd->sense_iu.sense);
-
- transport_send_check_condition_and_sense(se_cmd,
- TCM_UNSUPPORTED_SCSI_OPCODE, 1);
- usbg_cleanup_cmd(cmd);
- return;
- }
-
- target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
- cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
- cmd->data_len, cmd->prio_attr, dir, 0);
-}
-
-static int bot_submit_command(struct f_uas *fu,
- void *cmdbuf, unsigned int len)
-{
- struct bulk_cb_wrap *cbw = cmdbuf;
- struct usbg_cmd *cmd;
- struct usbg_tpg *tpg;
- struct se_cmd *se_cmd;
- struct tcm_usbg_nexus *tv_nexus;
- u32 cmd_len;
- int ret;
-
- if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) {
- pr_err("Wrong signature on CBW\n");
- return -EINVAL;
- }
- if (len != 31) {
- pr_err("Wrong length for CBW\n");
- return -EINVAL;
- }
-
- cmd_len = cbw->Length;
- if (cmd_len < 1 || cmd_len > 16)
- return -EINVAL;
-
- cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
- if (!cmd)
- return -ENOMEM;
-
- cmd->fu = fu;
-
- /* XXX until I figure out why I can't free in on complete */
- kref_init(&cmd->ref);
- kref_get(&cmd->ref);
-
- tpg = fu->tpg;
-
- memcpy(cmd->cmd_buf, cbw->CDB, cmd_len);
-
- cmd->bot_tag = cbw->Tag;
-
- tv_nexus = tpg->tpg_nexus;
- if (!tv_nexus) {
- pr_err("Missing nexus, ignoring command\n");
- goto err;
- }
-
- cmd->prio_attr = MSG_SIMPLE_TAG;
- se_cmd = &cmd->se_cmd;
- cmd->unpacked_lun = cbw->Lun;
- cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0;
- cmd->data_len = le32_to_cpu(cbw->DataTransferLength);
-
- INIT_WORK(&cmd->work, bot_cmd_work);
- ret = queue_work(tpg->workqueue, &cmd->work);
- if (ret < 0)
- goto err;
-
- return 0;
-err:
- kfree(cmd);
- return -EINVAL;
-}
-
-/* Start fabric.c code */
-
-static int usbg_check_true(struct se_portal_group *se_tpg)
-{
- return 1;
-}
-
-static int usbg_check_false(struct se_portal_group *se_tpg)
-{
- return 0;
-}
-
-static char *usbg_get_fabric_name(void)
-{
- return "usb_gadget";
-}
-
-static u8 usbg_get_fabric_proto_ident(struct se_portal_group *se_tpg)
-{
- struct usbg_tpg *tpg = container_of(se_tpg,
- struct usbg_tpg, se_tpg);
- struct usbg_tport *tport = tpg->tport;
- u8 proto_id;
-
- switch (tport->tport_proto_id) {
- case SCSI_PROTOCOL_SAS:
- default:
- proto_id = sas_get_fabric_proto_ident(se_tpg);
- break;
- }
-
- return proto_id;
-}
-
-static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg)
-{
- struct usbg_tpg *tpg = container_of(se_tpg,
- struct usbg_tpg, se_tpg);
- struct usbg_tport *tport = tpg->tport;
-
- return &tport->tport_name[0];
-}
-
-static u16 usbg_get_tag(struct se_portal_group *se_tpg)
-{
- struct usbg_tpg *tpg = container_of(se_tpg,
- struct usbg_tpg, se_tpg);
- return tpg->tport_tpgt;
-}
-
-static u32 usbg_get_default_depth(struct se_portal_group *se_tpg)
-{
- return 1;
-}
-
-static u32 usbg_get_pr_transport_id(
- struct se_portal_group *se_tpg,
- struct se_node_acl *se_nacl,
- struct t10_pr_registration *pr_reg,
- int *format_code,
- unsigned char *buf)
-{
- struct usbg_tpg *tpg = container_of(se_tpg,
- struct usbg_tpg, se_tpg);
- struct usbg_tport *tport = tpg->tport;
- int ret = 0;
-
- switch (tport->tport_proto_id) {
- case SCSI_PROTOCOL_SAS:
- default:
- ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
- format_code, buf);
- break;
- }
-
- return ret;
-}
-
-static u32 usbg_get_pr_transport_id_len(
- struct se_portal_group *se_tpg,
- struct se_node_acl *se_nacl,
- struct t10_pr_registration *pr_reg,
- int *format_code)
-{
- struct usbg_tpg *tpg = container_of(se_tpg,
- struct usbg_tpg, se_tpg);
- struct usbg_tport *tport = tpg->tport;
- int ret = 0;
-
- switch (tport->tport_proto_id) {
- case SCSI_PROTOCOL_SAS:
- default:
- ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
- format_code);
- break;
- }
-
- return ret;
-}
-
-static char *usbg_parse_pr_out_transport_id(
- struct se_portal_group *se_tpg,
- const char *buf,
- u32 *out_tid_len,
- char **port_nexus_ptr)
-{
- struct usbg_tpg *tpg = container_of(se_tpg,
- struct usbg_tpg, se_tpg);
- struct usbg_tport *tport = tpg->tport;
- char *tid = NULL;
-
- switch (tport->tport_proto_id) {
- case SCSI_PROTOCOL_SAS:
- default:
- tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
- port_nexus_ptr);
- }
-
- return tid;
-}
-
-static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg)
-{
- struct usbg_nacl *nacl;
-
- nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL);
- if (!nacl) {
- printk(KERN_ERR "Unable to alocate struct usbg_nacl\n");
- return NULL;
- }
-
- return &nacl->se_node_acl;
-}
-
-static void usbg_release_fabric_acl(
- struct se_portal_group *se_tpg,
- struct se_node_acl *se_nacl)
-{
- struct usbg_nacl *nacl = container_of(se_nacl,
- struct usbg_nacl, se_node_acl);
- kfree(nacl);
-}
-
-static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg)
-{
- return 1;
-}
-
-static int usbg_new_cmd(struct se_cmd *se_cmd)
-{
- struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
- se_cmd);
- int ret;
-
- ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf);
- if (ret)
- return ret;
-
- return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0);
-}
-
-static void usbg_cmd_release(struct kref *ref)
-{
- struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd,
- ref);
-
- transport_generic_free_cmd(&cmd->se_cmd, 0);
-}
-
-static void usbg_release_cmd(struct se_cmd *se_cmd)
-{
- struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
- se_cmd);
- kfree(cmd->data_buf);
- kfree(cmd);
- return;
-}
-
-static int usbg_shutdown_session(struct se_session *se_sess)
-{
- return 0;
-}
-
-static void usbg_close_session(struct se_session *se_sess)
-{
- return;
-}
-
-static u32 usbg_sess_get_index(struct se_session *se_sess)
-{
- return 0;
-}
-
-/*
- * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be
- */
-static int usbg_write_pending_status(struct se_cmd *se_cmd)
-{
- return 0;
-}
-
-static void usbg_set_default_node_attrs(struct se_node_acl *nacl)
-{
- return;
-}
-
-static u32 usbg_get_task_tag(struct se_cmd *se_cmd)
-{
- struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
- se_cmd);
- struct f_uas *fu = cmd->fu;
-
- if (fu->flags & USBG_IS_BOT)
- return le32_to_cpu(cmd->bot_tag);
- else
- return cmd->tag;
-}
-
-static int usbg_get_cmd_state(struct se_cmd *se_cmd)
-{
- return 0;
-}
-
-static int usbg_queue_tm_rsp(struct se_cmd *se_cmd)
-{
- return 0;
-}
-
-static u16 usbg_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
-{
- return 0;
-}
-
-static u16 usbg_get_fabric_sense_len(void)
-{
- return 0;
-}
-
-static const char *usbg_check_wwn(const char *name)
-{
- const char *n;
- unsigned int len;
-
- n = strstr(name, "naa.");
- if (!n)
- return NULL;
- n += 4;
- len = strlen(n);
- if (len == 0 || len > USBG_NAMELEN - 1)
- return NULL;
- return n;
-}
-
-static struct se_node_acl *usbg_make_nodeacl(
- struct se_portal_group *se_tpg,
- struct config_group *group,
- const char *name)
-{
- struct se_node_acl *se_nacl, *se_nacl_new;
- struct usbg_nacl *nacl;
- u64 wwpn = 0;
- u32 nexus_depth;
- const char *wnn_name;
-
- wnn_name = usbg_check_wwn(name);
- if (!wnn_name)
- return ERR_PTR(-EINVAL);
- se_nacl_new = usbg_alloc_fabric_acl(se_tpg);
- if (!(se_nacl_new))
- return ERR_PTR(-ENOMEM);
-
- nexus_depth = 1;
- /*
- * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
- * when converting a NodeACL from demo mode -> explict
- */
- se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
- name, nexus_depth);
- if (IS_ERR(se_nacl)) {
- usbg_release_fabric_acl(se_tpg, se_nacl_new);
- return se_nacl;
- }
- /*
- * Locate our struct usbg_nacl and set the FC Nport WWPN
- */
- nacl = container_of(se_nacl, struct usbg_nacl, se_node_acl);
- nacl->iport_wwpn = wwpn;
- snprintf(nacl->iport_name, sizeof(nacl->iport_name), "%s", name);
- return se_nacl;
-}
-
-static void usbg_drop_nodeacl(struct se_node_acl *se_acl)
-{
- struct usbg_nacl *nacl = container_of(se_acl,
- struct usbg_nacl, se_node_acl);
- core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
- kfree(nacl);
-}
-
-struct usbg_tpg *the_only_tpg_I_currently_have;
-
-static struct se_portal_group *usbg_make_tpg(
- struct se_wwn *wwn,
- struct config_group *group,
- const char *name)
-{
- struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
- tport_wwn);
- struct usbg_tpg *tpg;
- unsigned long tpgt;
- int ret;
-
- if (strstr(name, "tpgt_") != name)
- return ERR_PTR(-EINVAL);
- if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
- return ERR_PTR(-EINVAL);
- if (the_only_tpg_I_currently_have) {
- pr_err("Until the gadget framework can't handle multiple\n");
- pr_err("gadgets, you can't do this here.\n");
- return ERR_PTR(-EBUSY);
- }
-
- tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
- if (!tpg) {
- printk(KERN_ERR "Unable to allocate struct usbg_tpg");
- return ERR_PTR(-ENOMEM);
- }
- mutex_init(&tpg->tpg_mutex);
- atomic_set(&tpg->tpg_port_count, 0);
- tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1);
- if (!tpg->workqueue) {
- kfree(tpg);
- return NULL;
- }
-
- tpg->tport = tport;
- tpg->tport_tpgt = tpgt;
-
- ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn,
- &tpg->se_tpg, tpg,
- TRANSPORT_TPG_TYPE_NORMAL);
- if (ret < 0) {
- destroy_workqueue(tpg->workqueue);
- kfree(tpg);
- return NULL;
- }
- the_only_tpg_I_currently_have = tpg;
- return &tpg->se_tpg;
-}
-
-static void usbg_drop_tpg(struct se_portal_group *se_tpg)
-{
- struct usbg_tpg *tpg = container_of(se_tpg,
- struct usbg_tpg, se_tpg);
-
- core_tpg_deregister(se_tpg);
- destroy_workqueue(tpg->workqueue);
- kfree(tpg);
- the_only_tpg_I_currently_have = NULL;
-}
-
-static struct se_wwn *usbg_make_tport(
- struct target_fabric_configfs *tf,
- struct config_group *group,
- const char *name)
-{
- struct usbg_tport *tport;
- const char *wnn_name;
- u64 wwpn = 0;
-
- wnn_name = usbg_check_wwn(name);
- if (!wnn_name)
- return ERR_PTR(-EINVAL);
-
- tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL);
- if (!(tport)) {
- printk(KERN_ERR "Unable to allocate struct usbg_tport");
- return ERR_PTR(-ENOMEM);
- }
- tport->tport_wwpn = wwpn;
- snprintf(tport->tport_name, sizeof(tport->tport_name), wnn_name);
- return &tport->tport_wwn;
-}
-
-static void usbg_drop_tport(struct se_wwn *wwn)
-{
- struct usbg_tport *tport = container_of(wwn,
- struct usbg_tport, tport_wwn);
- kfree(tport);
-}
-
-/*
- * If somebody feels like dropping the version property, go ahead.
- */
-static ssize_t usbg_wwn_show_attr_version(
- struct target_fabric_configfs *tf,
- char *page)
-{
- return sprintf(page, "usb-gadget fabric module\n");
-}
-TF_WWN_ATTR_RO(usbg, version);
-
-static struct configfs_attribute *usbg_wwn_attrs[] = {
- &usbg_wwn_version.attr,
- NULL,
-};
-
-static ssize_t tcm_usbg_tpg_show_enable(
- struct se_portal_group *se_tpg,
- char *page)
-{
- struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-
- return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect);
-}
-
-static int usbg_attach(struct usbg_tpg *);
-static void usbg_detach(struct usbg_tpg *);
-
-static ssize_t tcm_usbg_tpg_store_enable(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
-{
- struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
- unsigned long op;
- ssize_t ret;
-
- ret = kstrtoul(page, 0, &op);
- if (ret < 0)
- return -EINVAL;
- if (op > 1)
- return -EINVAL;
-
- if (op && tpg->gadget_connect)
- goto out;
- if (!op && !tpg->gadget_connect)
- goto out;
-
- if (op) {
- ret = usbg_attach(tpg);
- if (ret)
- goto out;
- } else {
- usbg_detach(tpg);
- }
- tpg->gadget_connect = op;
-out:
- return count;
-}
-TF_TPG_BASE_ATTR(tcm_usbg, enable, S_IRUGO | S_IWUSR);
-
-static ssize_t tcm_usbg_tpg_show_nexus(
- struct se_portal_group *se_tpg,
- char *page)
-{
- struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
- struct tcm_usbg_nexus *tv_nexus;
- ssize_t ret;
-
- mutex_lock(&tpg->tpg_mutex);
- tv_nexus = tpg->tpg_nexus;
- if (!tv_nexus) {
- ret = -ENODEV;
- goto out;
- }
- ret = snprintf(page, PAGE_SIZE, "%s\n",
- tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
-out:
- mutex_unlock(&tpg->tpg_mutex);
- return ret;
-}
-
-static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
-{
- struct se_portal_group *se_tpg;
- struct tcm_usbg_nexus *tv_nexus;
- int ret;
-
- mutex_lock(&tpg->tpg_mutex);
- if (tpg->tpg_nexus) {
- ret = -EEXIST;
- pr_debug("tpg->tpg_nexus already exists\n");
- goto err_unlock;
- }
- se_tpg = &tpg->se_tpg;
-
- ret = -ENOMEM;
- tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
- if (!tv_nexus) {
- pr_err("Unable to allocate struct tcm_vhost_nexus\n");
- goto err_unlock;
- }
- tv_nexus->tvn_se_sess = transport_init_session();
- if (IS_ERR(tv_nexus->tvn_se_sess))
- goto err_free;
-
- /*
- * Since we are running in 'demo mode' this call with generate a
- * struct se_node_acl for the tcm_vhost struct se_portal_group with
- * the SCSI Initiator port name of the passed configfs group 'name'.
- */
- tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
- se_tpg, name);
- if (!tv_nexus->tvn_se_sess->se_node_acl) {
- pr_debug("core_tpg_check_initiator_node_acl() failed"
- " for %s\n", name);
- goto err_session;
- }
- /*
- * Now register the TCM vHost virtual I_T Nexus as active with the
- * call to __transport_register_session()
- */
- __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
- tv_nexus->tvn_se_sess, tv_nexus);
- tpg->tpg_nexus = tv_nexus;
- mutex_unlock(&tpg->tpg_mutex);
- return 0;
-
-err_session:
- transport_free_session(tv_nexus->tvn_se_sess);
-err_free:
- kfree(tv_nexus);
-err_unlock:
- mutex_unlock(&tpg->tpg_mutex);
- return ret;
-}
-
-static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg)
-{
- struct se_session *se_sess;
- struct tcm_usbg_nexus *tv_nexus;
- int ret = -ENODEV;
-
- mutex_lock(&tpg->tpg_mutex);
- tv_nexus = tpg->tpg_nexus;
- if (!tv_nexus)
- goto out;
-
- se_sess = tv_nexus->tvn_se_sess;
- if (!se_sess)
- goto out;
-
- if (atomic_read(&tpg->tpg_port_count)) {
- ret = -EPERM;
- pr_err("Unable to remove Host I_T Nexus with"
- " active TPG port count: %d\n",
- atomic_read(&tpg->tpg_port_count));
- goto out;
- }
-
- pr_debug("Removing I_T Nexus to Initiator Port: %s\n",
- tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
- /*
- * Release the SCSI I_T Nexus to the emulated vHost Target Port
- */
- transport_deregister_session(tv_nexus->tvn_se_sess);
- tpg->tpg_nexus = NULL;
-
- kfree(tv_nexus);
-out:
- mutex_unlock(&tpg->tpg_mutex);
- return 0;
-}
-
-static ssize_t tcm_usbg_tpg_store_nexus(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
-{
- struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
- unsigned char i_port[USBG_NAMELEN], *ptr;
- int ret;
-
- if (!strncmp(page, "NULL", 4)) {
- ret = tcm_usbg_drop_nexus(tpg);
- return (!ret) ? count : ret;
- }
- if (strlen(page) > USBG_NAMELEN) {
- pr_err("Emulated NAA Sas Address: %s, exceeds"
- " max: %d\n", page, USBG_NAMELEN);
- return -EINVAL;
- }
- snprintf(i_port, USBG_NAMELEN, "%s", page);
-
- ptr = strstr(i_port, "naa.");
- if (!ptr) {
- pr_err("Missing 'naa.' prefix\n");
- return -EINVAL;
- }
-
- if (i_port[strlen(i_port) - 1] == '\n')
- i_port[strlen(i_port) - 1] = '\0';
-
- ret = tcm_usbg_make_nexus(tpg, &i_port[4]);
- if (ret < 0)
- return ret;
- return count;
-}
-TF_TPG_BASE_ATTR(tcm_usbg, nexus, S_IRUGO | S_IWUSR);
-
-static struct configfs_attribute *usbg_base_attrs[] = {
- &tcm_usbg_tpg_enable.attr,
- &tcm_usbg_tpg_nexus.attr,
- NULL,
-};
-
-static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)
-{
- struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-
- atomic_inc(&tpg->tpg_port_count);
- smp_mb__after_atomic_inc();
- return 0;
-}
-
-static void usbg_port_unlink(struct se_portal_group *se_tpg,
- struct se_lun *se_lun)
-{
- struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-
- atomic_dec(&tpg->tpg_port_count);
- smp_mb__after_atomic_dec();
-}
-
-static int usbg_check_stop_free(struct se_cmd *se_cmd)
-{
- struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
- se_cmd);
-
- kref_put(&cmd->ref, usbg_cmd_release);
- return 1;
-}
-
-static struct target_core_fabric_ops usbg_ops = {
- .get_fabric_name = usbg_get_fabric_name,
- .get_fabric_proto_ident = usbg_get_fabric_proto_ident,
- .tpg_get_wwn = usbg_get_fabric_wwn,
- .tpg_get_tag = usbg_get_tag,
- .tpg_get_default_depth = usbg_get_default_depth,
- .tpg_get_pr_transport_id = usbg_get_pr_transport_id,
- .tpg_get_pr_transport_id_len = usbg_get_pr_transport_id_len,
- .tpg_parse_pr_out_transport_id = usbg_parse_pr_out_transport_id,
- .tpg_check_demo_mode = usbg_check_true,
- .tpg_check_demo_mode_cache = usbg_check_false,
- .tpg_check_demo_mode_write_protect = usbg_check_false,
- .tpg_check_prod_mode_write_protect = usbg_check_false,
- .tpg_alloc_fabric_acl = usbg_alloc_fabric_acl,
- .tpg_release_fabric_acl = usbg_release_fabric_acl,
- .tpg_get_inst_index = usbg_tpg_get_inst_index,
- .new_cmd_map = usbg_new_cmd,
- .release_cmd = usbg_release_cmd,
- .shutdown_session = usbg_shutdown_session,
- .close_session = usbg_close_session,
- .sess_get_index = usbg_sess_get_index,
- .sess_get_initiator_sid = NULL,
- .write_pending = usbg_send_write_request,
- .write_pending_status = usbg_write_pending_status,
- .set_default_node_attributes = usbg_set_default_node_attrs,
- .get_task_tag = usbg_get_task_tag,
- .get_cmd_state = usbg_get_cmd_state,
- .queue_data_in = usbg_send_read_response,
- .queue_status = usbg_send_status_response,
- .queue_tm_rsp = usbg_queue_tm_rsp,
- .get_fabric_sense_len = usbg_get_fabric_sense_len,
- .set_fabric_sense_len = usbg_set_fabric_sense_len,
- .check_stop_free = usbg_check_stop_free,
-
- .fabric_make_wwn = usbg_make_tport,
- .fabric_drop_wwn = usbg_drop_tport,
- .fabric_make_tpg = usbg_make_tpg,
- .fabric_drop_tpg = usbg_drop_tpg,
- .fabric_post_link = usbg_port_link,
- .fabric_pre_unlink = usbg_port_unlink,
- .fabric_make_np = NULL,
- .fabric_drop_np = NULL,
- .fabric_make_nodeacl = usbg_make_nodeacl,
- .fabric_drop_nodeacl = usbg_drop_nodeacl,
-};
-
-static int usbg_register_configfs(void)
-{
- struct target_fabric_configfs *fabric;
- int ret;
-
- fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget");
- if (IS_ERR(fabric)) {
- printk(KERN_ERR "target_fabric_configfs_init() failed\n");
- return PTR_ERR(fabric);
- }
-
- fabric->tf_ops = usbg_ops;
- TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = usbg_wwn_attrs;
- TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = usbg_base_attrs;
- TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
- TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
- TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
- TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
- TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
- TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
- TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
- ret = target_fabric_configfs_register(fabric);
- if (ret < 0) {
- printk(KERN_ERR "target_fabric_configfs_register() failed"
- " for usb-gadget\n");
- return ret;
- }
- usbg_fabric_configfs = fabric;
- return 0;
-};
-
-static void usbg_deregister_configfs(void)
-{
- if (!(usbg_fabric_configfs))
- return;
-
- target_fabric_configfs_deregister(usbg_fabric_configfs);
- usbg_fabric_configfs = NULL;
-};
-
-/* Start gadget.c code */
-
-static struct usb_interface_descriptor bot_intf_desc = {
- .bLength = sizeof(bot_intf_desc),
- .bDescriptorType = USB_DT_INTERFACE,
- .bAlternateSetting = 0,
- .bNumEndpoints = 2,
- .bAlternateSetting = USB_G_ALT_INT_BBB,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = USB_SC_SCSI,
- .bInterfaceProtocol = USB_PR_BULK,
- .iInterface = USB_G_STR_INT_UAS,
-};
-
-static struct usb_interface_descriptor uasp_intf_desc = {
- .bLength = sizeof(uasp_intf_desc),
- .bDescriptorType = USB_DT_INTERFACE,
- .bNumEndpoints = 4,
- .bAlternateSetting = USB_G_ALT_INT_UAS,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = USB_SC_SCSI,
- .bInterfaceProtocol = USB_PR_UAS,
- .iInterface = USB_G_STR_INT_BBB,
-};
-
-static struct usb_endpoint_descriptor uasp_bi_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_bi_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = {
- .bLength = sizeof(uasp_bi_pipe_desc),
- .bDescriptorType = USB_DT_PIPE_USAGE,
- .bPipeID = DATA_IN_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_bi_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = {
- .bLength = sizeof(uasp_bi_ep_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bMaxBurst = 0,
- .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
- .wBytesPerInterval = 0,
-};
-
-static struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = {
- .bLength = sizeof(bot_bi_ep_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bMaxBurst = 0,
-};
-
-static struct usb_endpoint_descriptor uasp_bo_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_bo_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = {
- .bLength = sizeof(uasp_bo_pipe_desc),
- .bDescriptorType = USB_DT_PIPE_USAGE,
- .bPipeID = DATA_OUT_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_bo_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(0x400),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = {
- .bLength = sizeof(uasp_bo_ep_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
-};
-
-static struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = {
- .bLength = sizeof(bot_bo_ep_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-};
-
-static struct usb_endpoint_descriptor uasp_status_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_status_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_status_pipe_desc = {
- .bLength = sizeof(uasp_status_pipe_desc),
- .bDescriptorType = USB_DT_PIPE_USAGE,
- .bPipeID = STATUS_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_status_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = {
- .bLength = sizeof(uasp_status_in_ep_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
-};
-
-static struct usb_endpoint_descriptor uasp_cmd_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_cmd_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = {
- .bLength = sizeof(uasp_cmd_pipe_desc),
- .bDescriptorType = USB_DT_PIPE_USAGE,
- .bPipeID = CMD_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_cmd_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = {
- .bLength = sizeof(uasp_cmd_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-};
-
-static struct usb_descriptor_header *uasp_fs_function_desc[] = {
- (struct usb_descriptor_header *) &bot_intf_desc,
- (struct usb_descriptor_header *) &uasp_fs_bi_desc,
- (struct usb_descriptor_header *) &uasp_fs_bo_desc,
-
- (struct usb_descriptor_header *) &uasp_intf_desc,
- (struct usb_descriptor_header *) &uasp_fs_bi_desc,
- (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
- (struct usb_descriptor_header *) &uasp_fs_bo_desc,
- (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
- (struct usb_descriptor_header *) &uasp_fs_status_desc,
- (struct usb_descriptor_header *) &uasp_status_pipe_desc,
- (struct usb_descriptor_header *) &uasp_fs_cmd_desc,
- (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
-};
-
-static struct usb_descriptor_header *uasp_hs_function_desc[] = {
- (struct usb_descriptor_header *) &bot_intf_desc,
- (struct usb_descriptor_header *) &uasp_bi_desc,
- (struct usb_descriptor_header *) &uasp_bo_desc,
-
- (struct usb_descriptor_header *) &uasp_intf_desc,
- (struct usb_descriptor_header *) &uasp_bi_desc,
- (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
- (struct usb_descriptor_header *) &uasp_bo_desc,
- (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
- (struct usb_descriptor_header *) &uasp_status_desc,
- (struct usb_descriptor_header *) &uasp_status_pipe_desc,
- (struct usb_descriptor_header *) &uasp_cmd_desc,
- (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
- NULL,
-};
-
-static struct usb_descriptor_header *uasp_ss_function_desc[] = {
- (struct usb_descriptor_header *) &bot_intf_desc,
- (struct usb_descriptor_header *) &uasp_ss_bi_desc,
- (struct usb_descriptor_header *) &bot_bi_ep_comp_desc,
- (struct usb_descriptor_header *) &uasp_ss_bo_desc,
- (struct usb_descriptor_header *) &bot_bo_ep_comp_desc,
-
- (struct usb_descriptor_header *) &uasp_intf_desc,
- (struct usb_descriptor_header *) &uasp_ss_bi_desc,
- (struct usb_descriptor_header *) &uasp_bi_ep_comp_desc,
- (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
- (struct usb_descriptor_header *) &uasp_ss_bo_desc,
- (struct usb_descriptor_header *) &uasp_bo_ep_comp_desc,
- (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
- (struct usb_descriptor_header *) &uasp_ss_status_desc,
- (struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc,
- (struct usb_descriptor_header *) &uasp_status_pipe_desc,
- (struct usb_descriptor_header *) &uasp_ss_cmd_desc,
- (struct usb_descriptor_header *) &uasp_cmd_comp_desc,
- (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
- NULL,
-};
+#include "f_tcm.c"
#define UAS_VENDOR_ID 0x0525 /* NetChip */
#define UAS_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
+#define USB_G_STR_MANUFACTOR 1
+#define USB_G_STR_PRODUCT 2
+#define USB_G_STR_SERIAL 3
+#define USB_G_STR_CONFIG 4
+
static struct usb_device_descriptor usbg_device_desc = {
.bLength = sizeof(usbg_device_desc),
.bDescriptorType = USB_DT_DEVICE,
@@ -2227,8 +47,6 @@
{ USB_G_STR_PRODUCT, "Target Product"},
{ USB_G_STR_SERIAL, "000000000001"},
{ USB_G_STR_CONFIG, "default config"},
- { USB_G_STR_INT_UAS, "USB Attached SCSI"},
- { USB_G_STR_INT_BBB, "Bulk Only Transport"},
{ },
};
@@ -2242,11 +60,6 @@
NULL,
};
-static int guas_unbind(struct usb_composite_dev *cdev)
-{
- return 0;
-}
-
static struct usb_configuration usbg_config_driver = {
.label = "Linux Target",
.bConfigurationValue = 1,
@@ -2254,183 +67,9 @@
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
};
-static void give_back_ep(struct usb_ep **pep)
-{
- struct usb_ep *ep = *pep;
- if (!ep)
- return;
- ep->driver_data = NULL;
-}
-
-static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
-{
- struct f_uas *fu = to_f_uas(f);
- struct usb_gadget *gadget = c->cdev->gadget;
- struct usb_ep *ep;
- int iface;
-
- iface = usb_interface_id(c, f);
- if (iface < 0)
- return iface;
-
- bot_intf_desc.bInterfaceNumber = iface;
- uasp_intf_desc.bInterfaceNumber = iface;
- fu->iface = iface;
- ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc,
- &uasp_bi_ep_comp_desc);
- if (!ep)
- goto ep_fail;
-
- ep->driver_data = fu;
- fu->ep_in = ep;
-
- ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
- &uasp_bo_ep_comp_desc);
- if (!ep)
- goto ep_fail;
- ep->driver_data = fu;
- fu->ep_out = ep;
-
- ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
- &uasp_status_in_ep_comp_desc);
- if (!ep)
- goto ep_fail;
- ep->driver_data = fu;
- fu->ep_status = ep;
-
- ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
- &uasp_cmd_comp_desc);
- if (!ep)
- goto ep_fail;
- ep->driver_data = fu;
- fu->ep_cmd = ep;
-
- /* Assume endpoint addresses are the same for both speeds */
- uasp_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
- uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
- uasp_status_desc.bEndpointAddress =
- uasp_ss_status_desc.bEndpointAddress;
- uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
-
- uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
- uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
- uasp_fs_status_desc.bEndpointAddress =
- uasp_ss_status_desc.bEndpointAddress;
- uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
-
- return 0;
-ep_fail:
- pr_err("Can't claim all required eps\n");
-
- give_back_ep(&fu->ep_in);
- give_back_ep(&fu->ep_out);
- give_back_ep(&fu->ep_status);
- give_back_ep(&fu->ep_cmd);
- return -ENOTSUPP;
-}
-
-static void usbg_unbind(struct usb_configuration *c, struct usb_function *f)
-{
- struct f_uas *fu = to_f_uas(f);
-
- kfree(fu);
-}
-
-struct guas_setup_wq {
- struct work_struct work;
- struct f_uas *fu;
- unsigned int alt;
-};
-
-static void usbg_delayed_set_alt(struct work_struct *wq)
-{
- struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
- work);
- struct f_uas *fu = work->fu;
- int alt = work->alt;
-
- kfree(work);
-
- if (fu->flags & USBG_IS_BOT)
- bot_cleanup_old_alt(fu);
- if (fu->flags & USBG_IS_UAS)
- uasp_cleanup_old_alt(fu);
-
- if (alt == USB_G_ALT_INT_BBB)
- bot_set_alt(fu);
- else if (alt == USB_G_ALT_INT_UAS)
- uasp_set_alt(fu);
- usb_composite_setup_continue(fu->function.config->cdev);
-}
-
-static int usbg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
-{
- struct f_uas *fu = to_f_uas(f);
-
- if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
- struct guas_setup_wq *work;
-
- work = kmalloc(sizeof(*work), GFP_ATOMIC);
- if (!work)
- return -ENOMEM;
- INIT_WORK(&work->work, usbg_delayed_set_alt);
- work->fu = fu;
- work->alt = alt;
- schedule_work(&work->work);
- return USB_GADGET_DELAYED_STATUS;
- }
- return -EOPNOTSUPP;
-}
-
-static void usbg_disable(struct usb_function *f)
-{
- struct f_uas *fu = to_f_uas(f);
-
- if (fu->flags & USBG_IS_UAS)
- uasp_cleanup_old_alt(fu);
- else if (fu->flags & USBG_IS_BOT)
- bot_cleanup_old_alt(fu);
- fu->flags = 0;
-}
-
-static int usbg_setup(struct usb_function *f,
- const struct usb_ctrlrequest *ctrl)
-{
- struct f_uas *fu = to_f_uas(f);
-
- if (!(fu->flags & USBG_IS_BOT))
- return -EOPNOTSUPP;
-
- return usbg_bot_setup(f, ctrl);
-}
-
static int usbg_cfg_bind(struct usb_configuration *c)
{
- struct f_uas *fu;
- int ret;
-
- fu = kzalloc(sizeof(*fu), GFP_KERNEL);
- if (!fu)
- return -ENOMEM;
- fu->function.name = "Target Function";
- fu->function.descriptors = uasp_fs_function_desc;
- fu->function.hs_descriptors = uasp_hs_function_desc;
- fu->function.ss_descriptors = uasp_ss_function_desc;
- fu->function.bind = usbg_bind;
- fu->function.unbind = usbg_unbind;
- fu->function.set_alt = usbg_set_alt;
- fu->function.setup = usbg_setup;
- fu->function.disable = usbg_disable;
- fu->tpg = the_only_tpg_I_currently_have;
-
- ret = usb_add_function(c, &fu->function);
- if (ret)
- goto err;
-
- return 0;
-err:
- kfree(fu);
- return ret;
+ return tcm_bind_config(c);
}
static int usb_target_bind(struct usb_composite_dev *cdev)
@@ -2439,6 +78,11 @@
ret = usb_add_config(cdev, &usbg_config_driver,
usbg_cfg_bind);
+ return ret;
+}
+
+static int guas_unbind(struct usb_composite_dev *cdev)
+{
return 0;
}
@@ -2450,28 +94,30 @@
.unbind = guas_unbind,
};
-static int usbg_attach(struct usbg_tpg *tpg)
+static int usbg_attach_cb(bool connect)
{
- return usb_composite_probe(&usbg_driver, usb_target_bind);
-}
+ int ret = 0;
-static void usbg_detach(struct usbg_tpg *tpg)
-{
- usb_composite_unregister(&usbg_driver);
+ if (connect)
+ ret = usb_composite_probe(&usbg_driver, usb_target_bind);
+ else
+ usb_composite_unregister(&usbg_driver);
+
+ return ret;
}
static int __init usb_target_gadget_init(void)
{
int ret;
- ret = usbg_register_configfs();
+ ret = f_tcm_init(&usbg_attach_cb);
return ret;
}
module_init(usb_target_gadget_init);
static void __exit usb_target_gadget_exit(void)
{
- usbg_deregister_configfs();
+ f_tcm_exit();
}
module_exit(usb_target_gadget_exit);
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 4657283..8a87a6a 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -660,6 +660,7 @@
skip_phy_resume:
+ usb_hcd_resume_root_hub(hcd);
atomic_set(&mhcd->in_lpm, 0);
if (mhcd->async_int) {
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 8467dc0..d895f27 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -12,6 +12,7 @@
*/
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb/otg.h>
@@ -173,6 +174,11 @@
usb_put_transceiver(phy);
goto put_usb3_hcd;
}
+ } else {
+ pm_runtime_no_callbacks(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get(&pdev->dev);
}
return 0;
@@ -211,6 +217,9 @@
if (phy && phy->otg) {
otg_set_host(phy->otg, NULL);
usb_put_transceiver(phy);
+ } else {
+ pm_runtime_put(&dev->dev);
+ pm_runtime_disable(&dev->dev);
}
return 0;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index c1e1e13..b6fc43f 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -40,6 +40,7 @@
#include <linux/mfd/pm8xxx/pm8921-charger.h>
#include <linux/mfd/pm8xxx/misc.h>
#include <linux/power_supply.h>
+#include <linux/mhl_8334.h>
#include <mach/clk.h>
#include <mach/msm_xo.h>
@@ -69,6 +70,7 @@
static struct msm_otg *the_msm_otg;
static bool debug_aca_enabled;
static bool debug_bus_voting_enabled;
+static bool mhl_det_in_progress;
static struct regulator *hsusb_3p3;
static struct regulator *hsusb_1p8;
@@ -738,7 +740,8 @@
return 0;
disable_irq(motg->irq);
- host_bus_suspend = phy->otg->host && !test_bit(ID, &motg->inputs);
+ host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
+ !test_bit(ID, &motg->inputs);
device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) &&
test_bit(A_BUS_SUSPEND, &motg->inputs) &&
motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
@@ -1402,6 +1405,102 @@
return 0;
}
+static int msm_otg_mhl_register_callback(struct msm_otg *motg,
+ void (*callback)(int on))
+{
+ struct usb_phy *phy = &motg->phy;
+ int ret;
+
+ if (motg->pdata->otg_control != OTG_PMIC_CONTROL ||
+ !motg->pdata->pmic_id_irq) {
+ dev_dbg(phy->dev, "MHL can not be supported without PMIC Id\n");
+ return -ENODEV;
+ }
+
+ if (!motg->pdata->mhl_dev_name) {
+ dev_dbg(phy->dev, "MHL device name does not exist.\n");
+ return -ENODEV;
+ }
+
+ if (callback)
+ ret = mhl_register_callback(motg->pdata->mhl_dev_name,
+ callback);
+ else
+ ret = mhl_unregister_callback(motg->pdata->mhl_dev_name);
+
+ if (ret)
+ dev_dbg(phy->dev, "mhl_register_callback(%s) return error=%d\n",
+ motg->pdata->mhl_dev_name, ret);
+ else
+ motg->mhl_enabled = true;
+
+ return ret;
+}
+
+static void msm_otg_mhl_notify_online(int on)
+{
+ struct msm_otg *motg = the_msm_otg;
+ struct usb_phy *phy = &motg->phy;
+ bool queue = false;
+
+ dev_dbg(phy->dev, "notify MHL %s%s\n", on ? "" : "dis", "connected");
+
+ if (on) {
+ set_bit(MHL, &motg->inputs);
+ } else {
+ clear_bit(MHL, &motg->inputs);
+ queue = true;
+ }
+
+ if (queue && phy->state != OTG_STATE_UNDEFINED)
+ schedule_work(&motg->sm_work);
+}
+
+static bool msm_otg_is_mhl(struct msm_otg *motg)
+{
+ struct usb_phy *phy = &motg->phy;
+ int is_mhl, ret;
+
+ ret = mhl_device_discovery(motg->pdata->mhl_dev_name, &is_mhl);
+ if (ret || is_mhl != MHL_DISCOVERY_RESULT_MHL) {
+ /*
+ * MHL driver calls our callback saying that MHL connected
+ * if RID_GND is detected. But at later part of discovery
+ * it may figure out MHL is not connected and returns
+ * false. Hence clear MHL input here.
+ */
+ clear_bit(MHL, &motg->inputs);
+ dev_dbg(phy->dev, "MHL device not found\n");
+ return false;
+ }
+
+ set_bit(MHL, &motg->inputs);
+ dev_dbg(phy->dev, "MHL device found\n");
+ return true;
+}
+
+static bool msm_chg_mhl_detect(struct msm_otg *motg)
+{
+ bool ret, id;
+ unsigned long flags;
+
+ if (!motg->mhl_enabled)
+ return false;
+
+ local_irq_save(flags);
+ id = irq_read_line(motg->pdata->pmic_id_irq);
+ local_irq_restore(flags);
+
+ if (id)
+ return false;
+
+ mhl_det_in_progress = true;
+ ret = msm_otg_is_mhl(motg);
+ mhl_det_in_progress = false;
+
+ return ret;
+}
+
static bool msm_chg_aca_detect(struct msm_otg *motg)
{
struct usb_phy *phy = &motg->phy;
@@ -1844,6 +1943,12 @@
unsigned long delay;
dev_dbg(phy->dev, "chg detection work\n");
+
+ if (test_bit(MHL, &motg->inputs)) {
+ dev_dbg(phy->dev, "detected MHL, escape chg detection work\n");
+ return;
+ }
+
switch (motg->chg_state) {
case USB_CHG_STATE_UNDEFINED:
msm_chg_block_on(motg);
@@ -1855,6 +1960,13 @@
delay = MSM_CHG_DCD_POLL_TIME;
break;
case USB_CHG_STATE_WAIT_FOR_DCD:
+ if (msm_chg_mhl_detect(motg)) {
+ msm_chg_block_off(motg);
+ motg->chg_state = USB_CHG_STATE_DETECTED;
+ motg->chg_type = USB_INVALID_CHARGER;
+ queue_work(system_nrt_wq, &motg->sm_work);
+ return;
+ }
is_aca = msm_chg_aca_detect(motg);
if (is_aca) {
/*
@@ -2048,9 +2160,17 @@
}
/* FALL THROUGH */
case OTG_STATE_B_IDLE:
- if ((!test_bit(ID, &motg->inputs) ||
+ if (test_bit(MHL, &motg->inputs)) {
+ /* allow LPM */
+ pm_runtime_put_noidle(otg->phy->dev);
+ pm_runtime_suspend(otg->phy->dev);
+ } else if ((!test_bit(ID, &motg->inputs) ||
test_bit(ID_A, &motg->inputs)) && otg->host) {
pr_debug("!id || id_A\n");
+ if (msm_chg_mhl_detect(motg)) {
+ work = 1;
+ break;
+ }
clear_bit(B_BUS_REQ, &motg->inputs);
set_bit(A_BUS_REQ, &motg->inputs);
otg->phy->state = OTG_STATE_A_IDLE;
@@ -2760,6 +2880,12 @@
return;
}
+ if (test_bit(MHL, &motg->inputs) ||
+ mhl_det_in_progress) {
+ pr_debug("PMIC: BSV interrupt ignored in MHL\n");
+ return;
+ }
+
if (atomic_read(&motg->pm_suspended))
motg->sm_work_pending = true;
else
@@ -2802,6 +2928,12 @@
{
struct msm_otg *motg = data;
+ if (test_bit(MHL, &motg->inputs) ||
+ mhl_det_in_progress) {
+ pr_debug("PMIC: Id interrupt ignored in MHL\n");
+ return IRQ_HANDLED;
+ }
+
if (!aca_id_turned_on)
/*schedule delayed work for 5msec for ID line state to settle*/
queue_delayed_work(system_nrt_wq, &motg->pmic_id_status_work,
@@ -3416,6 +3548,9 @@
/* Ensure that above STOREs are completed before enabling interrupts */
mb();
+ ret = msm_otg_mhl_register_callback(motg, msm_otg_mhl_notify_online);
+ if (ret)
+ dev_dbg(&pdev->dev, "MHL can not be supported\n");
wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
msm_otg_init_timer(motg);
INIT_WORK(&motg->sm_work, msm_otg_sm_work);
@@ -3563,6 +3698,7 @@
msm_otg_setup_devices(pdev, motg->pdata->mode, false);
if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
pm8921_charger_unregister_vbus_sn(0);
+ msm_otg_mhl_register_callback(motg, NULL);
msm_otg_debugfs_cleanup();
cancel_delayed_work_sync(&motg->chg_work);
cancel_delayed_work_sync(&motg->pmic_id_status_work);
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index bf30c0b..68500a3 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -302,7 +302,7 @@
tty = tty_port_tty_get(&port->port);
if (!tty)
- continue;
+ break;
list_del_init(&urb->urb_list);
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index b6bf47d..9f301fe 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -1858,6 +1858,9 @@
/* EDID_BLOCK_SIZE[0x80] Each page size in the EDID ROM */
uint8 edid_buf[0x80 * 4];
+ external_common_state->pt_scan_info = 0;
+ external_common_state->it_scan_info = 0;
+ external_common_state->ce_scan_info = 0;
external_common_state->preferred_video_format = 0;
external_common_state->present_3d = 0;
memset(&external_common_state->disp_mode_list, 0,
@@ -1974,13 +1977,15 @@
bool hdmi_common_get_video_format_from_drv_data(struct msm_fb_data_type *mfd)
{
- uint32 format;
+ uint32 format = HDMI_VFRMT_1920x1080p60_16_9;
struct fb_var_screeninfo *var = &mfd->fbi->var;
bool changed = TRUE;
if (var->reserved[2]) {
format = var->reserved[2]-1;
DEV_DBG("reserved format is %d\n", format);
+ } else if (hdmi_prim_resolution) {
+ format = hdmi_prim_resolution - 1;
} else {
DEV_DBG("detecting resolution from %dx%d use var->reserved[3]"
" to specify mode", mfd->var_xres, mfd->var_yres);
@@ -1995,15 +2000,33 @@
: HDMI_VFRMT_720x576p50_16_9;
break;
case 1280:
- format = HDMI_VFRMT_1280x720p60_16_9;
+ if (mfd->var_frame_rate == 50000)
+ format = HDMI_VFRMT_1280x720p50_16_9;
+ else
+ format = HDMI_VFRMT_1280x720p60_16_9;
break;
case 1440:
- format = (mfd->var_yres == 480)
+ format = (mfd->var_yres == 240) /* interlaced has half
+ of y res.
+ */
? HDMI_VFRMT_1440x480i60_16_9
: HDMI_VFRMT_1440x576i50_16_9;
break;
case 1920:
- format = HDMI_VFRMT_1920x1080p60_16_9;
+ if (mfd->var_yres == 540) {/* interlaced */
+ format = HDMI_VFRMT_1920x1080i60_16_9;
+ } else if (mfd->var_yres == 1080) {
+ if (mfd->var_frame_rate == 50000)
+ format = HDMI_VFRMT_1920x1080p50_16_9;
+ else if (mfd->var_frame_rate == 24000)
+ format = HDMI_VFRMT_1920x1080p24_16_9;
+ else if (mfd->var_frame_rate == 25000)
+ format = HDMI_VFRMT_1920x1080p25_16_9;
+ else if (mfd->var_frame_rate == 30000)
+ format = HDMI_VFRMT_1920x1080p30_16_9;
+ else
+ format = HDMI_VFRMT_1920x1080p60_16_9;
+ }
break;
}
}
diff --git a/drivers/video/msm/external_common.h b/drivers/video/msm/external_common.h
index 57c0804..43a8794 100644
--- a/drivers/video/msm/external_common.h
+++ b/drivers/video/msm/external_common.h
@@ -112,6 +112,8 @@
#define HDMI_VFRMT_MAX 59
#define HDMI_VFRMT_FORCE_32BIT 0x7FFFFFFF
+extern int ext_resolution;
+
struct hdmi_disp_mode_timing_type {
uint32 video_format;
uint32 active_h;
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 0655daf..4a1427d 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -840,6 +840,9 @@
DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
kobject_uevent(external_common_state->uevent_kobj,
KOBJ_ONLINE);
+ switch_set_state(&external_common_state->sdev, 1);
+ DEV_INFO("Hdmi state switch to %d: %s\n",
+ external_common_state->sdev.state, __func__);
#ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
/* Send Audio for HDMI Compliance Cases*/
envp[0] = "HDCP_STATE=PASS";
@@ -4739,7 +4742,14 @@
}
external_common_state = &hdmi_msm_state->common;
- external_common_state->video_resolution = HDMI_VFRMT_1920x1080p30_16_9;
+
+ if (hdmi_prim_display && hdmi_prim_resolution)
+ external_common_state->video_resolution =
+ hdmi_prim_resolution - 1;
+ else
+ external_common_state->video_resolution =
+ HDMI_VFRMT_1920x1080p60_16_9;
+
#ifdef CONFIG_FB_MSM_HDMI_3D
external_common_state->switch_3d = hdmi_msm_switch_3d;
#endif
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 2cbef69..c9be60a 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -52,7 +52,7 @@
int mdp_iommu_split_domain;
static struct platform_device *mdp_init_pdev;
-static struct regulator *footswitch, *hdmi_pll_fs;
+static struct regulator *footswitch;
static unsigned int mdp_footswitch_on;
struct completion mdp_ppp_comp;
@@ -848,8 +848,11 @@
MDP_OUTP(base + 0x0018, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- mgmt->hist = NULL;
- complete(&mgmt->mdp_hist_comp);
+ if (mgmt->hist != NULL) {
+ mgmt->hist = NULL;
+ complete(&mgmt->mdp_hist_comp);
+ }
+
mdp_disable_irq(mgmt->irq_term);
return 0;
}
@@ -964,8 +967,10 @@
if (!mfd->panel_power_on) {
mgmt->mdp_is_hist_data = FALSE;
- mgmt->hist = NULL;
- complete(&mgmt->mdp_hist_comp);
+ if (mgmt->hist != NULL) {
+ mgmt->hist = NULL;
+ complete(&mgmt->mdp_hist_comp);
+ }
ret = -EINVAL;
goto error_lock;
}
@@ -1132,7 +1137,8 @@
*/
if (!ret && mgmt->mdp_is_hist_valid && mgmt->mdp_is_hist_init) {
mgmt->hist = NULL;
- complete(&mgmt->mdp_hist_comp);
+ if (waitqueue_active(&mgmt->mdp_hist_comp.wait))
+ complete(&mgmt->mdp_hist_comp);
}
if (mgmt->mdp_is_hist_valid == FALSE)
@@ -1233,6 +1239,7 @@
ret = -EPERM;
goto error_lock;
}
+ INIT_COMPLETION(mgmt->mdp_hist_comp);
mgmt->hist = hist;
mutex_unlock(&mgmt->mdp_hist_mutex);
@@ -2125,27 +2132,10 @@
}
disable_irq(mdp_irq);
- hdmi_pll_fs = regulator_get(&pdev->dev, "hdmi_pll_fs");
- if (IS_ERR(hdmi_pll_fs)) {
- hdmi_pll_fs = NULL;
- } else {
- if (mdp_rev != MDP_REV_44) {
- ret = regulator_set_voltage(hdmi_pll_fs, 1800000,
- 1800000);
- if (ret) {
- pr_err("set_voltage failed for hdmi_pll_fs, ret=%d\n",
- ret);
- }
- }
- }
-
footswitch = regulator_get(&pdev->dev, "vdd");
- if (IS_ERR(footswitch)) {
+ if (IS_ERR(footswitch))
footswitch = NULL;
- } else {
- if (hdmi_pll_fs)
- regulator_enable(hdmi_pll_fs);
-
+ else {
regulator_enable(footswitch);
mdp_footswitch_on = 1;
@@ -2154,8 +2144,6 @@
msleep(20);
regulator_enable(footswitch);
}
- if (hdmi_pll_fs)
- regulator_disable(hdmi_pll_fs);
}
mdp_clk = clk_get(&pdev->dev, "core_clk");
@@ -2410,6 +2398,8 @@
#ifdef CONFIG_FB_MSM_MIPI_DSI
case MIPI_VIDEO_PANEL:
#ifndef CONFIG_FB_MSM_MDP303
+ mipi = &mfd->panel_info.mipi;
+ configure_mdp_core_clk_table((mipi->dsi_pclk_rate) * 23 / 20);
pdata->on = mdp4_dsi_video_on;
pdata->off = mdp4_dsi_video_off;
mfd->hw_refresh = TRUE;
@@ -2500,6 +2490,9 @@
mfd->cursor_update = mdp_hw_cursor_update;
mfd->dma_fnc = mdp4_dtv_overlay;
mfd->dma = &dma_e_data;
+ mfd->do_histogram = mdp_do_histogram;
+ mfd->start_histogram = mdp_histogram_start;
+ mfd->stop_histogram = mdp_histogram_stop;
mdp4_display_intf_sel(EXTERNAL_INTF_SEL, DTV_INTF);
break;
#endif
@@ -2648,9 +2641,6 @@
return;
}
- if (hdmi_pll_fs)
- regulator_enable(hdmi_pll_fs);
-
if (on && !mdp_footswitch_on) {
pr_debug("Enable MDP FS\n");
regulator_enable(footswitch);
@@ -2661,9 +2651,6 @@
mdp_footswitch_on = 0;
}
- if (hdmi_pll_fs)
- regulator_disable(hdmi_pll_fs);
-
mutex_unlock(&mdp_suspend_mutex);
}
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 3fd51ba..184c5ce 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -88,6 +88,7 @@
extern struct mdp_ccs mdp_ccs_yuv2rgb ;
extern struct mdp_ccs mdp_ccs_rgb2yuv ;
extern unsigned char hdmi_prim_display;
+extern unsigned char hdmi_prim_resolution;
/*
* MDP Image Structure
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index c7c2476..bc4476e 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -570,8 +570,13 @@
{
if (blt_cfg_changed) {
mdp_is_in_isr = TRUE;
- mdp4_overlayproc_cfg(dsi_pipe);
- mdp4_overlay_dmap_xy(dsi_pipe);
+ if (dsi_pipe->ov_blt_addr) {
+ mdp4_overlay_dmap_xy(dsi_pipe);
+ mdp4_overlayproc_cfg(dsi_pipe);
+ } else {
+ mdp4_overlayproc_cfg(dsi_pipe);
+ mdp4_overlay_dmap_xy(dsi_pipe);
+ }
mdp_is_in_isr = FALSE;
if (dsi_pipe->ov_blt_addr) {
mdp4_dsi_video_blt_ov_update(dsi_pipe);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 12448e4..b9d6037 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -678,8 +678,8 @@
msleep(20);
}
- mdp4_overlayproc_cfg(dtv_pipe);
mdp4_overlay_dmae_xy(dtv_pipe);
+ mdp4_overlayproc_cfg(dtv_pipe);
MDP_OUTP(MDP_BASE + DTV_BASE, 1); /* start dtv */
}
@@ -698,11 +698,7 @@
struct mdp4_overlay_pipe *pipe;
if (!mfd->panel_power_on)
return;
- if (!dtv_pipe) {
- pr_debug("%s: no mixer1 base layer pipe allocated!\n",
- __func__);
- return;
- }
+
mutex_lock(&mfd->dma->ov_mutex);
if (dtv_pipe == NULL) {
if (mdp4_overlay_dtv_set(mfd, NULL)) {
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 3739332..bcc4ea6 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -561,8 +561,8 @@
msleep(20);
}
- mdp4_overlayproc_cfg(lcdc_pipe);
mdp4_overlay_dmap_xy(lcdc_pipe);
+ mdp4_overlayproc_cfg(lcdc_pipe);
if (lcdc_pipe->ov_blt_addr) {
mdp4_overlay_lcdc_prefill(mfd);
mdp4_overlay_lcdc_prefill(mfd);
diff --git a/drivers/video/msm/mhl/mhl_8334.c b/drivers/video/msm/mhl/mhl_8334.c
index d6e3f6f..646dd29 100644
--- a/drivers/video/msm/mhl/mhl_8334.c
+++ b/drivers/video/msm/mhl/mhl_8334.c
@@ -30,11 +30,11 @@
#include <linux/regulator/consumer.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/mhl_8334.h>
#include "msm_fb.h"
#include "external_common.h"
#include "hdmi_msm.h"
-#include "mhl_8334.h"
#include "mhl_i2c_utils.h"
@@ -53,6 +53,8 @@
static void release_usb_switch_open(void);
static void switch_mode(enum mhl_st_type to_mode);
static irqreturn_t mhl_tx_isr(int irq, void *dev_id);
+void (*notify_usb_online)(int online);
+static void mhl_drive_hpd(uint8_t to_state);
static struct i2c_driver mhl_sii_i2c_driver = {
.driver = {
@@ -227,6 +229,58 @@
return true;
}
+
+/* USB_HANDSHAKING FUNCTIONS */
+
+int mhl_device_discovery(const char *name, int *result)
+
+{
+ int timeout ;
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0010, 0x27);
+ msleep(50);
+ if (mhl_msm_state->cur_state == POWER_STATE_D3) {
+ /* give MHL driver chance to handle RGND interrupt */
+ INIT_COMPLETION(mhl_msm_state->rgnd_done);
+ timeout = wait_for_completion_interruptible_timeout
+ (&mhl_msm_state->rgnd_done, HZ/2);
+ if (!timeout) {
+ /* most likely nothing plugged in USB */
+ /* USB HOST connected or already in USB mode */
+ pr_debug("Timedout Returning from discovery mode\n");
+ *result = MHL_DISCOVERY_RESULT_USB;
+ return 0;
+ }
+ *result = mhl_msm_state->mhl_mode ?
+ MHL_DISCOVERY_RESULT_MHL : MHL_DISCOVERY_RESULT_USB;
+ } else
+ /* not in D3. already in MHL mode */
+ *result = MHL_DISCOVERY_RESULT_MHL;
+
+ return 0;
+}
+EXPORT_SYMBOL(mhl_device_discovery);
+
+int mhl_register_callback(const char *name, void (*callback)(int online))
+{
+ pr_debug("%s\n", __func__);
+ if (!callback)
+ return -EINVAL;
+ if (!notify_usb_online)
+ notify_usb_online = callback;
+ return 0;
+}
+EXPORT_SYMBOL(mhl_register_callback);
+
+int mhl_unregister_callback(const char *name)
+{
+ pr_debug("%s\n", __func__);
+ if (notify_usb_online)
+ notify_usb_online = NULL;
+ return 0;
+}
+EXPORT_SYMBOL(mhl_unregister_callback);
+
+
static void cbus_reset(void)
{
uint8_t i;
@@ -240,7 +294,7 @@
/*
* REG_INTR1 and REG_INTR4
*/
- mhl_i2c_reg_write(TX_PAGE_L0, 0x0075, BIT6 | BIT5);
+ mhl_i2c_reg_write(TX_PAGE_L0, 0x0075, BIT6);
mhl_i2c_reg_write(TX_PAGE_3, 0x0022,
BIT0 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6);
/* REG5 */
@@ -340,7 +394,7 @@
/*
* Configure the initial reg settings
*/
-static void mhl_init_reg_settings(void)
+static void mhl_init_reg_settings(bool mhl_disc_en)
{
/*
@@ -419,15 +473,19 @@
/* Pull-up resistance off for IDLE state */
mhl_i2c_reg_write(TX_PAGE_3, 0x0013, 0x8C);
/* Enable CBUS Discovery */
- mhl_i2c_reg_write(TX_PAGE_3, 0x0010, 0x27);
+ if (mhl_disc_en)
+ /* Enable MHL Discovery */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0010, 0x27);
+ else
+ /* Disable MHL Discovery */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0010, 0x26);
mhl_i2c_reg_write(TX_PAGE_3, 0x0016, 0x20);
/* MHL CBUS Discovery - immediate comm. */
mhl_i2c_reg_write(TX_PAGE_3, 0x0012, 0x86);
/* Do not force HPD to 0 during wake-up from D3 */
- if (mhl_msm_state->cur_state != POWER_STATE_D3) {
- mhl_i2c_reg_modify(TX_PAGE_3, 0x0020,
- BIT5 | BIT4, BIT4);
- }
+ if (mhl_msm_state->cur_state != POWER_STATE_D0_MHL)
+ mhl_drive_hpd(HPD_DOWN);
+
/* Enable Auto Soft RESET */
mhl_i2c_reg_write(TX_PAGE_3, 0x0000, 0x084);
/* HDMI Transcode mode enable */
@@ -452,7 +510,10 @@
/* MHL spec requires a 100 ms wait here. */
msleep(100);
- mhl_init_reg_settings();
+ /*
+ * Need to disable MHL discovery
+ */
+ mhl_init_reg_settings(true);
/*
* Power down the chip to the
@@ -563,6 +624,7 @@
/* MHL SII 8334 chip specific init */
mhl_chip_init();
+ init_completion(&mhl_msm_state->rgnd_done);
return 0;
init_exit:
@@ -583,10 +645,9 @@
case POWER_STATE_D0_NO_MHL:
break;
case POWER_STATE_D0_MHL:
- mhl_init_reg_settings();
-
+ mhl_init_reg_settings(true);
/* REG_DISC_CTRL1 */
- mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT1, 0);
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT1 | BIT0, BIT0);
/*
* TPI_DEVICE_POWER_STATE_CTRL_REG
@@ -597,16 +658,15 @@
case POWER_STATE_D3:
if (mhl_msm_state->cur_state != POWER_STATE_D3) {
/* Force HPD to 0 when not in MHL mode. */
- mhl_i2c_reg_modify(TX_PAGE_3, 0x0020,
- BIT5 | BIT4, BIT4);
-
+ mhl_drive_hpd(HPD_DOWN);
/*
* Change TMDS termination to high impedance
* on disconnection.
*/
mhl_i2c_reg_write(TX_PAGE_3, 0x0030, 0xD0);
- mhl_i2c_reg_modify(TX_PAGE_L1, 0x003D,
- BIT1 | BIT0, BIT0);
+ msleep(50);
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0010,
+ BIT1 | BIT0, BIT1);
spin_lock_irqsave(&mhl_state_lock, flags);
mhl_msm_state->cur_state = POWER_STATE_D3;
spin_unlock_irqrestore(&mhl_state_lock, flags);
@@ -619,6 +679,11 @@
static void mhl_drive_hpd(uint8_t to_state)
{
+ if (mhl_msm_state->cur_state != POWER_STATE_D0_MHL) {
+ pr_err("MHL: invalid state to ctrl HPD\n");
+ return;
+ }
+
pr_debug("%s: To state=[0x%x]\n", __func__, to_state);
if (to_state == HPD_UP) {
/*
@@ -644,6 +709,7 @@
* Disable TMDS Output on REG_TMDS_CCTRL
* Enable/Disable TMDS output (MHL TMDS output only)
*/
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x20, BIT4 | BIT5, BIT4);
mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080, BIT4, 0x00);
}
return;
@@ -682,20 +748,11 @@
static void mhl_msm_disconnection(void)
{
- uint8_t reg;
- /* Clear interrupts - REG INTR4 */
- reg = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);
- mhl_i2c_reg_write(TX_PAGE_3, 0x0021, reg);
/*
* MHL TX CTL1
* Disabling Tx termination
*/
mhl_i2c_reg_write(TX_PAGE_3, 0x30, 0xD0);
- /*
- * MSC REQUESTOR ABORT REASON
- * Clear CBUS_HPD status
- */
- mhl_i2c_reg_modify(TX_PAGE_CBUS, 0x000D, BIT6, 0x00);
/* Change HPD line to drive it low */
mhl_drive_hpd(HPD_DOWN);
/* switch power state to D3 */
@@ -704,11 +761,11 @@
}
/*
- * If hardware detected a change in impedence and raised an INTR
- * We check the range of this impedence to infer if the connected
+ * If hardware detected a change in impedance and raised an INTR
+ * We check the range of this impedance to infer if the connected
* device is MHL or USB and take appropriate actions.
*/
-static void mhl_msm_read_rgnd_int(void)
+static int mhl_msm_read_rgnd_int(void)
{
uint8_t rgnd_imp;
@@ -720,20 +777,27 @@
* 10 - 1 kOHM ***(MHL)**** It's range 800 - 1200 OHM from MHL spec
* 11 - short (USB)
*/
- rgnd_imp = mhl_i2c_reg_read(TX_PAGE_3, 0x001C);
+ rgnd_imp = (mhl_i2c_reg_read(TX_PAGE_3, 0x001C) & (BIT1 | BIT0));
pr_debug("Imp Range read = %02X\n", (int)rgnd_imp);
-
if (0x02 == rgnd_imp) {
pr_debug("MHL: MHL DEVICE!!!\n");
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT0, BIT0);
/*
* Handling the MHL event in driver
*/
- mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT0, BIT0);
+ mhl_msm_state->mhl_mode = TRUE;
+ if (notify_usb_online)
+ notify_usb_online(1);
} else {
pr_debug("MHL: NON-MHL DEVICE!!!\n");
+ mhl_msm_state->mhl_mode = FALSE;
mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT3, BIT3);
+ switch_mode(POWER_STATE_D3);
}
+ complete(&mhl_msm_state->rgnd_done);
+ return mhl_msm_state->mhl_mode ?
+ MHL_DISCOVERY_RESULT_MHL : MHL_DISCOVERY_RESULT_USB;
}
static void force_usb_switch_open(void)
@@ -756,7 +820,7 @@
static void int_4_isr(void)
{
- uint8_t status;
+ uint8_t status, reg ;
/* INTR_STATUS4 */
status = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);
@@ -767,7 +831,7 @@
* do nothing.
*/
if ((0x00 == status) && (mhl_msm_state->cur_state == POWER_STATE_D3)) {
- mhl_chip_init();
+ pr_debug("MHL: spurious interrupt\n");
return;
}
if (0xFF != status) {
@@ -816,8 +880,13 @@
if (status & BIT5) {
mhl_connect_api(false);
+ /* Clear interrupts - REG INTR4 */
+ reg = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0021, reg);
mhl_msm_disconnection();
- pr_debug("MHL Disconn Drv: INT4 Status = %02X\n",
+ if (notify_usb_online)
+ notify_usb_online(0);
+ pr_debug("MHL Disconnect Drv: INT4 Status = %02X\n",
(int)status);
}
@@ -971,6 +1040,122 @@
return;
}
+static void clear_all_intrs(void)
+{
+ uint8_t regval = 0x00;
+ /*
+ * intr status debug
+ */
+ pr_debug("********* EXITING ISR MASK CHECK ?? *************\n");
+ pr_debug("Drv: INT1 MASK = %02X\n",
+ (int) mhl_i2c_reg_read(TX_PAGE_L0, 0x0071));
+ pr_debug("Drv: INT3 MASK = %02X\n",
+ (int) mhl_i2c_reg_read(TX_PAGE_L0, 0x0077));
+ pr_debug("Drv: INT4 MASK = %02X\n",
+ (int) mhl_i2c_reg_read(TX_PAGE_3, 0x0021));
+ pr_debug("Drv: INT5 MASK = %02X\n",
+ (int) mhl_i2c_reg_read(TX_PAGE_3, 0x0023));
+ pr_debug("Drv: CBUS1 MASK = %02X\n",
+ (int) mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0009));
+ pr_debug("Drv: CBUS2 MASK = %02X\n",
+ (int) mhl_i2c_reg_read(TX_PAGE_CBUS, 0x001F));
+ pr_debug("********* END OF ISR MASK CHECK *************\n");
+
+ pr_debug("********* EXITING IN ISR ?? *************\n");
+ regval = mhl_i2c_reg_read(TX_PAGE_L0, 0x0071);
+ pr_debug("Drv: INT1 Status = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_L0, 0x0071, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_L0, 0x0072);
+ pr_debug("Drv: INT2 Status = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_L0, 0x0072, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_L0, 0x0073);
+ pr_debug("Drv: INT3 Status = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_L0, 0x0073, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);
+ pr_debug("Drv: INT4 Status = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0021, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_3, 0x0023);
+ pr_debug("Drv: INT5 Status = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0023, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0008);
+ pr_debug("Drv: cbusInt Status = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0008, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x001E);
+ pr_debug("Drv: CBUS INTR_2: %d\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x001E, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00A0);
+ pr_debug("Drv: A0 INT Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00A0, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00A1);
+ pr_debug("Drv: A1 INT Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00A1, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00A2);
+ pr_debug("Drv: A2 INT Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00A2, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00A3);
+ pr_debug("Drv: A3 INT Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00A3, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00B0);
+ pr_debug("Drv: B0 STATUS Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00B0, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00B1);
+ pr_debug("Drv: B1 STATUS Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00B1, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00B2);
+ pr_debug("Drv: B2 STATUS Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00B2, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00B3);
+ pr_debug("Drv: B3 STATUS Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00B3, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00E0);
+ pr_debug("Drv: E0 STATUS Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00E0, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00E1);
+ pr_debug("Drv: E1 STATUS Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00E1, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00E2);
+ pr_debug("Drv: E2 STATUS Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00E2, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00E3);
+ pr_debug("Drv: E3 STATUS Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00E3, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00F0);
+ pr_debug("Drv: F0 INT Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00F0, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00F1);
+ pr_debug("Drv: F1 INT Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00F1, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00F2);
+ pr_debug("Drv: F2 INT Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00F2, regval);
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x00F3);
+ pr_debug("Drv: F3 INT Set = %02X\n", (int)regval);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x00F3, regval);
+ pr_debug("********* END OF EXITING IN ISR *************\n");
+}
+
static irqreturn_t mhl_tx_isr(int irq, void *dev_id)
{
/*
@@ -997,6 +1182,7 @@
mhl_cbus_isr();
int_1_isr();
}
+ clear_all_intrs();
return IRQ_HANDLED;
}
diff --git a/drivers/video/msm/mhl/mhl_i2c_utils.c b/drivers/video/msm/mhl/mhl_i2c_utils.c
index aab6e02..ee069bb 100644
--- a/drivers/video/msm/mhl/mhl_i2c_utils.c
+++ b/drivers/video/msm/mhl/mhl_i2c_utils.c
@@ -11,9 +11,9 @@
*
*/
#include <linux/i2c.h>
+#include <linux/mhl_8334.h>
#include "mhl_i2c_utils.h"
-#include "mhl_8334.h"
uint8_t slave_addrs[MAX_PAGES] = {
DEV_PAGE_TPI_0 ,
diff --git a/drivers/video/msm/mhl/mhl_i2c_utils.h b/drivers/video/msm/mhl/mhl_i2c_utils.h
index 76498d4..5a2d199 100644
--- a/drivers/video/msm/mhl/mhl_i2c_utils.h
+++ b/drivers/video/msm/mhl/mhl_i2c_utils.h
@@ -16,8 +16,7 @@
#include <linux/i2c.h>
#include <linux/types.h>
-
-#include "mhl_defs.h"
+#include <linux/mhl_defs.h>
/*
* I2C command to the adapter to append
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 18ee3e6..176f56b 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -107,6 +107,9 @@
static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg);
static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma);
+static int mdp_bl_scale_config(struct msm_fb_data_type *mfd,
+ struct mdp_bl_scale_data *data);
+static void msm_fb_scale_bl(__u32 *bl_lvl);
#ifdef MSM_FB_ENABLE_DBGFS
@@ -116,6 +119,7 @@
int msm_fb_debugfs_file_index;
struct dentry *msm_fb_debugfs_root;
struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS];
+static int bl_scale, bl_min_lvl;
DEFINE_MUTEX(msm_fb_notify_update_sem);
void msmfb_no_update_notify_timer_cb(unsigned long data)
@@ -189,6 +193,7 @@
static struct msm_fb_platform_data *msm_fb_pdata;
unsigned char hdmi_prim_display;
+unsigned char hdmi_prim_resolution;
int msm_fb_detect_client(const char *name)
{
@@ -209,6 +214,8 @@
if (!strncmp((char *)msm_fb_pdata->prim_panel_name,
"hdmi_msm", len))
hdmi_prim_display = 1;
+ hdmi_prim_resolution =
+ msm_fb_pdata->ext_resolution;
return 0;
} else {
ret = -EPERM;
@@ -372,6 +379,8 @@
mfd->panel_info.frame_count = 0;
mfd->bl_level = 0;
+ bl_scale = 1024;
+ bl_min_lvl = 255;
#ifdef CONFIG_FB_MSM_OVERLAY
mfd->overlay_play_enable = 1;
#endif
@@ -633,6 +642,12 @@
struct msm_fb_panel_data *pdata = NULL;
int ret = 0;
+ if (hdmi_prim_display) {
+ MSM_FB_INFO("%s: hdmi primary handles early suspend only\n",
+ __func__);
+ return 0;
+ }
+
if ((!mfd) || (mfd->key != MFD_KEY))
return 0;
@@ -658,6 +673,12 @@
struct msm_fb_panel_data *pdata = NULL;
int ret = 0;
+ if (hdmi_prim_display) {
+ MSM_FB_INFO("%s: hdmi primary handles early resume only\n",
+ __func__);
+ return 0;
+ }
+
if ((!mfd) || (mfd->key != MFD_KEY))
return 0;
@@ -682,7 +703,8 @@
.runtime_suspend = msm_fb_runtime_suspend,
.runtime_resume = msm_fb_runtime_resume,
.runtime_idle = msm_fb_runtime_idle,
-#if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL))
+#if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL) && \
+ !defined(CONFIG_FB_MSM_HDMI_AS_PRIMARY))
.suspend = msm_fb_ext_suspend,
.resume = msm_fb_ext_resume,
#endif
@@ -716,7 +738,9 @@
static void msmfb_early_suspend(struct early_suspend *h)
{
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
- early_suspend);
+ early_suspend);
+ struct msm_fb_panel_data *pdata = NULL;
+
#if defined(CONFIG_FB_MSM_MDP303)
/*
* For MDP with overlay, set framebuffer with black pixels
@@ -734,23 +758,78 @@
}
#endif
msm_fb_suspend_sub(mfd);
+
+ pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
+ if (hdmi_prim_display &&
+ (mfd->panel_info.type == HDMI_PANEL ||
+ mfd->panel_info.type == DTV_PANEL)) {
+ /* Turn off the HPD circuitry */
+ if (pdata->power_ctrl) {
+ MSM_FB_INFO("%s: Turning off HPD circuitry\n",
+ __func__);
+ pdata->power_ctrl(FALSE);
+ }
+ }
}
static void msmfb_early_resume(struct early_suspend *h)
{
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
- early_suspend);
+ early_suspend);
+ struct msm_fb_panel_data *pdata = NULL;
+
+ pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
+ if (hdmi_prim_display &&
+ (mfd->panel_info.type == HDMI_PANEL ||
+ mfd->panel_info.type == DTV_PANEL)) {
+ /* Turn on the HPD circuitry */
+ if (pdata->power_ctrl) {
+ MSM_FB_INFO("%s: Turning on HPD circuitry\n", __func__);
+ pdata->power_ctrl(TRUE);
+ }
+ }
+
msm_fb_resume_sub(mfd);
}
#endif
static int unset_bl_level, bl_updated;
static int bl_level_old;
+static int mdp_bl_scale_config(struct msm_fb_data_type *mfd,
+ struct mdp_bl_scale_data *data)
+{
+ int ret = 0;
+ int curr_bl = mfd->bl_level;
+ bl_scale = data->scale;
+ bl_min_lvl = data->min_lvl;
+ pr_debug("%s: update scale = %d, min_lvl = %d\n", __func__, bl_scale,
+ bl_min_lvl);
+
+ /* update current backlight to use new scaling*/
+ msm_fb_set_backlight(mfd, curr_bl);
+
+ return ret;
+}
+
+static void msm_fb_scale_bl(__u32 *bl_lvl)
+{
+ __u32 temp = *bl_lvl;
+ if (temp >= bl_min_lvl) {
+ /* bl_scale is the numerator of scaling fraction (x/1024)*/
+ temp = ((*bl_lvl) * bl_scale) / 1024;
+
+ /*if less than minimum level, use min level*/
+ if (temp < bl_min_lvl)
+ temp = bl_min_lvl;
+ }
+
+ (*bl_lvl) = temp;
+}
void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl)
{
struct msm_fb_panel_data *pdata;
-
+ __u32 temp = bkl_lvl;
if (!mfd->panel_power_on || !bl_updated) {
unset_bl_level = bkl_lvl;
return;
@@ -758,17 +837,19 @@
unset_bl_level = 0;
}
+ msm_fb_scale_bl(&temp);
pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
if ((pdata) && (pdata->set_backlight)) {
down(&mfd->sem);
- if (bl_level_old == bkl_lvl) {
+ if (bl_level_old == temp) {
up(&mfd->sem);
return;
}
- mfd->bl_level = bkl_lvl;
+ mfd->bl_level = temp;
pdata->set_backlight(mfd);
- bl_level_old = mfd->bl_level;
+ mfd->bl_level = bkl_lvl;
+ bl_level_old = temp;
up(&mfd->sem);
}
}
@@ -1394,7 +1475,7 @@
ret = 0;
#ifdef CONFIG_HAS_EARLYSUSPEND
- if (mfd->panel_info.type != DTV_PANEL) {
+ if (hdmi_prim_display || mfd->panel_info.type != DTV_PANEL) {
mfd->early_suspend.suspend = msmfb_early_suspend;
mfd->early_suspend.resume = msmfb_early_resume;
mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2;
@@ -3133,7 +3214,8 @@
return 0;
}
-static int msmfb_handle_pp_ioctl(struct msmfb_mdp_pp *pp_ptr)
+static int msmfb_handle_pp_ioctl(struct msm_fb_data_type *mfd,
+ struct msmfb_mdp_pp *pp_ptr)
{
int ret = -1;
@@ -3178,6 +3260,11 @@
&pp_ptr->data.qseed_cfg_data);
break;
#endif
+ case mdp_bl_scale_cfg:
+ ret = mdp_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
+ &pp_ptr->data.bl_scale_data);
+ break;
+
default:
pr_warn("Unsupported request to MDP_PP IOCTL.\n");
ret = -EINVAL;
@@ -3496,7 +3583,7 @@
if (ret)
return ret;
- ret = msmfb_handle_pp_ioctl(&mdp_pp);
+ ret = msmfb_handle_pp_ioctl(mfd, &mdp_pp);
break;
default:
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 6571245..22eaf4f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -161,11 +161,6 @@
encoder = &ddl->codec_data.encoder;
vidc_1080p_get_encoder_sequence_header_size(
&encoder->seq_header_length);
- if ((encoder->codec.codec == VCD_CODEC_H264) &&
- (encoder->profile.profile == VCD_PROFILE_H264_BASELINE))
- if ((encoder->seq_header.align_virtual_addr) &&
- (encoder->seq_header_length > 6))
- encoder->seq_header.align_virtual_addr[6] = 0xC0;
ddl_context->ddl_callback(VCD_EVT_RESP_START, VCD_S_SUCCESS,
NULL, 0, (u32 *) ddl, ddl->client_data);
ddl_release_command_channel(ddl_context,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index a6001eb..d1f6e07 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -380,7 +380,7 @@
encode_profile = VIDC_1080P_PROFILE_MPEG4_ADV_SIMPLE;
break;
case VCD_PROFILE_H264_BASELINE:
- encode_profile = VIDC_1080P_PROFILE_H264_BASELINE;
+ encode_profile = VIDC_1080P_PROFILE_H264_CONSTRAINED_BASELINE;
break;
case VCD_PROFILE_H264_MAIN:
encode_profile = VIDC_1080P_PROFILE_H264_MAIN;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.h b/drivers/video/msm/vidc/1080p/ddl/vidc.h
index 7460ef3..7b8dc6f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.h
@@ -311,6 +311,7 @@
#define VIDC_1080P_PROFILE_H264_MAIN 0x00000000
#define VIDC_1080P_PROFILE_H264_HIGH 0x00000001
#define VIDC_1080P_PROFILE_H264_BASELINE 0x00000002
+#define VIDC_1080P_PROFILE_H264_CONSTRAINED_BASELINE 0x00000003
enum vidc_1080p_decode{
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 28c0917..b2b79b1 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -259,6 +259,7 @@
header-y += msdos_fs.h
header-y += msg.h
header-y += msm_adc.h
+header-y += epm_adc.h
header-y += mtio.h
header-y += n_r3964.h
header-y += nbd.h
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index e0058d3..d19dfa5 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -36,6 +36,9 @@
#define DMX_FILTER_SIZE 16
+/* Min recording chunk upon which event is generated */
+#define DMX_REC_BUFF_CHUNK_MIN_SIZE (100*188)
+
typedef enum
{
DMX_OUT_DECODER, /* Streaming directly to decoder. */
@@ -135,7 +138,6 @@
enum dmx_indexing_video_profile profile;
};
-
struct dmx_pes_filter_params
{
__u16 pid;
@@ -144,6 +146,18 @@
dmx_pes_type_t pes_type;
__u32 flags;
+ /*
+ * The following configures when the event
+ * DMX_EVENT_NEW_REC_CHUNK will be triggered.
+ * When new recorded data is received with size
+ * equal or larger than this value a new event
+ * will be triggered. This is relevent when
+ * output is DMX_OUT_TS_TAP or DMX_OUT_TSDEMUX_TAP,
+ * size must be at least DMX_REC_BUFF_CHUNK_MIN_SIZE
+ * and smaller than buffer size.
+ */
+ __u32 rec_chunk_size;
+
struct dmx_indexing_video_params video_params;
};
@@ -170,6 +184,129 @@
int error;
};
+/* Events associated with each demux filter */
+enum dmx_event {
+ /* New PES packet is ready to be consumed */
+ DMX_EVENT_NEW_PES,
+
+ /* New section is ready to be consumed */
+ DMX_EVENT_NEW_SECTION,
+
+ /* New recording chunk is ready to be consumed */
+ DMX_EVENT_NEW_REC_CHUNK,
+
+ /* New PCR value is ready */
+ DMX_EVENT_NEW_PCR,
+
+ /* Overflow */
+ DMX_EVENT_BUFFER_OVERFLOW,
+
+ /* Section was dropped due to CRC error */
+ DMX_EVENT_SECTION_CRC_ERROR,
+
+ /* End-of-stream, no more data from this filter */
+ DMX_EVENT_EOS
+};
+
+/* Flags passed in filter events */
+
+/* Continuity counter error was detected */
+#define DMX_FILTER_CC_ERROR 0x01
+
+/* Discontinuity indicator was set */
+#define DMX_FILTER_DISCONTINUITY_INDEICATOR 0x02
+
+/* PES legnth in PES header is not correct */
+#define DMX_FILTER_PES_LENGTH_ERROR 0x04
+
+
+/* PES info associated with DMX_EVENT_NEW_PES event */
+struct dmx_pes_event_info {
+ /* Offset at which PES information starts */
+ __u32 base_offset;
+
+ /*
+ * Start offset at which PES data
+ * from the stream starts.
+ * Equal to base_offset if PES data
+ * starts from the beginning.
+ */
+ __u32 start_offset;
+
+ /* Total length holding the PES information */
+ __u32 total_length;
+
+ /* Actual length holding the PES data */
+ __u32 actual_length;
+
+ /* Local receiver timestamp in 27MHz */
+ __u64 stc;
+
+ /* Flags passed in filter events */
+ __u32 flags;
+};
+
+/* Section info associated with DMX_EVENT_NEW_SECTION event */
+struct dmx_section_event_info {
+ /* Offset at which section information starts */
+ __u32 base_offset;
+
+ /*
+ * Start offset at which section data
+ * from the stream starts.
+ * Equal to base_offset if section data
+ * starts from the beginning.
+ */
+ __u32 start_offset;
+
+ /* Total length holding the section information */
+ __u32 total_length;
+
+ /* Actual length holding the section data */
+ __u32 actual_length;
+
+ /* Flags passed in filter events */
+ __u32 flags;
+};
+
+/* Recording info associated with DMX_EVENT_NEW_REC_CHUNK event */
+struct dmx_rec_chunk_event_info {
+ /* Offset at which recording chunk starts */
+ __u32 offset;
+
+ /* Size of recording chunk in bytes */
+ __u32 size;
+};
+
+/* PCR info associated with DMX_EVENT_NEW_PCR event */
+struct dmx_pcr_event_info {
+ /* Local timestamp in 27MHz
+ * when PCR packet was received
+ */
+ __u64 stc;
+
+ /* PCR value in 27MHz */
+ __u64 pcr;
+
+ /* Flags passed in filter events */
+ __u32 flags;
+};
+
+/*
+ * Filter's event returned through DMX_GET_EVENT.
+ * poll with POLLPRI would block until events are available.
+ */
+struct dmx_filter_event {
+ enum dmx_event type;
+
+ union {
+ struct dmx_pes_event_info pes;
+ struct dmx_section_event_info section;
+ struct dmx_rec_chunk_event_info recording_chunk;
+ struct dmx_pcr_event_info pcr;
+ } params;
+};
+
typedef struct dmx_caps {
__u32 caps;
@@ -292,5 +429,6 @@
#define DMX_RELEASE_DATA _IO('o', 57)
#define DMX_FEED_DATA _IO('o', 58)
#define DMX_SET_PLAYBACK_MODE _IOW('o', 59, enum dmx_playback_mode_t)
+#define DMX_GET_EVENT _IOR('o', 60, struct dmx_filter_event)
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/epm_adc.h b/include/linux/epm_adc.h
index 1af97fe..9cf2acf 100644
--- a/include/linux/epm_adc.h
+++ b/include/linux/epm_adc.h
@@ -1,16 +1,3 @@
-/*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
- *
- * This 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 __EPM_ADC_H
#define __EPM_ADC_H
@@ -26,6 +13,7 @@
int32_t physical;
};
+#ifdef __KERNEL__
struct epm_chan_properties {
uint32_t resistorValue;
uint32_t gain;
@@ -41,6 +29,7 @@
uint32_t bus_id;
uint32_t gpio_expander_base_addr;
};
+#endif
#define EPM_ADC_IOCTL_CODE 0x91
diff --git a/include/linux/leds-msm-tricolor.h b/include/linux/leds-msm-tricolor.h
new file mode 100644
index 0000000..314645e
--- /dev/null
+++ b/include/linux/leds-msm-tricolor.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This 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 __LEDS_MSM_TRICOLOR__
+enum tri_color_led_color {
+ LED_COLOR_RED,
+ LED_COLOR_GREEN,
+ LED_COLOR_BLUE,
+ LED_COLOR_MAX
+};
+#endif
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 2657ec3..17be2cb 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -155,6 +155,11 @@
int num_rx_port;
int num_tx_port;
+
+ u8 idbyte_0;
+ u8 idbyte_1;
+ u8 idbyte_2;
+ u8 idbyte_3;
};
int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
diff --git a/drivers/video/msm/mhl/mhl_8334.h b/include/linux/mhl_8334.h
similarity index 66%
rename from drivers/video/msm/mhl/mhl_8334.h
rename to include/linux/mhl_8334.h
index eba544a..1b19103 100644
--- a/drivers/video/msm/mhl/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -17,9 +17,8 @@
#include <linux/types.h>
#include <linux/platform_device.h>
#include <mach/board.h>
-
-#include "mhl_devcap.h"
-#include "mhl_defs.h"
+#include <linux/mhl_devcap.h>
+#include <linux/mhl_defs.h>
#define MHL_DEVICE_NAME "sii8334"
#define MHL_DRIVER_NAME "sii8334"
@@ -27,12 +26,48 @@
#define HPD_UP 1
#define HPD_DOWN 0
+enum discovery_result_enum {
+ MHL_DISCOVERY_RESULT_USB = 0,
+ MHL_DISCOVERY_RESULT_MHL,
+};
+
+/* USB driver interface */
+
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+ /* mhl_device_discovery */
+extern int mhl_device_discovery(const char *name, int *result);
+
+/* - register|unregister MHL cable plug callback. */
+extern int mhl_register_callback
+ (const char *name, void (*callback)(int online));
+extern int mhl_unregister_callback(const char *name);
+#else
+static inline int mhl_device_discovery(const char *name, int *result)
+{
+ return -ENODEV;
+}
+
+static inline int
+ mhl_register_callback(const char *name, void (*callback)(int online))
+{
+ return -ENODEV;
+}
+
+static inline int mhl_unregister_callback(const char *name)
+{
+ return -ENODEV;
+}
+#endif
+
struct mhl_msm_state_t {
struct i2c_client *i2c_client;
struct i2c_driver *i2c_driver;
uint8_t cur_state;
uint8_t chip_rev_id;
struct msm_mhl_platform_data *mhl_data;
+ /* Device Discovery stuff */
+ int mhl_mode;
+ struct completion rgnd_done;
};
enum {
diff --git a/drivers/video/msm/mhl/mhl_defs.h b/include/linux/mhl_defs.h
similarity index 100%
rename from drivers/video/msm/mhl/mhl_defs.h
rename to include/linux/mhl_defs.h
diff --git a/drivers/video/msm/mhl/mhl_devcap.h b/include/linux/mhl_devcap.h
similarity index 100%
rename from drivers/video/msm/mhl/mhl_devcap.h
rename to include/linux/mhl_devcap.h
diff --git a/include/linux/msm_charm.h b/include/linux/msm_charm.h
index c31e493..44d2553 100644
--- a/include/linux/msm_charm.h
+++ b/include/linux/msm_charm.h
@@ -11,10 +11,15 @@
#define RAM_DUMP_DONE _IOW(CHARM_CODE, 6, int)
#define WAIT_FOR_RESTART _IOR(CHARM_CODE, 7, int)
#define GET_DLOAD_STATUS _IOR(CHARM_CODE, 8, int)
+#define IMAGE_UPGRADE _IOW(CHARM_CODE, 9, int)
enum charm_boot_type {
CHARM_NORMAL_BOOT = 0,
CHARM_RAM_DUMPS,
};
+enum image_upgrade_type {
+ APQ_CONTROLLED_UPGRADE = 0,
+ MDM_CONTROLLED_UPGRADE,
+};
#endif
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index e67190f..7afc896 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -49,8 +49,6 @@
KGSL_CTX_STAT_UNKNOWN_CONTEXT_RESET_EXT = 0x00000003
};
-#define KGSL_MAX_PWRLEVELS 5
-
#define KGSL_CONVERT_TO_MBPS(val) \
(val*1000*1000U)
@@ -135,12 +133,6 @@
unsigned int flags; /* contains KGSL_FLAGS_ values */
};
-struct kgsl_pwrlevel {
- unsigned int gpu_freq;
- unsigned int bus_freq;
- unsigned int io_fraction;
-};
-
struct kgsl_version {
unsigned int drv_major;
unsigned int drv_minor;
@@ -148,50 +140,6 @@
unsigned int dev_minor;
};
-#ifdef __KERNEL__
-
-#define KGSL_3D0_REG_MEMORY "kgsl_3d0_reg_memory"
-#define KGSL_3D0_IRQ "kgsl_3d0_irq"
-#define KGSL_2D0_REG_MEMORY "kgsl_2d0_reg_memory"
-#define KGSL_2D0_IRQ "kgsl_2d0_irq"
-#define KGSL_2D1_REG_MEMORY "kgsl_2d1_reg_memory"
-#define KGSL_2D1_IRQ "kgsl_2d1_irq"
-
-enum kgsl_iommu_context_id {
- KGSL_IOMMU_CONTEXT_USER = 0,
- KGSL_IOMMU_CONTEXT_PRIV = 1,
-};
-
-struct kgsl_iommu_ctx {
- const char *iommu_ctx_name;
- enum kgsl_iommu_context_id ctx_id;
-};
-
-struct kgsl_device_iommu_data {
- const struct kgsl_iommu_ctx *iommu_ctxs;
- int iommu_ctx_count;
- unsigned int physstart;
- unsigned int physend;
-};
-
-struct kgsl_device_platform_data {
- struct kgsl_pwrlevel pwrlevel[KGSL_MAX_PWRLEVELS];
- int init_level;
- int num_levels;
- int (*set_grp_async)(void);
- unsigned int idle_timeout;
- bool strtstp_sleepwake;
- unsigned int nap_allowed;
- unsigned int clk_map;
- unsigned int idle_needed;
- struct msm_bus_scale_pdata *bus_scale_table;
- struct kgsl_device_iommu_data *iommu_data;
- int iommu_count;
- struct msm_dcvs_core_info *core_info;
-};
-
-#endif
-
/* structure holds list of ibs */
struct kgsl_ibdesc {
unsigned int gpuaddr;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 19728fe..d8edbc8 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -434,7 +434,6 @@
uint32_t *data;
};
-
struct mdp_lut_cfg_data {
uint32_t lut_type;
union {
@@ -452,12 +451,17 @@
uint32_t *data;
};
+struct mdp_bl_scale_data {
+ uint32_t min_lvl;
+ uint32_t scale;
+};
enum {
mdp_op_pcc_cfg,
mdp_op_csc_cfg,
mdp_op_lut_cfg,
mdp_op_qseed_cfg,
+ mdp_bl_scale_cfg,
mdp_op_max,
};
@@ -468,6 +472,7 @@
struct mdp_csc_cfg_data csc_cfg_data;
struct mdp_lut_cfg_data lut_cfg_data;
struct mdp_qseed_cfg_data qseed_cfg_data;
+ struct mdp_bl_scale_data bl_scale_data;
} data;
};
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index ed136ad..e3d59cd 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -119,6 +119,11 @@
extern void early_init_devtree(void *);
#else /* CONFIG_OF_FLATTREE */
static inline void unflatten_device_tree(void) {}
+static inline void *of_get_flat_dt_prop(unsigned long node, const char *name,
+ unsigned long *size) { return NULL; }
+
+static inline int of_flat_dt_is_compatible(unsigned long node,
+ const char *name) { return 0; }
#endif /* CONFIG_OF_FLATTREE */
#endif /* __ASSEMBLY__ */
diff --git a/include/linux/qseecom.h b/include/linux/qseecom.h
index 0fcf96f..b0f089b 100644
--- a/include/linux/qseecom.h
+++ b/include/linux/qseecom.h
@@ -110,9 +110,11 @@
/*
* struct qseecom_qseos_app_load_query - verify if app is loaded in qsee
* @app_name[MAX_APP_NAME_SIZE]- name of the app.
+ * @app_id - app id.
*/
struct qseecom_qseos_app_load_query {
char app_name[MAX_APP_NAME_SIZE]; /* in */
+ int app_id; /* out */
};
#define QSEECOM_IOC_MAGIC 0x97
diff --git a/include/linux/test-iosched.h b/include/linux/test-iosched.h
index 8054409..1e428c5 100644
--- a/include/linux/test-iosched.h
+++ b/include/linux/test-iosched.h
@@ -65,6 +65,7 @@
REQ_UNIQUE_NONE,
REQ_UNIQUE_DISCARD,
REQ_UNIQUE_FLUSH,
+ REQ_UNIQUE_SANITIZE,
};
/**
diff --git a/include/linux/tick.h b/include/linux/tick.h
index ab8be90..494a314 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -44,7 +44,6 @@
* @idle_exittime: Time when the idle state was left
* @idle_sleeptime: Sum of the time slept in idle with sched tick stopped
* @iowait_sleeptime: Sum of the time slept in idle with sched tick stopped, with IO outstanding
- * @sleep_length: Duration of the current idle sleep
* @do_timer_lst: CPU was the last one doing do_timer before going idle
*/
struct tick_sched {
@@ -63,7 +62,6 @@
ktime_t idle_exittime;
ktime_t idle_sleeptime;
ktime_t iowait_sleeptime;
- ktime_t sleep_length;
unsigned long last_jiffies;
unsigned long next_jiffies;
ktime_t idle_expires;
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
index bf65ebb..7c2b33b 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -21,6 +21,7 @@
int (*update_pid_and_serial_num)(uint32_t, const char *);
u32 swfi_latency;
u8 usb_core_id;
+ bool cdrom;
};
#endif /* __LINUX_USB_ANDROID_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index c0a23a3..3b1d06d 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -199,6 +199,7 @@
* @core_clk_always_on_workaround: Don't disable core_clk when
* USB enters LPM.
* @bus_scale_table: parameters for bus bandwidth requirements
+ * @mhl_dev_name: MHL device name used to register with MHL driver.
*/
struct msm_otg_platform_data {
int *phy_init_seq;
@@ -216,6 +217,7 @@
bool enable_lpm_on_dev_suspend;
bool core_clk_always_on_workaround;
struct msm_bus_scale_pdata *bus_scale_table;
+ const char *mhl_dev_name;
};
/* Timeout (in msec) values (min - max) associated with OTG timers */
@@ -287,6 +289,7 @@
* @id_timer: The timer used for polling ID line to detect ACA states.
* @xo_handle: TCXO buffer handle
* @bus_perf_client: Bus performance client handle to request BUS bandwidth
+ * @mhl_enabled: MHL driver registration successful and MHL enabled.
*/
struct msm_otg {
struct usb_phy phy;
@@ -314,6 +317,7 @@
#define A_BUS_SUSPEND 14
#define A_CONN 15
#define B_BUS_REQ 16
+#define MHL 17
unsigned long inputs;
struct work_struct sm_work;
bool sm_work_pending;
@@ -333,6 +337,7 @@
unsigned long caps;
struct msm_xo_voter *xo_handle;
uint32_t bus_perf_client;
+ bool mhl_enabled;
/*
* Allowing PHY power collpase turns off the HSUSB 3.3v and 1.8v
* analog regulators while going to low power mode.
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 42f7349..3e2f39b 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1751,6 +1751,31 @@
#define V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF (V4L2_CID_MPEG_MSM_VIDC_BASE+18)
#define V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE+19)
+#define V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE (V4L2_CID_MPEG_MSM_VIDC_BASE+20)
+enum v4l2_mpeg_vidc_video_h263_profile {
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE = 0,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING = 1,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE = 2,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2 = 3,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3 = 4,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION = 5,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET = 6,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE = 7,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY = 8,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE+21)
+enum v4l2_mpeg_vidc_video_h263_level {
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0 = 0,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0 = 1,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0 = 2,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0 = 3,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5 = 4,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0 = 5,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0 = 6,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0 = 7,
+};
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1)
@@ -2047,6 +2072,7 @@
#define V4L2_DEC_CMD_STOP (1)
#define V4L2_DEC_CMD_PAUSE (2)
#define V4L2_DEC_CMD_RESUME (3)
+#define V4L2_DEC_QCOM_CMD_FLUSH (4)
/* Flags for V4L2_DEC_CMD_START */
#define V4L2_DEC_CMD_START_MUTE_AUDIO (1 << 0)
@@ -2058,6 +2084,10 @@
#define V4L2_DEC_CMD_STOP_TO_BLACK (1 << 0)
#define V4L2_DEC_CMD_STOP_IMMEDIATELY (1 << 1)
+/* Flags for V4L2_DEC_QCOM_CMD_FLUSH */
+#define V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT (1 << 0)
+#define V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE (1 << 1)
+
/* Play format requirements (returned by the driver): */
/* The decoder has no special format requirements */
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 48058e6..ae81dcd 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -204,6 +204,15 @@
#define MSM_CAM_IOCTL_STATS_FLUSH_BUFQ \
_IOR(MSM_CAM_IOCTL_MAGIC, 57, struct msm_stats_flush_bufq *)
+#define MSM_CAM_IOCTL_SET_MCTL_SDEV \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 58, struct msm_mctl_set_sdev_data *)
+
+#define MSM_CAM_IOCTL_UNSET_MCTL_SDEV \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 59, struct msm_mctl_set_sdev_data *)
+
+#define MSM_CAM_IOCTL_GET_INST_HANDLE \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 60, uint32_t *)
+
struct msm_stats_reqbuf {
int num_buf; /* how many buffers requested */
int stats_type; /* stats type */
@@ -334,6 +343,7 @@
struct msm_pp_frame_mp mp[MAX_PLANES];
};
int node_type;
+ uint32_t inst_handle;
};
struct msm_cam_evt_divert_frame {
@@ -767,7 +777,7 @@
#define MSM_V4L2_PID_CTRL_CMD (V4L2_CID_PRIVATE_BASE+13)
#define MSM_V4L2_PID_EVT_SUB_INFO (V4L2_CID_PRIVATE_BASE+14)
#define MSM_V4L2_PID_STROBE_FLASH (V4L2_CID_PRIVATE_BASE+15)
-#define MSM_V4L2_PID_MMAP_ENTRY (V4L2_CID_PRIVATE_BASE+16)
+#define MSM_V4L2_PID_INST_HANDLE (V4L2_CID_PRIVATE_BASE+16)
#define MSM_V4L2_PID_MMAP_INST (V4L2_CID_PRIVATE_BASE+17)
#define MSM_V4L2_PID_PP_PLANE_INFO (V4L2_CID_PRIVATE_BASE+18)
#define MSM_V4L2_PID_MAX MSM_V4L2_PID_PP_PLANE_INFO
@@ -1623,13 +1633,35 @@
uint8_t num_planes;
struct plane_data plane[MAX_PLANES];
uint32_t sp_y_offset;
- uint8_t vpe_can_use;
+ uint32_t inst_handle;
};
#define QCAMERA_NAME "qcamera"
+#define QCAMERA_SERVER_NAME "qcamera_server"
#define QCAMERA_DEVICE_GROUP_ID 1
#define QCAMERA_VNODE_GROUP_ID 2
+enum msm_cam_subdev_type {
+ CSIPHY_DEV,
+ CSID_DEV,
+ CSIC_DEV,
+ ISPIF_DEV,
+ VFE_DEV,
+ AXI_DEV,
+ VPE_DEV,
+ SENSOR_DEV,
+ ACTUATOR_DEV,
+ EEPROM_DEV,
+ GESTURE_DEV,
+ IRQ_ROUTER_DEV,
+ CPP_DEV,
+};
+
+struct msm_mctl_set_sdev_data {
+ uint32_t revision;
+ enum msm_cam_subdev_type sdev_type;
+};
+
#define MSM_CAM_V4L2_IOCTL_GET_CAMERA_INFO \
_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl_t)
@@ -1654,6 +1686,39 @@
#define MSM_CAM_V4L2_IOCTL_PRIVATE_S_CTRL \
_IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_camera_v4l2_ioctl_t)
+#define MSM_CAM_V4L2_IOCTL_PRIVATE_G_CTRL \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_INIT \
+ _IO('V', BASE_VIDIOC_PRIVATE + 15)
+
+#define VIDIOC_MSM_VPE_RELEASE \
+ _IO('V', BASE_VIDIOC_PRIVATE + 16)
+
+#define VIDIOC_MSM_VPE_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 17, struct msm_mctl_pp_params *)
+
+#define VIDIOC_MSM_AXI_INIT \
+ _IO('V', BASE_VIDIOC_PRIVATE + 18)
+
+#define VIDIOC_MSM_AXI_RELEASE \
+ _IO('V', BASE_VIDIOC_PRIVATE + 19)
+
+#define VIDIOC_MSM_AXI_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 20, void *)
+
+#define VIDIOC_MSM_AXI_IRQ \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 21, void *)
+
+#define VIDIOC_MSM_AXI_BUF_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 22, void *)
+
+#define VIDIOC_MSM_VFE_INIT \
+ _IO('V', BASE_VIDIOC_PRIVATE + 22)
+
+#define VIDIOC_MSM_VFE_RELEASE \
+ _IO('V', BASE_VIDIOC_PRIVATE + 23)
+
struct msm_camera_v4l2_ioctl_t {
uint32_t id;
void __user *ioctl_ptr;
@@ -1804,4 +1869,38 @@
#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0)
+/* Instance Handle - inst_handle
+ * Data bundle containing the information about where
+ * to get a buffer for a particular camera instance.
+ * This is a bitmask containing the following data:
+ * Buffer Handle Bitmask:
+ * ------------------------------------
+ * Bits : Purpose
+ * ------------------------------------
+ * 31 - 24 : Reserved.
+ * 23 : is Image mode valid?
+ * 22 - 16 : Image mode.
+ * 15 : is MCTL PP inst idx valid?
+ * 14 - 8 : MCTL PP inst idx.
+ * 7 : is Video inst idx valid?
+ * 6 - 0 : Video inst idx.
+ */
+#define CLR_IMG_MODE(handle) (handle &= 0xFF00FFFF)
+#define SET_IMG_MODE(handle, data) \
+ (handle |= ((0x1 << 23) | ((data & 0x7F) << 16)))
+#define GET_IMG_MODE(handle) \
+ ((handle & 0x800000) ? ((handle & 0x7F0000) >> 16) : 0xFF)
+
+#define CLR_MCTLPP_INST_IDX(handle) (handle &= 0xFFFF00FF)
+#define SET_MCTLPP_INST_IDX(handle, data) \
+ (handle |= ((0x1 << 15) | ((data & 0x7F) << 8)))
+#define GET_MCTLPP_INST_IDX(handle) \
+ ((handle & 0x8000) ? ((handle & 0x7F00) >> 8) : 0xFF)
+
+#define CLR_VIDEO_INST_IDX(handle) (handle &= 0xFFFFFF00)
+#define GET_VIDEO_INST_IDX(handle) \
+ ((handle & 0x80) ? (handle & 0x7F) : 0xFF)
+#define SET_VIDEO_INST_IDX(handle, data) \
+ (handle |= (0x1 << 7) | (data & 0x7F))
+
#endif /* __LINUX_MSM_CAMERA_H */
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 1f3527b..3df6ded 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -336,7 +336,7 @@
#define VFE_OUTPUTS_RDI1 BIT(12)
struct msm_frame_info {
- uint32_t image_mode;
+ uint32_t inst_handle;
uint32_t path;
};
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index 25a1d84..988de6a 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -599,6 +599,7 @@
V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI,
V4L2_CID_PRIVATE_SPUR_SELECTION,
V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE,
+ V4L2_CID_PRIVATE_VALID_CHANNEL,
/*using private CIDs under userclass*/
V4L2_CID_PRIVATE_IRIS_READ_DEFAULT = 0x00980928,
@@ -786,6 +787,11 @@
#define CALIB_DATA_OFSET 2
#define CALIB_MODE_OFSET 1
#define MAX_CALIB_SIZE 75
+
+/* Channel validity */
+#define INVALID_CHANNEL (0)
+#define VALID_CHANNEL (1)
+
struct hci_fm_set_cal_req_proc {
__u8 mode;
/*Max process calibration data size*/
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index 045c107..f7d1e6b 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -126,7 +126,6 @@
struct vp_work_t {
struct work_struct work;
struct vcap_client_data *cd;
- uint32_t irq;
};
struct vcap_dev {
@@ -221,9 +220,6 @@
extern struct vcap_hacked_vals hacked_buf[];
#endif
-int free_ion_handle(struct vcap_dev *dev, struct vb2_queue *q,
- struct v4l2_buffer *b);
-
-int get_phys_addr(struct vcap_dev *dev, struct vb2_queue *q,
- struct v4l2_buffer *b);
+int vcvp_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
+int vcvp_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b);
#endif
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index c770f13..979db58 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -402,11 +402,15 @@
#define AFE_MODULE_ID_PORT_INFO 0x00010200
/* Module ID for the loopback-related parameters. */
#define AFE_MODULE_LOOPBACK 0x00010205
-struct afe_param_payload {
+struct afe_param_payload_base {
u32 module_id;
u32 param_id;
u16 param_size;
u16 reserved;
+} __packed;
+
+struct afe_param_payload {
+ struct afe_param_payload_base base;
union {
struct afe_param_sidetone_gain sidetone_gain;
struct afe_param_sampling_rate sampling_rate;
@@ -1348,6 +1352,14 @@
u32 uid;
} __attribute__((packed));
+#define ASM_DATA_CMD_READ_COMPRESSED 0x00010DBC
+struct asm_stream_cmd_read_compressed {
+ struct apr_hdr hdr;
+ u32 buf_add;
+ u32 buf_size;
+ u32 uid;
+} __packed;
+
#define ASM_DATA_CMD_MEDIA_FORMAT_UPDATE 0x00010BDC
#define ASM_DATA_EVENT_ENC_SR_CM_NOTIFY 0x00010BDE
struct asm_stream_media_format_update{
@@ -1411,6 +1423,19 @@
u32 id;
} __attribute__((packed));
+#define ASM_DATA_EVENT_READ_COMPRESSED_DONE 0x00010DBD
+struct asm_data_event_read_compressed_done {
+ u32 status;
+ u32 buffer_add;
+ u32 enc_frame_size;
+ u32 offset;
+ u32 msw_ts;
+ u32 lsw_ts;
+ u32 flags;
+ u32 num_frames;
+ u32 id;
+} __packed;
+
#define ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY 0x00010C65
struct asm_data_event_sr_cm_change_notify {
u32 sample_rate;
diff --git a/include/sound/compress_params.h b/include/sound/compress_params.h
index 75558bf..31d684b 100644
--- a/include/sound/compress_params.h
+++ b/include/sound/compress_params.h
@@ -56,6 +56,15 @@
#define MAX_NUM_CODEC_DESCRIPTORS 32
#define MAX_NUM_BITRATES 32
+/* compressed TX */
+#define MAX_NUM_FRAMES_PER_BUFFER 1
+#define COMPRESSED_META_DATA_MODE 0x10
+#define META_DATA_LEN_BYTES 36
+#define Q6_AC3_DECODER 0x00010BF6
+#define Q6_EAC3_DECODER 0x00010C3C
+#define Q6_DTS 0x00010D88
+#define Q6_DTS_LBR 0x00010DBB
+
/* Codecs are listed linearly to allow for extensibility */
#define SND_AUDIOCODEC_PCM ((__u32) 0x00000001)
#define SND_AUDIOCODEC_MP3 ((__u32) 0x00000002)
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index d38dbd5..ea77974 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -151,6 +151,7 @@
atomic_t cmd_state;
atomic_t time_flag;
+ atomic_t nowait_cmd_cnt;
wait_queue_head_t cmd_wait;
wait_queue_head_t time_wait;
@@ -182,7 +183,8 @@
int q6asm_open_read(struct audio_client *ac, uint32_t format);
-int q6asm_open_read_compressed(struct audio_client *ac, uint32_t format);
+int q6asm_open_read_compressed(struct audio_client *ac,
+ uint32_t frames_per_buffer, uint32_t meta_data_mode);
int q6asm_open_write(struct audio_client *ac, uint32_t format);
@@ -203,6 +205,9 @@
int q6asm_async_read(struct audio_client *ac,
struct audio_aio_read_param *param);
+int q6asm_async_read_compressed(struct audio_client *ac,
+ struct audio_aio_read_param *param);
+
int q6asm_read(struct audio_client *ac);
int q6asm_read_nolock(struct audio_client *ac);
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 08f52bb..c6cd85b 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -447,7 +447,6 @@
out:
ts->next_jiffies = next_jiffies;
ts->last_jiffies = last_jiffies;
- ts->sleep_length = ktime_sub(dev->next_event, now);
}
/**
@@ -516,8 +515,8 @@
ktime_t tick_nohz_get_sleep_length(void)
{
struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
-
- return ts->sleep_length;
+ struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
+ return ktime_sub(dev->next_event, ts->idle_entrytime);
}
static void tick_nohz_restart(struct tick_sched *ts, ktime_t now)
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index dd8e2aa..fc15fb1 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -253,7 +253,9 @@
sync_supers_tsk = kthread_run(bdi_sync_supers, NULL, "sync_supers");
BUG_ON(IS_ERR(sync_supers_tsk));
- setup_timer(&sync_supers_timer, sync_supers_timer_fn, 0);
+ init_timer_deferrable(&sync_supers_timer);
+ sync_supers_timer.function = sync_supers_timer_fn;
+ sync_supers_timer.data = 0;
bdi_arm_supers_timer();
err = bdi_init(&default_backing_dev_info);
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 6bbb34b..276ff71 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -711,10 +711,6 @@
invalid_key:
hcon->sec_req = FALSE;
- /* Switch to Pairing Connection Parameters */
- hci_le_conn_update(hcon, SMP_MIN_CONN_INTERVAL, SMP_MAX_CONN_INTERVAL,
- SMP_MAX_CONN_LATENCY, SMP_SUPERVISION_TIMEOUT);
-
skb_pull(skb, sizeof(*rp));
memset(&cp, 0, sizeof(cp));
@@ -776,11 +772,6 @@
if (hcon->link_mode & HCI_LM_MASTER) {
struct smp_cmd_pairing cp;
- /* Switch to Pairing Connection Parameters */
- hci_le_conn_update(hcon, SMP_MIN_CONN_INTERVAL,
- SMP_MAX_CONN_INTERVAL, SMP_MAX_CONN_LATENCY,
- SMP_SUPERVISION_TIMEOUT);
-
build_pairing_cmd(conn, &cp, NULL, authreq);
hcon->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&hcon->preq[1], &cp, sizeof(cp));
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 74ae595..3164a9b 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -3747,20 +3747,6 @@
return 0;
}
-static void tabla_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
- pr_debug("%s(): substream = %s stream = %d\n" , __func__,
- substream->name, substream->stream);
- if ((tabla_core != NULL) &&
- (tabla_core->dev != NULL) &&
- (tabla_core->dev->parent != NULL)) {
- pm_runtime_mark_last_busy(tabla_core->dev->parent);
- pm_runtime_put(tabla_core->dev->parent);
- }
-}
-
int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
{
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
@@ -4310,7 +4296,6 @@
static struct snd_soc_dai_ops tabla_dai_ops = {
.startup = tabla_startup,
- .shutdown = tabla_shutdown,
.hw_params = tabla_hw_params,
.set_sysclk = tabla_set_dai_sysclk,
.set_fmt = tabla_set_dai_fmt,
@@ -4481,9 +4466,17 @@
u32 ret = 0;
codec->control_data = dev_get_drvdata(codec->dev->parent);
tabla = codec->control_data;
+
/* Execute the callback only if interface type is slimbus */
- if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ if (event == SND_SOC_DAPM_POST_PMD && (tabla != NULL) &&
+ (tabla->dev != NULL) &&
+ (tabla->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(tabla->dev->parent);
+ pm_runtime_put(tabla->dev->parent);
+ }
return 0;
+ }
pr_debug("%s: %s %d\n", __func__, w->name, event);
@@ -4534,6 +4527,12 @@
ret = tabla_codec_enable_chmask(tabla_p,
SND_SOC_DAPM_POST_PMD,
j);
+ if ((tabla != NULL) &&
+ (tabla->dev != NULL) &&
+ (tabla->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(tabla->dev->parent);
+ pm_runtime_put(tabla->dev->parent);
+ }
}
}
return ret;
@@ -4553,8 +4552,15 @@
tabla = codec->control_data;
/* Execute the callback only if interface type is slimbus */
- if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ if (event == SND_SOC_DAPM_POST_PMD && (tabla != NULL) &&
+ (tabla->dev != NULL) &&
+ (tabla->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(tabla->dev->parent);
+ pm_runtime_put(tabla->dev->parent);
+ }
return 0;
+ }
pr_debug("%s(): %s %d\n", __func__, w->name, event);
@@ -4604,6 +4610,12 @@
ret = tabla_codec_enable_chmask(tabla_p,
SND_SOC_DAPM_POST_PMD,
j);
+ if ((tabla != NULL) &&
+ (tabla->dev != NULL) &&
+ (tabla->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(tabla->dev->parent);
+ pm_runtime_put(tabla->dev->parent);
+ }
}
}
return ret;
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index a4bc2ef..d8a4624 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -98,8 +98,6 @@
static struct clk *codec_clk;
static int clk_users;
-static int msm_headset_gpios_configured;
-
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
@@ -1971,57 +1969,6 @@
static struct platform_device *msm_snd_device;
-static int msm_configure_headset_mic_gpios(void)
-{
- int ret;
- struct pm_gpio param = {
- .direction = PM_GPIO_DIR_OUT,
- .output_buffer = PM_GPIO_OUT_BUF_CMOS,
- .output_value = 1,
- .pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_S4,
- .out_strength = PM_GPIO_STRENGTH_MED,
- .function = PM_GPIO_FUNC_NORMAL,
- };
-
- ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH");
- if (ret) {
- pr_err("%s: Failed to request gpio %d\n", __func__,
- PM8921_GPIO_PM_TO_SYS(23));
- return ret;
- }
-
- ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), ¶m);
- if (ret)
- pr_err("%s: Failed to configure gpio %d\n", __func__,
- PM8921_GPIO_PM_TO_SYS(23));
- else
- gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
-
- ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
- if (ret) {
- pr_err("%s: Failed to request gpio %d\n", __func__,
- PM8921_GPIO_PM_TO_SYS(35));
- gpio_free(PM8921_GPIO_PM_TO_SYS(23));
- return ret;
- }
- ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), ¶m);
- if (ret)
- pr_err("%s: Failed to configure gpio %d\n", __func__,
- PM8921_GPIO_PM_TO_SYS(35));
- else
- gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 0);
-
- return 0;
-}
-static void msm_free_headset_mic_gpios(void)
-{
- if (msm_headset_gpios_configured) {
- gpio_free(PM8921_GPIO_PM_TO_SYS(23));
- gpio_free(PM8921_GPIO_PM_TO_SYS(35));
- }
-}
-
static int __init msm_audio_init(void)
{
int ret;
@@ -2052,12 +1999,6 @@
return ret;
}
- if (msm_configure_headset_mic_gpios()) {
- pr_err("%s Fail to configure headset mic gpios\n", __func__);
- msm_headset_gpios_configured = 0;
- } else
- msm_headset_gpios_configured = 1;
-
mutex_init(&cdc_mclk_mutex);
return ret;
@@ -2070,7 +2011,6 @@
pr_err("%s: Not the right machine type\n", __func__);
return ;
}
- msm_free_headset_mic_gpios();
platform_device_unregister(msm_snd_device);
if (mbhc_cfg.gpio)
gpio_free(mbhc_cfg.gpio);
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index c894921..35cbb5b 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -38,8 +38,9 @@
/* 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)
-#define COMPRE_CAPTURE_PERIOD_SIZE (COMPRE_CAPTURE_MAX_FRAME_SIZE + \
- COMPRE_CAPTURE_HEADER_SIZE)
+#define COMPRE_CAPTURE_PERIOD_SIZE ((COMPRE_CAPTURE_MAX_FRAME_SIZE + \
+ COMPRE_CAPTURE_HEADER_SIZE) * \
+ MAX_NUM_FRAMES_PER_BUFFER)
struct snd_msm {
struct msm_audio *prtd;
@@ -207,6 +208,31 @@
q6asm_async_read(prtd->audio_client, &read_param);
break;
}
+ case ASM_DATA_EVENT_READ_COMPRESSED_DONE: {
+ pr_debug("ASM_DATA_EVENT_READ_COMPRESSED_DONE\n");
+ pr_debug("buf = %p, data = 0x%X, *data = %p,\n"
+ "prtd->pcm_irq_pos = %d\n",
+ prtd->audio_client->port[OUT].buf,
+ *(uint32_t *)prtd->audio_client->port[OUT].buf->data,
+ prtd->audio_client->port[OUT].buf->data,
+ prtd->pcm_irq_pos);
+
+ if (!atomic_read(&prtd->start))
+ break;
+ buf = prtd->audio_client->port[OUT].buf;
+ pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%X\n",
+ prtd->pcm_irq_pos, (uint32_t)buf[0].phys);
+ read_param.len = prtd->pcm_count;
+ read_param.paddr = (unsigned long)(buf[0].phys) +
+ prtd->pcm_irq_pos;
+ prtd->pcm_irq_pos += prtd->pcm_count;
+
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+
+ q6asm_async_read_compressed(prtd->audio_client, &read_param);
+ break;
+ }
case APR_BASIC_RSP_RESULT: {
switch (payload[0]) {
case ASM_SESSION_CMD_RUN: {
@@ -392,7 +418,7 @@
if (prtd->enabled)
return ret;
- read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE;
+ read_param.len = prtd->pcm_count;
pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n"
"pcm_count = %d, periods = %d\n",
__func__, prtd->samp_rate, prtd->channel_mode,
@@ -400,9 +426,8 @@
for (i = 0; i < runtime->periods; i++) {
read_param.uid = i;
- read_param.paddr = ((unsigned long)(buf[i].phys) +
- COMPRE_CAPTURE_HEADER_SIZE);
- q6asm_async_read(prtd->audio_client, &read_param);
+ read_param.paddr = (unsigned long)(buf[i].phys);
+ q6asm_async_read_compressed(prtd->audio_client, &read_param);
}
prtd->periods = runtime->periods;
@@ -749,7 +774,8 @@
}
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
ret = q6asm_open_read_compressed(prtd->audio_client,
- compr->codec);
+ MAX_NUM_FRAMES_PER_BUFFER,
+ COMPRESSED_META_DATA_MODE);
if (ret < 0) {
pr_err("%s: compressed Session out open failed\n",
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index afc14f5..c0c679d 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -65,6 +65,10 @@
static const DECLARE_TLV_DB_LINEAR(multimedia2_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
+static int msm_route_multimedia5_vol_control;
+static const DECLARE_TLV_DB_LINEAR(multimedia5_rx_vol_gain, 0,
+ INT_RX_VOL_MAX_STEPS);
+
static int msm_route_compressed_vol_control;
static const DECLARE_TLV_DB_LINEAR(compressed_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
@@ -798,6 +802,25 @@
return 0;
}
+static int msm_routing_get_multimedia5_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ ucontrol->value.integer.value[0] = msm_route_multimedia5_vol_control;
+ return 0;
+}
+
+static int msm_routing_set_multimedia5_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ if (!multi_ch_pcm_set_volume(ucontrol->value.integer.value[0]))
+ msm_route_multimedia5_vol_control =
+ ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
static int msm_routing_get_compressed_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1737,6 +1760,12 @@
msm_routing_set_multimedia2_vol_mixer, multimedia2_rx_vol_gain),
};
+static const struct snd_kcontrol_new multimedia5_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("HIFI3 RX Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0, msm_routing_get_multimedia5_vol_mixer,
+ msm_routing_set_multimedia5_vol_mixer, multimedia5_rx_vol_gain),
+};
+
static const struct snd_kcontrol_new compressed_vol_mixer_controls[] = {
SOC_SINGLE_EXT_TLV("COMPRESSED RX Volume", SND_SOC_NOPM, 0,
INT_RX_VOL_GAIN, 0, msm_routing_get_compressed_vol_mixer,
@@ -2446,20 +2475,26 @@
{"BE_OUT", NULL, "PRI_I2S_RX"},
{"BE_OUT", NULL, "SEC_I2S_RX"},
{"BE_OUT", NULL, "SLIMBUS_0_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_1_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_3_RX"},
+ {"BE_OUT", NULL, "SLIMBUS_4_RX"},
{"BE_OUT", NULL, "HDMI"},
{"BE_OUT", NULL, "MI2S_RX"},
{"PRI_I2S_TX", NULL, "BE_IN"},
{"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" },
{"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, "STUB_RX"},
{"STUB_TX", NULL, "BE_IN"},
+ {"STUB_1_TX", NULL, "BE_IN"},
{"BE_OUT", NULL, "SEC_AUX_PCM_RX"},
{"SEC_AUX_PCM_TX", NULL, "BE_IN"},
{"BE_OUT", NULL, "AUX_PCM_RX"},
@@ -2639,6 +2674,10 @@
ARRAY_SIZE(multimedia2_vol_mixer_controls));
snd_soc_add_platform_controls(platform,
+ multimedia5_vol_mixer_controls,
+ ARRAY_SIZE(multimedia5_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform,
compressed_vol_mixer_controls,
ARRAY_SIZE(compressed_vol_mixer_controls));
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 38ff34c..5f8a63e 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1688,7 +1688,7 @@
{
int ret;
- if (!cpu_is_msm8960()) {
+ if (!cpu_is_msm8960() && !cpu_is_msm8960ab()) {
pr_debug("%s: Not the right machine type\n", __func__);
return -ENODEV ;
}
@@ -1753,7 +1753,7 @@
static void __exit msm8960_audio_exit(void)
{
- if (!cpu_is_msm8960()) {
+ if (!cpu_is_msm8960() && !cpu_is_msm8960ab()) {
pr_debug("%s: Not the right machine type\n", __func__);
return ;
}
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 2f6772d..4c0ac9e 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -799,13 +799,14 @@
lp_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
lp_cfg.port_id = src_port;
- lp_cfg.payload_size = sizeof(struct afe_param_payload);
+ lp_cfg.payload_size = sizeof(struct afe_param_payload_base) +
+ sizeof(struct afe_param_loopback_cfg);
lp_cfg.payload_address = 0;
- lp_cfg.payload.module_id = AFE_MODULE_LOOPBACK;
- lp_cfg.payload.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
- lp_cfg.payload.param_size = sizeof(struct afe_param_loopback_cfg);
- lp_cfg.payload.reserved = 0;
+ lp_cfg.payload.base.module_id = AFE_MODULE_LOOPBACK;
+ lp_cfg.payload.base.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
+ lp_cfg.payload.base.param_size = sizeof(struct afe_param_loopback_cfg);
+ lp_cfg.payload.base.reserved = 0;
lp_cfg.payload.param.loopback_cfg.loopback_cfg_minor_version =
AFE_API_VERSION_LOOPBACK_CONFIG;
@@ -879,13 +880,15 @@
set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
set_param.port_id = port_id;
- set_param.payload_size = sizeof(struct afe_param_payload);
+ set_param.payload_size = sizeof(struct afe_param_payload_base) +
+ sizeof(struct afe_param_loopback_gain);
set_param.payload_address = 0;
- set_param.payload.module_id = AFE_MODULE_ID_PORT_INFO;
- set_param.payload.param_id = AFE_PARAM_ID_LOOPBACK_GAIN;
- set_param.payload.param_size = sizeof(struct afe_param_loopback_gain);
- set_param.payload.reserved = 0;
+ set_param.payload.base.module_id = AFE_MODULE_ID_PORT_INFO;
+ set_param.payload.base.param_id = AFE_PARAM_ID_LOOPBACK_GAIN;
+ set_param.payload.base.param_size =
+ sizeof(struct afe_param_loopback_gain);
+ set_param.payload.base.reserved = 0;
set_param.payload.param.loopback_gain.gain = volume;
set_param.payload.param.loopback_gain.reserved = 0;
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 59c390e..06be186 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -805,6 +805,7 @@
uint32_t token;
unsigned long dsp_flags;
uint32_t *payload;
+ uint32_t wakeup_flag = 1;
if ((ac == NULL) || (data == NULL)) {
@@ -816,7 +817,13 @@
ac->session);
return -EINVAL;
}
-
+ if (atomic_read(&ac->nowait_cmd_cnt) > 0) {
+ pr_debug("%s: nowait_cmd_cnt %d\n",
+ __func__,
+ atomic_read(&ac->nowait_cmd_cnt));
+ atomic_dec(&ac->nowait_cmd_cnt);
+ wakeup_flag = 0;
+ }
payload = data->payload;
if (data->opcode == RESET_EVENTS) {
@@ -862,7 +869,7 @@
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
- if (atomic_read(&ac->cmd_state)) {
+ if (atomic_read(&ac->cmd_state) && wakeup_flag) {
atomic_set(&ac->cmd_state, 0);
if (payload[1] == ADSP_EUNSUPPORTED)
atomic_set(&ac->cmd_response, 1);
@@ -1269,7 +1276,8 @@
return -EINVAL;
}
-int q6asm_open_read_compressed(struct audio_client *ac, uint32_t format)
+int q6asm_open_read_compressed(struct audio_client *ac,
+ uint32_t frames_per_buffer, uint32_t meta_data_mode)
{
int rc = 0x00;
struct asm_stream_cmd_open_read_compressed open;
@@ -1285,8 +1293,8 @@
q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_COMPRESSED;
/* hardcoded as following*/
- open.frame_per_buf = 1;
- open.uMode = 0;
+ open.frame_per_buf = frames_per_buffer;
+ open.uMode = meta_data_mode;
rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
if (rc < 0) {
@@ -1618,12 +1626,12 @@
run.flags = flags;
run.msw_ts = msw_ts;
run.lsw_ts = lsw_ts;
-
rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
if (rc < 0) {
pr_err("%s:Commmand run failed[%d]", __func__, rc);
return -EINVAL;
}
+ atomic_inc(&ac->nowait_cmd_cnt);
return 0;
}
@@ -3259,6 +3267,40 @@
return -EINVAL;
}
+int q6asm_async_read_compressed(struct audio_client *ac,
+ struct audio_aio_read_param *param)
+{
+ int rc = 0;
+ struct asm_stream_cmd_read read;
+
+ if (!ac || ac->apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
+
+ /* Pass physical address as token for AIO scheme */
+ read.hdr.token = param->paddr;
+ read.hdr.opcode = ASM_DATA_CMD_READ_COMPRESSED;
+ read.buf_add = param->paddr;
+ read.buf_size = param->len;
+ read.uid = param->uid;
+
+ pr_debug("%s: session[%d] bufadd[0x%x]len[0x%x]", __func__, ac->session,
+ read.buf_add, read.buf_size);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+ if (rc < 0) {
+ pr_debug("[%s] read op[0x%x]rc[%d]\n", __func__,
+ read.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
uint32_t lsw_ts, uint32_t flags)
{
@@ -3541,11 +3583,13 @@
pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
ac->session,
hdr.opcode);
+
rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
if (rc < 0) {
pr_err("%s:Commmand 0x%x failed\n", __func__, hdr.opcode);
goto fail_cmd;
}
+ atomic_inc(&ac->nowait_cmd_cnt);
return 0;
fail_cmd:
return -EINVAL;
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 1cf32aa..3791f24 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -2344,6 +2344,9 @@
/* send stop voice cmd */
voice_send_stop_voice_cmd(v);
+ /* Clear mute setting */
+ v->dev_tx.mute = common.default_mute_val;
+
/* detach VOCPROC and wait for response from mvm */
mvm_d_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
@@ -3106,7 +3109,9 @@
v->dev_tx.mute = mute;
- if (v->voc_state == VOC_RUN)
+ if ((v->voc_state == VOC_RUN) ||
+ (v->voc_state == VOC_CHANGE) ||
+ (v->voc_state == VOC_STANDBY))
ret = voice_send_mute_cmd(v);
mutex_unlock(&v->lock);
@@ -3312,7 +3317,9 @@
v->dev_rx.volume = vol_idx;
- if (v->voc_state == VOC_RUN)
+ if ((v->voc_state == VOC_RUN) ||
+ (v->voc_state == VOC_CHANGE) ||
+ (v->voc_state == VOC_STANDBY))
ret = voice_send_vol_index_cmd(v);
mutex_unlock(&v->lock);
@@ -3501,6 +3508,15 @@
pr_err("setup voice failed\n");
goto fail;
}
+
+ ret = voice_send_vol_index_cmd(v);
+ if (ret < 0)
+ pr_err("voice volume failed\n");
+
+ ret = voice_send_mute_cmd(v);
+ if (ret < 0)
+ pr_err("voice mute failed\n");
+
ret = voice_send_start_voice_cmd(v);
if (ret < 0) {
pr_err("start voice failed\n");
@@ -3998,7 +4014,7 @@
memset((void *)common.cvs_cal.buf, 0, CVS_CAL_SIZE);
cont:
/* set default value */
- common.default_mute_val = 1; /* default is mute */
+ common.default_mute_val = 0; /* default is un-mute */
common.default_vol_val = 0;
common.default_sample_val = 8000;
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 691ca21..aed6273 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -433,7 +433,7 @@
mmap_regions->hdr.dest_port = 0;
mmap_regions->hdr.token = 0;
mmap_regions->hdr.opcode = ADM_CMD_SHARED_MEM_MAP_REGIONS;
- mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL & 0x00ff;
+ mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
mmap_regions->num_regions = bufcnt & 0x00ff;
mmap_regions->property_flag = 0x00;
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 5b30e8e..4875a69 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -867,7 +867,7 @@
mregion->hdr.dest_port = 0;
mregion->hdr.token = 0;
mregion->hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS;
- mregion->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL;
+ mregion->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
mregion->num_regions = 1;
mregion->property_flag = 0x00;
/* Todo */
@@ -946,7 +946,7 @@
mregion->hdr.dest_port = 0;
mregion->hdr.token = 0;
mregion->hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS;
- mregion->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL;
+ mregion->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
mregion->num_regions = 1;
mregion->property_flag = 0x00;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 0bb88e8..a3af263 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -2265,7 +2265,7 @@
q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size,
TRUE, ((ac->session << 8) | dir));
mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
- mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL;
+ mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
mmap_regions->num_regions = bufcnt & 0x00ff;
mmap_regions->property_flag = 0x00;
payload = ((u8 *) mmap_region_cmd +
@@ -2408,7 +2408,7 @@
mmap_regions, ((ac->session << 8) | dir));
mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
- mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL;
+ mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
mmap_regions->num_regions = 1; /*bufcnt & 0x00ff; */
mmap_regions->property_flag = 0x00;
pr_debug("map_regions->nregions = %d\n", mmap_regions->num_regions);