Merge "msm: camera: Add null check for VFE subdev"
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index ee5836c..ca98706 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -18,6 +18,8 @@
reg-names = "mdp_phys", "vbif_phys";
interrupts = <0 72 0>;
vdd-supply = <&gdsc_mdss>;
+ qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+ qcom,memory-reservation-size = <0x800000>; /* size 8MB */
};
mdss_dsi: qcom,mdss_dsi@fd922800 {
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 157f159..47dfa10 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1909,7 +1909,7 @@
config MSM_PIL_QDSP6V3
tristate "QDSP6v3 (Hexagon) Boot Support"
- depends on MSM_PIL
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
help
Support for booting and shutting down QDSP6v3 processors (hexagon).
The QDSP6 is a low power DSP used in audio software applications.
@@ -1984,8 +1984,8 @@
Venus is the Video subsystem processor used for video codecs.
config MSM_PIL_GSS
- tristate "GSS (Coretx A5) Boot Support"
- depends on MSM_PIL
+ tristate "GSS (Cortex A5) Boot Support"
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
help
Support for booting and shutting down Cortex A5 processors which run
GPS subsystem firmware.
@@ -2026,14 +2026,6 @@
monitors WCNSS hardware watchdog interrupt lines and plugs WCNSS
into the subsystem restart framework.
-config MSM_GSS_SSR_8064
- bool "MSM 8064 GSS restart driver"
- depends on (ARCH_APQ8064)
- help
- This option enables the gps subsystem restart driver for APQ8064, which monitors
- gss hardware watchdog interrupt lines and plugs into the subsystem
- restart and PIL drivers.
-
config MSM_MODEM_SSR_8974
bool "MSM 8974 Modem restart driver"
depends on (ARCH_MSM8974)
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 1b42d2d..43e0a34 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -195,7 +195,6 @@
obj-y += subsystem_notif.o
obj-y += subsystem_restart.o
obj-y += ramdump.o
- obj-$(CONFIG_ARCH_MSM8X60) += lpass-8660.o
endif
obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
obj-$(CONFIG_MSM_MODEM_8960) += modem-8960.o
@@ -203,7 +202,6 @@
obj-$(CONFIG_MSM_LPASS_8960) += lpass-8960.o
obj-$(CONFIG_MSM_ADSP_SSR_8974) += adsp-8974.o
obj-$(CONFIG_MSM_WCNSS_SSR_8960) += wcnss-ssr-8960.o
-obj-$(CONFIG_MSM_GSS_SSR_8064) += gss-8064.o
ifdef CONFIG_CPU_IDLE
obj-$(CONFIG_ARCH_APQ8064) += cpuidle.o
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index d5e4638..44d7a38 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -223,6 +223,7 @@
static void rx_timer_work_func(struct work_struct *work);
static DECLARE_WORK(rx_timer_work, rx_timer_work_func);
+static struct delayed_work queue_rx_work;
static struct workqueue_struct *bam_mux_rx_workqueue;
static struct workqueue_struct *bam_mux_tx_workqueue;
@@ -430,21 +431,27 @@
rx_len_cached = bam_rx_pool_len;
mutex_unlock(&bam_rx_pool_mutexlock);
- while (rx_len_cached < NUM_BUFFERS) {
+ while (bam_connection_is_active && rx_len_cached < NUM_BUFFERS) {
if (in_global_reset)
goto fail;
- info = kmalloc(sizeof(struct rx_pkt_info), GFP_KERNEL);
+ info = kmalloc(sizeof(struct rx_pkt_info),
+ GFP_NOWAIT | __GFP_NOWARN);
if (!info) {
- pr_err("%s: unable to alloc rx_pkt_info\n", __func__);
+ DMUX_LOG_KERR(
+ "%s: unable to alloc rx_pkt_info, will retry later\n",
+ __func__);
goto fail;
}
INIT_WORK(&info->work, handle_bam_mux_cmd);
- info->skb = __dev_alloc_skb(BUFFER_SIZE, GFP_KERNEL);
+ info->skb = __dev_alloc_skb(BUFFER_SIZE,
+ GFP_NOWAIT | __GFP_NOWARN);
if (info->skb == NULL) {
- DMUX_LOG_KERR("%s: unable to alloc skb\n", __func__);
+ DMUX_LOG_KERR(
+ "%s: unable to alloc skb, will retry later\n",
+ __func__);
goto fail_info;
}
ptr = skb_put(info->skb, BUFFER_SIZE);
@@ -488,11 +495,16 @@
fail:
if (rx_len_cached == 0) {
- DMUX_LOG_KERR("%s: RX queue failure\n", __func__);
- in_global_reset = 1;
+ DMUX_LOG_KERR("%s: rescheduling\n", __func__);
+ schedule_delayed_work(&queue_rx_work, msecs_to_jiffies(100));
}
}
+static void queue_rx_work_func(struct work_struct *work)
+{
+ queue_rx();
+}
+
static void bam_mux_process_data(struct sk_buff *rx_skb)
{
unsigned long flags;
@@ -2422,6 +2434,7 @@
init_completion(&bam_connection_completion);
init_completion(&dfab_unvote_completion);
INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
+ INIT_DELAYED_WORK(&queue_rx_work, queue_rx_work_func);
wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");
rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL,
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 8983e95..cb03d4b 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -363,6 +363,22 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting audio_auxpcm[] = {
+/* Suspended state */
+ {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+/* Active state */
+ {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+};
+
+
static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -846,6 +862,37 @@
},
};
+static struct msm_gpiomux_config mpq8064_audio_auxpcm_configs[] __initdata = {
+ {
+ .gpio = 43,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 44,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 45,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 46,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+};
+
/* External 3.3 V regulator enable */
static struct msm_gpiomux_config apq8064_ext_regulator_configs[] __initdata = {
{
@@ -1527,6 +1574,10 @@
if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
machine_is_mpq8064_dtv()) {
+
+ msm_gpiomux_install(mpq8064_audio_auxpcm_configs,
+ ARRAY_SIZE(mpq8064_audio_auxpcm_configs));
+
msm_gpiomux_install(mpq8064_spkr_i2s_config,
ARRAY_SIZE(mpq8064_spkr_i2s_config));
}
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 3b47d2e..f6423c8 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -115,7 +115,6 @@
/* Initial PM8921 GPIO configurations */
static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
PM8921_GPIO_OUTPUT(14, 1, HIGH), /* HDMI Mux Selector */
- PM8921_GPIO_OUTPUT(23, 0, HIGH), /* touchscreen power FET */
PM8921_GPIO_OUTPUT_BUFCONF(25, 0, LOW, CMOS), /* DISP_RESET_N */
PM8921_GPIO_OUTPUT_FUNC(26, 0, PM_GPIO_FUNC_2), /* Bl: Off, PWM mode */
PM8921_GPIO_OUTPUT_VIN(30, 1, PM_GPIO_VIN_VPH), /* SMB349 susp line */
@@ -146,10 +145,13 @@
PM8921_GPIO_OUTPUT(37, 0, LOW), /* MUX1_SEL */
};
+static struct pm8xxx_gpio_init touchscreen_gpios[] __initdata = {
+ PM8921_GPIO_OUTPUT(23, 0, HIGH), /* touchscreen power FET */
+};
+
/* Initial PM8917 GPIO configurations */
static struct pm8xxx_gpio_init pm8917_gpios[] __initdata = {
PM8921_GPIO_OUTPUT(14, 1, HIGH), /* HDMI Mux Selector */
- PM8921_GPIO_OUTPUT(23, 0, HIGH), /* touchscreen power FET */
PM8921_GPIO_OUTPUT_BUFCONF(25, 0, LOW, CMOS), /* DISP_RESET_N */
PM8921_GPIO_OUTPUT(26, 1, HIGH), /* Backlight: on */
PM8921_GPIO_OUTPUT_BUFCONF(36, 1, LOW, OPEN_DRAIN),
@@ -210,6 +212,8 @@
apq8064_configure_gpios(pm8917_gpios, ARRAY_SIZE(pm8917_gpios));
if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid()) {
+ apq8064_configure_gpios(touchscreen_gpios,
+ ARRAY_SIZE(touchscreen_gpios));
if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
apq8064_configure_gpios(pm8921_cdp_kp_gpios,
ARRAY_SIZE(pm8921_cdp_kp_gpios));
@@ -395,6 +399,8 @@
.max_voltage = MAX_VOLTAGE_MV,
.min_voltage = 3200,
.uvd_thresh_voltage = 4050,
+ .alarm_low_mv = 3400,
+ .alarm_high_mv = 4000,
.resume_voltage_delta = 100,
.term_current = CHG_TERM_MA,
.cool_temp = 10,
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 6cdafbc..ef3c81d 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -771,4 +771,10 @@
= ARRAY_SIZE(vreg_consumers_8917_S1);
}
}
+
+ /*
+ * Switch to 8960_PM8917 rpm-regulator version so that TCXO workaround
+ * is applied to PM8917 regulators L25, L26, L27, and L28.
+ */
+ apq8064_rpm_regulator_pdata.version = RPM_VREG_VERSION_8960_PM8917;
}
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 2fd1a68..01e5b14 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2467,7 +2467,6 @@
&apq8064_device_ext_3p3v_vreg,
&apq8064_device_ssbi_pmic1,
&apq8064_device_ssbi_pmic2,
- &apq8064_device_ext_ts_sw_vreg,
};
static struct platform_device *pm8917_common_devices[] __initdata = {
@@ -2475,7 +2474,6 @@
&apq8064_device_ext_3p3v_vreg,
&apq8064_device_ssbi_pmic1,
&apq8064_device_ssbi_pmic2,
- &apq8064_device_ext_ts_sw_vreg,
};
static struct platform_device *common_devices[] __initdata = {
@@ -3372,6 +3370,8 @@
else
platform_add_devices(pm8917_common_devices,
ARRAY_SIZE(pm8917_common_devices));
+ if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
+ platform_device_register(&apq8064_device_ext_ts_sw_vreg);
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
if (!(machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
machine_is_mpq8064_dtv()))
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 59e4ba1..402aec4 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -320,6 +320,8 @@
.max_voltage = MAX_VOLTAGE_MV,
.min_voltage = 3200,
.uvd_thresh_voltage = 4050,
+ .alarm_low_mv = 3400,
+ .alarm_high_mv = 4000,
.resume_voltage_delta = 100,
.term_current = CHG_TERM_MA,
.cool_temp = 10,
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index ae74285..f6c3653 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -401,6 +401,8 @@
.max_voltage = MAX_VOLTAGE_MV,
.min_voltage = 3200,
.uvd_thresh_voltage = 4050,
+ .alarm_low_mv = 3400,
+ .alarm_high_mv = 4000,
.resume_voltage_delta = 100,
.term_current = CHG_TERM_MA,
.cool_temp = 10,
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 797f5f1..37e93b6 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -31,8 +31,39 @@
#include <mach/gpio.h>
#include <mach/clk-provider.h>
#include <mach/qpnp-int.h>
+#include <mach/msm_memtypes.h>
#include "clock.h"
+#define MSM_KERNEL_EBI_SIZE 0x51000
+
+static struct memtype_reserve msm9625_reserve_table[] __initdata = {
+ [MEMTYPE_SMI] = {
+ },
+ [MEMTYPE_EBI0] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+ [MEMTYPE_EBI1] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+};
+
+static int msm9625_paddr_to_memtype(unsigned int paddr)
+{
+ return MEMTYPE_EBI1;
+}
+
+static void __init msm9625_calculate_reserve_sizes(void)
+{
+ msm9625_reserve_table[MEMTYPE_EBI1].size += MSM_KERNEL_EBI_SIZE;
+}
+
+static struct reserve_info msm9625_reserve_info __initdata = {
+ .memtype_reserve_table = msm9625_reserve_table,
+ .calculate_reserve_sizes = msm9625_calculate_reserve_sizes,
+ .paddr_to_memtype = msm9625_paddr_to_memtype,
+};
+
+
#define L2CC_AUX_CTRL ((0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | \
(0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | \
(0x1 << L2X0_AUX_CTRL_EVNT_MON_BUS_EN_SHIFT))
@@ -97,6 +128,13 @@
.init = msm_dt_timer_init
};
+static void __init msm9625_reserve(void)
+{
+ reserve_info = &msm9625_reserve_info;
+ msm_reserve();
+}
+
+
void __init msm9625_init(void)
{
if (socinfo_init() < 0)
@@ -115,4 +153,5 @@
.handle_irq = gic_handle_irq,
.timer = &msm_dt_timer,
.dt_compat = msm9625_dt_match,
+ .reserve = msm9625_reserve,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index b4f6968..1d6eb01 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -941,6 +941,8 @@
static void __init fsm9xxx_init(void)
{
+ msm_clock_init(&fsm9xxx_clock_init_data);
+
regulator_has_full_constraints();
#if defined(CONFIG_I2C_SSBI) || defined(CONFIG_MSM_SSBI)
@@ -977,7 +979,6 @@
{
msm_shared_ram_phys = 0x00100000;
msm_map_fsm9xxx_io();
- msm_clock_init(&fsm9xxx_clock_init_data);
if (socinfo_init() < 0)
pr_err("%s: socinfo_init() failed!\n",
__func__);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index c0461e1..d680977 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -1962,6 +1962,11 @@
.end = 0x10008000 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
+ {
+ .start = GSS_A5_WDOG_EXPIRED,
+ .end = GSS_A5_WDOG_EXPIRED,
+ .flags = IORESOURCE_IRQ,
+ },
};
struct platform_device msm_gss = {
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 0a9bbf6..46853ac 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1316,8 +1316,8 @@
};
static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
- .phys_addr_base = 0x0010D204,
- .phys_size = SZ_8K,
+ .phys_addr_base = 0x0010DD04,
+ .phys_size = SZ_256,
};
struct platform_device msm9615_rpm_stat_device = {
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index b88fb50..37cdc98 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -192,7 +192,9 @@
gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE, (void *)MSM_QGIC_CPU_BASE);
}
-#define MSM_LPASS_QDSP6SS_PHYS 0x28800000
+#define MSM_LPASS_QDSP6SS_PHYS 0x28800000
+#define MSM_LPASS_QDSP6SS_WDOG_PHYS 0x28882000
+#define MSM_LPASS_QDSP6SS_IM_PHYS 0x288A0000
static struct resource msm_8660_q6_resources[] = {
{
@@ -200,6 +202,21 @@
.end = MSM_LPASS_QDSP6SS_PHYS + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
+ {
+ .start = MSM_LPASS_QDSP6SS_IM_PHYS,
+ .end = MSM_LPASS_QDSP6SS_IM_PHYS + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM_LPASS_QDSP6SS_WDOG_PHYS,
+ .end = MSM_LPASS_QDSP6SS_WDOG_PHYS + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = LPASS_Q6SS_WDOG_EXPIRED,
+ .end = LPASS_Q6SS_WDOG_EXPIRED,
+ .flags = IORESOURCE_IRQ,
+ },
};
struct platform_device msm_pil_q6v3 = {
diff --git a/arch/arm/mach-msm/gss-8064.c b/arch/arm/mach-msm/gss-8064.c
deleted file mode 100644
index ba6af61..0000000
--- a/arch/arm/mach-msm/gss-8064.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/* 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/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <linux/stringify.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-
-#include <mach/irqs.h>
-#include <mach/msm_smsm.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-#include <mach/socinfo.h>
-
-#include "smd_private.h"
-#include "modem_notifier.h"
-#include "ramdump.h"
-
-static struct gss_8064_data {
- struct miscdevice gss_dev;
- void *pil_handle;
- void *gss_ramdump_dev;
- void *smem_ramdump_dev;
-} gss_data;
-
-static int crash_shutdown;
-
-static struct subsys_device *gss_8064_dev;
-
-#define MAX_SSR_REASON_LEN 81U
-
-static void log_gss_sfr(void)
-{
- u32 size;
- char *smem_reason, reason[MAX_SSR_REASON_LEN];
-
- smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
- if (!smem_reason || !size) {
- pr_err("GSS subsystem failure reason: (unknown, smem_get_entry failed).\n");
- return;
- }
- if (!smem_reason[0]) {
- pr_err("GSS subsystem failure reason: (unknown, init string found).\n");
- return;
- }
-
- size = min(size, MAX_SSR_REASON_LEN-1);
- memcpy(reason, smem_reason, size);
- reason[size] = '\0';
- pr_err("GSS subsystem failure reason: %s.\n", reason);
-
- smem_reason[0] = '\0';
- wmb();
-}
-
-static void restart_gss(void)
-{
- log_gss_sfr();
- subsystem_restart_dev(gss_8064_dev);
-}
-
-static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
-{
- /* Ignore if we're the one that set SMSM_RESET */
- if (crash_shutdown)
- return;
-
- if (new_state & SMSM_RESET) {
- pr_err("GSS SMSM state changed to SMSM_RESET.\n"
- "Probable err_fatal on the GSS. "
- "Calling subsystem restart...\n");
- restart_gss();
- }
-}
-
-#define Q6_FW_WDOG_ENABLE 0x08882024
-#define Q6_SW_WDOG_ENABLE 0x08982024
-static int gss_shutdown(const struct subsys_desc *desc)
-{
- pil_force_shutdown("gss");
- disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
-
- return 0;
-}
-
-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_desc *desc)
-{
- crash_shutdown = 1;
- smsm_reset_modem(SMSM_RESET);
-}
-
-/* FIXME: Get address, size from PIL */
-static struct ramdump_segment gss_segments[] = {
- {0x89000000, 0x00D00000}
-};
-
-static struct ramdump_segment smem_segments[] = {
- {0x80000000, 0x00200000},
-};
-
-static int gss_ramdump(int enable,
- const struct subsys_desc *crashed_subsys)
-{
- int ret = 0;
-
- if (enable) {
- ret = do_ramdump(gss_data.gss_ramdump_dev, gss_segments,
- ARRAY_SIZE(gss_segments));
-
- if (ret < 0) {
- pr_err("Unable to dump gss memory (rc = %d).\n",
- ret);
- goto out;
- }
-
- ret = do_ramdump(gss_data.smem_ramdump_dev, smem_segments,
- ARRAY_SIZE(smem_segments));
-
- if (ret < 0) {
- pr_err("Unable to dump smem memory (rc = %d).\n", ret);
- goto out;
- }
- }
-
-out:
- return ret;
-}
-
-static irqreturn_t gss_wdog_bite_irq(int irq, void *dev_id)
-{
- pr_err("Watchdog bite received from GSS!\n");
- restart_gss();
-
- return IRQ_HANDLED;
-}
-
-static struct subsys_desc gss_8064 = {
- .name = "gss",
- .shutdown = gss_shutdown,
- .powerup = gss_powerup,
- .ramdump = gss_ramdump,
- .crash_shutdown = gss_crash_shutdown
-};
-
-static int gss_subsystem_restart_init(void)
-{
- 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)
-{
- void *ret;
- gss_data.pil_handle = ret = pil_get("gss");
- if (!ret)
- pr_debug("%s - pil_get returned NULL\n", __func__);
- return 0;
-}
-
-static int gss_release(struct inode *inode, struct file *filep)
-{
- pil_put(gss_data.pil_handle);
- pr_debug("%s pil_put called on GSS\n", __func__);
- return 0;
-}
-
-const struct file_operations gss_file_ops = {
- .open = gss_open,
- .release = gss_release,
-};
-
-static int __init gss_8064_init(void)
-{
- int ret;
-
- if (!(cpu_is_apq8064() || cpu_is_apq8064ab()))
- return -ENODEV;
-
- ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
- smsm_state_cb, 0);
-
- if (ret < 0)
- pr_err("%s: Unable to register SMSM callback! (%d)\n",
- __func__, ret);
-
- ret = request_irq(GSS_A5_WDOG_EXPIRED, gss_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "gss_a5_wdog", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to request gss watchdog IRQ. (%d)\n",
- __func__, ret);
- disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
- goto out;
- }
-
- ret = gss_subsystem_restart_init();
-
- if (ret < 0) {
- pr_err("%s: Unable to reg with subsystem restart. (%d)\n",
- __func__, ret);
- goto out;
- }
-
- gss_data.gss_dev.minor = MISC_DYNAMIC_MINOR;
- gss_data.gss_dev.name = "gss";
- gss_data.gss_dev.fops = &gss_file_ops;
- ret = misc_register(&gss_data.gss_dev);
-
- if (ret) {
- pr_err("%s: misc_registers failed for %s (%d)", __func__,
- gss_data.gss_dev.name, ret);
- goto out;
- }
-
- gss_data.gss_ramdump_dev = create_ramdump_device("gss");
-
- if (!gss_data.gss_ramdump_dev) {
- pr_err("%s: Unable to create gss ramdump device. (%d)\n",
- __func__, -ENOMEM);
- ret = -ENOMEM;
- goto out;
- }
-
- gss_data.smem_ramdump_dev = create_ramdump_device("smem-gss");
-
- if (!gss_data.smem_ramdump_dev) {
- pr_err("%s: Unable to create smem ramdump device. (%d)\n",
- __func__, -ENOMEM);
- ret = -ENOMEM;
- goto out;
- }
-
- pr_info("%s: gss fatal driver init'ed.\n", __func__);
-out:
- return ret;
-}
-
-module_init(gss_8064_init);
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs.h b/arch/arm/mach-msm/include/mach/msm_dcvs.h
index fa7e6f0..78d0d4a 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,8 @@
#define CORE_NAME_MAX (32)
#define CORES_MAX (10)
+#define CPU_OFFSET 1 /* used to notify TZ the core number */
+
enum msm_core_idle_state {
MSM_DCVS_IDLE_ENTER,
MSM_DCVS_IDLE_EXIT,
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
index 3cc2595..8d1e24a 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,12 +14,17 @@
#define _ARCH_ARM_MACH_MSM_MSM_DCVS_SCM_H
enum msm_dcvs_scm_event {
- MSM_DCVS_SCM_IDLE_ENTER,
- MSM_DCVS_SCM_IDLE_EXIT,
- MSM_DCVS_SCM_QOS_TIMER_EXPIRED,
- MSM_DCVS_SCM_CLOCK_FREQ_UPDATE,
- MSM_DCVS_SCM_ENABLE_CORE,
- MSM_DCVS_SCM_RESET_CORE,
+ MSM_DCVS_SCM_IDLE_ENTER = 0, /* Core enters idle */
+ MSM_DCVS_SCM_IDLE_EXIT = 1, /* Core exits idle */
+ MSM_DCVS_SCM_QOS_TIMER_EXPIRED = 2, /* Core slack timer expired */
+ MSM_DCVS_SCM_CLOCK_FREQ_UPDATE = 3, /* Core freq change complete */
+ MSM_DCVS_SCM_CORE_ONLINE = 4, /* Core is online */
+ MSM_DCVS_SCM_CORE_OFFLINE = 5, /* Core is offline */
+ MSM_DCVS_SCM_CORE_UNAVAILABLE = 6, /* Core is offline + unavailable */
+ MSM_DCVS_SCM_DCVS_ENABLE = 7, /* DCVS is enabled/disabled for core */
+ MSM_DCVS_SCM_MPD_ENABLE = 8, /* Enable/disable MP Decision */
+ MSM_DCVS_SCM_RUNQ_UPDATE = 9, /* Update running threads */
+ MSM_DCVS_SCM_MPD_QOS_TIMER_EXPIRED = 10, /* MPDecision slack timer */
};
struct msm_dcvs_algo_param {
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
index eecdd67..765de13 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
@@ -34,9 +34,27 @@
#define MSM9625_TLMM_PHYS 0xFD510000
#define MSM9625_TLMM_SIZE SZ_16K
+/*
+ * TODO: Revert IMEM_PHYS back to actual
+ * address 0xfe807800
+ * after IMEM issues resolved.
+ *
+ */
+#define MSM9625_IMEM_PHYS 0xFC42B000
+#define MSM9625_IMEM_SIZE SZ_2K
+
#ifdef CONFIG_DEBUG_MSM9625_UART
#define MSM_DEBUG_UART_BASE IOMEM(0xFA71E000)
#define MSM_DEBUG_UART_PHYS 0xF991E000
#endif
+/*
+ * IMEM is retained for secure watchdog reset
+ * Debug Image looks at actual IMEM to
+ * do memory dumping.
+ */
+
+#define MSM9625_DBG_IMEM_PHYS 0xFE807800
+#define MSM9625_DBG_IMEM_SIZE SZ_4K
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index f6e082d..075d20f 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -32,7 +32,8 @@
RPM_VREG_VERSION_9615,
RPM_VREG_VERSION_8930,
RPM_VREG_VERSION_8930_PM8917,
- RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8930_PM8917,
+ RPM_VREG_VERSION_8960_PM8917,
+ RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8960_PM8917,
};
#define RPM_VREG_PIN_CTRL_NONE 0x00
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 5ee7068..39ac253 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -462,6 +462,7 @@
MSM_CHIP_DEVICE(APCS_GCC, MSM9625),
MSM_CHIP_DEVICE(TLMM, MSM9625),
MSM_CHIP_DEVICE(TMR, MSM9625),
+ MSM_CHIP_DEVICE(IMEM, MSM9625),
{
.virtual = (unsigned long) MSM_SHARED_RAM_BASE,
.length = MSM_SHARED_RAM_SIZE,
@@ -470,6 +471,7 @@
#ifdef CONFIG_DEBUG_MSM9625_UART
MSM_DEVICE(DEBUG_UART),
#endif
+ MSM_CHIP_DEVICE(DBG_IMEM, MSM9625),
};
void __init msm_map_msm9625_io(void)
diff --git a/arch/arm/mach-msm/lpass-8660.c b/arch/arm/mach-msm/lpass-8660.c
deleted file mode 100644
index be18b68..0000000
--- a/arch/arm/mach-msm/lpass-8660.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/* 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/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <linux/stringify.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/err.h>
-
-#include <mach/irqs.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-
-#include "smd_private.h"
-#include "modem_notifier.h"
-#include "ramdump.h"
-
-#define Q6SS_WDOG_ENABLE 0x28882024
-#define Q6SS_SOFT_INTR_WAKEUP 0x288A001C
-#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 *);
-static DECLARE_WORK(q6_fatal_work, q6_fatal_fn);
-static void __iomem *q6_wakeup_intr;
-
-static void q6_fatal_fn(struct work_struct *work)
-{
- pr_err("%s: Watchdog bite received from Q6!\n", MODULE_NAME);
- subsystem_restart_dev(subsys_8x60_q6_dev);
- enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
-}
-
-static void send_q6_nmi(void)
-{
- /* Send NMI to QDSP6 via an SCM call. */
- scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1);
-
- /* Wakeup the Q6 */
- if (q6_wakeup_intr)
- writel_relaxed(0x2000, q6_wakeup_intr);
- else
- pr_warn("lpass-8660: Unable to send wakeup interrupt to Q6.\n");
-
- /* Q6 requires atleast 100ms to dump caches etc.*/
- mdelay(100);
-
- pr_info("subsystem-fatal-8x60: Q6 NMI was sent.\n");
-}
-
-int subsys_q6_shutdown(const struct subsys_desc *crashed_subsys)
-{
- void __iomem *q6_wdog_addr =
- ioremap_nocache(Q6SS_WDOG_ENABLE, 8);
-
- send_q6_nmi();
- writel_relaxed(0x0, q6_wdog_addr);
- /* The write needs to go through before the q6 is shutdown. */
- mb();
- iounmap(q6_wdog_addr);
-
- pil_force_shutdown("q6");
- disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
-
- return 0;
-}
-
-int subsys_q6_powerup(const struct subsys_desc *crashed_subsys)
-{
- int ret = pil_force_boot("q6");
- enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
- return ret;
-}
-
-/* FIXME: Get address, size from PIL */
-static struct ramdump_segment q6_segments[] = { {0x46700000, 0x47F00000 -
- 0x46700000}, {0x28400000, 0x12800} };
-static int subsys_q6_ramdump(int enable,
- const struct subsys_desc *crashed_subsys)
-{
- if (enable)
- return do_ramdump(q6_ramdump_dev, q6_segments,
- ARRAY_SIZE(q6_segments));
- else
- return 0;
-}
-
-void subsys_q6_crash_shutdown(const struct subsys_desc *crashed_subsys)
-{
- send_q6_nmi();
-}
-
-static irqreturn_t lpass_wdog_bite_irq(int irq, void *dev_id)
-{
- int ret;
-
- ret = schedule_work(&q6_fatal_work);
- disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
-
- return IRQ_HANDLED;
-}
-
-static struct subsys_desc subsys_8x60_q6 = {
- .name = "lpass",
- .shutdown = subsys_q6_shutdown,
- .powerup = subsys_q6_powerup,
- .ramdump = subsys_q6_ramdump,
- .crash_shutdown = subsys_q6_crash_shutdown
-};
-
-static void __exit lpass_fatal_exit(void)
-{
- subsys_unregister(subsys_8x60_q6_dev);
- iounmap(q6_wakeup_intr);
- free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
-}
-
-static int __init lpass_fatal_init(void)
-{
- int ret;
-
- ret = request_irq(LPASS_Q6SS_WDOG_EXPIRED, lpass_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "q6_wdog", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to request LPASS_Q6SS_WDOG_EXPIRED irq.",
- __func__);
- goto out;
- }
-
- q6_ramdump_dev = create_ramdump_device("lpass");
-
- if (!q6_ramdump_dev) {
- ret = -ENOMEM;
- goto out;
- }
-
- q6_wakeup_intr = ioremap_nocache(Q6SS_SOFT_INTR_WAKEUP, 8);
-
- if (!q6_wakeup_intr)
- pr_warn("lpass-8660: Unable to ioremap q6 wakeup address.");
-
- 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;
-}
-
-module_init(lpass_fatal_init);
-module_exit(lpass_fatal_exit);
-
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 0c158de..890e450 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -582,7 +582,7 @@
if (core->idle_driver) {
core->actual_freq = core->freq_driver->get_frequency(drv);
/* Notify TZ to start receiving idle info for the core */
- ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_ENABLE_CORE, 1,
+ ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_DCVS_ENABLE, 1,
&ret1, &ret2);
core->idle_driver->enable(core->idle_driver,
MSM_DCVS_ENABLE_IDLE_PULSE);
@@ -615,7 +615,7 @@
core->idle_driver->enable(core->idle_driver,
MSM_DCVS_DISABLE_IDLE_PULSE);
/* Notify TZ to stop receiving idle info for the core */
- ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_ENABLE_CORE, 0,
+ ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_DCVS_ENABLE, 0,
&ret1, &ret2);
hrtimer_cancel(&core->timer);
core->idle_driver->enable(core->idle_driver,
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 73248db..bccbce2 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -21,15 +21,22 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/smp.h>
+#include <linux/miscdevice.h>
+#include <linux/reboot.h>
+#include <linux/interrupt.h>
#include <mach/msm_iomap.h>
#include <mach/msm_xo.h>
#include <mach/socinfo.h>
#include <mach/msm_bus_board.h>
#include <mach/msm_bus.h>
+#include <mach/subsystem_restart.h>
+#include <mach/peripheral-loader.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
+#include "smd_private.h"
+#include "ramdump.h"
#define GSS_CSR_AHB_CLK_SEL 0x0
#define GSS_CSR_RESET 0x4
@@ -63,6 +70,14 @@
unsigned long start_addr;
struct clk *xo;
struct pil_device *pil;
+ struct miscdevice misc_dev;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+ int crash_shutdown;
+ int irq;
+ void *pil_handle;
+ struct ramdump_device *ramdump_dev;
+ struct ramdump_device *smem_ramdump_dev;
};
static int pil_gss_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -308,11 +323,160 @@
.proxy_unvote = remove_gss_proxy_votes,
};
+#define MAX_SSR_REASON_LEN 81U
+
+static void log_gss_sfr(void)
+{
+ u32 size;
+ char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+ smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+ if (!smem_reason || !size) {
+ pr_err("GSS subsystem failure reason: (unknown, smem_get_entry failed).\n");
+ return;
+ }
+ if (!smem_reason[0]) {
+ pr_err("GSS subsystem failure reason: (unknown, init string found).\n");
+ return;
+ }
+
+ size = min(size, MAX_SSR_REASON_LEN-1);
+ memcpy(reason, smem_reason, size);
+ reason[size] = '\0';
+ pr_err("GSS subsystem failure reason: %s.\n", reason);
+
+ smem_reason[0] = '\0';
+ wmb();
+}
+
+static void restart_gss(struct gss_data *drv)
+{
+ log_gss_sfr();
+ subsystem_restart_dev(drv->subsys);
+}
+
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+{
+ struct gss_data *drv = data;
+
+ /* Ignore if we're the one that set SMSM_RESET */
+ if (drv->crash_shutdown)
+ return;
+
+ if (new_state & SMSM_RESET) {
+ pr_err("GSS SMSM state changed to SMSM_RESET.\n"
+ "Probable err_fatal on the GSS. "
+ "Calling subsystem restart...\n");
+ restart_gss(drv);
+ }
+}
+
+static int gss_shutdown(const struct subsys_desc *desc)
+{
+ struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
+
+ pil_force_shutdown("gss");
+ disable_irq_nosync(drv->irq);
+
+ return 0;
+}
+
+static int gss_powerup(const struct subsys_desc *desc)
+{
+ struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
+
+ pil_force_boot("gss");
+ enable_irq(drv->irq);
+ return 0;
+}
+
+void gss_crash_shutdown(const struct subsys_desc *desc)
+{
+ struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
+
+ drv->crash_shutdown = 1;
+ smsm_reset_modem(SMSM_RESET);
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment gss_segments[] = {
+ {0x89000000, 0x00D00000}
+};
+
+static struct ramdump_segment smem_segments[] = {
+ {0x80000000, 0x00200000},
+};
+
+static int gss_ramdump(int enable, const struct subsys_desc *desc)
+{
+ int ret;
+ struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
+
+ if (enable) {
+ ret = do_ramdump(drv->ramdump_dev, gss_segments,
+ ARRAY_SIZE(gss_segments));
+ if (ret < 0) {
+ pr_err("Unable to dump gss memory\n");
+ return ret;
+ }
+
+ ret = do_ramdump(drv->smem_ramdump_dev, smem_segments,
+ ARRAY_SIZE(smem_segments));
+ if (ret < 0) {
+ pr_err("Unable to dump smem memory (rc = %d).\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static irqreturn_t gss_wdog_bite_irq(int irq, void *dev_id)
+{
+ struct gss_data *drv = dev_id;
+
+ pr_err("Watchdog bite received from GSS!\n");
+ restart_gss(drv);
+
+ return IRQ_HANDLED;
+}
+
+static int gss_open(struct inode *inode, struct file *filp)
+{
+ void *ret;
+ struct miscdevice *c = filp->private_data;
+ struct gss_data *drv = container_of(c, struct gss_data, misc_dev);
+
+ drv->pil_handle = ret = pil_get("gss");
+ if (!ret)
+ pr_debug("%s - pil_get returned NULL\n", __func__);
+
+ return 0;
+}
+
+static int gss_release(struct inode *inode, struct file *filp)
+{
+ struct miscdevice *c = filp->private_data;
+ struct gss_data *drv = container_of(c, struct gss_data, misc_dev);
+
+ pil_put(drv->pil_handle);
+ pr_debug("%s pil_put called on GSS\n", __func__);
+
+ return 0;
+}
+
+const struct file_operations gss_file_ops = {
+ .open = gss_open,
+ .release = gss_release,
+ .owner = THIS_MODULE,
+};
+
static int __devinit pil_gss_probe(struct platform_device *pdev)
{
struct gss_data *drv;
struct resource *res;
struct pil_desc *desc;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -344,6 +508,10 @@
if (IS_ERR(drv->xo))
return PTR_ERR(drv->xo);
+ drv->irq = platform_get_irq(pdev, 0);
+ if (drv->irq < 0)
+ return drv->irq;
+
desc->name = "gss";
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
@@ -363,13 +531,71 @@
if (IS_ERR(drv->pil)) {
return PTR_ERR(drv->pil);
}
+
+ ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+ smsm_state_cb, drv);
+ if (ret < 0)
+ dev_warn(&pdev->dev, "Unable to register SMSM callback\n");
+
+ drv->subsys_desc.name = "gss";
+ drv->subsys_desc.shutdown = gss_shutdown;
+ drv->subsys_desc.powerup = gss_powerup;
+ drv->subsys_desc.ramdump = gss_ramdump;
+ drv->subsys_desc.crash_shutdown = gss_crash_shutdown;
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ ret = PTR_ERR(drv->subsys);
+ goto err_subsys;
+ }
+
+ drv->misc_dev.minor = MISC_DYNAMIC_MINOR;
+ drv->misc_dev.name = "gss";
+ drv->misc_dev.fops = &gss_file_ops;
+ ret = misc_register(&drv->misc_dev);
+ if (ret)
+ goto err_misc;
+
+ drv->ramdump_dev = create_ramdump_device("gss");
+ if (!drv->ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_ramdump;
+ }
+
+ drv->smem_ramdump_dev = create_ramdump_device("smem-gss");
+ if (!drv->smem_ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_smem;
+ }
+
+ ret = devm_request_irq(&pdev->dev, drv->irq, gss_wdog_bite_irq,
+ IRQF_TRIGGER_RISING, "gss_a5_wdog", drv);
+ if (ret < 0)
+ goto err;
return 0;
+err:
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+err_smem:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ misc_deregister(&drv->misc_dev);
+err_misc:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ msm_pil_unregister(drv->pil);
+ return ret;
}
static int __devexit pil_gss_remove(struct platform_device *pdev)
{
struct gss_data *drv = platform_get_drvdata(pdev);
+
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+ destroy_ramdump_device(drv->ramdump_dev);
+ misc_deregister(&drv->misc_dev);
+ subsys_unregister(drv->subsys);
msm_pil_unregister(drv->pil);
+
return 0;
}
diff --git a/arch/arm/mach-msm/pil-q6v3.c b/arch/arm/mach-msm/pil-q6v3.c
index 28b9dee..1a226de 100644
--- a/arch/arm/mach-msm/pil-q6v3.c
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -19,9 +19,15 @@
#include <linux/elf.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
#include <mach/msm_iomap.h>
+#include <mach/subsystem_restart.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include "ramdump.h"
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -60,11 +66,34 @@
#define Q6_STRAP_TCM_BASE (0x28C << 15)
#define Q6_STRAP_TCM_CONFIG 0x28B
+#define SCM_Q6_NMI_CMD 0x1
+
+/**
+ * struct q6v3_data - LPASS driver data
+ * @base: register base
+ * @wk_base: wakeup register base
+ * @wd_base: watchdog register base
+ * @start_addr: address that processor starts running at
+ * @irq: watchdog irq
+ * @pil: peripheral handle
+ * @subsys: subsystem restart handle
+ * @subsys_desc: subsystem restart descriptor
+ * @fatal_wrk: fatal error workqueue
+ * @pll: pll clock handle
+ * @ramdump_dev: ramdump device
+ */
struct q6v3_data {
void __iomem *base;
+ void __iomem *wk_base;
+ void __iomem *wd_base;
unsigned long start_addr;
+ int irq;
struct pil_device *pil;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+ struct work_struct fatal_wrk;
struct clk *pll;
+ struct ramdump_device *ramdump_dev;
};
static int pil_q6v3_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -198,11 +227,96 @@
.proxy_unvote = pil_q6v3_remove_proxy_votes,
};
+static void q6_fatal_fn(struct work_struct *work)
+{
+ struct q6v3_data *drv = container_of(work, struct q6v3_data, fatal_wrk);
+
+ pr_err("Watchdog bite received from Q6!\n");
+ subsystem_restart_dev(drv->subsys);
+ enable_irq(drv->irq);
+}
+
+static void send_q6_nmi(struct q6v3_data *drv)
+{
+ /* Send NMI to QDSP6 via an SCM call. */
+ scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1);
+
+ /* Wakeup the Q6 */
+ writel_relaxed(0x2000, drv->wk_base + 0x1c);
+ /* Q6 requires atleast 100ms to dump caches etc.*/
+ mdelay(100);
+ pr_info("Q6 NMI was sent.\n");
+}
+
+static int lpass_q6_shutdown(const struct subsys_desc *subsys)
+{
+ struct q6v3_data *drv;
+
+ drv = container_of(subsys, struct q6v3_data, subsys_desc);
+ send_q6_nmi(drv);
+ writel_relaxed(0x0, drv->wd_base + 0x24);
+ mb();
+
+ pil_force_shutdown("q6");
+ disable_irq_nosync(drv->irq);
+
+ return 0;
+}
+
+static int lpass_q6_powerup(const struct subsys_desc *subsys)
+{
+ struct q6v3_data *drv;
+ int ret;
+
+ drv = container_of(subsys, struct q6v3_data, subsys_desc);
+ ret = pil_force_boot("q6");
+ enable_irq(drv->irq);
+ return ret;
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment q6_segments[] = {
+ { 0x46700000, 0x47f00000 - 0x46700000 },
+ { 0x28400000, 0x12800 }
+};
+
+static int lpass_q6_ramdump(int enable, const struct subsys_desc *subsys)
+{
+ struct q6v3_data *drv;
+
+ drv = container_of(subsys, struct q6v3_data, subsys_desc);
+ if (enable)
+ return do_ramdump(drv->ramdump_dev, q6_segments,
+ ARRAY_SIZE(q6_segments));
+ else
+ return 0;
+}
+
+static void lpass_q6_crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct q6v3_data *drv;
+
+ drv = container_of(subsys, struct q6v3_data, subsys_desc);
+ send_q6_nmi(drv);
+}
+
+static irqreturn_t lpass_wdog_bite_irq(int irq, void *dev_id)
+{
+ int ret;
+ struct q6v3_data *drv = dev_id;
+
+ ret = schedule_work(&drv->fatal_wrk);
+ disable_irq_nosync(drv->irq);
+
+ return IRQ_HANDLED;
+}
+
static int __devinit pil_q6v3_driver_probe(struct platform_device *pdev)
{
struct q6v3_data *drv;
struct resource *res;
struct pil_desc *desc;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -217,14 +331,34 @@
if (!drv->base)
return -ENOMEM;
- desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
- if (!drv)
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ return -EINVAL;
+
+ drv->wk_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!drv->wk_base)
return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (!res)
+ return -EINVAL;
+
+ drv->wd_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!drv->wd_base)
+ return -ENOMEM;
+
+ drv->irq = platform_get_irq(pdev, 0);
+ if (drv->irq < 0)
+ return drv->irq;
+
drv->pll = devm_clk_get(&pdev->dev, "pll4");
if (IS_ERR(drv->pll))
return PTR_ERR(drv->pll);
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+
desc->name = "q6";
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
@@ -239,15 +373,51 @@
}
drv->pil = msm_pil_register(desc);
- if (IS_ERR(drv->pil)) {
+ if (IS_ERR(drv->pil))
return PTR_ERR(drv->pil);
+
+ drv->subsys_desc.name = "lpass";
+ drv->subsys_desc.shutdown = lpass_q6_shutdown;
+ drv->subsys_desc.powerup = lpass_q6_powerup;
+ drv->subsys_desc.ramdump = lpass_q6_ramdump;
+ drv->subsys_desc.crash_shutdown = lpass_q6_crash_shutdown;
+
+ INIT_WORK(&drv->fatal_wrk, q6_fatal_fn);
+
+ drv->ramdump_dev = create_ramdump_device("lpass");
+ if (!drv->ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_ramdump;
}
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ ret = PTR_ERR(drv->subsys);
+ goto err_subsys;
+ }
+
+ ret = devm_request_irq(&pdev->dev, drv->irq, lpass_wdog_bite_irq,
+ IRQF_TRIGGER_RISING, "lpass_wdog", drv);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to request wdog irq.\n");
+ goto err_irq;
+ }
+
return 0;
+err_irq:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ msm_pil_unregister(drv->pil);
+ return ret;
}
static int __devexit pil_q6v3_driver_exit(struct platform_device *pdev)
{
struct q6v3_data *drv = platform_get_drvdata(pdev);
+ subsys_unregister(drv->subsys);
+ destroy_ramdump_device(drv->ramdump_dev);
msm_pil_unregister(drv->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/rpm-regulator-8960.c b/arch/arm/mach-msm/rpm-regulator-8960.c
index 8fe3571..c5c01c2 100644
--- a/arch/arm/mach-msm/rpm-regulator-8960.c
+++ b/arch/arm/mach-msm/rpm-regulator-8960.c
@@ -325,3 +325,32 @@
{
return &config;
}
+
+struct vreg_config *get_config_8960_pm8917(void)
+{
+ int i;
+
+ /*
+ * PM8917 regulators L24, L25, L26, L27, and L28 require CXO to be ON
+ * while they are enabled. These same regulators on PM8921 do not
+ * require CXO to be ON. Therefore, set the require_cxo flag for these
+ * regulators only when using PM8917.
+ *
+ * Do not apply the workaround to L24 (VDD_MX) because it is always on
+ * and using the TCXO workaround with it would result in additional
+ * latency during every Krait upscaling event.
+ */
+ for (i = 0; i < ARRAY_SIZE(vregs); i++) {
+ switch (vregs[i].id) {
+ case RPM_VREG_ID_PM8921_L25:
+ case RPM_VREG_ID_PM8921_L26:
+ case RPM_VREG_ID_PM8921_L27:
+ case RPM_VREG_ID_PM8921_L28:
+ vregs[i].requires_cxo = true;
+ default:
+ break;
+ }
+ }
+
+ return &config;
+}
diff --git a/arch/arm/mach-msm/rpm-regulator-private.h b/arch/arm/mach-msm/rpm-regulator-private.h
index d55bd73..703335f 100644
--- a/arch/arm/mach-msm/rpm-regulator-private.h
+++ b/arch/arm/mach-msm/rpm-regulator-private.h
@@ -158,11 +158,16 @@
#if defined(CONFIG_MSM_RPM_REGULATOR) && \
(defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064))
struct vreg_config *get_config_8960(void);
+struct vreg_config *get_config_8960_pm8917(void);
#else
static inline struct vreg_config *get_config_8960(void)
{
return NULL;
}
+static inline struct vreg_config *get_config_8960_pm8917(void)
+{
+ return NULL;
+}
#endif
#if defined(CONFIG_MSM_RPM_REGULATOR) && defined(CONFIG_ARCH_MSM9615)
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index 424a4fe..01543a2 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -63,6 +63,7 @@
[RPM_VREG_VERSION_9615] = get_config_9615,
[RPM_VREG_VERSION_8930] = get_config_8930,
[RPM_VREG_VERSION_8930_PM8917] = get_config_8930_pm8917,
+ [RPM_VREG_VERSION_8960_PM8917] = get_config_8960_pm8917,
};
static struct rpm_regulator_consumer_mapping *consumer_map;
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 5516e30..cd73acd 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -162,9 +162,12 @@
return ret;
}
-/* 5MB RAM segments for Riva SS */
-static struct ramdump_segment riva_segments[] = {{0x8f200000,
- 0x8f700000 - 0x8f200000} };
+/* 7MB RAM segments for Riva SS;
+ * Riva 1.1 0x8f000000 - 0x8f700000
+ * Riva 1.0 0x8f200000 - 0x8f700000
+ */
+static struct ramdump_segment riva_segments[] = {{0x8f000000,
+ 0x8f700000 - 0x8f000000} };
static int riva_ramdump(int enable, const struct subsys_desc *subsys)
{
diff --git a/drivers/bluetooth/hci_ibs.c b/drivers/bluetooth/hci_ibs.c
index 6253605..acff5a5 100644
--- a/drivers/bluetooth/hci_ibs.c
+++ b/drivers/bluetooth/hci_ibs.c
@@ -254,13 +254,14 @@
struct ibs_struct *ibs = container_of(work, struct ibs_struct,
ws_awake_device);
struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+ unsigned long flags;
BT_DBG(" %p ", hu);
/* Vote for serial clock */
ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
- spin_lock(&ibs->hci_ibs_lock);
+ spin_lock_irqsave(&ibs->hci_ibs_lock, flags);
/* send wake indication to device */
if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0)
@@ -271,7 +272,8 @@
/* start retransmit timer */
mod_timer(&ibs->wake_retrans_timer, jiffies + wake_retrans);
- spin_unlock(&ibs->hci_ibs_lock);
+ spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+
}
static void ibs_wq_awake_rx(struct work_struct *work)
@@ -279,12 +281,14 @@
struct ibs_struct *ibs = container_of(work, struct ibs_struct,
ws_awake_rx);
struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+ unsigned long flags;
BT_DBG(" %p ", hu);
ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
- spin_lock(&ibs->hci_ibs_lock);
+ spin_lock_irqsave(&ibs->hci_ibs_lock, flags);
+
ibs->rx_ibs_state = HCI_IBS_RX_AWAKE;
/* Always acknowledge device wake up,
* sending IBS message doesn't count as TX ON
@@ -294,7 +298,8 @@
ibs->ibs_sent_wacks++; /* debug */
- spin_unlock(&ibs->hci_ibs_lock);
+ spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+
/* actually send the packets */
hci_uart_tx_wakeup(hu);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index e0d40be..129ca7e 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2163,6 +2163,9 @@
if (!adreno_dev->fast_hang_detect)
return 0;
+ if (device->ftbl->isidle(device))
+ return 0;
+
for (i = 0; i < hang_detect_regs_count; i++) {
if (hang_detect_regs[i] == 0)
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index aa39aad..a017cf2 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -304,7 +304,7 @@
}
if (irq & 0x01000000) {
v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
- VCAP_VC_LINE_ERR_EVENT;
+ VCAP_VP_REG_W_ERR_EVENT;
v4l2_event_queue(dev->vfd, &v4l2_evt);
}
if (irq & 0x00020000) {
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index ed84f4a..595bc5d 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -2410,7 +2410,8 @@
curr_slot = host->plat->vreg_data;
if (!curr_slot) {
- rc = -EINVAL;
+ pr_debug("%s: vreg info unavailable, assuming the slot is powered by always on domain\n",
+ mmc_hostname(host->mmc));
goto out;
}
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index b107040..e6e2f30 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -148,8 +148,9 @@
int ibat_at_cv_ua;
int soc_at_cv;
int prev_chg_soc;
-
struct power_supply *batt_psy;
+ bool low_voltage_wake_lock_held;
+ struct wake_lock low_voltage_wake_lock;
};
/*
@@ -1319,6 +1320,28 @@
return chip->prev_chg_soc;
}
+static void very_low_voltage_check(struct pm8921_bms_chip *chip,
+ int ibat_ua, int vbat_uv)
+{
+ /*
+ * if battery is very low (v_cutoff voltage + 20mv) hold
+ * a wakelock untill soc = 0%
+ */
+ if (vbat_uv <= (chip->v_cutoff + 20) * 1000
+ && !chip->low_voltage_wake_lock_held) {
+ pr_debug("voltage = %d low holding wakelock\n", vbat_uv);
+ wake_lock(&chip->low_voltage_wake_lock);
+ chip->low_voltage_wake_lock_held = 1;
+ }
+
+ if (vbat_uv > (chip->v_cutoff + 20) * 1000
+ && chip->low_voltage_wake_lock_held) {
+ pr_debug("voltage = %d releasing wakelock\n", vbat_uv);
+ chip->low_voltage_wake_lock_held = 0;
+ wake_unlock(&chip->low_voltage_wake_lock);
+ }
+}
+
static int last_soc_est = -EINVAL;
static int adjust_soc(struct pm8921_bms_chip *chip, int soc,
int batt_temp, int chargecycles,
@@ -1343,6 +1366,7 @@
goto out;
}
+ very_low_voltage_check(chip, ibat_ua, vbat_uv);
delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
@@ -2897,6 +2921,9 @@
goto free_chip;
}
+ wake_lock_init(&chip->low_voltage_wake_lock,
+ WAKE_LOCK_SUSPEND, "pm8921_bms_low");
+
rc = pm8921_bms_hw_init(chip);
if (rc) {
pr_err("couldn't init hardware rc = %d\n", rc);
@@ -2954,12 +2981,33 @@
return 0;
}
+static int pm8921_bms_resume(struct device *dev)
+{
+ int rc, ibat_ua, vbat_uv;
+
+ rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
+ &ibat_ua,
+ &vbat_uv);
+ if (rc < 0) {
+ pr_err("simultaneous vbat ibat failed err = %d\n", rc);
+ return 0;
+ }
+
+ very_low_voltage_check(the_chip, ibat_ua, vbat_uv);
+ return 0;
+}
+
+static const struct dev_pm_ops pm8921_bms_pm_ops = {
+ .resume = pm8921_bms_resume,
+};
+
static struct platform_driver pm8921_bms_driver = {
.probe = pm8921_bms_probe,
.remove = __devexit_p(pm8921_bms_remove),
.driver = {
.name = PM8921_BMS_DEV_NAME,
.owner = THIS_MODULE,
+ .pm = &pm8921_bms_pm_ops,
},
};
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index e983081..19454ca 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -27,6 +27,7 @@
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
+#include <linux/mfd/pm8xxx/batt-alarm.h>
#include <mach/msm_xo.h>
#include <mach/msm_hsusb.h>
@@ -115,6 +116,13 @@
int batt_state;
};
+static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
+ unsigned long status, void *unused);
+
+static struct notifier_block alarm_notifier = {
+ .notifier_call = pm8921_battery_gauge_alarm_notify,
+};
+
static struct fsm_state_to_batt_status map[] = {
{FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
{FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
@@ -205,6 +213,8 @@
* @max_voltage_mv: the max volts the batt should be charged up to
* @min_voltage_mv: the min battery voltage before turning the FETon
* @uvd_voltage_mv: (PM8917 only) the falling UVD threshold voltage
+ * @alarm_low_mv: the battery alarm voltage low
+ * @alarm_high_mv: the battery alarm voltage high
* @cool_temp_dc: the cool temp threshold in deciCelcius
* @warm_temp_dc: the warm temp threshold in deciCelcius
* @resume_voltage_delta: the voltage delta from vdd max at which the
@@ -225,6 +235,8 @@
unsigned int max_voltage_mv;
unsigned int min_voltage_mv;
unsigned int uvd_voltage_mv;
+ unsigned int alarm_low_mv;
+ unsigned int alarm_high_mv;
int cool_temp_dc;
int warm_temp_dc;
unsigned int temp_check_period;
@@ -250,6 +262,7 @@
bool ext_charge_done;
bool iusb_fine_res;
bool dc_unplug_check;
+ bool disable_hw_clock_switching;
DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
struct work_struct battery_id_valid_work;
int64_t batt_id_min;
@@ -2003,6 +2016,73 @@
return get_prop_batt_temp(the_chip);
}
+static int pm8921_charger_enable_batt_alarm(struct pm8921_chg_chip *chip)
+{
+ int rc = 0;
+
+ rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_enable(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
+ if (rc) {
+ pr_err("unable to set batt alarm state rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+static int pm8921_charger_configure_batt_alarm(struct pm8921_chg_chip *chip)
+{
+ int rc = 0;
+
+ rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_disable(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
+ if (rc) {
+ pr_err("unable to set batt alarm state rc=%d\n", rc);
+ return rc;
+ }
+
+ /*
+ * The batt-alarm driver requires sane values for both min / max,
+ * regardless of whether they're both activated.
+ */
+ rc = pm8xxx_batt_alarm_threshold_set(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR,
+ chip->alarm_low_mv);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_threshold_set(
+ PM8XXX_BATT_ALARM_UPPER_COMPARATOR,
+ chip->alarm_high_mv);
+ if (rc) {
+ pr_err("unable to set batt alarm threshold rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_batt_alarm_hold_time_set(
+ PM8XXX_BATT_ALARM_HOLD_TIME_16_MS);
+ if (rc) {
+ pr_err("unable to set batt alarm hold time rc=%d\n", rc);
+ return rc;
+ }
+
+ /* PWM enabled at 2Hz */
+ rc = pm8xxx_batt_alarm_pwm_rate_set(1, 7, 4);
+ if (rc) {
+ pr_err("unable to set batt alarm pwm rate rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_batt_alarm_register_notifier(&alarm_notifier);
+ if (rc) {
+ pr_err("unable to register alarm notifier rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
{
int usb_present;
@@ -2138,6 +2218,61 @@
}
}
+static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
+ unsigned long status, void *unused)
+{
+ int rc;
+
+ pr_info("status: %lu\n", status);
+
+ /* Check if called before init */
+
+ switch (status) {
+ case 0:
+ pr_err("spurious interrupt\n");
+ break;
+ /* expected case - trip of low threshold */
+ case 1:
+ if (!the_chip) {
+ pr_err("not initialized\n");
+ return -EINVAL;
+ }
+
+ the_chip->disable_hw_clock_switching = 1;
+
+ rc = pm8xxx_batt_alarm_disable(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_enable(
+ PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+ if (rc)
+ pr_err("unable to set alarm state rc=%d\n", rc);
+ break;
+ case 2:
+ if (!the_chip) {
+ pr_err("not initialized\n");
+ return -EINVAL;
+ }
+
+ the_chip->disable_hw_clock_switching = 0;
+
+ rc = pm8xxx_batt_alarm_disable(
+ PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_enable(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
+ if (rc)
+ pr_err("unable to set alarm state rc=%d\n", rc);
+
+ pr_err("trip of high threshold\n");
+ break;
+ default:
+ pr_err("error received\n");
+ };
+
+ return 0;
+}
+
static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
{
u8 temp;
@@ -3038,6 +3173,18 @@
return;
}
+ /* If the disable hw clock switching
+ * flag was set it can now be unset. Also, re-enable
+ * the battery alarm to set the flag again when needed
+ */
+ if (chip->disable_hw_clock_switching) {
+ /* Unset the hw clock switching flag */
+ chip->disable_hw_clock_switching = 0;
+
+ if (pm8921_charger_enable_batt_alarm(chip))
+ pr_err("couldn't set up batt alarm!\n");
+ }
+
if (end == CHG_FINISHED) {
count++;
} else {
@@ -3297,6 +3444,7 @@
{
unsigned long flags;
int fsm_state;
+ int is_fast_chg;
chip->dc_present = !!is_dc_chg_plugged_in(chip);
chip->usb_present = !!is_usb_chg_plugged_in(chip);
@@ -3324,9 +3472,17 @@
if (usb_chg_current) {
/* reissue a vbus draw call */
__pm8921_charger_vbus_draw(usb_chg_current);
- fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
}
spin_unlock_irqrestore(&vbus_lock, flags);
+ /*
+ * The bootloader could have started charging, a fastchg interrupt
+ * might not happen. Check the real time status and if it is fast
+ * charging invoke the handler so that the eoc worker could be
+ * started
+ */
+ is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
+ if (is_fast_chg)
+ fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
fsm_state = pm_chg_get_fsm_state(chip);
if (is_battery_charging(fsm_state)) {
@@ -3944,7 +4100,8 @@
rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
if (rc)
pr_err("Failed to Force Vref therm off rc=%d\n", rc);
- pm8921_chg_set_hw_clk_switching(chip);
+ if (!(chip->disable_hw_clock_switching))
+ pm8921_chg_set_hw_clk_switching(chip);
return 0;
}
@@ -4027,6 +4184,8 @@
chip->ttrkl_time = pdata->ttrkl_time;
chip->update_time = pdata->update_time;
chip->max_voltage_mv = pdata->max_voltage;
+ chip->alarm_low_mv = pdata->alarm_low_mv;
+ chip->alarm_high_mv = pdata->alarm_high_mv;
chip->min_voltage_mv = pdata->min_voltage;
chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
chip->resume_voltage_delta = pdata->resume_voltage_delta;
@@ -4147,6 +4306,17 @@
}
}
+ rc = pm8921_charger_configure_batt_alarm(chip);
+ if (rc) {
+ pr_err("Couldn't configure battery alarm! rc=%d\n", rc);
+ goto free_irq;
+ }
+
+ rc = pm8921_charger_enable_batt_alarm(chip);
+ if (rc) {
+ pr_err("Couldn't enable battery alarm! rc=%d\n", rc);
+ goto free_irq;
+ }
create_debugfs_entries(chip);
INIT_WORK(&chip->bms_notify.work, bms_notify);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index efb4da6..9f29887 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -42,6 +42,9 @@
#include <linux/vmalloc.h>
#include <mach/board.h>
+#include <mach/memory.h>
+#include <mach/msm_memtypes.h>
+#include <mach/iommu_domains.h>
#include "mdss_fb.h"
#include "mdss_mdp.h"
@@ -596,37 +599,17 @@
size *= mfd->fb_page;
if (mfd->index == 0) {
- struct ion_client *iclient = mdss_get_ionclient();
-
- if (iclient) {
- mfd->ihdl = ion_alloc(iclient, size, SZ_4K,
- ION_HEAP(ION_CP_MM_HEAP_ID) |
- ION_HEAP(ION_SF_HEAP_ID), 0);
- if (IS_ERR_OR_NULL(mfd->ihdl)) {
- pr_err("unable to alloc fbmem from ion (%p)\n",
- mfd->ihdl);
- return -ENOMEM;
- }
-
- virt = ion_map_kernel(iclient, mfd->ihdl);
- ion_phys(iclient, mfd->ihdl, &phys, &size);
-
- if (is_mdss_iommu_attached()) {
- ion_map_iommu(iclient, mfd->ihdl,
- mdss_get_iommu_domain(),
- 0, SZ_4K, 0, &mfd->iova,
- (unsigned long *) &size,
- 0, 0);
- }
- } else {
- virt = dma_alloc_coherent(NULL, size,
- (dma_addr_t *) &phys, GFP_KERNEL);
- if (!virt) {
- pr_err("unable to alloc fbmem size=%u\n", size);
- return -ENOMEM;
- }
+ virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
+ if (!virt) {
+ pr_err("unable to alloc fbmem size=%u\n", size);
+ return -ENOMEM;
}
-
+ phys = memory_pool_node_paddr(virt);
+ if (is_mdss_iommu_attached()) {
+ msm_iommu_map_contig_buffer(phys,
+ mdss_get_iommu_domain(), 0, size, SZ_4K, 0,
+ &(mfd->iova));
+ }
pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
size, virt, phys, mfd->index);
} else {
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 4f641cc..0f6cfe9 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -1081,8 +1081,10 @@
static const struct of_device_id mdss_mdp_dt_match[] = {
{ .compatible = "qcom,mdss_mdp",},
+ {}
};
MODULE_DEVICE_TABLE(of, mdss_mdp_dt_match);
+EXPORT_COMPAT("qcom,mdss_mdp");
static struct platform_driver mdss_mdp_driver = {
.probe = mdss_mdp_probe,
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 7b389c5..0e86f2a 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -63,6 +63,8 @@
* @ttrkl_time: max trckl charging time in minutes
* valid range 1 to 64 mins. PON default 15 min
* @update_time: how often the userland be updated of the charging (msec)
+ * @alarm_low_mv: the voltage (mV) when low battery alarm is triggered
+ * @alarm_high_mv: the voltage (mV) when high battery alarm is triggered
* @max_voltage: the max voltage (mV) the battery should be charged up to
* @min_voltage: the voltage (mV) where charging method switches from
* trickle to fast. This is also the minimum voltage the
@@ -128,6 +130,8 @@
unsigned int max_voltage;
unsigned int min_voltage;
unsigned int uvd_thresh_voltage;
+ unsigned int alarm_low_mv;
+ unsigned int alarm_high_mv;
unsigned int resume_voltage_delta;
unsigned int term_current;
int cool_temp;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 2c9509d..1f13da3 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -142,6 +142,8 @@
extern unsigned long nr_iowait_cpu(int cpu);
extern unsigned long this_cpu_load(void);
+extern void sched_update_nr_prod(int cpu, unsigned long nr, bool inc);
+extern void sched_get_nr_running_avg(int *avg, int *iowait_avg);
extern void calc_global_load(unsigned long ticks);
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
index 9a7dd35..3ede7d9 100644
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -11,7 +11,7 @@
CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer
endif
-obj-y += core.o clock.o idle_task.o fair.o rt.o stop_task.o
+obj-y += core.o clock.o idle_task.o fair.o rt.o stop_task.o sched_avg.o
obj-$(CONFIG_SMP) += cpupri.o
obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
obj-$(CONFIG_SCHEDSTATS) += stats.o
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index fb3acba..451bd4f 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -916,11 +916,13 @@
static inline void inc_nr_running(struct rq *rq)
{
+ sched_update_nr_prod(cpu_of(rq), rq->nr_running, true);
rq->nr_running++;
}
static inline void dec_nr_running(struct rq *rq)
{
+ sched_update_nr_prod(cpu_of(rq), rq->nr_running, false);
rq->nr_running--;
}
diff --git a/kernel/sched/sched_avg.c b/kernel/sched/sched_avg.c
new file mode 100644
index 0000000..8eaf2f7
--- /dev/null
+++ b/kernel/sched/sched_avg.c
@@ -0,0 +1,106 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Scheduler hook for average runqueue determination
+ */
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/hrtimer.h>
+#include <linux/sched.h>
+#include <linux/math64.h>
+
+static DEFINE_PER_CPU(u64, nr_prod_sum);
+static DEFINE_PER_CPU(u64, last_time);
+static DEFINE_PER_CPU(u64, nr);
+static DEFINE_PER_CPU(unsigned long, iowait_prod_sum);
+static DEFINE_PER_CPU(spinlock_t, nr_lock) = __SPIN_LOCK_UNLOCKED(nr_lock);
+static s64 last_get_time;
+
+/**
+ * sched_get_nr_running_avg
+ * @return: Average nr_running and iowait value since last poll.
+ * Returns the avg * 100 to return up to two decimal points
+ * of accuracy.
+ *
+ * Obtains the average nr_running value since the last poll.
+ * This function may not be called concurrently with itself
+ */
+void sched_get_nr_running_avg(int *avg, int *iowait_avg)
+{
+ int cpu;
+ u64 curr_time = sched_clock();
+ u64 diff = curr_time - last_get_time;
+ u64 tmp_avg = 0, tmp_iowait = 0;
+
+ *avg = 0;
+ *iowait_avg = 0;
+
+ if (!diff)
+ return;
+
+ last_get_time = curr_time;
+ /* read and reset nr_running counts */
+ for_each_possible_cpu(cpu) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&per_cpu(nr_lock, cpu), flags);
+ tmp_avg += per_cpu(nr_prod_sum, cpu);
+ tmp_avg += per_cpu(nr, cpu) *
+ (curr_time - per_cpu(last_time, cpu));
+ tmp_iowait = per_cpu(iowait_prod_sum, cpu);
+ tmp_iowait += nr_iowait_cpu(cpu) *
+ (curr_time - per_cpu(last_time, cpu));
+ per_cpu(last_time, cpu) = curr_time;
+ per_cpu(nr_prod_sum, cpu) = 0;
+ per_cpu(iowait_prod_sum, cpu) = 0;
+ spin_unlock_irqrestore(&per_cpu(nr_lock, cpu), flags);
+ }
+
+ *avg = (int)div64_u64(tmp_avg * 100, diff);
+ *iowait_avg = (int)div64_u64(tmp_iowait * 100, diff);
+
+ BUG_ON(*avg < 0);
+ pr_debug("%s - avg:%d\n", __func__, *avg);
+ BUG_ON(*iowait_avg < 0);
+ pr_debug("%s - avg:%d\n", __func__, *iowait_avg);
+}
+EXPORT_SYMBOL(sched_get_nr_running_avg);
+
+/**
+ * sched_update_nr_prod
+ * @cpu: The core id of the nr running driver.
+ * @nr: Updated nr running value for cpu.
+ * @inc: Whether we are increasing or decreasing the count
+ * @return: N/A
+ *
+ * Update average with latest nr_running value for CPU
+ */
+void sched_update_nr_prod(int cpu, unsigned long nr_running, bool inc)
+{
+ int diff;
+ s64 curr_time;
+ unsigned long flags;
+
+ spin_lock_irqsave(&per_cpu(nr_lock, cpu), flags);
+ curr_time = sched_clock();
+ diff = curr_time - per_cpu(last_time, cpu);
+ per_cpu(last_time, cpu) = curr_time;
+ per_cpu(nr, cpu) = nr_running + (inc ? 1 : -1);
+
+ BUG_ON(per_cpu(nr, cpu) < 0);
+
+ per_cpu(nr_prod_sum, cpu) += nr_running * diff;
+ per_cpu(iowait_prod_sum, cpu) += nr_iowait_cpu(cpu) * diff;
+ spin_unlock_irqrestore(&per_cpu(nr_lock, cpu), flags);
+}
+EXPORT_SYMBOL(sched_update_nr_prod);
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 550a492..0b9d54f 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -551,9 +551,7 @@
prtd->enabled = 1;
if (compr->info.codec_param.codec.id ==
- SND_AUDIOCODEC_AC3_PASS_THROUGH ||
- compr->info.codec_param.codec.id ==
- SND_AUDIOCODEC_DTS_PASS_THROUGH)
+ SND_AUDIOCODEC_PASS_THROUGH)
msm_pcm_routing_reg_psthr_stream(
soc_prtd->dai_link->be_id,
prtd->session_id, substream->stream,
@@ -768,9 +766,7 @@
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
if (compr->info.codec_param.codec.id ==
- SND_AUDIOCODEC_AC3_PASS_THROUGH ||
- compr->info.codec_param.codec.id ==
- SND_AUDIOCODEC_DTS_PASS_THROUGH)
+ SND_AUDIOCODEC_PASS_THROUGH)
msm_pcm_routing_reg_psthr_stream(
soc_prtd->dai_link->be_id,
prtd->session_id, substream->stream,