Merge "msm: clock-9625: Remove qpic clocks from lookup table"
diff --git a/Documentation/devicetree/bindings/pil/pil-mba.txt b/Documentation/devicetree/bindings/pil/pil-mba.txt
index 9692059..ce6bb8f 100644
--- a/Documentation/devicetree/bindings/pil/pil-mba.txt
+++ b/Documentation/devicetree/bindings/pil/pil-mba.txt
@@ -12,6 +12,7 @@
the primary modem image metadata should be stored.
- reg-names: Names for the above base addresses. "rmb_base" and
"metadata_base" are expected.
+- interrupts: The modem watchdog interrupt
- qcom,firmware-name: Base name of the firmware image. Ex. "modem"
Optional properties:
@@ -24,6 +25,7 @@
reg = <0xfc820000 0x0020>,
<0x0d1f0000 0x4000>;
reg-names = "rmb_base", "metadata_base";
+ interrupts = <0 56 1>;
qcom,firmware-name = "modem";
qcom,depends-on = "mba";
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
index e123bdb..e3108ac 100644
--- a/Documentation/devicetree/bindings/pil/pil-pronto.txt
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -10,6 +10,7 @@
- reg: offset and length of the register set for the device.
- reg-names: names of the bases for the above registers. "pmu_base", "clk_base",
and "halt_base" are expected.
+- interrupts: WCNSS to Apps watchdog bite interrupt
- vdd_pronto_pll-supply: regulator to supply pronto pll.
- qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
@@ -21,6 +22,7 @@
<0xfd485300 0xc>;
reg-names = "pmu_base", "clk_base", "halt_base";
vdd_pronto_pll-supply = <&pm8941_l12>;
+ interrupts = <0 231 1>;
qcom,firmware-name = "wcnss";
};
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index d39c98c..ac9600d 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -11,6 +11,7 @@
memory mapped registers.
- reg-names: Names of the bases for the above registers. "qdsp6_base"
and "halt_base" are expected.
+- interrupts: The lpass watchdog interrupt
- qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
Example:
@@ -19,6 +20,7 @@
reg = <0xfe200000 0x00100>,
<0xfd485100 0x00010>;
reg-names = "qdsp6_base", "halt_base";
+ interrupts = <0 194 1>;
qcom,firmware-name = "lpass";
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index a445a81..23635de 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -659,6 +659,7 @@
reg = <0xfe200000 0x00100>,
<0xfd485100 0x00010>;
reg-names = "qdsp6_base", "halt_base";
+ interrupts = <0 194 1>;
qcom,firmware-name = "adsp";
};
@@ -804,6 +805,7 @@
reg = <0xfc820000 0x0020>,
<0x0d1fc000 0x4000>;
reg-names = "rmb_base", "metadata_base";
+ interrupts = <0 56 1>;
qcom,firmware-name = "modem";
qcom,depends-on = "mba";
@@ -815,6 +817,7 @@
<0xfc401700 0x4>,
<0xfd485300 0xc>;
reg-names = "pmu_base", "clk_base", "halt_base";
+ interrupts = <0 181 1>;
vdd_pronto_pll-supply = <&pm8941_l12>;
qcom,firmware-name = "wcnss";
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index cdc435c..7ee0eb2 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1958,11 +1958,13 @@
If unsure, say N.
config MSM_PIL_LPASS_QDSP6V5
- tristate "LPASS QDSP6v5 (Hexagon) Boot Support"
- depends on MSM_PIL
- help
- Support for booting and shutting down QDSP6v5 (Hexagon) processors
- in low power audio subsystems.
+ tristate "LPASS QDSP6v5 (Hexagon) Boot Support"
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
+ help
+ Support for booting and shutting down QDSP6v5 (Hexagon) processors
+ in low power audio subsystems. This driver also monitors the ADSP
+ SMSM status bits and the ADSP's watchdog interrupt and restarts the
+ ADSP if the processor encounters a fatal error.
config MSM_PIL_MSS_QDSP6V5
tristate "MSS QDSP6v5 (Hexagon) Boot Support"
@@ -1973,7 +1975,7 @@
config MSM_PIL_MBA
tristate "Support for modem self-authentication"
- depends on MSM_PIL_MSS_QDSP6V5
+ depends on MSM_PIL_MSS_QDSP6V5 && MSM_SUBSYSTEM_RESTART
help
Support for booting self-authenticating modems using the Modem Boot
Authenticator.
@@ -1998,7 +2000,7 @@
config MSM_PIL_DSPS
tristate "DSPS Boot Support"
- depends on MSM_PIL
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
help
Support for booting and shutting down ARM7 DSPS processors.
@@ -2027,7 +2029,7 @@
config MSM_PIL_PRONTO
tristate "PRONTO (WCNSS) Boot Support"
- depends on MSM_PIL
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
help
Support for booting and shutting down the PRONTO processor (WCNSS).
PRONTO is the wireless subsystem processor used in bluetooth, wireless
@@ -2037,33 +2039,6 @@
bool "Secure Channel Manager (SCM) support"
default n
-config MSM_MODEM_SSR_8974
- bool "MSM 8974 Modem restart driver"
- depends on (ARCH_MSM8974)
- help
- This option enables the modem subsystem restart driver for the MSM8974.
- It monitors the modem SMSM status bits and the modem watchdog line and
- restarts the modem or the 8974 when the modem encounters a fatal error,
- depending on the restart level selected in the subsystem restart driver.
-
-config MSM_ADSP_SSR_8974
- bool "MSM 8974 adsp restart driver"
- depends on (ARCH_MSM8974)
- help
- This option enables the adsp restart driver for the MSM8974.
- It monitors the adsp SMSM status bits and the adsp watchdog line and
- restarts the adsp or the 8974 when the adsp encounters a fatal error,
- depending on the restart level selected in the subsystem restart driver.
-
-config MSM_WCNSS_SSR_8974
- tristate "MSM 8974 WCNSS restart module"
- depends on (ARCH_MSM8974)
- help
- This option enables the WCNSS restart module for MSM8974. It monitors
- WCNSS SMSM status bits and WCNSS hardware watchdog interrupt line; and
- depending on the restart level, it will restart WCNSS when a fatal error
- occurs at WCNSS.
-
config SCORPION_Uni_45nm_BUG
bool "Scorpion Uni 45nm(SC45U): Workaround for ICIMVAU and BPIMVA"
depends on ARCH_MSM7X30 || (ARCH_QSD8X50 && MSM_SOC_REV_A)
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 5bb80ce..f073e70 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -207,9 +207,6 @@
obj-y += ramdump.o
endif
obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
-obj-$(CONFIG_MSM_MODEM_SSR_8974) += modem-ssr-8974.o
-obj-$(CONFIG_MSM_ADSP_SSR_8974) += adsp-8974.o
-obj-$(CONFIG_MSM_WCNSS_SSR_8974) += wcnss-ssr-8974.o
ifdef CONFIG_CPU_IDLE
obj-$(CONFIG_ARCH_APQ8064) += cpuidle.o
diff --git a/arch/arm/mach-msm/adsp-8974.c b/arch/arm/mach-msm/adsp-8974.c
deleted file mode 100644
index fa7d9d4..0000000
--- a/arch/arm/mach-msm/adsp-8974.c
+++ /dev/null
@@ -1,301 +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/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 "ramdump.h"
-#include "sysmon.h"
-
-#define SCM_Q6_NMI_CMD 0x1
-#define MODULE_NAME "adsp_8974"
-#define MAX_BUF_SIZE 0x51
-
-/* Interrupt line for WDOG bite*/
-#define ADSP_Q6SS_WDOG_EXPIRED 194
-
-/* Subsystem restart: QDSP6 data, functions */
-static void adsp_fatal_fn(struct work_struct *);
-static DECLARE_WORK(adsp_fatal_work, adsp_fatal_fn);
-
-struct adsp_ssr {
- void *adsp_ramdump_dev;
-} adsp_ssr;
-
-static struct adsp_ssr adsp_ssr_8974;
-static int q6_crash_shutdown;
-
-static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
- void *ss_handle)
-{
- int ret;
- switch (code) {
- case SUBSYS_BEFORE_SHUTDOWN:
- pr_debug("%s: R-Notify: Shutdown started\n", __func__);
- ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
- SUBSYS_BEFORE_SHUTDOWN);
- if (ret < 0)
- pr_err("%s: sysmon_send_event error %d", __func__,
- ret);
- break;
- }
- return NOTIFY_DONE;
-}
-
-static void *ssr_notif_hdle;
-static struct notifier_block rnb = {
- .notifier_call = riva_notifier_cb,
-};
-
-static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
- void *ss_handle)
-{
- int ret;
- switch (code) {
- case SUBSYS_BEFORE_SHUTDOWN:
- pr_debug("%s: M-Notify: Shutdown started\n", __func__);
- ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
- SUBSYS_BEFORE_SHUTDOWN);
- if (ret < 0)
- pr_err("%s: sysmon_send_event error %d", __func__,
- ret);
- break;
- }
- return NOTIFY_DONE;
-}
-
-static void *ssr_modem_notif_hdle;
-static struct notifier_block mnb = {
- .notifier_call = modem_notifier_cb,
-};
-
-static void adsp_log_failure_reason(void)
-{
- char *reason;
- char buffer[MAX_BUF_SIZE];
- unsigned size;
-
- reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
-
- if (!reason) {
- pr_err("%s: subsystem failure reason: (unknown, smem_get_entry failed).",
- MODULE_NAME);
- return;
- }
-
- if (reason[0] == '\0') {
- pr_err("%s: subsystem failure reason: (unknown, init value found)",
- MODULE_NAME);
- return;
- }
-
- size = size < MAX_BUF_SIZE ? size : (MAX_BUF_SIZE-1);
- memcpy(buffer, reason, size);
- buffer[size] = '\0';
- pr_err("%s: subsystem failure reason: %s", MODULE_NAME, buffer);
- memset((void *)reason, 0x0, size);
- wmb();
-}
-
-static void restart_adsp(void)
-{
- adsp_log_failure_reason();
- subsystem_restart("adsp");
-}
-
-static void adsp_fatal_fn(struct work_struct *work)
-{
- pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
- __func__);
- restart_adsp();
-}
-
-static void adsp_smsm_state_cb(void *data, uint32_t old_state,
- uint32_t new_state)
-{
- /* Ignore if we're the one that set SMSM_RESET */
- if (q6_crash_shutdown)
- return;
-
- if (new_state & SMSM_RESET) {
- pr_debug("%s: ADSP SMSM state changed to SMSM_RESET, new_state= 0x%x, old_state = 0x%x\n",
- __func__, new_state, old_state);
- restart_adsp();
- }
-}
-
-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);
- pr_debug("%s: Q6 NMI was sent.\n", __func__);
-}
-
-static int adsp_shutdown(const struct subsys_desc *subsys)
-{
- send_q6_nmi();
-
- /* The write needs to go through before the q6 is shutdown. */
- mb();
-
- pil_force_shutdown("adsp");
- disable_irq_nosync(ADSP_Q6SS_WDOG_EXPIRED);
-
- return 0;
-}
-
-static int adsp_powerup(const struct subsys_desc *subsys)
-{
- int ret;
-
- if (get_restart_level() == RESET_SUBSYS_INDEPENDENT) {
- pr_debug("%s: Wait for ADSP power up!", __func__);
- msleep(10000);
- }
-
- ret = pil_force_boot("adsp");
- enable_irq(ADSP_Q6SS_WDOG_EXPIRED);
- return ret;
-}
-/* RAM segments - address and size for 8974 */
-static struct ramdump_segment q6_segment = {0xdc00000, 0x1800000};
-
-static int adsp_ramdump(int enable, const struct subsys_desc *subsys)
-{
- pr_debug("%s: enable[%d]\n", __func__, enable);
- if (enable)
- return do_ramdump(adsp_ssr_8974.adsp_ramdump_dev,
- &q6_segment, 1);
- else
- return 0;
-}
-
-static void adsp_crash_shutdown(const struct subsys_desc *subsys)
-{
- q6_crash_shutdown = 1;
- send_q6_nmi();
-}
-
-static irqreturn_t adsp_wdog_bite_irq(int irq, void *dev_id)
-{
- int ret;
-
- pr_debug("%s: rxed irq[0x%x]", __func__, irq);
- disable_irq_nosync(ADSP_Q6SS_WDOG_EXPIRED);
- ret = schedule_work(&adsp_fatal_work);
-
- return IRQ_HANDLED;
-}
-
-static struct subsys_device *adsp_8974_dev;
-
-static struct subsys_desc adsp_8974 = {
- .name = "adsp",
- .shutdown = adsp_shutdown,
- .powerup = adsp_powerup,
- .ramdump = adsp_ramdump,
- .crash_shutdown = adsp_crash_shutdown
-};
-
-static int __init adsp_restart_init(void)
-{
- adsp_8974_dev = subsys_register(&adsp_8974);
- if (IS_ERR(adsp_8974_dev))
- return PTR_ERR(adsp_8974_dev);
- return 0;
-}
-
-static int __init adsp_fatal_init(void)
-{
- int ret;
-
- ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
- adsp_smsm_state_cb, 0);
-
- if (ret < 0)
- pr_err("%s: Unable to register SMSM callback! (%d)\n",
- __func__, ret);
-
- ret = request_irq(ADSP_Q6SS_WDOG_EXPIRED, adsp_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "q6_wdog", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to request ADSP_Q6SS_WDOG_EXPIRED irq.",
- __func__);
- goto out;
- }
- ret = adsp_restart_init();
- if (ret < 0) {
- pr_err("%s: Unable to reg with adsp ssr. (%d)\n",
- __func__, ret);
- goto out;
- }
-
- adsp_ssr_8974.adsp_ramdump_dev = create_ramdump_device("adsp");
-
- if (!adsp_ssr_8974.adsp_ramdump_dev) {
- pr_err("%s: Unable to create ramdump device.\n",
- __func__);
- ret = -ENOMEM;
- goto out;
- }
- ssr_notif_hdle = subsys_notif_register_notifier("riva",
- &rnb);
- if (IS_ERR(ssr_notif_hdle) < 0) {
- ret = PTR_ERR(ssr_notif_hdle);
- pr_err("%s: subsys_register_notifier for Riva: err = %d\n",
- __func__, ret);
- free_irq(ADSP_Q6SS_WDOG_EXPIRED, NULL);
- goto out;
- }
-
- ssr_modem_notif_hdle = subsys_notif_register_notifier("modem",
- &mnb);
- if (IS_ERR(ssr_modem_notif_hdle) < 0) {
- ret = PTR_ERR(ssr_modem_notif_hdle);
- pr_err("%s: subsys_register_notifier for Modem: err = %d\n",
- __func__, ret);
- subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
- free_irq(ADSP_Q6SS_WDOG_EXPIRED, NULL);
- goto out;
- }
-
- pr_info("%s: adsp ssr driver init'ed.\n", __func__);
-out:
- return ret;
-}
-
-static void __exit adsp_fatal_exit(void)
-{
- subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
- subsys_notif_unregister_notifier(ssr_modem_notif_hdle, &mnb);
- subsys_unregister(adsp_8974_dev);
- free_irq(ADSP_Q6SS_WDOG_EXPIRED, NULL);
-}
-
-module_init(adsp_fatal_init);
-module_exit(adsp_fatal_exit);
-
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 4b03a7a..adf1733 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -6710,22 +6710,22 @@
struct clk *mmfpb_a_clk = clk_get_sys("clock-8960", "mmfpb_a_clk");
struct clk *cfpb_a_clk = clk_get_sys("clock-8960", "cfpb_a_clk");
- /* Vote for MMFPB to be at least 76.8MHz when an Apps CPU is active. */
+ /* Vote for MMFPB to be on when Apps is active. */
if (WARN(IS_ERR(mmfpb_a_clk), "mmfpb_a_clk not found (%ld)\n",
PTR_ERR(mmfpb_a_clk)))
return PTR_ERR(mmfpb_a_clk);
- rc = clk_set_rate(mmfpb_a_clk, 76800000);
+ rc = clk_set_rate(mmfpb_a_clk, 38400000);
if (WARN(rc, "mmfpb_a_clk rate was not set (%d)\n", rc))
return rc;
rc = clk_prepare_enable(mmfpb_a_clk);
if (WARN(rc, "mmfpb_a_clk not enabled (%d)\n", rc))
return rc;
- /* Vote for CFPB to be at least 64MHz when an Apps CPU is active. */
+ /* Vote for CFPB to be on when Apps is active. */
if (WARN(IS_ERR(cfpb_a_clk), "cfpb_a_clk not found (%ld)\n",
PTR_ERR(cfpb_a_clk)))
return PTR_ERR(cfpb_a_clk);
- rc = clk_set_rate(cfpb_a_clk, 64000000);
+ rc = clk_set_rate(cfpb_a_clk, 32000000);
if (WARN(rc, "cfpb_a_clk rate was not set (%d)\n", rc))
return rc;
rc = clk_prepare_enable(cfpb_a_clk);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index a49a145..d727c54 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2404,19 +2404,6 @@
/* Sensors DSPS platform data */
-#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
-#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
-#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
-#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
-#define PPSS_DSPS_PIPE_BASE 0x12800000
-#define PPSS_DSPS_PIPE_SIZE 0x4000
-#define PPSS_DSPS_DDR_BASE 0x8fe00000
-#define PPSS_DSPS_DDR_SIZE 0x100000
-#define PPSS_SMEM_BASE 0x80000000
-#define PPSS_SMEM_SIZE 0x200000
-#define PPSS_REG_PHYS_BASE 0x12080000
-#define PPSS_WDOG_UNMASKED_INT_EN 0x1808
-
static struct dsps_clk_info dsps_clks[] = {};
static struct dsps_regulator_info dsps_regs[] = {};
@@ -2425,6 +2412,8 @@
* apq8064_init_dsps().
*/
+#define PPSS_REG_PHYS_BASE 0x12080000
+
struct msm_dsps_platform_data msm_dsps_pdata_8064 = {
.clks = dsps_clks,
.clks_num = ARRAY_SIZE(dsps_clks),
@@ -2433,17 +2422,6 @@
.regs = dsps_regs,
.regs_num = ARRAY_SIZE(dsps_regs),
.dsps_pwr_ctl_en = 1,
- .tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
- .tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
- .tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
- .tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
- .pipe_start = PPSS_DSPS_PIPE_BASE,
- .pipe_size = PPSS_DSPS_PIPE_SIZE,
- .ddr_start = PPSS_DSPS_DDR_BASE,
- .ddr_size = PPSS_DSPS_DDR_SIZE,
- .smem_start = PPSS_SMEM_BASE,
- .smem_size = PPSS_SMEM_SIZE,
- .ppss_wdog_unmasked_int_en_reg = PPSS_WDOG_UNMASKED_INT_EN,
.signature = DSPS_SIGNATURE,
};
@@ -2454,13 +2432,6 @@
.name = "ppss_reg",
.flags = IORESOURCE_MEM,
},
-
- {
- .start = PPSS_WDOG_TIMER_IRQ,
- .end = PPSS_WDOG_TIMER_IRQ,
- .name = "ppss_wdog",
- .flags = IORESOURCE_IRQ,
- },
};
struct platform_device msm_dsps_device_8064 = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 5b04fa7..0f71bc4 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1462,9 +1462,24 @@
.id = -1,
};
+static struct resource msm_pil_dsps_resources[] = {
+ {
+ .start = PPSS_WDOG_TIMER_IRQ,
+ .end = PPSS_WDOG_TIMER_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = 0x12080000,
+ .end = 0x12080000 + SZ_8K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
struct platform_device msm_pil_dsps = {
- .name = "pil_dsps",
- .id = -1,
+ .name = "pil_dsps",
+ .id = -1,
+ .resource = msm_pil_dsps_resources,
+ .num_resources = ARRAY_SIZE(msm_pil_dsps_resources),
.dev.platform_data = "dsps",
};
@@ -3801,18 +3816,7 @@
/* Sensors DSPS platform data */
#ifdef CONFIG_MSM_DSPS
-#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
-#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
-#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
-#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
-#define PPSS_DSPS_PIPE_BASE 0x12800000
-#define PPSS_DSPS_PIPE_SIZE 0x4000
-#define PPSS_DSPS_DDR_BASE 0x8fe00000
-#define PPSS_DSPS_DDR_SIZE 0x100000
-#define PPSS_SMEM_BASE 0x80000000
-#define PPSS_SMEM_SIZE 0x200000
-#define PPSS_REG_PHYS_BASE 0x12080000
-#define PPSS_WDOG_UNMASKED_INT_EN 0x1808
+#define PPSS_REG_PHYS_BASE 0x12080000
static struct dsps_clk_info dsps_clks[] = {};
static struct dsps_regulator_info dsps_regs[] = {};
@@ -3830,17 +3834,6 @@
.regs = dsps_regs,
.regs_num = ARRAY_SIZE(dsps_regs),
.dsps_pwr_ctl_en = 1,
- .tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
- .tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
- .tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
- .tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
- .pipe_start = PPSS_DSPS_PIPE_BASE,
- .pipe_size = PPSS_DSPS_PIPE_SIZE,
- .ddr_start = PPSS_DSPS_DDR_BASE,
- .ddr_size = PPSS_DSPS_DDR_SIZE,
- .smem_start = PPSS_SMEM_BASE,
- .smem_size = PPSS_SMEM_SIZE,
- .ppss_wdog_unmasked_int_en_reg = PPSS_WDOG_UNMASKED_INT_EN,
.signature = DSPS_SIGNATURE,
};
@@ -3851,12 +3844,6 @@
.name = "ppss_reg",
.flags = IORESOURCE_MEM,
},
- {
- .start = PPSS_WDOG_TIMER_IRQ,
- .end = PPSS_WDOG_TIMER_IRQ,
- .name = "ppss_wdog",
- .flags = IORESOURCE_IRQ,
- },
};
struct platform_device msm_dsps_device = {
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 37cdc98..5554eb8 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1622,16 +1622,6 @@
/* Sensors DSPS platform data */
#ifdef CONFIG_MSM_DSPS
-#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
-#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
-#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
-#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
-#define PPSS_DSPS_PIPE_BASE 0x12800000
-#define PPSS_DSPS_PIPE_SIZE 0x0 /* 8660 V2 does not use PIPE memory */
-#define PPSS_DSPS_DDR_BASE 0x8fe00000
-#define PPSS_DSPS_DDR_SIZE 0x0 /* 8660 V2 does not use DDR memory */
-#define PPSS_SMEM_BASE 0x40000000
-#define PPSS_SMEM_SIZE 0x4000
#define PPSS_REG_PHYS_BASE 0x12080000
#define PPSS_PAUSE_REG 0x1804
@@ -1696,16 +1686,6 @@
.regs = dsps_regs,
.regs_num = ARRAY_SIZE(dsps_regs),
.init = dsps_init1,
- .tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
- .tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
- .tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
- .tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
- .pipe_start = PPSS_DSPS_PIPE_BASE,
- .pipe_size = PPSS_DSPS_PIPE_SIZE,
- .ddr_start = PPSS_DSPS_DDR_BASE,
- .ddr_size = PPSS_DSPS_DDR_SIZE,
- .smem_start = PPSS_SMEM_BASE,
- .smem_size = PPSS_SMEM_SIZE,
.ppss_pause_reg = PPSS_PAUSE_REG,
.signature = DSPS_SIGNATURE,
};
diff --git a/arch/arm/mach-msm/include/mach/msm_dsps.h b/arch/arm/mach-msm/include/mach/msm_dsps.h
index a876798..ac81616 100644
--- a/arch/arm/mach-msm/include/mach/msm_dsps.h
+++ b/arch/arm/mach-msm/include/mach/msm_dsps.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -75,16 +75,6 @@
* @regs_num - number of regulators.
* @dsps_pwr_ctl_en - to enable DSPS to do power control if set 1
* otherwise the apps will do power control
- * @tcm_code_start - start of the TCM code region as physical address
- * @tcm_code_size - size of the TCM code region in bytes
- * @tcm_buf_start - start of the TCM buf region as physical address
- * @tcm_buf_size - size of the TCM buf region in bytes
- * @pipe_start - start of the PIPE region as physical address
- * @pipe_size - size of the PIPE region in bytes
- * @ddr_start - start of the DDR region as physical address
- * @ddr_size - size of the DDR region in bytes
- * @smem_start - start of the smem region as physical address
- * @smem_size - size of the smem region in bytes
* @ppss_pause_reg - Offset to the PPSS_PAUSE register
* @ppss_wdog_unmasked_int_en_reg - Offset to PPSS_WDOG_UNMASKED_INT_EN register
* @signature - signature for validity check.
@@ -99,16 +89,6 @@
int regs_num;
int dsps_pwr_ctl_en;
void (*init)(struct msm_dsps_platform_data *data);
- int tcm_code_start;
- int tcm_code_size;
- int tcm_buf_start;
- int tcm_buf_size;
- int pipe_start;
- int pipe_size;
- int ddr_start;
- int ddr_size;
- int smem_start;
- int smem_size;
int ppss_pause_reg;
int ppss_wdog_unmasked_int_en_reg;
u32 signature;
diff --git a/arch/arm/mach-msm/modem-ssr-8974.c b/arch/arm/mach-msm/modem-ssr-8974.c
deleted file mode 100644
index 942eca5..0000000
--- a/arch/arm/mach-msm/modem-ssr-8974.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/err.h>
-
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/msm_smsm.h>
-
-#include "ramdump.h"
-
-static int crash_shutdown;
-static int modem_ssr_ignore_errors;
-static struct subsys_device *modem_ssr_dev;
-
-#define MAX_SSR_REASON_LEN 81U
-#define Q6SS_WDOG_ENABLE 0xFC802004
-#define MSS_Q6SS_WDOG_EXP_IRQ 56
-
-static void log_modem_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("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
- return;
- }
- if (!smem_reason[0]) {
- pr_err("modem subsystem failure reason: (unknown, empty string found).\n");
- return;
- }
-
- strlcpy(reason, smem_reason, min(size, sizeof(reason)));
- pr_err("modem subsystem failure reason: %s.\n", reason);
-
- smem_reason[0] = '\0';
- wmb();
-}
-
-static void restart_modem(void)
-{
- log_modem_sfr();
- modem_ssr_ignore_errors = 1;
- subsystem_restart("modem");
-}
-
-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("Probable fatal error on the modem.\n");
- restart_modem();
- }
-}
-
-static int modem_shutdown(const struct subsys_desc *subsys)
-{
- pil_force_shutdown("modem");
- pil_force_shutdown("mba");
- return 0;
-}
-
-static int modem_powerup(const struct subsys_desc *subsys)
-{
- /*
- * At this time, the modem is shutdown. Therefore this function cannot
- * run concurrently with either the watchdog bite error handler or the
- * SMSM callback, making it safe to unset the flag below.
- */
- modem_ssr_ignore_errors = 0;
- pil_force_boot("mba");
- pil_force_boot("modem");
- return 0;
-}
-
-void modem_crash_shutdown(const struct subsys_desc *subsys)
-{
- crash_shutdown = 1;
- smsm_reset_modem(SMSM_RESET);
-}
-
-static struct ramdump_segment modem_segments[] = {
- {0x08400000, 0x0D100000 - 0x08400000},
-};
-
-static struct ramdump_segment smem_segments[] = {
- {0x0FA00000, 0x0FC00000 - 0x0FA00000},
-};
-
-static void *modem_ramdump_dev;
-static void *smem_ramdump_dev;
-
-static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
-{
- int ret = 0;
-
- if (!enable)
- return ret;
-
- pil_force_boot("mba");
-
- ret = do_ramdump(modem_ramdump_dev, modem_segments,
- ARRAY_SIZE(modem_segments));
-
- if (ret < 0) {
- pr_err("Unable to dump modem fw memory (rc = %d).\n",
- ret);
- goto out;
- }
-
- ret = do_ramdump(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:
- pil_force_shutdown("mba");
- return ret;
-}
-
-static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
-{
- if (modem_ssr_ignore_errors)
- return IRQ_HANDLED;
- pr_err("Watchdog bite received from the modem!\n");
- restart_modem();
- return IRQ_HANDLED;
-}
-
-static struct subsys_desc modem_8974 = {
- .name = "modem",
- .shutdown = modem_shutdown,
- .powerup = modem_powerup,
- .ramdump = modem_ramdump,
- .crash_shutdown = modem_crash_shutdown
-};
-
-static int __init modem_8974_init(void)
-{
- int ret;
-
- 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);
- goto out;
- }
-
- ret = request_irq(MSS_Q6SS_WDOG_EXP_IRQ, modem_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "modem_wdog_sw", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to request q6sw watchdog IRQ. (%d)\n",
- __func__, ret);
- goto out;
- }
-
- modem_ssr_dev = subsys_register(&modem_8974);
-
- if (IS_ERR_OR_NULL(modem_ssr_dev)) {
- pr_err("%s: Unable to reg with subsystem restart. (%ld)\n",
- __func__, PTR_ERR(modem_ssr_dev));
- ret = PTR_ERR(modem_ssr_dev);
- goto out;
- }
-
- modem_ramdump_dev = create_ramdump_device("modem");
-
- if (!modem_ramdump_dev) {
- pr_err("%s: Unable to create a modem ramdump device.\n",
- __func__);
- ret = -ENOMEM;
- goto out;
- }
-
- smem_ramdump_dev = create_ramdump_device("smem-modem");
-
- if (!smem_ramdump_dev) {
- pr_err("%s: Unable to create an smem ramdump device.\n",
- __func__);
- ret = -ENOMEM;
- goto out;
- }
-
- pr_info("%s: modem subsystem restart driver init'ed.\n", __func__);
-out:
- return ret;
-}
-
-module_init(modem_8974_init);
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index c39829b..b85c812 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -15,8 +15,6 @@
*
*/
-#include <asm/atomic.h>
-
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -39,7 +37,6 @@
#include <mach/msm_smsm.h>
#include <mach/msm_dsps.h>
#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
#include "ramdump.h"
#include "timer.h"
@@ -66,8 +63,6 @@
* @smem_ramdump_segments - Ramdump segment information for smem
* @is_on - DSPS is on.
* @ref_count - open/close reference count.
- * @wdog_irq - DSPS Watchdog IRQ
- * @crash_in_progress - 1 if crash recovery is in progress
* @ppss_base - ppss registers virtual base address.
*/
struct dsps_drv {
@@ -81,17 +76,9 @@
void *pil;
- void *dspsfw_ramdump_dev;
- struct ramdump_segment dspsfw_ramdump_segments[4];
-
- void *smem_ramdump_dev;
- struct ramdump_segment smem_ramdump_segments[1];
-
int is_on;
int ref_count;
- int wdog_irq;
- atomic_t crash_in_progress;
void __iomem *ppss_base;
};
@@ -101,13 +88,6 @@
static struct dsps_drv *drv;
/**
- * self-initiated shutdown flag
- */
-static int dsps_crash_shutdown_g;
-
-static void dsps_restart_handler(void);
-
-/**
* Load DSPS Firmware.
*/
static int dsps_load(const char *name)
@@ -382,41 +362,6 @@
}
/**
- *
- * Log subsystem restart failure reason
- */
-static void dsps_log_sfr(void)
-{
- const char dflt_reason[] = "Died too early due to unknown reason";
- char *smem_reset_reason;
- unsigned smem_reset_size;
-
- smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_DSPS0,
- &smem_reset_size);
- if (smem_reset_reason != NULL && smem_reset_reason[0] != 0) {
- smem_reset_reason[smem_reset_size-1] = 0;
- pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
- __func__, smem_reset_reason);
- memset(smem_reset_reason, 0, smem_reset_size);
- wmb();
- } else
- pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
- __func__, dflt_reason);
-}
-
-/**
- * Watchdog interrupt handler
- *
- */
-static irqreturn_t dsps_wdog_bite_irq(int irq, void *dev_id)
-{
- pr_err("%s\n", __func__);
- dsps_log_sfr();
- dsps_restart_handler();
- return IRQ_HANDLED;
-}
-
-/**
* IO Control - handle commands from client.
*
*/
@@ -452,7 +397,7 @@
case DSPS_IOCTL_RESET:
pr_err("%s: User-initiated DSPS reset.\nResetting DSPS\n",
__func__);
- dsps_restart_handler();
+ subsystem_restart("dsps");
ret = 0;
break;
default:
@@ -471,7 +416,6 @@
{
int ret = -ENODEV;
struct resource *ppss_res;
- struct resource *ppss_wdog;
int i;
pr_debug("%s.\n", __func__);
@@ -541,58 +485,11 @@
drv->ppss_base = ioremap(ppss_res->start,
resource_size(ppss_res));
- ppss_wdog = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
- "ppss_wdog");
- if (ppss_wdog) {
- drv->wdog_irq = ppss_wdog->start;
- ret = request_irq(drv->wdog_irq, dsps_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "dsps_wdog", NULL);
- if (ret) {
- pr_err("%s: request_irq fail %d\n", __func__, ret);
- goto request_irq_err;
- }
- } else {
- drv->wdog_irq = -1;
- pr_debug("%s: ppss_wdog not supported.\n", __func__);
- }
-
- drv->dspsfw_ramdump_segments[0].address = drv->pdata->tcm_code_start;
- drv->dspsfw_ramdump_segments[0].size = drv->pdata->tcm_code_size;
- drv->dspsfw_ramdump_segments[1].address = drv->pdata->tcm_buf_start;
- drv->dspsfw_ramdump_segments[1].size = drv->pdata->tcm_buf_size;
- drv->dspsfw_ramdump_segments[2].address = drv->pdata->pipe_start;
- drv->dspsfw_ramdump_segments[2].size = drv->pdata->pipe_size;
- drv->dspsfw_ramdump_segments[3].address = drv->pdata->ddr_start;
- drv->dspsfw_ramdump_segments[3].size = drv->pdata->ddr_size;
-
- drv->dspsfw_ramdump_dev = create_ramdump_device("dsps");
- if (!drv->dspsfw_ramdump_dev) {
- pr_err("%s: create_ramdump_device(\"dsps\") fail\n",
- __func__);
- goto create_ramdump_err;
- }
-
- drv->smem_ramdump_segments[0].address = drv->pdata->smem_start;
- drv->smem_ramdump_segments[0].size = drv->pdata->smem_size;
- drv->smem_ramdump_dev = create_ramdump_device("smem-dsps");
- if (!drv->smem_ramdump_dev) {
- pr_err("%s: create_ramdump_device(\"smem\") fail\n",
- __func__);
- goto create_ramdump_err;
- }
-
if (drv->pdata->init)
drv->pdata->init(drv->pdata);
return 0;
-create_ramdump_err:
- disable_irq_nosync(drv->wdog_irq);
- free_irq(drv->wdog_irq, NULL);
-
-request_irq_err:
- iounmap(drv->ppss_base);
-
reg_err:
for (i = 0; i < drv->pdata->regs_num; i++) {
if (drv->pdata->regs[i].reg) {
@@ -678,8 +575,6 @@
}
}
- free_irq(drv->wdog_irq, NULL);
-
iounmap(drv->ppss_base);
}
@@ -722,138 +617,6 @@
.unlocked_ioctl = dsps_ioctl,
};
-static struct subsys_device *dsps_dev;
-
-/**
- * Fatal error handler
- * Resets DSPS.
- */
-static void dsps_restart_handler(void)
-{
- pr_debug("%s: Restart lvl %d\n",
- __func__, get_restart_level());
-
- if (atomic_add_return(1, &drv->crash_in_progress) > 1) {
- pr_err("%s: DSPS already resetting. Count %d\n", __func__,
- atomic_read(&drv->crash_in_progress));
- } else {
- subsystem_restart_dev(dsps_dev);
- }
-}
-
-
-/**
- * SMSM state change callback
- *
- */
-static void dsps_smsm_state_cb(void *data, uint32_t old_state,
- uint32_t new_state)
-{
- pr_debug("%s\n", __func__);
- if (dsps_crash_shutdown_g == 1) {
- pr_debug("%s: SMSM_RESET state change ignored\n",
- __func__);
- dsps_crash_shutdown_g = 0;
- return;
- }
- if (new_state & SMSM_RESET) {
- dsps_log_sfr();
- dsps_restart_handler();
- }
-}
-
-/**
- * Shutdown function
- * called by the restart notifier
- *
- */
-static int dsps_shutdown(const struct subsys_desc *subsys)
-{
- pr_debug("%s\n", __func__);
- disable_irq_nosync(drv->wdog_irq);
- if (drv->pdata->ppss_wdog_unmasked_int_en_reg) {
- writel_relaxed(0, (drv->ppss_base+
- drv->pdata->ppss_wdog_unmasked_int_en_reg));
- mb(); /* Make sure wdog is disabled before shutting down */
- }
- pil_force_shutdown(drv->pdata->pil_name);
- dsps_power_off_handler();
- return 0;
-}
-
-/**
- * Powerup function
- * called by the restart notifier
- *
- */
-static int dsps_powerup(const struct subsys_desc *subsys)
-{
- pr_debug("%s\n", __func__);
- dsps_power_on_handler();
- pil_force_boot(drv->pdata->pil_name);
- atomic_set(&drv->crash_in_progress, 0);
- enable_irq(drv->wdog_irq);
- return 0;
-}
-
-/**
- * Crash shutdown function
- * called by the restart notifier
- *
- */
-static void dsps_crash_shutdown(const struct subsys_desc *subsys)
-{
- pr_debug("%s\n", __func__);
- disable_irq_nosync(drv->wdog_irq);
- dsps_crash_shutdown_g = 1;
- smsm_change_state(SMSM_DSPS_STATE, SMSM_RESET, SMSM_RESET);
-}
-
-/**
- * Ramdump function
- * called by the restart notifier
- *
- */
-static int dsps_ramdump(int enable, const struct subsys_desc *subsys)
-{
- int ret = 0;
- pr_debug("%s\n", __func__);
-
- if (enable) {
- if (drv->dspsfw_ramdump_dev != NULL) {
- ret = do_ramdump(drv->dspsfw_ramdump_dev,
- drv->dspsfw_ramdump_segments,
- ARRAY_SIZE(drv->dspsfw_ramdump_segments));
- if (ret < 0) {
- pr_err("%s: Unable to dump DSPS memory (rc = %d).\n",
- __func__, ret);
- goto dsps_ramdump_out;
- }
- }
- if (drv->smem_ramdump_dev != NULL) {
- ret = do_ramdump(drv->smem_ramdump_dev,
- drv->smem_ramdump_segments,
- ARRAY_SIZE(drv->smem_ramdump_segments));
- if (ret < 0) {
- pr_err("%s: Unable to dump smem memory (rc = %d).\n",
- __func__, ret);
- goto dsps_ramdump_out;
- }
- }
- }
-
-dsps_ramdump_out:
- return ret;
-}
-
-static struct subsys_desc dsps_ssrops = {
- .name = "dsps",
- .shutdown = dsps_shutdown,
- .powerup = dsps_powerup,
- .ramdump = dsps_ramdump,
- .crash_shutdown = dsps_crash_shutdown
-};
-
/**
* platform driver
*
@@ -874,8 +637,6 @@
pr_err("%s: kzalloc fail.\n", __func__);
goto alloc_err;
}
- atomic_set(&drv->crash_in_progress, 0);
-
drv->pdata = pdev->dev.platform_data;
drv->dev_class = class_create(THIS_MODULE, DRV_NAME);
@@ -918,31 +679,6 @@
goto cdev_add_err;
}
- ret =
- smsm_state_cb_register(SMSM_DSPS_STATE, SMSM_RESET,
- dsps_smsm_state_cb, 0);
- if (ret) {
- pr_err("%s: smsm_state_cb_register fail %d\n", __func__,
- ret);
- goto smsm_register_err;
- }
-
- dsps_dev = subsys_register(&dsps_ssrops);
- if (IS_ERR(dsps_dev)) {
- ret = PTR_ERR(dsps_dev);
- pr_err("%s: subsys_register fail %d\n", __func__,
- ret);
- goto ssr_register_err;
- }
-
- return 0;
-
-ssr_register_err:
- smsm_state_cb_deregister(SMSM_DSPS_STATE, SMSM_RESET,
- dsps_smsm_state_cb,
- 0);
-smsm_register_err:
- cdev_del(drv->cdev);
cdev_add_err:
kfree(drv->cdev);
cdev_alloc_err:
@@ -962,7 +698,6 @@
{
pr_debug("%s.\n", __func__);
- subsys_unregister(dsps_dev);
dsps_power_off_handler();
dsps_free_resources();
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
index 81f5330..dc80a3a 100644
--- a/arch/arm/mach-msm/pil-dsps.c
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -17,11 +17,17 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/atomic.h>
+#include <linux/interrupt.h>
#include <mach/msm_iomap.h>
+#include <mach/subsystem_restart.h>
+#include <mach/msm_smsm.h>
+#include <mach/peripheral-loader.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
+#include "ramdump.h"
#define PPSS_RESET (MSM_CLK_CTL_BASE + 0x2594)
#define PPSS_RESET_PROC_RESET 0x2
@@ -31,6 +37,28 @@
#define PPSS_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2580)
#define CLK_HALT_DFAB_STATE (MSM_CLK_CTL_BASE + 0x2FC8)
+#define PPSS_WDOG_UNMASKED_INT_EN 0x1808
+
+struct dsps_data {
+ struct pil_device *pil;
+ struct pil_desc desc;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+ int crash;
+ int wdog_irq;
+ atomic_t wd_crash;
+ atomic_t crash_in_progress;
+ void __iomem *ppss_base;
+
+ void *ramdump_dev;
+ struct ramdump_segment fw_ramdump_segments[4];
+
+ void *smem_ramdump_dev;
+ struct ramdump_segment smem_ramdump_segments[1];
+};
+
+#define desc_to_drv(d) container_of(d, struct dsps_data, subsys_desc)
+
static int init_image_dsps(struct pil_desc *pil, const u8 *metadata,
size_t size)
{
@@ -88,15 +116,143 @@
.shutdown = shutdown_dsps_trusted,
};
+static void dsps_log_sfr(void)
+{
+ const char dflt_reason[] = "Died too early due to unknown reason";
+ char *smem_reset_reason;
+ unsigned smem_reset_size;
+
+ smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_DSPS0,
+ &smem_reset_size);
+ if (smem_reset_reason != NULL && smem_reset_reason[0] != 0) {
+ smem_reset_reason[smem_reset_size-1] = 0;
+ pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
+ __func__, smem_reset_reason);
+ memset(smem_reset_reason, 0, smem_reset_size);
+ wmb();
+ } else
+ pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
+ __func__, dflt_reason);
+}
+
+
+static void dsps_restart_handler(struct dsps_data *drv)
+{
+ pr_debug("%s: Restart lvl %d\n",
+ __func__, get_restart_level());
+
+ if (atomic_add_return(1, &drv->crash_in_progress) > 1) {
+ pr_err("%s: DSPS already resetting. Count %d\n", __func__,
+ atomic_read(&drv->crash_in_progress));
+ } else {
+ subsystem_restart_dev(drv->subsys);
+ }
+}
+
+static void dsps_smsm_state_cb(void *data, uint32_t old_state,
+ uint32_t new_state)
+{
+ struct dsps_data *drv = data;
+
+ if (drv->crash == 1) {
+ pr_debug("SMSM_RESET state change ignored\n");
+ drv->crash = 0;
+ } else if (new_state & SMSM_RESET) {
+ dsps_log_sfr();
+ dsps_restart_handler(drv);
+ }
+}
+
+static int dsps_shutdown(const struct subsys_desc *desc)
+{
+ struct dsps_data *drv = desc_to_drv(desc);
+ disable_irq_nosync(drv->wdog_irq);
+ if (drv->ppss_base) {
+ writel_relaxed(0, drv->ppss_base + PPSS_WDOG_UNMASKED_INT_EN);
+ mb(); /* Make sure wdog is disabled before shutting down */
+ }
+ pil_force_shutdown(drv->desc.name);
+ return 0;
+}
+
+static int dsps_powerup(const struct subsys_desc *desc)
+{
+ struct dsps_data *drv = desc_to_drv(desc);
+
+ pil_force_boot(drv->desc.name);
+ atomic_set(&drv->crash_in_progress, 0);
+ enable_irq(drv->wdog_irq);
+
+ return 0;
+}
+
+static int dsps_ramdump(int enable, const struct subsys_desc *desc)
+{
+ int ret;
+ struct dsps_data *drv = desc_to_drv(desc);
+
+ if (!enable)
+ return 0;
+
+ ret = do_ramdump(drv->ramdump_dev,
+ drv->fw_ramdump_segments,
+ ARRAY_SIZE(drv->fw_ramdump_segments));
+ if (ret < 0) {
+ pr_err("%s: Unable to dump DSPS memory (rc = %d).\n",
+ __func__, ret);
+ return ret;
+ }
+ ret = do_ramdump(drv->smem_ramdump_dev,
+ drv->smem_ramdump_segments,
+ ARRAY_SIZE(drv->smem_ramdump_segments));
+ if (ret < 0) {
+ pr_err("%s: Unable to dump smem memory (rc = %d).\n",
+ __func__, ret);
+ return ret;
+ }
+ return 0;
+}
+
+static void dsps_crash_shutdown(const struct subsys_desc *desc)
+{
+ struct dsps_data *drv = desc_to_drv(desc);
+
+ disable_irq_nosync(drv->wdog_irq);
+ drv->crash = 1;
+ smsm_change_state(SMSM_DSPS_STATE, SMSM_RESET, SMSM_RESET);
+}
+
+static irqreturn_t dsps_wdog_bite_irq(int irq, void *dev_id)
+{
+ struct dsps_data *drv = dev_id;
+
+ atomic_set(&drv->wd_crash, 1);
+ dsps_log_sfr();
+ dsps_restart_handler(drv);
+ return IRQ_HANDLED;
+}
+
static int __devinit pil_dsps_driver_probe(struct platform_device *pdev)
{
+ struct dsps_data *drv;
struct pil_desc *desc;
- struct pil_device *pil;
+ int ret;
+ struct resource *res;
- desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
- if (!desc)
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ drv->ppss_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->ppss_base)
+ return -ENOMEM;
+ }
+
+ desc = &drv->desc;
desc->name = pdev->dev.platform_data;
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
@@ -107,17 +263,85 @@
desc->ops = &pil_dsps_ops;
dev_info(&pdev->dev, "using non-secure boot\n");
}
- pil = msm_pil_register(desc);
- if (IS_ERR(pil))
- return PTR_ERR(pil);
- platform_set_drvdata(pdev, pil);
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil))
+ return PTR_ERR(drv->pil);
+
+ drv->fw_ramdump_segments[0].address = 0x12000000;
+ drv->fw_ramdump_segments[0].size = 0x28000;
+ drv->fw_ramdump_segments[1].address = 0x12040000;
+ drv->fw_ramdump_segments[1].size = 0x4000;
+ drv->fw_ramdump_segments[2].address = 0x12800000;
+ drv->fw_ramdump_segments[2].size = 0x4000;
+ drv->fw_ramdump_segments[3].address = 0x8fe00000;
+ drv->fw_ramdump_segments[3].size = 0x100000;
+ drv->ramdump_dev = create_ramdump_device("dsps");
+ if (!drv->ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_ramdump;
+ }
+
+ drv->smem_ramdump_segments[0].address = PHYS_OFFSET - SZ_2M;
+ drv->smem_ramdump_segments[0].size = SZ_2M;
+ drv->smem_ramdump_dev = create_ramdump_device("smem-dsps");
+ if (!drv->smem_ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_smem_ramdump;
+ }
+
+ drv->subsys_desc.name = "dsps";
+ drv->subsys_desc.shutdown = dsps_shutdown;
+ drv->subsys_desc.powerup = dsps_powerup;
+ drv->subsys_desc.ramdump = dsps_ramdump,
+ drv->subsys_desc.crash_shutdown = dsps_crash_shutdown;
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ ret = PTR_ERR(drv->subsys);
+ goto err_subsys;
+ }
+
+ ret = smsm_state_cb_register(SMSM_DSPS_STATE, SMSM_RESET,
+ dsps_smsm_state_cb, drv);
+ if (ret)
+ goto err_smsm;
+
+ drv->wdog_irq = platform_get_irq(pdev, 0);
+ if (drv->wdog_irq >= 0) {
+ ret = devm_request_irq(&pdev->dev, drv->wdog_irq,
+ dsps_wdog_bite_irq, IRQF_TRIGGER_RISING,
+ "dsps_wdog", drv);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ goto err_smsm;
+ }
+ } else {
+ drv->wdog_irq = -1;
+ dev_dbg(&pdev->dev, "ppss_wdog not supported\n");
+ }
+
return 0;
+
+err_smsm:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+err_smem_ramdump:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ msm_pil_unregister(drv->pil);
+ return ret;
}
static int __devexit pil_dsps_driver_exit(struct platform_device *pdev)
{
- struct pil_device *pil = platform_get_drvdata(pdev);
- msm_pil_unregister(pil);
+ struct dsps_data *drv = platform_get_drvdata(pdev);
+ smsm_state_cb_deregister(SMSM_DSPS_STATE, SMSM_RESET,
+ dsps_smsm_state_cb, drv);
+ subsys_unregister(drv->subsys);
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+ destroy_ramdump_device(drv->ramdump_dev);
+ msm_pil_unregister(drv->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-mba.c b/arch/arm/mach-msm/pil-mba.c
index 0207f0b..8432328 100644
--- a/arch/arm/mach-msm/pil-mba.c
+++ b/arch/arm/mach-msm/pil-mba.c
@@ -23,8 +23,14 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/of.h>
+#include <linux/interrupt.h>
+
+#include <mach/subsystem_restart.h>
+#include <mach/msm_smsm.h>
+#include <mach/peripheral-loader.h>
#include "peripheral-loader.h"
+#include "ramdump.h"
#define RMB_MBA_COMMAND 0x08
#define RMB_MBA_STATUS 0x0C
@@ -41,6 +47,8 @@
#define PROXY_TIMEOUT_MS 10000
#define POLL_INTERVAL_US 50
+#define MAX_SSR_REASON_LEN 81U
+
static int modem_auth_timeout_ms = 10000;
module_param(modem_auth_timeout_ms, int, S_IRUGO | S_IWUSR);
@@ -49,7 +57,13 @@
void __iomem *metadata_base;
unsigned long metadata_phys;
struct pil_device *pil;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
struct clk *xo;
+ void *ramdump_dev;
+ void *smem_ramdump_dev;
+ bool crash_shutdown;
+ bool ignore_errors;
u32 img_length;
};
@@ -160,18 +174,142 @@
.shutdown = pil_mba_shutdown,
};
+#define subsys_to_drv(d) container_of(d, struct mba_data, subsys_desc)
+
+static void log_modem_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("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
+ return;
+ }
+ if (!smem_reason[0]) {
+ pr_err("modem subsystem failure reason: (unknown, empty string found).\n");
+ return;
+ }
+
+ strlcpy(reason, smem_reason, min(size, sizeof(reason)));
+ pr_err("modem subsystem failure reason: %s.\n", reason);
+
+ smem_reason[0] = '\0';
+ wmb();
+}
+
+static void restart_modem(struct mba_data *drv)
+{
+ log_modem_sfr();
+ drv->ignore_errors = true;
+ subsystem_restart_dev(drv->subsys);
+}
+
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+{
+ struct mba_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("Probable fatal error on the modem.\n");
+ restart_modem(drv);
+ }
+}
+
+static int modem_shutdown(const struct subsys_desc *subsys)
+{
+ pil_force_shutdown("modem");
+ pil_force_shutdown("mba");
+ return 0;
+}
+
+static int modem_powerup(const struct subsys_desc *subsys)
+{
+ struct mba_data *drv = subsys_to_drv(subsys);
+ /*
+ * At this time, the modem is shutdown. Therefore this function cannot
+ * run concurrently with either the watchdog bite error handler or the
+ * SMSM callback, making it safe to unset the flag below.
+ */
+ drv->ignore_errors = 0;
+ pil_force_boot("mba");
+ pil_force_boot("modem");
+ return 0;
+}
+
+static void modem_crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct mba_data *drv = subsys_to_drv(subsys);
+ drv->crash_shutdown = true;
+ smsm_reset_modem(SMSM_RESET);
+}
+
+static struct ramdump_segment modem_segments[] = {
+ {0x08400000, 0x0D100000 - 0x08400000},
+};
+
+static struct ramdump_segment smem_segments[] = {
+ {0x0FA00000, 0x0FC00000 - 0x0FA00000},
+};
+
+static int modem_ramdump(int enable, const struct subsys_desc *subsys)
+{
+ struct mba_data *drv = subsys_to_drv(subsys);
+ int ret;
+
+ if (!enable)
+ return 0;
+
+ pil_force_boot("mba");
+
+ ret = do_ramdump(drv->ramdump_dev, modem_segments,
+ ARRAY_SIZE(modem_segments));
+ if (ret < 0) {
+ pr_err("Unable to dump modem fw memory (rc = %d).\n", ret);
+ goto out;
+ }
+
+ 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);
+ goto out;
+ }
+
+out:
+ pil_force_shutdown("mba");
+ return ret;
+}
+
+static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
+{
+ struct mba_data *drv = dev_id;
+ if (drv->ignore_errors)
+ return IRQ_HANDLED;
+ pr_err("Watchdog bite received from modem software!\n");
+ restart_modem(drv);
+ return IRQ_HANDLED;
+}
+
static int __devinit pil_mba_driver_probe(struct platform_device *pdev)
{
struct mba_data *drv;
struct resource *res;
struct pil_desc *desc;
- int ret;
+ int ret, irq;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;
platform_set_drvdata(pdev, drv);
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb_base");
if (!res)
return -EINVAL;
@@ -215,12 +353,71 @@
if (IS_ERR(drv->pil))
return PTR_ERR(drv->pil);
+ drv->subsys_desc.name = desc->name;
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.shutdown = modem_shutdown;
+ drv->subsys_desc.powerup = modem_powerup;
+ drv->subsys_desc.ramdump = modem_ramdump;
+ drv->subsys_desc.crash_shutdown = modem_crash_shutdown;
+
+ drv->ramdump_dev = create_ramdump_device("modem");
+ if (!drv->ramdump_dev) {
+ pr_err("%s: Unable to create a modem ramdump device.\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err_ramdump;
+ }
+
+ drv->smem_ramdump_dev = create_ramdump_device("smem-modem");
+ if (!drv->smem_ramdump_dev) {
+ pr_err("%s: Unable to create an smem ramdump device.\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err_ramdump_smem;
+ }
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ goto err_subsys;
+ ret = PTR_ERR(drv->subsys);
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, modem_wdog_bite_irq,
+ IRQF_TRIGGER_RISING, "modem_wdog", drv);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to request watchdog IRQ.\n");
+ goto err_irq;
+ }
+
+ ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+ smsm_state_cb, drv);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to register SMSM callback!\n");
+ goto err_irq;
+ }
+
return 0;
+
+err_irq:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+err_ramdump_smem:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ msm_pil_unregister(drv->pil);
+ return ret;
}
static int __devexit pil_mba_driver_exit(struct platform_device *pdev)
{
struct mba_data *drv = platform_get_drvdata(pdev);
+ smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET,
+ smsm_state_cb, drv);
+ subsys_unregister(drv->subsys);
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+ destroy_ramdump_device(drv->ramdump_dev);
msm_pil_unregister(drv->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 1e39043..5685787 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -22,6 +22,14 @@
#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+#include <linux/wcnss_wlan.h>
+
+#include <mach/subsystem_restart.h>
+#include <mach/peripheral-loader.h>
+#include <mach/msm_smsm.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -67,8 +75,14 @@
void __iomem *axi_halt_base;
unsigned long start_addr;
struct pil_device *pil;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
struct clk *cxo;
struct regulator *vreg;
+ bool restart_inprogress;
+ bool crash;
+ struct delayed_work cancel_vote_work;
+ int irq;
};
static int pil_pronto_make_proxy_vote(struct pil_desc *pil)
@@ -225,6 +239,129 @@
.proxy_unvote = pil_pronto_remove_proxy_vote,
};
+#define subsys_to_drv(d) container_of(d, struct pronto_data, subsys_desc)
+
+static void log_wcnss_sfr(void)
+{
+ char *smem_reset_reason;
+ unsigned smem_reset_size;
+
+ smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
+ &smem_reset_size);
+
+ if (!smem_reset_reason || !smem_reset_size) {
+ pr_err("wcnss subsystem failure reason:\n"
+ "(unknown, smem_get_entry failed)");
+ } else if (!smem_reset_reason[0]) {
+ pr_err("wcnss subsystem failure reason:\n"
+ "(unknown, init string found)");
+ } else {
+ pr_err("wcnss subsystem failure reason: %.81s\n",
+ smem_reset_reason);
+ memset(smem_reset_reason, 0, smem_reset_size);
+ wmb();
+ }
+}
+
+static void restart_wcnss(struct pronto_data *drv)
+{
+ log_wcnss_sfr();
+ subsystem_restart_dev(drv->subsys);
+}
+
+static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
+ uint32_t new_state)
+{
+ struct pronto_data *drv = data;
+
+ drv->crash = true;
+
+ pr_err("wcnss smsm state changed\n");
+
+ if (!(new_state & SMSM_RESET))
+ return;
+
+ if (drv->restart_inprogress) {
+ pr_err("wcnss: Ignoring smsm reset req, restart in progress\n");
+ return;
+ }
+
+ drv->restart_inprogress = true;
+ restart_wcnss(drv);
+}
+
+static irqreturn_t wcnss_wdog_bite_irq_hdlr(int irq, void *dev_id)
+{
+ struct pronto_data *drv = dev_id;
+
+ drv->crash = true;
+
+ if (drv->restart_inprogress) {
+ pr_err("Ignoring wcnss bite irq, restart in progress\n");
+ return IRQ_HANDLED;
+ }
+
+ drv->restart_inprogress = true;
+ restart_wcnss(drv);
+
+ return IRQ_HANDLED;
+}
+
+static void wcnss_post_bootup(struct work_struct *work)
+{
+ struct platform_device *pdev = wcnss_get_platform_device();
+ struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
+
+ wcnss_wlan_power(&pdev->dev, pwlanconfig, WCNSS_WLAN_SWITCH_OFF);
+}
+
+static int wcnss_shutdown(const struct subsys_desc *subsys)
+{
+ struct pronto_data *drv = subsys_to_drv(subsys);
+
+ pil_force_shutdown("wcnss");
+ flush_delayed_work(&drv->cancel_vote_work);
+ wcnss_flush_delayed_boot_votes();
+ disable_irq_nosync(drv->irq);
+
+ return 0;
+}
+
+static int wcnss_powerup(const struct subsys_desc *subsys)
+{
+ struct pronto_data *drv = subsys_to_drv(subsys);
+ struct platform_device *pdev = wcnss_get_platform_device();
+ struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
+ int ret = -1;
+
+ if (pdev && pwlanconfig)
+ ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
+ WCNSS_WLAN_SWITCH_ON);
+ if (!ret) {
+ msleep(1000);
+ pil_force_boot("wcnss");
+ }
+ drv->restart_inprogress = false;
+ enable_irq(drv->irq);
+ schedule_delayed_work(&drv->cancel_vote_work, msecs_to_jiffies(5000));
+
+ return 0;
+}
+
+static void crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct pronto_data *drv = subsys_to_drv(subsys);
+
+ pr_err("wcnss crash shutdown %d\n", drv->crash);
+ if (!drv->crash)
+ smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
+}
+
+static int wcnss_ramdump(int enable, const struct subsys_desc *crashed_subsys)
+{
+ return 0;
+}
+
static int __devinit pil_pronto_probe(struct platform_device *pdev)
{
struct pronto_data *drv;
@@ -242,6 +379,10 @@
return -ENOMEM;
platform_set_drvdata(pdev, drv);
+ drv->irq = platform_get_irq(pdev, 0);
+ if (drv->irq < 0)
+ return drv->irq;
+
drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!drv->base)
return -ENOMEM;
@@ -303,6 +444,32 @@
if (IS_ERR(drv->pil))
return PTR_ERR(drv->pil);
+ ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
+ smsm_state_cb_hdlr, drv);
+ if (ret < 0)
+ goto err_smsm;
+
+ drv->subsys_desc.name = desc->name;
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.shutdown = wcnss_shutdown;
+ drv->subsys_desc.powerup = wcnss_powerup;
+ drv->subsys_desc.ramdump = wcnss_ramdump;
+ drv->subsys_desc.crash_shutdown = crash_shutdown;
+
+ INIT_DELAYED_WORK(&drv->cancel_vote_work, wcnss_post_bootup);
+
+ 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, wcnss_wdog_bite_irq_hdlr,
+ IRQF_TRIGGER_HIGH, "wcnss_wdog", drv);
+ if (ret < 0)
+ goto err_irq;
+
/* Initialize common_ss GDSCR to wait 4 cycles between states */
regval = readl_relaxed(drv->base + PRONTO_PMU_COMMON_GDSCR)
& PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE;
@@ -311,11 +478,22 @@
writel_relaxed(regval, drv->base + PRONTO_PMU_COMMON_GDSCR);
return 0;
+err_irq:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
+ smsm_state_cb_hdlr, drv);
+err_smsm:
+ msm_pil_unregister(drv->pil);
+ return ret;
}
static int __devexit pil_pronto_remove(struct platform_device *pdev)
{
struct pronto_data *drv = platform_get_drvdata(pdev);
+ subsys_unregister(drv->subsys);
+ smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
+ smsm_state_cb_hdlr, drv);
msm_pil_unregister(drv->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index ed072ea..c48ea02 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -18,14 +18,39 @@
#include <linux/err.h>
#include <linux/of.h>
#include <linux/clk.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
#include <mach/clk.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+
#include "peripheral-loader.h"
#include "pil-q6v5.h"
#include "scm-pas.h"
+#include "ramdump.h"
+#include "sysmon.h"
#define QDSP6SS_RST_EVB 0x010
#define PROXY_TIMEOUT_MS 10000
+struct lpass_data {
+ struct q6v5_data *q6;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+ void *ramdump_dev;
+ int wdog_irq;
+ struct work_struct work;
+ void *riva_notif_hdle;
+ void *modem_notif_hdle;
+ int crash_shutdown;
+};
+
+#define subsys_to_drv(d) container_of(d, struct lpass_data, subsys_desc)
+
static int pil_lpass_enable_clks(struct q6v5_data *drv)
{
int ret;
@@ -71,7 +96,7 @@
static int pil_lpass_shutdown(struct pil_desc *pil)
{
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
pil_q6v5_halt_axi_port(pil, drv->axi_halt_base);
@@ -93,7 +118,7 @@
static int pil_lpass_reset(struct pil_desc *pil)
{
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
int ret;
ret = pil_lpass_enable_clks(drv);
@@ -147,38 +172,211 @@
.shutdown = pil_lpass_shutdown_trusted,
};
+static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *ss_handle)
+{
+ int ret;
+ switch (code) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ pr_debug("%s: R-Notify: Shutdown started\n", __func__);
+ ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
+ SUBSYS_BEFORE_SHUTDOWN);
+ if (ret < 0)
+ pr_err("%s: sysmon_send_event error %d", __func__, ret);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block rnb = {
+ .notifier_call = riva_notifier_cb,
+};
+
+static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *ss_handle)
+{
+ int ret;
+ switch (code) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ pr_debug("%s: M-Notify: Shutdown started\n", __func__);
+ ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
+ SUBSYS_BEFORE_SHUTDOWN);
+ if (ret < 0)
+ pr_err("%s: sysmon_send_event error %d", __func__, ret);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block mnb = {
+ .notifier_call = modem_notifier_cb,
+};
+
+static void adsp_log_failure_reason(void)
+{
+ char *reason;
+ char buffer[81];
+ unsigned size;
+
+ reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
+
+ if (!reason) {
+ pr_err("ADSP subsystem failure reason: (unknown, smem_get_entry failed).");
+ return;
+ }
+
+ if (reason[0] == '\0') {
+ pr_err("ADSP subsystem failure reason: (unknown, init value found)");
+ return;
+ }
+
+ size = min(size, sizeof(buffer) - 1);
+ memcpy(buffer, reason, size);
+ buffer[size] = '\0';
+ pr_err("ADSP subsystem failure reason: %s", buffer);
+ memset((void *)reason, 0x0, size);
+ wmb();
+}
+
+static void restart_adsp(struct lpass_data *drv)
+{
+ adsp_log_failure_reason();
+ subsystem_restart_dev(drv->subsys);
+}
+
+static void adsp_fatal_fn(struct work_struct *work)
+{
+ struct lpass_data *drv = container_of(work, struct lpass_data, work);
+
+ pr_err("Watchdog bite received from ADSP!\n");
+ restart_adsp(drv);
+}
+
+static void adsp_smsm_state_cb(void *data, uint32_t old_state,
+ uint32_t new_state)
+{
+ struct lpass_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("%s: ADSP SMSM state changed to SMSM_RESET, new_state = %#x, old_state = %#x\n",
+ __func__, new_state, old_state);
+ restart_adsp(drv);
+ }
+}
+
+#define SCM_Q6_NMI_CMD 0x1
+
+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);
+ pr_debug("%s: Q6 NMI was sent.\n", __func__);
+}
+
+#define subsys_to_lpass(d) container_of(d, struct lpass_data, subsys_desc)
+
+static int adsp_shutdown(const struct subsys_desc *subsys)
+{
+ struct lpass_data *drv = subsys_to_lpass(subsys);
+
+ send_q6_nmi();
+ /* The write needs to go through before the q6 is shutdown. */
+ mb();
+ pil_force_shutdown("adsp");
+ disable_irq_nosync(drv->wdog_irq);
+
+ return 0;
+}
+
+static int adsp_powerup(const struct subsys_desc *subsys)
+{
+ struct lpass_data *drv = subsys_to_lpass(subsys);
+ int ret = 0;
+
+ if (get_restart_level() == RESET_SUBSYS_INDEPENDENT) {
+ pr_debug("%s: Wait for ADSP power up!", __func__);
+ msleep(10000);
+ }
+
+ ret = pil_force_boot("adsp");
+ enable_irq(drv->wdog_irq);
+
+ return ret;
+}
+
+static struct ramdump_segment segments = { 0xdc00000, 0x1800000 };
+
+static int adsp_ramdump(int enable, const struct subsys_desc *subsys)
+{
+ struct lpass_data *drv = subsys_to_lpass(subsys);
+
+ if (!enable)
+ return 0;
+ return do_ramdump(drv->ramdump_dev, &segments, 1);
+}
+
+static void adsp_crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct lpass_data *drv = subsys_to_lpass(subsys);
+
+ drv->crash_shutdown = 1;
+ send_q6_nmi();
+}
+
+static irqreturn_t adsp_wdog_bite_irq(int irq, void *dev_id)
+{
+ struct lpass_data *drv = dev_id;
+
+ disable_irq_nosync(drv->wdog_irq);
+ schedule_work(&drv->work);
+
+ return IRQ_HANDLED;
+}
+
static int __devinit pil_lpass_driver_probe(struct platform_device *pdev)
{
- struct q6v5_data *drv;
+ struct lpass_data *drv;
+ struct q6v5_data *q6;
struct pil_desc *desc;
+ int ret;
- desc = pil_q6v5_init(pdev);
- if (IS_ERR(desc))
- return PTR_ERR(desc);
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
- drv = platform_get_drvdata(pdev);
- if (drv == NULL)
- return -ENODEV;
+ drv->wdog_irq = platform_get_irq(pdev, 0);
+ if (drv->wdog_irq < 0)
+ return drv->wdog_irq;
- desc->ops = &pil_lpass_ops;
+ q6 = pil_q6v5_init(pdev);
+ if (IS_ERR(q6))
+ return PTR_ERR(q6);
+ drv->q6 = q6;
+
+ desc = &q6->desc;
desc->owner = THIS_MODULE;
desc->proxy_timeout = PROXY_TIMEOUT_MS;
- drv->core_clk = devm_clk_get(&pdev->dev, "core_clk");
- if (IS_ERR(drv->core_clk))
- return PTR_ERR(drv->core_clk);
+ q6->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+ if (IS_ERR(q6->core_clk))
+ return PTR_ERR(q6->core_clk);
- drv->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
- if (IS_ERR(drv->ahb_clk))
- return PTR_ERR(drv->ahb_clk);
+ q6->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
+ if (IS_ERR(q6->ahb_clk))
+ return PTR_ERR(q6->ahb_clk);
- drv->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
- if (IS_ERR(drv->axi_clk))
- return PTR_ERR(drv->axi_clk);
+ q6->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
+ if (IS_ERR(q6->axi_clk))
+ return PTR_ERR(q6->axi_clk);
- drv->reg_clk = devm_clk_get(&pdev->dev, "reg_clk");
- if (IS_ERR(drv->reg_clk))
- return PTR_ERR(drv->reg_clk);
+ q6->reg_clk = devm_clk_get(&pdev->dev, "reg_clk");
+ if (IS_ERR(q6->reg_clk))
+ return PTR_ERR(q6->reg_clk);
if (pas_supported(PAS_Q6) > 0) {
desc->ops = &pil_lpass_ops_trusted;
@@ -188,17 +386,79 @@
dev_info(&pdev->dev, "using non-secure boot\n");
}
- drv->pil = msm_pil_register(desc);
- if (IS_ERR(drv->pil))
- return PTR_ERR(drv->pil);
+ drv->q6->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->q6->pil))
+ return PTR_ERR(drv->q6->pil);
+ drv->subsys_desc.name = desc->name;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.shutdown = adsp_shutdown;
+ drv->subsys_desc.powerup = adsp_powerup;
+ drv->subsys_desc.ramdump = adsp_ramdump;
+ drv->subsys_desc.crash_shutdown = adsp_crash_shutdown;
+
+ INIT_WORK(&drv->work, adsp_fatal_fn);
+
+ drv->ramdump_dev = create_ramdump_device("adsp");
+ 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->wdog_irq, adsp_wdog_bite_irq,
+ IRQF_TRIGGER_RISING, dev_name(&pdev->dev), drv);
+ if (ret)
+ goto err_irq;
+
+ ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
+ adsp_smsm_state_cb, drv);
+ if (ret < 0)
+ goto err_smsm;
+
+ drv->riva_notif_hdle = subsys_notif_register_notifier("riva", &rnb);
+ if (IS_ERR(drv->riva_notif_hdle)) {
+ ret = PTR_ERR(drv->riva_notif_hdle);
+ goto err_notif_riva;
+ }
+
+ drv->modem_notif_hdle = subsys_notif_register_notifier("modem", &mnb);
+ if (IS_ERR(drv->modem_notif_hdle)) {
+ ret = PTR_ERR(drv->modem_notif_hdle);
+ goto err_notif_modem;
+ }
+ return 0;
+err_notif_modem:
+ subsys_notif_unregister_notifier(drv->riva_notif_hdle, &rnb);
+err_notif_riva:
+ smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
+ adsp_smsm_state_cb, drv);
+err_smsm:
+err_irq:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ msm_pil_unregister(drv->q6->pil);
return 0;
}
static int __devexit pil_lpass_driver_exit(struct platform_device *pdev)
{
- struct q6v5_data *drv = platform_get_drvdata(pdev);
- msm_pil_unregister(drv->pil);
+ struct lpass_data *drv = platform_get_drvdata(pdev);
+ subsys_notif_unregister_notifier(drv->riva_notif_hdle, &rnb);
+ subsys_notif_unregister_notifier(drv->modem_notif_hdle, &mnb);
+ smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
+ adsp_smsm_state_cb, drv);
+ subsys_unregister(drv->subsys);
+ destroy_ramdump_device(drv->ramdump_dev);
+ msm_pil_unregister(drv->q6->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 9ff1234..f3c731f 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -57,10 +57,10 @@
static int pbl_mba_boot_timeout_ms = 100;
module_param(pbl_mba_boot_timeout_ms, int, S_IRUGO | S_IWUSR);
-static int pil_mss_power_up(struct device *dev)
+static int pil_mss_power_up(struct q6v5_data *drv)
{
int ret;
- struct q6v5_data *drv = dev_get_drvdata(dev);
+ struct device *dev = drv->desc.dev;
ret = regulator_enable(drv->vreg);
if (ret)
@@ -69,10 +69,8 @@
return ret;
}
-static int pil_mss_power_down(struct device *dev)
+static int pil_mss_power_down(struct q6v5_data *drv)
{
- struct q6v5_data *drv = dev_get_drvdata(dev);
-
return regulator_disable(drv->vreg);
}
@@ -107,9 +105,9 @@
clk_disable_unprepare(drv->ahb_clk);
}
-static int wait_for_mba_ready(struct device *dev)
+static int wait_for_mba_ready(struct q6v5_data *drv)
{
- struct q6v5_data *drv = dev_get_drvdata(dev);
+ struct device *dev = drv->desc.dev;
int ret;
u32 status;
@@ -143,7 +141,7 @@
static int pil_mss_shutdown(struct pil_desc *pil)
{
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_Q6_HALT_BASE);
pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_MODEM_HALT_BASE);
@@ -155,13 +153,13 @@
* writes performed during the shutdown succeed.
*/
if (drv->is_booted == false) {
- pil_mss_power_up(pil->dev);
+ pil_mss_power_up(drv);
pil_mss_enable_clks(drv);
}
pil_q6v5_shutdown(pil);
pil_mss_disable_clks(drv);
- pil_mss_power_down(pil->dev);
+ pil_mss_power_down(drv);
writel_relaxed(1, drv->restart_reg);
@@ -172,7 +170,7 @@
static int pil_mss_reset(struct pil_desc *pil)
{
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
int ret;
/* Deassert reset to subsystem and wait for propagation */
@@ -184,7 +182,7 @@
* Bring subsystem out of reset and enable required
* regulators and clocks.
*/
- ret = pil_mss_power_up(pil->dev);
+ ret = pil_mss_power_up(drv);
if (ret)
goto err_power;
@@ -211,7 +209,7 @@
/* Wait for MBA to start. Check for PBL and MBA errors while waiting. */
if (drv->self_auth) {
- ret = wait_for_mba_ready(pil->dev);
+ ret = wait_for_mba_ready(drv);
if (ret)
goto err_auth;
}
@@ -225,7 +223,7 @@
err_q6v5_reset:
pil_mss_disable_clks(drv);
err_clks:
- pil_mss_power_down(pil->dev);
+ pil_mss_power_down(drv);
err_power:
return ret;
}
@@ -245,13 +243,12 @@
struct resource *res;
int ret;
- desc = pil_q6v5_init(pdev);
- if (IS_ERR(desc))
- return PTR_ERR(desc);
- drv = platform_get_drvdata(pdev);
- if (drv == NULL)
- return -ENODEV;
+ drv = pil_q6v5_init(pdev);
+ if (IS_ERR(drv))
+ return PTR_ERR(drv);
+ platform_set_drvdata(pdev, drv);
+ desc = &drv->desc;
desc->ops = &pil_mss_ops;
desc->owner = THIS_MODULE;
desc->proxy_timeout = PROXY_TIMEOUT_MS;
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index f4e8844..70a12de 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -61,7 +61,7 @@
int pil_q6v5_make_proxy_votes(struct pil_desc *pil)
{
int ret;
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
ret = clk_prepare_enable(drv->xo);
if (ret) {
@@ -74,7 +74,7 @@
void pil_q6v5_remove_proxy_votes(struct pil_desc *pil)
{
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
clk_disable_unprepare(drv->xo);
}
EXPORT_SYMBOL(pil_q6v5_remove_proxy_votes);
@@ -104,7 +104,7 @@
size_t size)
{
const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
drv->start_addr = ehdr->e_entry;
return 0;
}
@@ -113,7 +113,7 @@
void pil_q6v5_shutdown(struct pil_desc *pil)
{
u32 val;
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
/* Turn off core clock */
val = readl_relaxed(drv->reg_base + QDSP6SS_GFMUX_CTL);
@@ -145,7 +145,7 @@
int pil_q6v5_reset(struct pil_desc *pil)
{
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
u32 val;
/* Assert resets, stop core */
@@ -193,7 +193,7 @@
}
EXPORT_SYMBOL(pil_q6v5_reset);
-struct pil_desc __devinit *pil_q6v5_init(struct platform_device *pdev)
+struct q6v5_data __devinit *pil_q6v5_init(struct platform_device *pdev)
{
struct q6v5_data *drv;
struct resource *res;
@@ -203,7 +203,6 @@
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return ERR_PTR(-ENOMEM);
- platform_set_drvdata(pdev, drv);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6_base");
if (!res)
@@ -218,10 +217,7 @@
if (!drv->axi_halt_base)
return ERR_PTR(-ENOMEM);
- desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
- if (!desc)
- return ERR_PTR(-ENOMEM);
-
+ desc = &drv->desc;
ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
&desc->name);
if (ret)
@@ -233,6 +229,6 @@
desc->dev = &pdev->dev;
- return desc;
+ return drv;
}
EXPORT_SYMBOL(pil_q6v5_init);
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index 03f93fa..f176d2d 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -13,10 +13,11 @@
#ifndef __MSM_PIL_Q6V5_H
#define __MSM_PIL_Q6V5_H
+#include "peripheral-loader.h"
+
struct regulator;
struct clk;
struct pil_device;
-struct pil_desc;
struct platform_device;
struct q6v5_data {
@@ -36,6 +37,7 @@
bool is_booted;
int self_auth;
struct pil_device *pil;
+ struct pil_desc desc;
};
int pil_q6v5_make_proxy_votes(struct pil_desc *pil);
@@ -45,6 +47,6 @@
size_t size);
void pil_q6v5_shutdown(struct pil_desc *pil);
int pil_q6v5_reset(struct pil_desc *pil);
-struct pil_desc *pil_q6v5_init(struct platform_device *pdev);
+struct q6v5_data *pil_q6v5_init(struct platform_device *pdev);
#endif
diff --git a/arch/arm/mach-msm/wcnss-ssr-8974.c b/arch/arm/mach-msm/wcnss-ssr-8974.c
deleted file mode 100644
index 8841b52..0000000
--- a/arch/arm/mach-msm/wcnss-ssr-8974.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/workqueue.h>
-#include <linux/wcnss_wlan.h>
-#include <linux/delay.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/msm_smsm.h>
-
-#define MODULE_NAME "wcnss_8974"
-#define MAX_SSR_REASON_LEN 0x51
-
-static int ss_restart_inprogress;
-static int wcnss_crash;
-static struct subsys_device *wcnss_ssr_dev;
-static struct delayed_work cancel_vote_work;
-
-#define WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ 181
-
-static void log_wcnss_sfr(void)
-{
- char *smem_reset_reason;
- char buffer[MAX_SSR_REASON_LEN];
- unsigned smem_reset_size;
- unsigned size;
-
- smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
- &smem_reset_size);
-
- if (!smem_reset_reason || !smem_reset_size) {
- pr_err("%s: wcnss subsystem failure reason: %s\n",
- __func__, "(unknown, smem_get_entry failed)");
- } else if (!smem_reset_reason[0]) {
- pr_err("%s: wcnss subsystem failure reason: %s\n",
- __func__, "(unknown, init string found)");
- } else {
- size = smem_reset_size < MAX_SSR_REASON_LEN ? smem_reset_size :
- (MAX_SSR_REASON_LEN - 1);
- memcpy(buffer, smem_reset_reason, size);
- buffer[size] = '\0';
- pr_err("%s: wcnss subsystem failure reason: %s\n",
- __func__, buffer);
- memset(smem_reset_reason, 0, smem_reset_size);
- wmb();
- }
-}
-
-static void restart_wcnss(void)
-{
- log_wcnss_sfr();
- subsystem_restart("wcnss");
-}
-
-static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
- uint32_t new_state)
-{
- wcnss_crash = true;
-
- pr_err("%s: smsm state changed\n", MODULE_NAME);
-
- if (!(new_state & SMSM_RESET))
- return;
-
- if (ss_restart_inprogress) {
- pr_err("%s: Ignoring smsm reset req, restart in progress\n",
- MODULE_NAME);
- return;
- }
-
- ss_restart_inprogress = true;
- restart_wcnss();
-}
-
-
-static irqreturn_t wcnss_wdog_bite_irq_hdlr(int irq, void *dev_id)
-{
- wcnss_crash = true;
-
- if (ss_restart_inprogress) {
- pr_err("%s: Ignoring wcnss bite irq, restart in progress\n",
- MODULE_NAME);
- return IRQ_HANDLED;
- }
-
- ss_restart_inprogress = true;
- restart_wcnss();
-
- return IRQ_HANDLED;
-}
-
-static void wcnss_post_bootup(struct work_struct *work)
-{
- struct platform_device *pdev = wcnss_get_platform_device();
- struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
-
- pr_debug(MODULE_NAME ": Cancel APPS vote for Iris & Pronto\n");
-
- wcnss_wlan_power(&pdev->dev, pwlanconfig,
- WCNSS_WLAN_SWITCH_OFF);
-}
-
-static int wcnss_shutdown(const struct subsys_desc *subsys)
-{
- pil_force_shutdown("wcnss");
- flush_delayed_work(&cancel_vote_work);
- wcnss_flush_delayed_boot_votes();
- disable_irq_nosync(WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ);
-
- return 0;
-}
-
-static int wcnss_powerup(const struct subsys_desc *subsys)
-{
- struct platform_device *pdev = wcnss_get_platform_device();
- struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
- int ret = -1;
-
- if (pdev && pwlanconfig)
- ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
- WCNSS_WLAN_SWITCH_ON);
- if (!ret) {
- msleep(1000);
- pil_force_boot("wcnss");
- }
- ss_restart_inprogress = false;
- enable_irq(WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ);
- schedule_delayed_work(&cancel_vote_work, msecs_to_jiffies(5000));
-
- return 0;
-}
-
-/* wcnss crash handler */
-static void wcnss_crash_shutdown(const struct subsys_desc *subsys)
-{
- pr_err("%s: crash shutdown : %d\n", MODULE_NAME, wcnss_crash);
- if (wcnss_crash != true)
- smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
-}
-
-static int wcnss_ramdump(int enable,
- const struct subsys_desc *crashed_subsys)
-{
- return 0;
-}
-
-static struct subsys_desc wcnss_ssr = {
- .name = "wcnss",
- .shutdown = wcnss_shutdown,
- .powerup = wcnss_powerup,
- .ramdump = wcnss_ramdump,
- .crash_shutdown = wcnss_crash_shutdown
-};
-
-static int __init wcnss_ssr_init(void)
-{
- int ret;
-
- ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
- smsm_state_cb_hdlr, 0);
- if (ret < 0) {
- pr_err("%s: Unable to register smsm callback for wcnss Reset! %d\n",
- MODULE_NAME, ret);
- goto out;
- }
- ret = request_irq(WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ,
- wcnss_wdog_bite_irq_hdlr, IRQF_TRIGGER_HIGH,
- "wcnss_wdog", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to register for wcnss bite interrupt (%d)\n",
- MODULE_NAME, ret);
- goto out;
- }
- wcnss_ssr_dev = subsys_register(&wcnss_ssr);
- if (IS_ERR(wcnss_ssr_dev))
- return PTR_ERR(wcnss_ssr_dev);
-
- INIT_DELAYED_WORK(&cancel_vote_work, wcnss_post_bootup);
-
- pr_info("%s: module initialized\n", MODULE_NAME);
-out:
- return ret;
-}
-
-arch_initcall(wcnss_ssr_init);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 4eca776..41fd7aa 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2263,7 +2263,7 @@
static uint io_cnt;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- struct adreno_context *adreno_ctx = context->devctxt;
+ struct adreno_context *adreno_ctx = context ? context->devctxt : NULL;
int retries = 0;
unsigned int ts_issued;
unsigned int context_id = _get_context_id(context);
@@ -2286,7 +2286,8 @@
* again after 'retry_ts_cmp_msecs' milliseconds.
*/
if (timestamp_cmp(timestamp, ts_issued) > 0) {
- if (!(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS)) {
+ if (adreno_ctx == NULL ||
+ !(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS)) {
KGSL_DRV_ERR(device,
"Cannot wait for invalid ts <%d:0x%x>, "
"last issued ts <%d:0x%x>\n",
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 0b1a16e..f596411 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -700,11 +700,19 @@
return mbim_bind_config(c, 0);
}
+static int mbim_function_ctrlrequest(struct android_usb_function *f,
+ struct usb_composite_dev *cdev,
+ const struct usb_ctrlrequest *c)
+{
+ return mbim_ctrlrequest(cdev, c);
+}
+
static struct android_usb_function mbim_function = {
.name = "usb_mbim",
.cleanup = mbim_function_cleanup,
.bind_config = mbim_function_bind_config,
.init = mbim_function_init,
+ .ctrlrequest = mbim_function_ctrlrequest,
};
#ifdef CONFIG_SND_PCM
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index b3cab7a..fa1bf43 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2406,7 +2406,8 @@
* bits. This is a temporary workaround till
* HW designers come back on this.
*/
- if (retval == -EBUSY && req_dequeue && mEp->dir == 0) {
+ if (retval == -EBUSY && req_dequeue &&
+ (mEp->dir == 0 || mEp->num == 0)) {
req_dequeue = 0;
udc->dTD_update_fail_count++;
mEp->dTD_update_fail_count++;
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 7a84ca3..681435a 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -19,7 +19,6 @@
#include <linux/usb/cdc.h>
#include <linux/usb/composite.h>
-#include <linux/usb/android_composite.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
@@ -41,6 +40,9 @@
#define NR_MBIM_PORTS 1
+/* ID for Microsoft OS String */
+#define MBIM_OS_STRING_ID 0xEE
+
struct ctrl_pkt {
void *buf;
int len;
@@ -356,6 +358,63 @@
NULL,
};
+/* Microsoft OS Descriptors */
+
+/*
+ * We specify our own bMS_VendorCode byte which Windows will use
+ * as the bRequest value in subsequent device get requests.
+ */
+#define MBIM_VENDOR_CODE 0xA5
+
+/* Microsoft OS String */
+static u8 mbim_os_string[] = {
+ 18, /* sizeof(mtp_os_string) */
+ USB_DT_STRING,
+ /* Signature field: "MSFT100" */
+ 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0,
+ /* vendor code */
+ MBIM_VENDOR_CODE,
+ /* padding */
+ 0
+};
+
+/* Microsoft Extended Configuration Descriptor Header Section */
+struct mbim_ext_config_desc_header {
+ __le32 dwLength;
+ __u16 bcdVersion;
+ __le16 wIndex;
+ __u8 bCount;
+ __u8 reserved[7];
+};
+
+/* Microsoft Extended Configuration Descriptor Function Section */
+struct mbim_ext_config_desc_function {
+ __u8 bFirstInterfaceNumber;
+ __u8 bInterfaceCount;
+ __u8 compatibleID[8];
+ __u8 subCompatibleID[8];
+ __u8 reserved[6];
+};
+
+/* Microsoft Extended Configuration Descriptor */
+static struct {
+ struct mbim_ext_config_desc_header header;
+ struct mbim_ext_config_desc_function function;
+} mbim_ext_config_desc = {
+ .header = {
+ .dwLength = __constant_cpu_to_le32(sizeof mbim_ext_config_desc),
+ .bcdVersion = __constant_cpu_to_le16(0x0100),
+ .wIndex = __constant_cpu_to_le16(4),
+ .bCount = 1,
+ },
+ .function = {
+ .bFirstInterfaceNumber = 0,
+ .bInterfaceCount = 1,
+ .compatibleID = { 'A', 'L', 'T', 'R', 'C', 'F', 'G' },
+ /* .subCompatibleID = DYNAMIC */
+ },
+};
+
/*
* Here are options for the Datagram Pointer table (NDP) parser.
* There are 2 different formats: NDP16 and NDP32 in the spec (ch. 3),
@@ -1108,6 +1167,63 @@
return value;
}
+/*
+ * This function handles the Microsoft-specific OS descriptor control
+ * requests that are issued by Windows host drivers to determine the
+ * configuration containing the MBIM function.
+ *
+ * Unlike mbim_setup() this function handles two specific device requests,
+ * and only when a configuration has not yet been selected.
+ */
+static int mbim_ctrlrequest(struct usb_composite_dev *cdev,
+ const struct usb_ctrlrequest *ctrl)
+{
+ int value = -EOPNOTSUPP;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ /* only respond to OS desciptors when no configuration selected */
+ if (cdev->config || !mbim_ext_config_desc.function.subCompatibleID[0])
+ return value;
+
+ pr_debug("%02x.%02x v%04x i%04x l%u",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+
+ /* Handle MSFT OS string */
+ if (ctrl->bRequestType ==
+ (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)
+ && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR
+ && (w_value >> 8) == USB_DT_STRING
+ && (w_value & 0xFF) == MBIM_OS_STRING_ID) {
+
+ value = (w_length < sizeof(mbim_os_string) ?
+ w_length : sizeof(mbim_os_string));
+ memcpy(cdev->req->buf, mbim_os_string, value);
+
+ } else if (ctrl->bRequestType ==
+ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+ && ctrl->bRequest == MBIM_VENDOR_CODE && w_index == 4) {
+
+ /* Handle Extended OS descriptor */
+ value = (w_length < sizeof(mbim_ext_config_desc) ?
+ w_length : sizeof(mbim_ext_config_desc));
+ memcpy(cdev->req->buf, &mbim_ext_config_desc, value);
+ }
+
+ /* respond with data transfer or status phase? */
+ if (value >= 0) {
+ int rc;
+ cdev->req->zero = value < w_length;
+ cdev->req->length = value;
+ rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
+ if (rc < 0)
+ pr_err("response queue error: %d", rc);
+ }
+ return value;
+}
+
static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct f_mbim *mbim = func_to_mbim(f);
@@ -1371,6 +1487,17 @@
goto fail;
}
+ /*
+ * If MBIM is bound in a config other than the first, tell Windows
+ * about it by returning the num as a string in the OS descriptor's
+ * subCompatibleID field. Windows only supports up to config #4.
+ */
+ if (c->bConfigurationValue >= 2 && c->bConfigurationValue <= 4) {
+ pr_debug("MBIM in configuration %d", c->bConfigurationValue);
+ mbim_ext_config_desc.function.subCompatibleID[0] =
+ c->bConfigurationValue + '0';
+ }
+
pr_info("mbim(%d): %s speed IN/%s OUT/%s NOTIFY/%s\n",
mbim->port_num,
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
@@ -1412,6 +1539,8 @@
kfree(mbim->not_port.notify_req->buf);
usb_ep_free_request(mbim->not_port.notify, mbim->not_port.notify_req);
+
+ mbim_ext_config_desc.function.subCompatibleID[0] = 0;
}
/**