Merge "msm: defconfig: enable SMD on 9625"
diff --git a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
index 5b4d3cf..b7dd427 100644
--- a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
+++ b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
@@ -7,10 +7,14 @@
- qcom,core-core-type: indicates whether this core is a CPU(0) or a GPU(1)
+- qcom,num-cores: The number of cores this entry represents
+- qcom,sensors: The vector of sensor ids for the cores
+
- qcom,algo-disable-pc-threshold: sets highest frequency at which DCVS
will allow the CPU to power collapse.
- qcom,algo-em-win-size-min-us: sets minimum Energy Minimization(EM)
window size.
+
- qcom,algo-em-win-size-max-us: sets maximum EM window size.
- qcom,algo-em-max-util-pct: sets maximum CPU utilization that will
not be exceeded by any core when
@@ -67,7 +71,7 @@
compatible = "qcom,dcvs-core-info";
- qcom,num_cores = <1>;
+ qcom,num-cores = <1>;
qcom,sensors = <0>;
qcom,core-core-type = <1>;
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 16925fb..38b2721 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -62,6 +62,7 @@
- qcom,chipid: If it exists this property is used to replace
the chip identification read from the GPU hardware.
This is used to override faulty hardware readings.
+- qcom,strtstp-sleepwake: Boolean. Enables use of GPU SLUMBER instead of SLEEP for power savings
Example of A330 GPU in MSM8974:
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 21d376a..adb93b8 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -11,18 +11,24 @@
- 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 PON.
+- interrupt-names: Specify the interrupt names associated with interrupts. Must be
+ one of "kpdpwr", "kpdpwr-bark", "resin", "resin-bark", "cblpwr".
+ Bark interrupts are associated with system reset configuration
+ to allow default reset configuration to be activated. If system
+ reset configuration is not supported then bark interrupts are
+ nops.
Optional properties:
-- qcom,pon-dbc-delay The debouce delay for the power-key interrupt
- specifed in us. The value ranges from 2 seconds
+- qcom,pon-dbc-delay The debounce delay for the power-key interrupt
+ specified 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_1 ...pon_n These represent the child nodes which describe
the properties (reset, key) for each of the pon
- reset source. All the child nodes are optional,
- if none of them are specified the driver fails
+ reset source. All the child nodes are optional.
+ If none of them is specified, the driver fails
to register.
- qcom,system-reset Specifies that this PON peripheral can be used
to reset the system. This property can only be
@@ -32,32 +38,32 @@
All the below properties are in the sub-node section (properties of the child
node).
+Sub-node required properties:
+- qcom,pon-type The type of PON/RESET source. The driver
+ currently supports KPDPWR(0), RESIN(1) and
+ CBLPWR(2) pon/reset sources.
+
+Sub-node optional properties:
- qcom,pull-up The initial state of the reset pin under
consideration.
0 = No pull-up
1 = pull-up enabled
- This property is optional and is set to '0'
- if not specified.
-- qcom,pon-type The type of PON/RESET source. The driver
- currently supports KPDPWR(0) and RESIN(1)
- pon/reset sources. This property must be
- specified.
+ This property is set to '0' if not specified.
- qcom,support-reset Indicates if this PON source supports
reset functionality.
0 = Not supported
1 = Supported
- This property is optional and is set to '0'
- if not specified.
-- qcom,s1-timer The debouce timer for the BARK interrupt for
+ This property is set to '0' if not specified.
+- qcom,s1-timer The debounce timer for the BARK interrupt for
that reset source. Value is specified in ms.
Supported values are -
- 0, 32, 56, 80, 128, 184, 272, 408, 608, 904
1352, 2048, 3072, 4480, 6720, 10256
This property must be specified only if
'support-reset' is set to 1.
-- qcom,s2-timer The debouce timer for the S2 reset specified
+- qcom,s2-timer The debounce timer for the S2 reset specified
in ms. On the expiry of this timer, the PMIC
- executes the reset sequence. Supoprted values -
+ executes the reset sequence. Supported values -
- 0, 10, 50, 100, 250, 500, 1000, 2000
This property is required only if
'support-reset' is set to 1.
@@ -68,7 +74,7 @@
'support-reset' is set to 1.
- linux,code The input key-code associated with the reset source.
The reset source in its default configuration can be
- used to support standard keys. This property is optional.
+ used to support standard keys.
Example:
qcom,power-on@800 {
diff --git a/arch/arm/boot/dts/msm-pm8019.dtsi b/arch/arm/boot/dts/msm-pm8019.dtsi
index 3b06450..e70eb36 100755
--- a/arch/arm/boot/dts/msm-pm8019.dtsi
+++ b/arch/arm/boot/dts/msm-pm8019.dtsi
@@ -22,6 +22,21 @@
#address-cells = <1>;
#size-cells = <1>;
+ qcom,power_on@800 {
+ compatible = "qcom,qpnp-power-on";
+ reg = <0x800 0x100>;
+ interrupts = <0x0 0x8 0x2>;
+ interrupt-names = "cblpwr";
+ qcom,pon-dbc-delay = <15625>;
+ qcom,system-reset;
+
+ qcom,pon_1 {
+ qcom,pon-type = <2>;
+ qcom,pull-up = <1>;
+ linux,code = <116>;
+ };
+ };
+
clkdiv@5b00 {
reg = <0x5b00 0x100>;
compatible = "qcom,qpnp-clkdiv";
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 017aea9..6d00b01 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -25,6 +25,7 @@
qcom,idle-timeout = <83>; //<HZ/12>
qcom,nap-allowed = <1>;
+ qcom,strtstp-sleepwake;
qcom,clk-map = <0x00000016>; //KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE
/* Bus Scale Settings */
@@ -85,6 +86,9 @@
compatible = "qcom,dcvs-core-info";
+ qcom,num-cores = <1>;
+ qcom,sensors = <0>;
+
qcom,core-core-type = <1>;
qcom,algo-disable-pc-threshold = <0>;
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 1893ae4..9b5aaac 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -70,7 +70,7 @@
reg = <28>;
qcom,heap-align = <0x1000>;
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x2B4000>;
+ qcom,memory-reservation-size = <0x314000>;
};
};
};
diff --git a/arch/arm/boot/dts/msm9625-ion.dtsi b/arch/arm/boot/dts/msm9625-ion.dtsi
new file mode 100644
index 0000000..8183264
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-ion.dtsi
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+ qcom,ion {
+ compatible = "qcom,msm-ion";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ion-heap@30 { /* SYSTEM HEAP */
+ reg = <30>;
+ };
+
+ qcom,ion-heap@25 { /* IOMMU HEAP */
+ reg = <25>;
+ };
+
+ qcom,ion-heap@28 { /* AUDIO HEAP */
+ compatible = "qcom,msm-ion-reserve";
+ reg = <28>;
+ qcom,heap-align = <0x1000>;
+ qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+ qcom,memory-reservation-size = <0xAF000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index f50d14f..a8a2bf1 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -11,6 +11,7 @@
*/
/include/ "skeleton.dtsi"
+/include/ "msm9625-ion.dtsi"
/ {
model = "Qualcomm MSM 9625";
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 9dd4347..6b8a374 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -1167,41 +1167,35 @@
/*
* Configure the GIC after we come out of power collapse.
* This function will configure some of the GIC registers so as to prepare the
- * core1 to receive an SPI(ACSR_MP_CORE_IPC1, (32 + 8)), which will bring
- * core1 out of GDFS.
+ * secondary cores to receive an SPI(ACSR_MP_CORE_IPC1/IPC2/IPC3, 40/92/93),
+ * which will bring cores out of GDFS.
*/
-void core1_gic_configure_and_raise(void)
+void gic_configure_and_raise(unsigned int irq, unsigned int cpu)
{
struct gic_chip_data *gic = &gic_data[0];
+ struct irq_data *d = irq_get_irq_data(irq);
void __iomem *base = gic_data_dist_base(gic);
- unsigned int value = 0;
+ unsigned int value = 0, byte_offset, offset, bit;
unsigned long flags;
+ offset = ((gic_irq(d) / 32) * 4);
+ bit = BIT(gic_irq(d) % 32);
+
raw_spin_lock_irqsave(&irq_controller_lock, flags);
- value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + 0x4);
- value |= BIT(8);
- __raw_writel(value, base + GIC_DIST_ACTIVE_BIT + 0x4);
+ value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + offset);
+ __raw_writel(value | bit, base + GIC_DIST_ACTIVE_BIT + offset);
mb();
- value = __raw_readl(base + GIC_DIST_TARGET + 0x24);
- value |= BIT(13);
- __raw_writel(value, base + GIC_DIST_TARGET + 0x24);
+ value = __raw_readl(base + GIC_DIST_TARGET + (gic_irq(d) / 4) * 4);
+ byte_offset = (gic_irq(d) % 4) * 8;
+ value |= 1 << (cpu + byte_offset);
+ __raw_writel(value, base + GIC_DIST_TARGET + (gic_irq(d) / 4) * 4);
mb();
- value = __raw_readl(base + GIC_DIST_TARGET + 0x28);
- value |= BIT(1);
- __raw_writel(value, base + GIC_DIST_TARGET + 0x28);
+ value = __raw_readl(base + GIC_DIST_ENABLE_SET + offset);
+ __raw_writel(value | bit, base + GIC_DIST_ENABLE_SET + offset);
mb();
- value = __raw_readl(base + GIC_DIST_ENABLE_SET + 0x4);
- value |= BIT(8);
- __raw_writel(value, base + GIC_DIST_ENABLE_SET + 0x4);
- mb();
-
- value = __raw_readl(base + GIC_DIST_PENDING_SET + 0x4);
- value |= BIT(8);
- __raw_writel(value, base + GIC_DIST_PENDING_SET + 0x4);
- mb();
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
}
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index d96a006..5984535 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -115,6 +115,7 @@
CONFIG_USB_BAM=y
CONFIG_SPS_SUPPORT_BAMDMA=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_POWER_ON=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_YAFFS_FS=y
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index ad12bcd..72c3c27 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -62,7 +62,7 @@
void msm_gic_save(void);
void msm_gic_restore(void);
-void core1_gic_configure_and_raise(void);
+void gic_configure_and_raise(unsigned int irq, unsigned int cpu);
#endif
#endif
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 2020422..6f5528e 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -359,6 +359,20 @@
select GPIO_MSM_V3
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
+
+config ARCH_MSM8910
+ bool "MSM8910"
+ select ARM_GIC
+ select GIC_SECURE
+ select SMP
+ select ARCH_MSM_CORTEXMP
+ select CPU_V7
+ select MSM_SCM if SMP
+ select MAY_HAVE_SPARSE_IRQ
+ select SPARSE_IRQ
+ select MULTI_IRQ_HANDLER
+ select GPIO_MSM_V3
+ select MSM_GPIOMUX
endmenu
choice
@@ -926,6 +940,7 @@
default "0x00000000" if ARCH_MSM8974
default "0x00000000" if ARCH_MPQ8092
default "0x00000000" if ARCH_MSM8226
+ default "0x00000000" if ARCH_MSM8910
default "0x10000000" if ARCH_FSM9XXX
default "0x00200000" if ARCH_MSM9625
default "0x00200000" if !MSM_STACKED_MEMORY
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 3be7fc6..c7075bc 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -32,6 +32,8 @@
static struct msm_dcvs_core_info grp3d_core_info = {
.freq_tbl = &grp3d_freq[0],
+ .num_cores = 1,
+ .sensors = (int[]){0},
.core_param = {
.core_type = MSM_DCVS_CORE_TYPE_GPU,
},
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8917.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
index db40e5d..b7f554c 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8917.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -547,7 +547,7 @@
RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL, 0, 1p60, NONE, NONE),
RPM_SMPS(S3, 0, 1, 1, 500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, AUTO, LPM),
- RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20, NONE, NONE),
+ RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20, AUTO, AUTO),
RPM_SMPS(S8, 1, 1, 1, 2050000, 2050000, NULL, 100000, 1p60, NONE, NONE),
/* ID a_on pd ss min_uV max_uV supply sys_uA init_ip */
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index e8baf6a..3cd4b2f 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2671,6 +2671,8 @@
static struct msm_dcvs_core_info apq8064_core_info = {
.freq_tbl = &apq8064_freq[0],
+ .num_cores = 4,
+ .sensors = (int[]){7, 8, 9, 10},
.core_param = {
.core_type = MSM_DCVS_CORE_TYPE_CPU,
},
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index 8b59b14..614037c 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -33,6 +33,6 @@
void __init msm8x25_spm_device_init(void);
void __init msm_pm_register_cpr_ops(void);
void __init msm8x25_kgsl_3d0_init(void);
-void __iomem *core1_reset_base(void);
+void __iomem *core_reset_base(unsigned int);
extern void setup_mm_for_reboot(void);
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs.h b/arch/arm/mach-msm/include/mach/msm_dcvs.h
index 490a34b..3ac0e74 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs.h
@@ -46,6 +46,17 @@
};
/**
+ * struct msm_dcvs_freq
+ *
+ * API for clock driver code to register and receive frequency change
+ * request for the core from the msm_dcvs driver.
+ */
+struct msm_dcvs_freq {
+ const char *core_name;
+ /* Callback from msm_dcvs to set the core frequency */
+};
+
+/**
* msm_dcvs_idle_source_register
* @drv: Pointer to the source driver
* @return: Handle to be used for sending idle state notifications.
@@ -90,6 +101,8 @@
* before the sink driver can be registered.
*/
struct msm_dcvs_core_info {
+ int num_cores;
+ int *sensors;
struct msm_dcvs_freq_entry *freq_tbl;
struct msm_dcvs_core_param core_param;
struct msm_dcvs_algo_param algo_param;
@@ -101,6 +114,7 @@
* msm_dcvs_register_core
* @core_name: Unique name identifier for the core.
* @info: The core specific algorithm parameters.
+ * @sensor: The thermal sensor number of the core in question
* @return :
* 0 on success,
* -ENOSYS,
@@ -110,35 +124,25 @@
* msm_dcvs_freq_sink_register
* Cores that need to run synchronously must share the same group id.
*/
-extern int msm_dcvs_register_core(const char *core_name,
- struct msm_dcvs_core_info *info);
+extern int msm_dcvs_register_core(
+ const char *core_name,
+ struct msm_dcvs_core_info *info,
+ int (*set_frequency)(struct msm_dcvs_freq *self, unsigned int freq),
+ unsigned int (*get_frequency)(struct msm_dcvs_freq *self),
+ int sensor);
/**
- * struct msm_dcvs_freq
- *
- * API for clock driver code to register and receive frequency change
- * request for the core from the msm_dcvs driver.
- */
-struct msm_dcvs_freq {
- const char *core_name;
- /* Callback from msm_dcvs to set the core frequency */
- int (*set_frequency)(struct msm_dcvs_freq *self,
- unsigned int freq);
- unsigned int (*get_frequency)(struct msm_dcvs_freq *self);
-};
-
-/**
- * msm_dcvs_freq_sink_register
+ * msm_dcvs_freq_sink_start
* @drv: The sink driver
* @return: Handle unique to the core.
*
* Register the clock driver code with the msm_dvs driver to get notified about
* frequency change requests.
*/
-extern int msm_dcvs_freq_sink_register(struct msm_dcvs_freq *drv);
+extern int msm_dcvs_freq_sink_start(struct msm_dcvs_freq *drv);
/**
- * msm_dcvs_freq_sink_unregister
+ * msm_dcvs_freq_sink_stop
* @drv: The sink driver
* @return:
* 0 on success,
@@ -147,6 +151,13 @@
* Unregister the sink driver for the core. This will cause the source driver
* for the core to stop sending idle pulses.
*/
-extern int msm_dcvs_freq_sink_unregister(struct msm_dcvs_freq *drv);
+extern int msm_dcvs_freq_sink_stop(struct msm_dcvs_freq *drv);
+/**
+ * msm_dcvs_update_limits
+ * @drv: The sink driver
+ *
+ * Update the frequency known to dcvs when the limits are changed.
+ */
+extern void msm_dcvs_update_limits(struct msm_dcvs_freq *drv);
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8910.h b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
new file mode 100644
index 0000000..e4cd312
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_8910_H
+#define __ASM_ARCH_MSM_IOMAP_8910_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM8910_MSM_SHARED_RAM_PHYS 0x0FA00000
+
+#define MSM8910_APCS_GCC_PHYS 0xF9011000
+#define MSM8910_APCS_GCC_SIZE SZ_4K
+
+#define MSM8910_TLMM_PHYS 0xFD510000
+#define MSM8910_TLMM_SIZE SZ_16K
+
+#define MSM8910_IMEM_PHYS 0xFC42B000
+#define MSM8910_IMEM_SIZE SZ_4K
+
+#ifdef CONFIG_DEBUG_MSM8910_UART
+#define MSM_DEBUG_UART_BASE IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS 0xF991E000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 8dbd29c..f372b1e 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -54,7 +54,7 @@
defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X01A) || \
defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30) || \
defined(CONFIG_ARCH_MSM9625) || defined(CONFIG_ARCH_MPQ8092) || \
- defined(CONFIG_ARCH_MSM8226)
+ defined(CONFIG_ARCH_MSM8226) || defined(CONFIG_ARCH_MSM8910)
/* Unified iomap */
@@ -122,6 +122,7 @@
#include "msm_iomap-9625.h"
#include "msm_iomap-8092.h"
#include "msm_iomap-8226.h"
+#include "msm_iomap-8910.h"
#else
/* Legacy single-target iomap */
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 225440c..86045b9 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -54,6 +54,12 @@
of_machine_is_compatible("qcom,msm8226")
#define machine_is_msm8226_sim() \
of_machine_is_compatible("qcom,msm8226-sim")
+#define early_machine_is_msm8910() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8910")
+#define machine_is_msm8910() \
+ of_machine_is_compatible("qcom,msm8910")
+#define machine_is_msm8910_sim() \
+ of_machine_is_compatible("qcom,msm8910-sim")
#else
#define early_machine_is_msm8974() 0
#define machine_is_msm8974() 0
@@ -66,6 +72,9 @@
#define early_machine_is_msm8226() 0
#define machine_is_msm8226() 0
#define machine_is_msm8226_sim() 0
+#define early_machine_is_msm8910() 0
+#define machine_is_msm8910() 0
+#define machine_is_msm8910_sim() 0
#endif
@@ -99,7 +108,8 @@
MSM_CPU_8625,
MSM_CPU_9625,
MSM_CPU_8092,
- MSM_CPU_8226
+ MSM_CPU_8226,
+ MSM_CPU_8910,
};
enum pmic_model {
@@ -415,4 +425,15 @@
#endif
}
+static inline int cpu_is_msm8910(void)
+{
+#ifdef CONFIG_ARCH_MSM8910
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_8910;
+#else
+ return 0;
+#endif
+}
#endif
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 39ac253..8ebead8 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -529,3 +529,22 @@
msm_map_io(msm_8226_io_desc, ARRAY_SIZE(msm_8226_io_desc));
}
#endif /* CONFIG_ARCH_MSM8226 */
+
+#ifdef CONFIG_ARCH_MSM8910
+static struct map_desc msm8910_io_desc[] __initdata = {
+ MSM_CHIP_DEVICE(APCS_GCC, MSM8910),
+ MSM_CHIP_DEVICE(TLMM, MSM8910),
+ MSM_CHIP_DEVICE(IMEM, MSM8910),
+ {
+ .virtual = (unsigned long) MSM_SHARED_RAM_BASE,
+ .length = MSM_SHARED_RAM_SIZE,
+ .type = MT_DEVICE,
+ },
+};
+
+void __init msm_map_msm8910_io(void)
+{
+ msm_shared_ram_phys = MSM8910_MSM_SHARED_RAM_PHYS;
+ msm_map_io(msm8910_io_desc, ARRAY_SIZE(msm8910_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM8910 */
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 9601b7e..288d6bb 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -23,6 +23,7 @@
#include <linux/spinlock.h>
#include <linux/stringify.h>
#include <linux/debugfs.h>
+#include <linux/msm_tsens.h>
#include <asm/atomic.h>
#include <asm/page.h>
#include <mach/msm_dcvs.h>
@@ -73,7 +74,6 @@
struct dcvs_core {
char core_name[CORE_NAME_MAX];
- uint32_t new_freq[MAX_PENDING];
uint32_t actual_freq;
uint32_t freq_change_us;
@@ -91,19 +91,21 @@
struct task_struct *task;
struct core_attribs attrib;
uint32_t handle;
- uint32_t freq_pending;
struct hrtimer timer;
int32_t timer_disabled;
- /* track if kthread for change_freq is active */
- int32_t change_freq_activated;
struct msm_dcvs_core_info *info;
+ int sensor;
+ int pending_freq;
+ wait_queue_head_t wait_q;
+ int (*set_frequency)(struct msm_dcvs_freq *self, unsigned int freq);
+ unsigned int (*get_frequency)(struct msm_dcvs_freq *self);
};
static int msm_dcvs_debug;
static int msm_dcvs_enabled = 1;
module_param_named(enable, msm_dcvs_enabled, int, S_IRUGO | S_IWUSR | S_IWGRP);
-static struct dentry *debugfs_base;
+static struct dentry *debugfs_base;
static struct dcvs_core core_list[CORES_MAX];
static DEFINE_MUTEX(core_list_lock);
@@ -123,28 +125,16 @@
uint32_t slack_us = 0;
uint32_t ret1 = 0;
- if (!core->freq_driver || !core->freq_driver->set_frequency) {
+ if (!core->freq_driver || !core->set_frequency) {
/* Core may have unregistered or hotplugged */
return -ENODEV;
}
-repeat:
spin_lock_irqsave(&core->cpu_lock, flags);
- if (unlikely(!core->freq_pending)) {
- spin_unlock_irqrestore(&core->cpu_lock, flags);
- return ret;
- }
- requested_freq = core->new_freq[core->freq_pending - 1];
- if (unlikely(core->freq_pending > 1) &&
- (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)) {
- int i;
- for (i = 0; i < core->freq_pending - 1; i++) {
- __info("Core %s missing freq %u\n",
- core->core_name, core->new_freq[i]);
- }
- }
+repeat:
+
+ requested_freq = core->pending_freq;
time_start = core->time_start;
core->time_start = 0;
- core->freq_pending = 0;
/**
* Cancel the timers, we dont want the timer firing as we are
* changing the clock rate. Dont let idle_exit and others setup
@@ -152,18 +142,18 @@
*/
hrtimer_cancel(&core->timer);
core->timer_disabled = 1;
+ if (requested_freq == core->actual_freq)
+ goto out;
+
spin_unlock_irqrestore(&core->cpu_lock, flags);
- if (requested_freq == core->actual_freq)
- return ret;
/**
* Call the frequency sink driver to change the frequency
* We will need to get back the actual frequency in KHz and
* the record the time taken to change it.
*/
- ret = core->freq_driver->set_frequency(core->freq_driver,
- requested_freq);
+ ret = core->set_frequency(core->freq_driver, requested_freq);
if (ret <= 0) {
__err("Core %s failed to set freq %u\n",
core->core_name, requested_freq);
@@ -229,14 +219,40 @@
core->actual_freq, prev_freq,
core->freq_change_us, slack_us);
+ spin_lock_irqsave(&core->cpu_lock, flags);
/**
* By the time we are done with freq changes, we could be asked to
* change again. Check before exiting.
*/
- if (core->freq_pending)
+ if (core->pending_freq)
goto repeat;
- core->change_freq_activated = 0;
+
+out: /* should always be jumped to with the spin_lock held */
+ core->pending_freq = 0;
+ spin_unlock_irqrestore(&core->cpu_lock, flags);
+
+ return ret;
+}
+
+static int __msm_dcvs_report_temp(struct dcvs_core *core)
+{
+ struct msm_dcvs_core_info *info = core->info;
+ struct tsens_device tsens_dev;
+ int ret;
+ unsigned long temp = 0;
+
+ tsens_dev.sensor_num = core->sensor;
+ ret = tsens_get_temp(&tsens_dev, &temp);
+ if (!ret) {
+ tsens_dev.sensor_num = 0;
+ ret = tsens_get_temp(&tsens_dev, &temp);
+ if (!ret)
+ return -ENODEV;
+ }
+
+ ret = msm_dcvs_scm_set_power_params(core->handle, &info->power_param,
+ &info->freq_tbl[0], &core->coeffs);
return ret;
}
@@ -246,23 +262,21 @@
static struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
sched_setscheduler(current, SCHED_FIFO, ¶m);
- set_current_state(TASK_UNINTERRUPTIBLE);
while (!kthread_should_stop()) {
- mutex_lock(&core->lock);
- __msm_dcvs_change_freq(core);
- mutex_unlock(&core->lock);
-
- schedule();
+ wait_event(core->wait_q, !(core->pending_freq == 0 ||
+ core->pending_freq == -1) ||
+ kthread_should_stop());
if (kthread_should_stop())
break;
- set_current_state(TASK_UNINTERRUPTIBLE);
+ mutex_lock(&core->lock);
+ __msm_dcvs_change_freq(core);
+ __msm_dcvs_report_temp(core);
+ mutex_unlock(&core->lock);
}
- __set_current_state(TASK_RUNNING);
-
return 0;
}
@@ -278,33 +292,25 @@
ret = msm_dcvs_scm_event(core->handle, event, param0,
core->actual_freq, &new_freq, ret1);
if (ret) {
- __err("Error (%d) sending SCM event %d for core %s\n",
+ if (ret == -13)
+ ret = 0;
+ else
+ __err("Error (%d) sending SCM event %d for core %s\n",
ret, event, core->core_name);
- goto freq_done;
+ goto out;
}
- if ((core->actual_freq != new_freq) &&
- (core->new_freq[core->freq_pending] != new_freq)) {
- if (core->freq_pending >= MAX_PENDING - 1)
- core->freq_pending = MAX_PENDING - 1;
- core->new_freq[core->freq_pending++] = new_freq;
+ if (core->actual_freq != new_freq && core->pending_freq != new_freq) {
+ core->pending_freq = new_freq;
core->time_start = ktime_to_ns(ktime_get());
- /* Schedule the frequency change */
- if (!core->task)
- __err("Uninitialized task for core %s\n",
- core->core_name);
- else {
- if (freq_changed)
- *freq_changed = 1;
- core->change_freq_activated = 1;
- wake_up_process(core->task);
- }
+ if (core->task)
+ wake_up(&core->wait_q);
} else {
if (freq_changed)
*freq_changed = 0;
}
-freq_done:
+out:
spin_unlock_irqrestore(&core->cpu_lock, flags);
return ret;
@@ -571,7 +577,10 @@
}
int msm_dcvs_register_core(const char *core_name,
- struct msm_dcvs_core_info *info)
+ struct msm_dcvs_core_info *info,
+ int (*set_frequency)(struct msm_dcvs_freq *self, unsigned int freq),
+ unsigned int (*get_frequency)(struct msm_dcvs_freq *self),
+ int sensor)
{
int ret = -EINVAL;
struct dcvs_core *core = NULL;
@@ -587,6 +596,9 @@
mutex_lock(&core->lock);
+ core->set_frequency = set_frequency;
+ core->get_frequency = get_frequency;
+
core->info = info;
memcpy(&core->algo_param, &info->algo_param,
sizeof(struct msm_dcvs_algo_param));
@@ -594,6 +606,9 @@
memcpy(&core->coeffs, &info->energy_coeffs,
sizeof(struct msm_dcvs_energy_curve_coeffs));
+ pr_debug("registering core with sensor %d\n", sensor);
+ core->sensor = sensor;
+
ret = msm_dcvs_scm_register_core(core->handle, &info->core_param);
if (ret)
goto bail;
@@ -618,14 +633,27 @@
core_handles[core->handle - CORE_HANDLE_OFFSET] = NULL;
goto bail;
}
-
+ init_waitqueue_head(&core->wait_q);
+ core->task = kthread_run(msm_dcvs_do_freq, (void *)core,
+ "msm_dcvs/%d", core->handle);
bail:
mutex_unlock(&core->lock);
return ret;
}
EXPORT_SYMBOL(msm_dcvs_register_core);
-int msm_dcvs_freq_sink_register(struct msm_dcvs_freq *drv)
+void msm_dcvs_update_limits(struct msm_dcvs_freq *drv)
+{
+ struct dcvs_core *core;
+
+ if (!drv || !drv->core_name)
+ return;
+
+ core = msm_dcvs_get_core(drv->core_name, false);
+ core->actual_freq = core->get_frequency(drv);
+}
+
+int msm_dcvs_freq_sink_start(struct msm_dcvs_freq *drv)
{
int ret = -EINVAL;
struct dcvs_core *core = NULL;
@@ -644,8 +672,6 @@
__info("Frequency notifier for %s being replaced\n",
core->core_name);
core->freq_driver = drv;
- core->task = kthread_create(msm_dcvs_do_freq, (void *)core,
- "msm_dcvs/%d", core->handle);
if (IS_ERR(core->task)) {
mutex_unlock(&core->lock);
return -EFAULT;
@@ -655,7 +681,7 @@
__info("Enabling idle pulse for %s\n", core->core_name);
if (core->idle_driver) {
- core->actual_freq = core->freq_driver->get_frequency(drv);
+ core->actual_freq = core->get_frequency(drv);
/* Notify TZ to start receiving idle info for the core */
ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_DCVS_ENABLE, 1,
&ret1, &ret2);
@@ -667,9 +693,9 @@
return core->handle;
}
-EXPORT_SYMBOL(msm_dcvs_freq_sink_register);
+EXPORT_SYMBOL(msm_dcvs_freq_sink_start);
-int msm_dcvs_freq_sink_unregister(struct msm_dcvs_freq *drv)
+int msm_dcvs_freq_sink_stop(struct msm_dcvs_freq *drv)
{
int ret = -EINVAL;
struct dcvs_core *core = NULL;
@@ -698,14 +724,12 @@
if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
__info("Enabling LPM for %s\n", core->core_name);
}
- core->freq_pending = 0;
core->freq_driver = NULL;
mutex_unlock(&core->lock);
- kthread_stop(core->task);
return 0;
}
-EXPORT_SYMBOL(msm_dcvs_freq_sink_unregister);
+EXPORT_SYMBOL(msm_dcvs_freq_sink_stop);
int msm_dcvs_idle_source_register(struct msm_dcvs_idle *drv)
{
@@ -785,7 +809,7 @@
__err("Error (%d) sending idle exit for %s\n",
ret, core->core_name);
/* only start slack timer if change_freq won't */
- if (freq_changed || core->change_freq_activated)
+ if (freq_changed)
break;
if (timer_interval_us && !core->timer_disabled) {
ret = hrtimer_start(&core->timer,
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index e8f8c59..3b31b9f 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -120,7 +120,7 @@
*/
write_pen_release(-1);
- /* clear the IPC1(SPI-8) pending SPI */
+ /* clear the IPC pending SPI */
if (power_collapsed) {
raise_clear_spi(cpu, false);
clear_pending_spi(cpu_data[cpu].ipc_irq);
@@ -173,9 +173,9 @@
return 0;
}
-void __iomem *core1_reset_base(void)
+void __iomem *core_reset_base(unsigned int cpu)
{
- return cpu_data[1].reset_core_base;
+ return cpu_data[cpu].reset_core_base;
}
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -217,7 +217,7 @@
*/
if (power_collapsed) {
- core1_gic_configure_and_raise();
+ gic_configure_and_raise(cpu_data[cpu].ipc_irq, cpu);
raise_clear_spi(cpu, true);
} else {
gic_raise_softirq(cpumask_of(cpu), 1);
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 10c5445..427e39f 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -487,7 +487,7 @@
void __iomem *base_ptr;
unsigned int value = 0;
- base_ptr = core1_reset_base();
+ base_ptr = core_reset_base(1);
if (!base_ptr)
return;
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index ac077e9..969af98 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -286,6 +286,9 @@
/* 8092 IDs */
[146] = MSM_CPU_8092,
+ /* 8910 IDs */
+ [147] = MSM_CPU_8910,
+
/* 8064AB IDs */
[153] = MSM_CPU_8064AB,
@@ -732,6 +735,10 @@
dummy_socinfo.id = 146;
strlcpy(dummy_socinfo.build_id, "mpq8092 - ",
sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_msm8910()) {
+ dummy_socinfo.id = 147;
+ strlcpy(dummy_socinfo.build_id, "msm8910 - ",
+ sizeof(dummy_socinfo.build_id));
}
strlcat(dummy_socinfo.build_id, "Dummy socinfo",
sizeof(dummy_socinfo.build_id));
diff --git a/drivers/cpufreq/cpufreq_gov_msm.c b/drivers/cpufreq/cpufreq_gov_msm.c
index 4eeff35..9ad1811 100644
--- a/drivers/cpufreq/cpufreq_gov_msm.c
+++ b/drivers/cpufreq/cpufreq_gov_msm.c
@@ -36,11 +36,13 @@
static void msm_gov_check_limits(struct cpufreq_policy *policy)
{
struct msm_gov *gov = &per_cpu(msm_gov_info, policy->cpu);
+ struct msm_dcvs_freq *dcvs_notifier =
+ &(per_cpu(msm_gov_info, policy->cpu).gov_notifier);
if (policy->max < gov->cur_freq)
__cpufreq_driver_target(policy, policy->max,
CPUFREQ_RELATION_H);
- else if (policy->min > gov->min_freq)
+ else if (policy->min > gov->cur_freq)
__cpufreq_driver_target(policy, policy->min,
CPUFREQ_RELATION_L);
else
@@ -50,6 +52,7 @@
gov->cur_freq = policy->cur;
gov->min_freq = policy->min;
gov->max_freq = policy->max;
+ msm_dcvs_update_limits(dcvs_notifier);
}
static int msm_dcvs_freq_set(struct msm_dcvs_freq *self,
@@ -66,13 +69,17 @@
if (freq > gov->max_freq)
freq = gov->max_freq;
- ret = __cpufreq_driver_target(gov->policy, freq, CPUFREQ_RELATION_L);
- gov->cur_freq = gov->policy->cur;
-
mutex_unlock(&per_cpu(gov_mutex, gov->cpu));
- if (!ret)
- return gov->cur_freq;
+ ret = cpufreq_driver_target(gov->policy, freq, CPUFREQ_RELATION_L);
+
+ if (!ret) {
+ gov->cur_freq = cpufreq_quick_get(gov->cpu);
+ if (freq != gov->cur_freq)
+ pr_err("cpu %d freq %u gov->cur_freq %u didn't match",
+ gov->cpu, freq, gov->cur_freq);
+ }
+ ret = gov->cur_freq;
return ret;
}
@@ -82,7 +89,12 @@
struct msm_gov *gov =
container_of(self, struct msm_gov, gov_notifier);
- return gov->cur_freq;
+ /*
+ * the rw_sem in cpufreq is always held when this is called.
+ * The policy->cur won't be updated in this case - so it is safe to
+ * access policy->cur
+ */
+ return gov->policy->cur;
}
static int cpufreq_governor_msm(struct cpufreq_policy *policy,
@@ -104,18 +116,14 @@
per_cpu(msm_gov_info, cpu).cpu = cpu;
gov->policy = policy;
dcvs_notifier->core_name = core_name[cpu];
- dcvs_notifier->set_frequency = msm_dcvs_freq_set;
- dcvs_notifier->get_frequency = msm_dcvs_freq_get;
- handle = msm_dcvs_freq_sink_register(dcvs_notifier);
+ handle = msm_dcvs_freq_sink_start(dcvs_notifier);
BUG_ON(handle < 0);
msm_gov_check_limits(policy);
mutex_unlock(&per_cpu(gov_mutex, cpu));
break;
case CPUFREQ_GOV_STOP:
- mutex_lock(&per_cpu(gov_mutex, cpu));
- msm_dcvs_freq_sink_unregister(dcvs_notifier);
- mutex_unlock(&per_cpu(gov_mutex, cpu));
+ msm_dcvs_freq_sink_stop(dcvs_notifier);
break;
case CPUFREQ_GOV_LIMITS:
@@ -139,13 +147,19 @@
int ret = 0;
int cpu;
struct msm_dcvs_core_info *core = NULL;
+ int sensor = 0;
core = pdev->dev.platform_data;
for_each_possible_cpu(cpu) {
mutex_init(&per_cpu(gov_mutex, cpu));
snprintf(core_name[cpu], 10, "cpu%d", cpu);
- ret = msm_dcvs_register_core(core_name[cpu], core);
+ if (cpu < core->num_cores)
+ sensor = core->sensors[cpu];
+ ret = msm_dcvs_register_core(core_name[cpu], core,
+ msm_dcvs_freq_set,
+ msm_dcvs_freq_get,
+ sensor);
if (ret)
pr_err("Unable to register core for %d\n", cpu);
}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 573e0a6..97711e2 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -896,6 +896,19 @@
info->freq_tbl[index].leakage_energy_offset = 0;
}
+ if (adreno_of_read_property(node, "qcom,num-cores", &info->num_cores))
+ goto err;
+
+ info->sensors = kzalloc(info->num_cores *
+ sizeof(int),
+ GFP_KERNEL);
+
+ for (count = 0; count < info->num_cores; count++) {
+ if (adreno_of_read_property(node, "qcom,sensors",
+ &(info->sensors[count])))
+ goto err;
+ }
+
if (adreno_of_read_property(node, "qcom,core-core-type",
&info->core_param.core_type))
goto err;
@@ -1094,6 +1107,9 @@
&pdata->nap_allowed))
pdata->nap_allowed = 1;
+ pdata->strtstp_sleepwake = of_property_read_bool(pdev->dev.of_node,
+ "qcom,strtstp-sleepwake");
+
if (adreno_of_read_property(pdev->dev.of_node, "qcom,clk-map",
&pdata->clk_map))
goto err;
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
index acf22ac..3f9b3d7 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_msm.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c
@@ -171,7 +171,9 @@
low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
for (i = 0; i <= low_level; i++)
tbl[i].freq = pwr->pwrlevels[low_level - i].gpu_freq / 1000;
- ret = msm_dcvs_register_core(device->name, priv->core_info);
+ ret = msm_dcvs_register_core(device->name, priv->core_info,
+ msm_set_freq, msm_get_freq,
+ priv->core_info->sensors[0]);
if (ret) {
KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");
goto err;
@@ -188,9 +190,7 @@
}
priv->freq_sink.core_name = device->name;
- priv->freq_sink.set_frequency = msm_set_freq;
- priv->freq_sink.get_frequency = msm_get_freq;
- ret = msm_dcvs_freq_sink_register(&priv->freq_sink);
+ ret = msm_dcvs_freq_sink_start(&priv->freq_sink);
if (ret >= 0) {
if (device->ftbl->isidle(device)) {
priv->gpu_busy = 0;
@@ -220,7 +220,7 @@
if (pwrscale->priv == NULL)
return;
msm_dcvs_idle_source_unregister(&priv->idle_source);
- msm_dcvs_freq_sink_unregister(&priv->freq_sink);
+ msm_dcvs_freq_sink_stop(&priv->freq_sink);
kfree(pwrscale->priv);
pwrscale->priv = NULL;
msm_restore_io_fraction(device);
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index 775e95d..abd66f4 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -104,14 +104,75 @@
static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
+static int pmic8xxx_set_pon1(struct device *dev, u32 debounce_us, bool pull_up)
+{
+ int err;
+ u32 delay;
+ u8 pon_cntl;
+
+ /* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
+ if (debounce_us > USEC_PER_SEC * 2 ||
+ debounce_us < USEC_PER_SEC / 64) {
+ dev_err(dev, "invalid power key trigger delay\n");
+ return -EINVAL;
+ }
+
+ delay = (debounce_us << 6) / USEC_PER_SEC;
+ delay = ilog2(delay);
+
+ err = pm8xxx_readb(dev->parent, PON_CNTL_1, &pon_cntl);
+ if (err < 0) {
+ dev_err(dev, "failed reading PON_CNTL_1 err=%d\n", err);
+ return err;
+ }
+
+ pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
+ pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
+
+ if (pull_up)
+ pon_cntl |= PON_CNTL_PULL_UP;
+ else
+ pon_cntl &= ~PON_CNTL_PULL_UP;
+
+ err = pm8xxx_writeb(dev->parent, PON_CNTL_1, pon_cntl);
+ if (err < 0) {
+ dev_err(dev, "failed writing PON_CNTL_1 err=%d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static ssize_t pmic8xxx_debounce_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
+ int err;
+ unsigned long val;
+
+ if (size > 8)
+ return -EINVAL;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ err = pmic8xxx_set_pon1(dev, val, pwrkey->pdata->pull_up);
+ if (err < 0)
+ return err;
+
+ return size;
+}
+
+static DEVICE_ATTR(debounce_us, 0664, NULL, pmic8xxx_debounce_store);
+
static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
{
struct input_dev *pwr;
int key_release_irq = platform_get_irq(pdev, 0);
int key_press_irq = platform_get_irq(pdev, 1);
int err;
- unsigned int delay;
- u8 pon_cntl;
struct pmic8xxx_pwrkey *pwrkey;
const struct pm8xxx_pwrkey_platform_data *pdata =
dev_get_platdata(&pdev->dev);
@@ -121,13 +182,6 @@
return -EINVAL;
}
- /* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
- if (pdata->kpd_trigger_delay_us > USEC_PER_SEC * 2 ||
- pdata->kpd_trigger_delay_us < USEC_PER_SEC / 64) {
- dev_err(&pdev->dev, "invalid power key trigger delay\n");
- return -EINVAL;
- }
-
pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
if (!pwrkey)
return -ENOMEM;
@@ -147,25 +201,10 @@
pwr->phys = "pmic8xxx_pwrkey/input0";
pwr->dev.parent = &pdev->dev;
- delay = (pdata->kpd_trigger_delay_us << 6) / USEC_PER_SEC;
- delay = ilog2(delay);
-
- err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
- if (err < 0) {
- dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
- goto free_input_dev;
- }
-
- pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
- pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
- if (pdata->pull_up)
- pon_cntl |= PON_CNTL_PULL_UP;
- else
- pon_cntl &= ~PON_CNTL_PULL_UP;
-
- err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
- if (err < 0) {
- dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
+ err = pmic8xxx_set_pon1(&pdev->dev,
+ pdata->kpd_trigger_delay_us, pdata->pull_up);
+ if (err) {
+ dev_dbg(&pdev->dev, "Can't set PON CTRL1 register: %d\n", err);
goto free_input_dev;
}
@@ -211,12 +250,22 @@
goto free_press_irq;
}
+ err = device_create_file(&pdev->dev, &dev_attr_debounce_us);
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "dev file creation for debounce failed: %d\n",
+ err);
+ goto free_rel_irq;
+ }
+
device_init_wakeup(&pdev->dev, pdata->wakeup);
return 0;
+free_rel_irq:
+ free_irq(key_release_irq, pwrkey);
free_press_irq:
- free_irq(key_press_irq, NULL);
+ free_irq(key_press_irq, pwrkey);
unreg_input_dev:
platform_set_drvdata(pdev, NULL);
input_unregister_device(pwr);
@@ -236,6 +285,7 @@
device_init_wakeup(&pdev->dev, 0);
+ device_remove_file(&pdev->dev, &dev_attr_debounce_us);
free_irq(key_press_irq, pwrkey);
free_irq(key_release_irq, pwrkey);
input_unregister_device(pwrkey->pwr);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.c b/drivers/media/video/msm_vidc/msm_vidc_debug.c
index 7921f84..fa62988 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.c
@@ -104,6 +104,7 @@
dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
goto failed_create_dir;
}
+ msm_vidc_debug = 0x3;
failed_create_dir:
return dir;
}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.h b/drivers/media/video/msm_vidc/msm_vidc_debug.h
index b7928e9..f7aa742 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.h
@@ -18,19 +18,24 @@
#define VIDC_DBG_TAG "msm_vidc: %d: "
+/*To enable messages OR these values and
+* echo the result to debugfs file*/
+
enum vidc_msg_prio {
- VIDC_ERR,
- VIDC_WARN,
- VIDC_INFO,
- VIDC_DBG,
+ VIDC_ERR = 0x0001,
+ VIDC_WARN = 0x0002,
+ VIDC_INFO = 0x0004,
+ VIDC_DBG = 0x0008,
+ VIDC_PROF = 0x0010,
+ VIDC_FW = 0x1000,
};
extern int msm_vidc_debug;
-#define dprintk(level, fmt, arg...) \
- do { \
- if (msm_vidc_debug >= level) \
- printk(KERN_DEBUG VIDC_DBG_TAG fmt, \
- level, ## arg); \
+#define dprintk(__level, __fmt, arg...) \
+ do { \
+ if (msm_vidc_debug & __level) \
+ printk(KERN_DEBUG VIDC_DBG_TAG __fmt,\
+ __level, ## arg); \
} while (0)
struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index 659cf7e..879418d 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -210,7 +210,7 @@
enum hal_mpeg4_profile {
HAL_MPEG4_PROFILE_SIMPLE = 0x00000001,
- HAL_MPEG4_PROFILE_SIMPLESCALABLE = 0x00000002,
+ HAL_MPEG4_PROFILE_ADVANCEDSIMPLE = 0x00000002,
HAL_MPEG4_PROFILE_CORE = 0x00000004,
HAL_MPEG4_PROFILE_MAIN = 0x00000008,
HAL_MPEG4_PROFILE_NBIT = 0x00000010,
@@ -224,7 +224,7 @@
HAL_MPEG4_PROFILE_ADVANCEDCODING = 0x00001000,
HAL_MPEG4_PROFILE_ADVANCEDCORE = 0x00002000,
HAL_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000,
- HAL_MPEG4_PROFILE_ADVANCEDSIMPLE = 0x00008000,
+ HAL_MPEG4_PROFILE_SIMPLESCALABLE = 0x00008000,
HAL_UNUSED_MPEG4_PROFILE = 0x10000000,
};
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 0ea843c..e7e11d0 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -263,6 +263,7 @@
{{0x0, 0x0, 0x2, 0x1}, taiko_devs, ARRAY_SIZE(taiko_devs)},
{{0x0, 0x0, 0x0, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
{{0x1, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
+ {{0x2, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
};
static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
@@ -314,18 +315,17 @@
struct mfd_cell **wcd9xxx_dev,
int *wcd9xxx_dev_size)
{
- struct wcd9xx_codec_type *cdc = wcd9xxx_codecs;
- int index;
+ int i;
int ret;
- index = WCD9XXX_A_CHIP_ID_BYTE_0;
- while (index <= WCD9XXX_A_CHIP_ID_BYTE_3) {
- ret = wcd9xxx_reg_read(wcd9xxx, index);
+ i = WCD9XXX_A_CHIP_ID_BYTE_0;
+ while (i <= WCD9XXX_A_CHIP_ID_BYTE_3) {
+ ret = wcd9xxx_reg_read(wcd9xxx, i);
if (ret < 0)
goto exit;
- wcd9xxx->idbyte[index-WCD9XXX_A_CHIP_ID_BYTE_0] = (u8)ret;
+ wcd9xxx->idbyte[i-WCD9XXX_A_CHIP_ID_BYTE_0] = (u8)ret;
pr_debug("%s: wcd9xx read = %x, byte = %x\n", __func__, ret,
- index);
- index++;
+ i);
+ i++;
}
/* Read codec version */
@@ -333,18 +333,19 @@
if (ret < 0)
goto exit;
wcd9xxx->version = (u8)ret & 0x1F;
-
- while (cdc < (cdc + ARRAY_SIZE(wcd9xxx_codecs)) && cdc != NULL) {
- if ((cdc->byte[0] == wcd9xxx->idbyte[0]) &&
- (cdc->byte[1] == wcd9xxx->idbyte[1]) &&
- (cdc->byte[2] == wcd9xxx->idbyte[2]) &&
- (cdc->byte[3] == wcd9xxx->idbyte[3])) {
- pr_info("%s: codec is %s", __func__, cdc->dev->name);
- *wcd9xxx_dev = cdc->dev;
- *wcd9xxx_dev_size = cdc->size;
+ i = 0;
+ while (i < ARRAY_SIZE(wcd9xxx_codecs)) {
+ if ((wcd9xxx_codecs[i].byte[0] == wcd9xxx->idbyte[0]) &&
+ (wcd9xxx_codecs[i].byte[1] == wcd9xxx->idbyte[1]) &&
+ (wcd9xxx_codecs[i].byte[2] == wcd9xxx->idbyte[2]) &&
+ (wcd9xxx_codecs[i].byte[3] == wcd9xxx->idbyte[3])) {
+ pr_info("%s: codec is %s", __func__,
+ wcd9xxx_codecs[i].dev->name);
+ *wcd9xxx_dev = wcd9xxx_codecs[i].dev;
+ *wcd9xxx_dev_size = wcd9xxx_codecs[i].size;
break;
}
- cdc++;
+ i++;
}
if (*wcd9xxx_dev == NULL || *wcd9xxx_dev_size == 0)
ret = -ENODEV;
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 68c4557..e9b2ef3 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -25,6 +25,8 @@
#define BYTE_BIT_MASK(nr) (1UL << ((nr) % BITS_PER_BYTE))
#define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE)
+#define WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS 100
+
struct wcd9xxx_irq {
bool level;
};
@@ -106,11 +108,17 @@
{
enum wcd9xxx_pm_state os;
- /* wcd9xxx_{lock/unlock}_sleep will be called by wcd9xxx_irq_thread
+ /*
+ * wcd9xxx_{lock/unlock}_sleep will be called by wcd9xxx_irq_thread
* and its subroutines only motly.
* but btn0_lpress_fn is not wcd9xxx_irq_thread's subroutine and
- * it can race with wcd9xxx_irq_thread.
- * so need to embrace wlock_holders with mutex.
+ * It can race with wcd9xxx_irq_thread.
+ * So need to embrace wlock_holders with mutex.
+ *
+ * If system didn't resume, we can simply return false so codec driver's
+ * IRQ handler can return without handling IRQ.
+ * As interrupt line is still active, codec will have another IRQ to
+ * retry shortly.
*/
mutex_lock(&wcd9xxx->pm_lock);
if (wcd9xxx->wlock_holders++ == 0) {
@@ -124,11 +132,11 @@
WCD9XXX_PM_AWAKE)) ==
WCD9XXX_PM_SLEEPABLE ||
(os == WCD9XXX_PM_AWAKE)),
- 5 * HZ)) {
- pr_err("%s: system didn't resume within 5000ms, state %d, "
- "wlock %d\n", __func__, wcd9xxx->pm_state,
- wcd9xxx->wlock_holders);
- WARN_ON(1);
+ msecs_to_jiffies(WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS))) {
+ pr_warn("%s: system didn't resume within %dms, s %d, w %d\n",
+ __func__,
+ WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, wcd9xxx->pm_state,
+ wcd9xxx->wlock_holders);
wcd9xxx_unlock_sleep(wcd9xxx);
return false;
}
@@ -141,8 +149,14 @@
{
mutex_lock(&wcd9xxx->pm_lock);
if (--wcd9xxx->wlock_holders == 0) {
- wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
- pr_debug("%s: releasing wake lock\n", __func__);
+ pr_debug("%s: releasing wake lock pm_state %d -> %d\n",
+ __func__, wcd9xxx->pm_state, WCD9XXX_PM_SLEEPABLE);
+ /*
+ * if wcd9xxx_lock_sleep failed, pm_state would be still
+ * WCD9XXX_PM_ASLEEP, don't overwrite
+ */
+ if (likely(wcd9xxx->pm_state == WCD9XXX_PM_AWAKE))
+ wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
pm_qos_update_request(&wcd9xxx->pm_qos_req,
PM_QOS_DEFAULT_VALUE);
}
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 33b12ae..76a758b 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -39,8 +39,10 @@
#define QPNP_PON_RESIN_PULL_UP BIT(0)
#define QPNP_PON_KPDPWR_PULL_UP BIT(1)
+#define QPNP_PON_CBLPWR_PULL_UP BIT(2)
#define QPNP_PON_S2_CNTL_EN BIT(7)
#define QPNP_PON_S2_RESET_ENABLE BIT(7)
+#define QPNP_PON_DELAY_BIT_SHIFT 6
#define QPNP_PON_S1_TIMER_MASK (0xF)
#define QPNP_PON_S2_TIMER_MASK (0x7)
@@ -49,6 +51,7 @@
#define QPNP_PON_DBC_DELAY_MASK (0x7)
#define QPNP_PON_KPDPWR_N_SET BIT(0)
#define QPNP_PON_RESIN_N_SET BIT(1)
+#define QPNP_PON_CBLPWR_N_SET BIT(2)
#define QPNP_PON_RESIN_BARK_N_SET BIT(4)
#define QPNP_PON_RESET_EN BIT(7)
@@ -66,6 +69,7 @@
enum pon_type {
PON_KPDPWR,
PON_RESIN,
+ PON_CBLPWR,
};
struct qpnp_pon_config {
@@ -214,6 +218,9 @@
case PON_RESIN:
pon_rt_bit = QPNP_PON_RESIN_N_SET;
break;
+ case PON_CBLPWR:
+ pon_rt_bit = QPNP_PON_CBLPWR_N_SET;
+ break;
default:
return -EINVAL;
}
@@ -253,6 +260,18 @@
return IRQ_HANDLED;
}
+static irqreturn_t qpnp_cblpwr_irq(int irq, void *_pon)
+{
+ int rc;
+ struct qpnp_pon *pon = _pon;
+
+ rc = qpnp_pon_input_dispatch(pon, PON_CBLPWR);
+ if (rc)
+ dev_err(&pon->spmi->dev, "Unable to send input event\n");
+
+ return IRQ_HANDLED;
+}
+
static void bark_work_func(struct work_struct *work)
{
int rc;
@@ -351,6 +370,9 @@
case PON_RESIN:
pull_bit = QPNP_PON_RESIN_PULL_UP;
break;
+ case PON_CBLPWR:
+ pull_bit = QPNP_PON_CBLPWR_PULL_UP;
+ break;
default:
return -EINVAL;
}
@@ -489,6 +511,17 @@
}
}
break;
+ case PON_CBLPWR:
+ rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+ qpnp_cblpwr_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "qpnp_cblpwr_status", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+ cfg->state_irq);
+ return rc;
+ }
+ break;
default:
return -EINVAL;
}
@@ -595,6 +628,15 @@
}
}
break;
+ case PON_CBLPWR:
+ cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "cblpwr");
+ if (cfg->state_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get cblpwr irq\n");
+ return rc;
+ }
+ break;
default:
dev_err(&pon->spmi->dev, "PON RESET %d not supported",
cfg->pon_type);
@@ -763,11 +805,13 @@
rc = of_property_read_u32(pon->spmi->dev.of_node,
"qcom,pon-dbc-delay", &delay);
- if (rc && rc != -EINVAL) {
- dev_err(&spmi->dev, "Unable to read debounce delay\n");
- return rc;
+ if (rc) {
+ if (rc != -EINVAL) {
+ dev_err(&spmi->dev, "Unable to read debounce delay\n");
+ return rc;
+ }
} else {
- delay = (delay << 6) / USEC_PER_SEC;
+ delay = (delay << QPNP_PON_DELAY_BIT_SHIFT) / USEC_PER_SEC;
delay = ilog2(delay);
rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon->base),
QPNP_PON_DBC_DELAY_MASK, delay);
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 6e332ef..5fdee02 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -920,7 +920,7 @@
u32 i;
u32 found = false;
- for (i = 0; i <= pool->count && !found; i++) {
+ for (i = 1; i <= pool->count && !found; i++) {
if (pool->entries[i].virtual == addr)
found = true;
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 32d3aef..9cc0de4 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -284,7 +284,8 @@
uint32_t rate, uint32_t channels);
int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
- uint32_t rate, uint32_t channels);
+ uint32_t rate, uint32_t channels,
+ char *channel_map);
int q6asm_media_format_block_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index d0c5baf..4eec66e 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -295,7 +295,9 @@
static int
cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
{
- return *rdp->nxttail[RCU_DONE_TAIL] && !rcu_gp_in_progress(rsp);
+ return *rdp->nxttail[RCU_DONE_TAIL +
+ ACCESS_ONCE(rsp->completed) != rdp->completed] &&
+ !rcu_gp_in_progress(rsp);
}
/*
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 4c655c2..d2f60a0 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1629,6 +1629,8 @@
$exec_file =~ /^.+\.ihex$/ or
$exec_file =~ /^.+\.hex$/ or
$exec_file =~ /^.+\.HEX$/ or
+ $exec_file =~ /^.+\.dts$/ or
+ $exec_file =~ /^.+\.dtsi$/ or
$exec_file =~ /^.+defconfig$/ or
$exec_file =~ /^Makefile$/ or
$exec_file =~ /^Kconfig$/) &&
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index deddbe8..5a819c9 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -33,6 +33,9 @@
#include <linux/pm_runtime.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/wakelock.h>
+#include <linux/suspend.h>
#include "wcd9310.h"
static int cfilt_adjust_ms = 10;
@@ -340,6 +343,9 @@
*/
struct work_struct hs_correct_plug_work_nogpio;
+ bool gpio_irq_resend;
+ struct wake_lock irq_resend_wlock;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_poke;
struct dentry *debugfs_mbhc;
@@ -7352,9 +7358,18 @@
{
int r = IRQ_HANDLED;
struct snd_soc_codec *codec = data;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
pr_warn("%s: failed to hold suspend\n", __func__);
+ /*
+ * Give up this IRQ for now and resend this IRQ so IRQ can be
+ * handled after system resume
+ */
+ TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+ tabla->gpio_irq_resend = true;
+ TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+ wake_lock_timeout(&tabla->irq_resend_wlock, HZ);
r = IRQ_NONE;
} else {
tabla_hs_gpio_handler(codec);
@@ -8267,6 +8282,15 @@
goto err_hphr_ocp_irq;
}
wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
+
+ /*
+ * Register suspend lock and notifier to resend edge triggered
+ * gpio IRQs
+ */
+ wake_lock_init(&tabla->irq_resend_wlock, WAKE_LOCK_SUSPEND,
+ "tabla_gpio_irq_resend");
+ tabla->gpio_irq_resend = false;
+
for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
switch (tabla_dai[i].id) {
case AIF1_PB:
@@ -8331,6 +8355,9 @@
{
int i;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+ wake_lock_destroy(&tabla->irq_resend_wlock);
+
wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
@@ -8380,11 +8407,29 @@
static int tabla_resume(struct device *dev)
{
+ int irq;
struct platform_device *pdev = to_platform_device(dev);
struct tabla_priv *tabla = platform_get_drvdata(pdev);
+
dev_dbg(dev, "%s: system resume tabla %p\n", __func__, tabla);
- if (tabla)
+ if (tabla) {
+ TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
tabla->mbhc_last_resume = jiffies;
+ if (tabla->gpio_irq_resend) {
+ WARN_ON(!tabla->mbhc_cfg.gpio_irq);
+ tabla->gpio_irq_resend = false;
+
+ irq = tabla->mbhc_cfg.gpio_irq;
+ pr_debug("%s: Resending GPIO IRQ %d\n", __func__, irq);
+ irq_set_pending(irq);
+ check_irq_resend(irq_to_desc(irq), irq);
+
+ /* release suspend lock */
+ wake_unlock(&tabla->irq_resend_wlock);
+ }
+ TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+ }
+
return 0;
}
diff --git a/sound/soc/msm/msm-lowlatency-pcm-q6.c b/sound/soc/msm/msm-lowlatency-pcm-q6.c
index 129f69f..fcfcb66 100644
--- a/sound/soc/msm/msm-lowlatency-pcm-q6.c
+++ b/sound/soc/msm/msm-lowlatency-pcm-q6.c
@@ -218,8 +218,27 @@
if (prtd->enabled)
return 0;
+ if (!prtd->set_channel_map) {
+ memset(prtd->channel_map, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+ if (prtd->channel_mode == 1) {
+ prtd->channel_map[0] = PCM_CHANNEL_FL;
+ } else if (prtd->channel_mode == 2) {
+ prtd->channel_map[0] = PCM_CHANNEL_FL;
+ prtd->channel_map[0] = PCM_CHANNEL_FR;
+ } else if (prtd->channel_mode == 6) {
+ prtd->channel_map[0] = PCM_CHANNEL_FC;
+ prtd->channel_map[0] = PCM_CHANNEL_FL;
+ prtd->channel_map[0] = PCM_CHANNEL_FR;
+ prtd->channel_map[0] = PCM_CHANNEL_LB;
+ prtd->channel_map[0] = PCM_CHANNEL_RB;
+ prtd->channel_map[0] = PCM_CHANNEL_LFE;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+ prtd->channel_mode);
+ }
+ }
ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
- runtime->rate, runtime->channels);
+ runtime->rate, runtime->channels, prtd->channel_map);
if (ret < 0)
pr_info("%s: CMD Format block failed\n", __func__);
@@ -389,6 +408,7 @@
}
prtd->dsp_cnt = 0;
+ prtd->set_channel_map = false;
runtime->private_data = prtd;
pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index 5b0759c..7d04f95 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -269,9 +269,29 @@
prtd->channel_mode = runtime->channels;
if (prtd->enabled)
return 0;
-
+ pr_debug("prtd->set_channel_map: %d", prtd->set_channel_map);
+ if (!prtd->set_channel_map) {
+ pr_debug("using default channel map");
+ memset(prtd->channel_map, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+ if (prtd->channel_mode == 1) {
+ prtd->channel_map[0] = PCM_CHANNEL_FL;
+ } else if (prtd->channel_mode == 2) {
+ prtd->channel_map[1] = PCM_CHANNEL_FL;
+ prtd->channel_map[2] = PCM_CHANNEL_FR;
+ } else if (prtd->channel_mode == 6) {
+ prtd->channel_map[0] = PCM_CHANNEL_FC;
+ prtd->channel_map[1] = PCM_CHANNEL_FL;
+ prtd->channel_map[2] = PCM_CHANNEL_FR;
+ prtd->channel_map[3] = PCM_CHANNEL_LB;
+ prtd->channel_map[4] = PCM_CHANNEL_RB;
+ prtd->channel_map[5] = PCM_CHANNEL_LFE;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+ prtd->channel_mode);
+ }
+ }
ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
- runtime->rate, runtime->channels);
+ runtime->rate, runtime->channels, prtd->channel_map);
if (ret < 0)
pr_info("%s: CMD Format block failed\n", __func__);
@@ -452,6 +472,7 @@
}
prtd->dsp_cnt = 0;
+ prtd->set_channel_map = false;
runtime->private_data = prtd;
pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
@@ -492,6 +513,15 @@
return rc;
}
+void multi_ch_pcm_set_channel_map(char *channel_mapping)
+{
+ pr_debug("%s\n", __func__);
+ if (multi_ch_pcm_audio.prtd) {
+ multi_ch_pcm_audio.prtd->set_channel_map = true;
+ memcpy(multi_ch_pcm_audio.prtd->channel_map, channel_mapping,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+}
static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
diff --git a/sound/soc/msm/msm-pcm-q6.h b/sound/soc/msm/msm-pcm-q6.h
index f1af99a..2678498 100644
--- a/sound/soc/msm/msm-pcm-q6.h
+++ b/sound/soc/msm/msm-pcm-q6.h
@@ -81,6 +81,8 @@
int periods;
int mmap_flag;
atomic_t pending_buffer;
+ bool set_channel_map;
+ char channel_map[8];
};
struct output_meta_data_st {
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 4d0caa3..f28d01a 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -78,6 +78,7 @@
static const DECLARE_TLV_DB_LINEAR(compressed2_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
static int msm_route_ec_ref_rx;
+static char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
/* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
#define MAX_EQ_SESSIONS MSM_FRONTEND_DAI_CS_VOICE
@@ -862,6 +863,27 @@
return 0;
}
+static int msm_routing_get_channel_map_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ ucontrol->value.integer.value[i] = channel_mapping[i];
+ return 0;
+}
+
+static int msm_routing_put_channel_map_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ channel_mapping[i] = (char)(ucontrol->value.integer.value[i]);
+ multi_ch_pcm_set_channel_map(channel_mapping);
+
+ return 0;
+}
+
static int msm_routing_set_compressed_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1891,6 +1913,12 @@
msm_routing_set_compressed2_vol_mixer, compressed2_rx_vol_gain),
};
+static const struct snd_kcontrol_new multi_ch_channel_map_mixer_controls[] = {
+ SOC_SINGLE_MULTI_EXT("Playback Channel Map", SND_SOC_NOPM, 0, 8,
+ 0, 8, msm_routing_get_channel_map_mixer,
+ msm_routing_put_channel_map_mixer),
+};
+
static const struct snd_kcontrol_new lpa_SRS_trumedia_controls[] = {
{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "SRS TruMedia",
@@ -2867,6 +2895,10 @@
snd_soc_add_platform_controls(platform,
ec_ref_rx_mixer_controls,
ARRAY_SIZE(ec_ref_rx_mixer_controls));
+
+ snd_soc_add_platform_controls(platform,
+ multi_ch_channel_map_mixer_controls,
+ ARRAY_SIZE(multi_ch_channel_map_mixer_controls));
return 0;
}
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 6b87475..14f330b 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -126,4 +126,6 @@
int compressed_set_volume(unsigned volume);
+void multi_ch_pcm_set_channel_map(char *channel_mapping);
+
#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 6865871..0aad217 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -2317,7 +2317,7 @@
}
int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
- uint32_t rate, uint32_t channels)
+ uint32_t rate, uint32_t channels, char *channel_map)
{
struct asm_stream_media_format_update fmt;
u8 *channel_mapping;
@@ -2340,39 +2340,7 @@
channel_mapping =
fmt.write_cfg.multi_ch_pcm_cfg.channel_mapping;
- memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
-
- if (channels == 1) {
- channel_mapping[0] = PCM_CHANNEL_FL;
- } else if (channels == 2) {
- channel_mapping[0] = PCM_CHANNEL_FL;
- channel_mapping[1] = PCM_CHANNEL_FR;
- } else if (channels == 4) {
- channel_mapping[0] = PCM_CHANNEL_FL;
- channel_mapping[1] = PCM_CHANNEL_FR;
- channel_mapping[1] = PCM_CHANNEL_LB;
- channel_mapping[1] = PCM_CHANNEL_RB;
- } else if (channels == 6) {
- channel_mapping[0] = PCM_CHANNEL_FC;
- channel_mapping[1] = PCM_CHANNEL_FL;
- channel_mapping[2] = PCM_CHANNEL_FR;
- channel_mapping[3] = PCM_CHANNEL_LB;
- channel_mapping[4] = PCM_CHANNEL_RB;
- channel_mapping[5] = PCM_CHANNEL_LFE;
- } else if (channels == 8) {
- channel_mapping[0] = PCM_CHANNEL_FC;
- channel_mapping[1] = PCM_CHANNEL_FL;
- channel_mapping[2] = PCM_CHANNEL_FR;
- channel_mapping[3] = PCM_CHANNEL_LB;
- channel_mapping[4] = PCM_CHANNEL_RB;
- channel_mapping[5] = PCM_CHANNEL_LFE;
- channel_mapping[6] = PCM_CHANNEL_FLC;
- channel_mapping[7] = PCM_CHANNEL_FRC;
- } else {
- pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
- channels);
- return -EINVAL;
- }
+ memcpy(channel_mapping, channel_map, PCM_FORMAT_MAX_NUM_CHANNEL);
rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
if (rc < 0) {
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 62257b4..fac55b4 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -116,8 +116,18 @@
wake_up(&this_adm.wait[index]);
break;
case ADM_CMD_SHARED_MEM_MAP_REGIONS:
- /* Block until memory handle comes back */
- /* via ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
+ pr_debug("%s: ADM_CMD_SHARED_MEM_MAP_REGIONS\n",
+ __func__);
+ /* Should only come here if there is an APR */
+ /* error or malformed APR packet. Otherwise */
+ /* response will be returned as */
+ /* ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
+ if (payload[1] != 0) {
+ pr_err("%s: ADM map error, resuming\n",
+ __func__);
+ atomic_set(&this_adm.copp_stat[0], 1);
+ wake_up(&this_adm.wait[index]);
+ }
break;
default:
pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
@@ -247,24 +257,27 @@
get_audproc_cal(acdb_path, &aud_cal);
/* map & cache buffers used */
+ atomic_set(&mem_map_index, acdb_path);
if (((mem_addr_audproc[acdb_path].cal_paddr != aud_cal.cal_paddr) &&
(aud_cal.cal_size > 0)) ||
(aud_cal.cal_size > mem_addr_audproc[acdb_path].cal_size)) {
- atomic_set(&mem_map_index, acdb_path);
if (mem_addr_audproc[acdb_path].cal_paddr != 0)
adm_memory_unmap_regions(port_id,
&mem_addr_audproc[acdb_path].cal_paddr,
&size, 1);
result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
- 0, &aud_cal.cal_size, 1);
- if (result < 0)
+ 0, &size, 1);
+ if (result < 0) {
pr_err("ADM audproc mmap did not work! path = %d, addr = 0x%x, size = %d\n",
acdb_path, aud_cal.cal_paddr,
aud_cal.cal_size);
- else
- mem_addr_audproc[acdb_path] = aud_cal;
+ } else {
+ mem_addr_audproc[acdb_path].cal_paddr =
+ aud_cal.cal_paddr;
+ mem_addr_audproc[acdb_path].cal_size = size;
+ }
}
if (!send_adm_cal_block(port_id, &aud_cal))
@@ -278,24 +291,27 @@
get_audvol_cal(acdb_path, &aud_cal);
/* map & cache buffers used */
+ atomic_set(&mem_map_index, (acdb_path + MAX_AUDPROC_TYPES));
if (((mem_addr_audvol[acdb_path].cal_paddr != aud_cal.cal_paddr) &&
(aud_cal.cal_size > 0)) ||
(aud_cal.cal_size > mem_addr_audvol[acdb_path].cal_size)) {
- atomic_set(&mem_map_index, (acdb_path + MAX_AUDPROC_TYPES));
if (mem_addr_audvol[acdb_path].cal_paddr != 0)
adm_memory_unmap_regions(port_id,
&mem_addr_audvol[acdb_path].cal_paddr,
&size, 1);
result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
- 0, &aud_cal.cal_size, 1);
- if (result < 0)
+ 0, &size, 1);
+ if (result < 0) {
pr_err("ADM audvol mmap did not work! path = %d, addr = 0x%x, size = %d\n",
acdb_path, aud_cal.cal_paddr,
aud_cal.cal_size);
- else
- mem_addr_audvol[acdb_path] = aud_cal;
+ } else {
+ mem_addr_audvol[acdb_path].cal_paddr =
+ aud_cal.cal_paddr;
+ mem_addr_audvol[acdb_path].cal_size = size;
+ }
}
if (!send_adm_cal_block(port_id, &aud_cal))
@@ -664,8 +680,8 @@
APR_PKT_VER);
mmap_regions->hdr.pkt_size = cmd_size;
mmap_regions->hdr.src_port = 0;
- mmap_regions->hdr.dest_port = 0;
- mmap_regions->hdr.token = 0;
+ mmap_regions->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ mmap_regions->hdr.token = port_id;
mmap_regions->hdr.opcode = ADM_CMD_SHARED_MEM_MAP_REGIONS;
mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
mmap_regions->num_regions = bufcnt & 0x00ff;
@@ -733,8 +749,8 @@
APR_PKT_VER);
unmap_regions.hdr.pkt_size = cmd_size;
unmap_regions.hdr.src_port = 0;
- unmap_regions.hdr.dest_port = 0;
- unmap_regions.hdr.token = 0;
+ unmap_regions.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ unmap_regions.hdr.token = port_id;
unmap_regions.hdr.opcode = ADM_CMD_SHARED_MEM_UNMAP_REGIONS;
unmap_regions.mem_map_handle = atomic_read(&mem_map_handles[
atomic_read(&mem_map_index)]);