Merge "msm: pil-modem: Combine SSR and PIL drivers"
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index d7872c3..157f159 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1903,7 +1903,7 @@
 
 config MSM_PIL_MODEM
 	tristate "Modem (ARM11) Boot Support"
-	depends on MSM_PIL
+	depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
 	help
 	  Support for booting and shutting down ARM11 Modem processors.
 
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 3b4cb47..1b42d2d 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -195,7 +195,7 @@
 	obj-y += subsystem_notif.o
 	obj-y += subsystem_restart.o
 	obj-y += ramdump.o
-	obj-$(CONFIG_ARCH_MSM8X60) += modem-8660.o lpass-8660.o
+	obj-$(CONFIG_ARCH_MSM8X60) += lpass-8660.o
 endif
 obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
 obj-$(CONFIG_MSM_MODEM_8960) += modem-8960.o
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 7bffd9b..b88fb50 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -210,6 +210,7 @@
 };
 
 #define MSM_MSS_REGS_PHYS 0x10200000
+#define MSM_MSS_WDOG_PHYS 0x10020000
 
 static struct resource msm_8660_modem_resources[] = {
 	{
@@ -217,6 +218,16 @@
 		.end    = MSM_MSS_REGS_PHYS + SZ_256 - 1,
 		.flags  = IORESOURCE_MEM,
 	},
+	{
+		.start	= MSM_MSS_WDOG_PHYS,
+		.end	= MSM_MSS_WDOG_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MARM_WDOG_EXPIRED,
+		.end	= MARM_WDOG_EXPIRED,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 struct platform_device msm_pil_modem = {
diff --git a/arch/arm/mach-msm/modem-8660.c b/arch/arm/mach-msm/modem-8660.c
deleted file mode 100644
index 096ed9c..0000000
--- a/arch/arm/mach-msm/modem-8660.c
+++ /dev/null
@@ -1,290 +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 MODEM_HWIO_MSS_RESET_ADDR       0x00902C48
-#define MODULE_NAME			"modem_8660"
-#define MODEM_WDOG_ENABLE		0x10020008
-#define MODEM_CLEANUP_DELAY_MS		20
-
-#define SUBSYS_FATAL_DEBUG
-
-#if defined(SUBSYS_FATAL_DEBUG)
-static void debug_crash_modem_fn(struct work_struct *);
-static int reset_modem;
-static int ignore_smsm_ack;
-
-static DECLARE_DELAYED_WORK(debug_crash_modem_work,
-				debug_crash_modem_fn);
-
-module_param(reset_modem, int, 0644);
-#endif
-
-static struct subsys_device *modem_8660_dev;
-
-/* Subsystem restart: Modem data, functions */
-static void *modem_ramdump_dev;
-static void modem_fatal_fn(struct work_struct *);
-static void modem_unlock_timeout(struct work_struct *work);
-static int modem_notif_handler(struct notifier_block *this,
-				unsigned long code,
-				void *_cmd);
-static DECLARE_WORK(modem_fatal_work, modem_fatal_fn);
-static DECLARE_DELAYED_WORK(modem_unlock_timeout_work,
-				modem_unlock_timeout);
-
-static struct notifier_block modem_notif_nb = {
-	.notifier_call = modem_notif_handler,
-};
-
-static void modem_unlock_timeout(struct work_struct *work)
-{
-	void __iomem *hwio_modem_reset_addr =
-			ioremap_nocache(MODEM_HWIO_MSS_RESET_ADDR, 8);
-	pr_crit("%s: Timeout waiting for modem to unlock.\n", MODULE_NAME);
-
-	/* Set MSS_MODEM_RESET to 0x0 since the unlock didn't work */
-	writel_relaxed(0x0, hwio_modem_reset_addr);
-	/* Write needs to go through before the modem is restarted. */
-	mb();
-	iounmap(hwio_modem_reset_addr);
-
-	subsystem_restart_dev(modem_8660_dev);
-	enable_irq(MARM_WDOG_EXPIRED);
-}
-
-static void modem_fatal_fn(struct work_struct *work)
-{
-	uint32_t modem_state;
-	uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
-	uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR |
-					SMSM_SYSTEM_PWRDWN_USR;
-
-	pr_err("%s: Watchdog bite received from modem!\n", MODULE_NAME);
-
-	modem_state = smsm_get_state(SMSM_MODEM_STATE);
-	pr_err("%s: Modem SMSM state = 0x%x!", MODULE_NAME, modem_state);
-
-	if (modem_state == 0 || modem_state & panic_smsm_states) {
-
-		subsystem_restart_dev(modem_8660_dev);
-		enable_irq(MARM_WDOG_EXPIRED);
-
-	} else if (modem_state & reset_smsm_states) {
-
-		pr_err("%s: User-invoked system reset/powerdown.",
-			MODULE_NAME);
-		kernel_restart(NULL);
-
-	} else {
-
-		int ret;
-		void *hwio_modem_reset_addr =
-				ioremap_nocache(MODEM_HWIO_MSS_RESET_ADDR, 8);
-
-		pr_err("%s: Modem AHB locked up.\n", MODULE_NAME);
-		pr_err("%s: Trying to free up modem!\n", MODULE_NAME);
-
-		writel_relaxed(0x3, hwio_modem_reset_addr);
-
-		/* If we are still alive after 6 seconds (allowing for
-		 * the 5-second-delayed-panic-reboot), modem is either
-		 * still wedged or SMSM didn't come through. Force panic
-		 * in that case.
-		*/
-		ret = schedule_delayed_work(&modem_unlock_timeout_work,
-					msecs_to_jiffies(6000));
-
-		iounmap(hwio_modem_reset_addr);
-	}
-}
-
-static int modem_notif_handler(struct notifier_block *this,
-				unsigned long code,
-				void *_cmd)
-{
-	if (code == MODEM_NOTIFIER_START_RESET) {
-		if (ignore_smsm_ack) {
-			ignore_smsm_ack = 0;
-			goto out;
-		}
-		pr_err("%s: Modem error fatal'ed.", MODULE_NAME);
-		subsystem_restart_dev(modem_8660_dev);
-	}
-out:
-	return NOTIFY_DONE;
-}
-
-static int modem_shutdown(const struct subsys_desc *crashed_subsys)
-{
-	void __iomem *modem_wdog_addr;
-
-	/* If the modem didn't already crash, setting SMSM_RESET
-	 * here will help flush caches etc. The ignore_smsm_ack
-	 * flag is set to ignore the SMSM_RESET notification
-	 * that is generated due to the modem settings its own
-	 * SMSM_RESET bit in response to the apps setting the
-	 * apps SMSM_RESET bit.
-	 */
-	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
-		ignore_smsm_ack = 1;
-		smsm_reset_modem(SMSM_RESET);
-	}
-
-	/* Disable the modem watchdog to allow clean modem bootup */
-	modem_wdog_addr = ioremap_nocache(MODEM_WDOG_ENABLE, 8);
-	writel_relaxed(0x0, modem_wdog_addr);
-
-	/*
-	 * The write above needs to go through before the modem is
-	 * powered up again (subsystem restart).
-	 */
-	mb();
-	iounmap(modem_wdog_addr);
-
-	/* Wait here to allow the modem to clean up caches etc. */
-	msleep(MODEM_CLEANUP_DELAY_MS);
-	pil_force_shutdown("modem");
-	disable_irq_nosync(MARM_WDOG_EXPIRED);
-
-
-
-	return 0;
-}
-
-static int modem_powerup(const struct subsys_desc *crashed_subsys)
-{
-	int ret;
-
-	ret = pil_force_boot("modem");
-	enable_irq(MARM_WDOG_EXPIRED);
-
-	return ret;
-}
-
-/* FIXME: Get address, size from PIL */
-static struct ramdump_segment modem_segments[] = {
-	{0x42F00000, 0x46000000 - 0x42F00000} };
-
-static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
-{
-	if (enable)
-		return do_ramdump(modem_ramdump_dev, modem_segments,
-			ARRAY_SIZE(modem_segments));
-	else
-		return 0;
-}
-
-static void modem_crash_shutdown(const struct subsys_desc *crashed_subsys)
-{
-	/* If modem hasn't already crashed, send SMSM_RESET. */
-	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
-		modem_unregister_notifier(&modem_notif_nb);
-		smsm_reset_modem(SMSM_RESET);
-	}
-
-	/* Wait to allow the modem to clean up caches etc. */
-	mdelay(5);
-}
-
-static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
-{
-	int ret;
-
-	ret = schedule_work(&modem_fatal_work);
-	disable_irq_nosync(MARM_WDOG_EXPIRED);
-
-	return IRQ_HANDLED;
-}
-
-static struct subsys_desc subsys_8660_modem = {
-	.name = "modem",
-	.shutdown = modem_shutdown,
-	.powerup = modem_powerup,
-	.ramdump = modem_ramdump,
-	.crash_shutdown = modem_crash_shutdown
-};
-
-static int __init modem_8660_init(void)
-{
-	int ret;
-
-	/* Need to listen for SMSM_RESET always */
-	modem_register_notifier(&modem_notif_nb);
-
-#if defined(SUBSYS_FATAL_DEBUG)
-	schedule_delayed_work(&debug_crash_modem_work, msecs_to_jiffies(5000));
-#endif
-
-	ret = request_irq(MARM_WDOG_EXPIRED, modem_wdog_bite_irq,
-			IRQF_TRIGGER_RISING, "modem_wdog", NULL);
-
-	if (ret < 0) {
-		pr_err("%s: Unable to request MARM_WDOG_EXPIRED irq.",
-			__func__);
-		goto out;
-	}
-
-	modem_ramdump_dev = create_ramdump_device("modem");
-
-	if (!modem_ramdump_dev) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	modem_8660_dev = subsys_register(&subsys_8660_modem);
-	if (IS_ERR(modem_8660_dev))
-		ret = PTR_ERR(modem_8660_dev);
-out:
-	return ret;
-}
-
-static void __exit modem_8660_exit(void)
-{
-	subsys_unregister(modem_8660_dev);
-	free_irq(MARM_WDOG_EXPIRED, NULL);
-}
-
-#ifdef SUBSYS_FATAL_DEBUG
-static void debug_crash_modem_fn(struct work_struct *work)
-{
-	if (reset_modem == 1)
-		smsm_reset_modem(SMSM_RESET);
-
-	reset_modem = 0;
-	schedule_delayed_work(&debug_crash_modem_work, msecs_to_jiffies(1000));
-}
-#endif
-
-module_init(modem_8660_init);
-module_exit(modem_8660_exit);
-
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
index 8344496..ecb3800 100644
--- a/arch/arm/mach-msm/pil-modem.c
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -19,11 +19,19 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
 
 #include <mach/msm_iomap.h>
+#include <mach/subsystem_restart.h>
+#include <mach/msm_smsm.h>
+#include <mach/peripheral-loader.h>
 
+#include "modem_notifier.h"
 #include "peripheral-loader.h"
 #include "scm-pas.h"
+#include "ramdump.h"
 
 #define MARM_BOOT_CONTROL		0x0010
 #define MARM_RESET			(MSM_CLK_CTL_BASE + 0x2BD4)
@@ -46,12 +54,22 @@
 #define PLL_ENA_MARM			(MSM_CLK_CTL_BASE + 0x3500)
 #define PLL8_STATUS			(MSM_CLK_CTL_BASE + 0x3158)
 #define CLK_HALT_MSS_SMPSS_MISC_STATE	(MSM_CLK_CTL_BASE + 0x2FDC)
+#define MSS_MODEM_RESET			(MSM_CLK_CTL_BASE + 0x2C48)
 
 struct modem_data {
 	void __iomem *base;
+	void __iomem *wdog;
 	unsigned long start_addr;
 	struct pil_device *pil;
 	struct clk *xo;
+	struct notifier_block notifier;
+	int ignore_smsm_ack;
+	int irq;
+	struct subsys_device *subsys;
+	struct subsys_desc subsys_desc;
+	struct delayed_work unlock_work;
+	struct work_struct fatal_work;
+	struct ramdump_device *ramdump_dev;
 };
 
 static int make_modem_proxy_votes(struct pil_desc *pil)
@@ -161,7 +179,7 @@
 	return 0;
 }
 
-static int modem_shutdown(struct pil_desc *pil)
+static int modem_pil_shutdown(struct pil_desc *pil)
 {
 	u32 reg;
 
@@ -203,7 +221,7 @@
 static struct pil_reset_ops pil_modem_ops = {
 	.init_image = modem_init_image,
 	.auth_and_reset = modem_reset,
-	.shutdown = modem_shutdown,
+	.shutdown = modem_pil_shutdown,
 	.proxy_vote = make_modem_proxy_votes,
 	.proxy_unvote = remove_modem_proxy_votes,
 };
@@ -232,11 +250,166 @@
 	.proxy_unvote = remove_modem_proxy_votes,
 };
 
+static void modem_crash_shutdown(const struct subsys_desc *subsys)
+{
+	struct modem_data *drv;
+
+	/* If modem hasn't already crashed, send SMSM_RESET. */
+	drv = container_of(subsys, struct modem_data, subsys_desc);
+	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
+		modem_unregister_notifier(&drv->notifier);
+		smsm_reset_modem(SMSM_RESET);
+	}
+
+	/* Wait to allow the modem to clean up caches etc. */
+	mdelay(5);
+}
+
+static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
+{
+	struct modem_data *drv = dev_id;
+
+	schedule_work(&drv->fatal_work);
+	disable_irq_nosync(drv->irq);
+
+	return IRQ_HANDLED;
+}
+
+static void modem_unlock_timeout(struct work_struct *work)
+{
+	struct modem_data *drv;
+	struct delayed_work *dwork = to_delayed_work(work);
+
+	pr_crit("Timeout waiting for modem to unlock.\n");
+
+	drv = container_of(dwork, struct modem_data, unlock_work);
+	/* The unlock didn't work, clear the reset */
+	writel_relaxed(0x0, MSS_MODEM_RESET);
+	mb();
+
+	subsystem_restart_dev(drv->subsys);
+	enable_irq(drv->irq);
+}
+
+static void modem_fatal_fn(struct work_struct *work)
+{
+	u32 modem_state;
+	u32 panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
+	u32 reset_smsm_states = SMSM_SYSTEM_REBOOT_USR | SMSM_SYSTEM_PWRDWN_USR;
+	struct modem_data *drv;
+
+	drv = container_of(work, struct modem_data, fatal_work);
+
+	pr_err("Watchdog bite received from modem!\n");
+
+	modem_state = smsm_get_state(SMSM_MODEM_STATE);
+	pr_err("Modem SMSM state = 0x%x!\n", modem_state);
+
+	if (modem_state == 0 || modem_state & panic_smsm_states) {
+		subsystem_restart_dev(drv->subsys);
+		enable_irq(drv->irq);
+	} else if (modem_state & reset_smsm_states) {
+		pr_err("User-invoked system reset/powerdown.");
+		kernel_restart(NULL);
+	} else {
+		unsigned long timeout = msecs_to_jiffies(6000);
+
+		pr_err("Modem AHB locked up. Trying to free up modem!\n");
+
+		writel_relaxed(0x3, MSS_MODEM_RESET);
+		/*
+		 * If we are still alive (allowing for the 5 second
+		 * delayed-panic-reboot), the modem is either still wedged or
+		 * SMSM didn't come through. Force panic in that case.
+		 */
+		schedule_delayed_work(&drv->unlock_work, timeout);
+	}
+}
+
+static int modem_notif_handler(struct notifier_block *nb, unsigned long code,
+				void *p)
+{
+	struct modem_data *drv = container_of(nb, struct modem_data, notifier);
+
+	if (code == MODEM_NOTIFIER_START_RESET) {
+		if (drv->ignore_smsm_ack) {
+			drv->ignore_smsm_ack = 0;
+		} else {
+			pr_err("Modem error fatal'ed.");
+			subsystem_restart_dev(drv->subsys);
+		}
+	}
+	return NOTIFY_DONE;
+}
+
+static int modem_shutdown(const struct subsys_desc *subsys)
+{
+	struct modem_data *drv;
+
+	drv = container_of(subsys, struct modem_data, subsys_desc);
+	/*
+	 * If the modem didn't already crash, setting SMSM_RESET here will help
+	 * flush caches etc. The ignore_smsm_ack flag is set to ignore the
+	 * SMSM_RESET notification that is generated due to the modem settings
+	 * its own SMSM_RESET bit in response to the apps setting the apps
+	 * SMSM_RESET bit.
+	 */
+	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
+		drv->ignore_smsm_ack = 1;
+		smsm_reset_modem(SMSM_RESET);
+	}
+
+	/* Disable the modem watchdog to allow clean modem bootup */
+	writel_relaxed(0x0, drv->wdog + 0x8);
+	/*
+	 * The write above needs to go through before the modem is powered up
+	 * again.
+	 */
+	mb();
+	/* Wait here to allow the modem to clean up caches, etc. */
+	msleep(20);
+
+	pil_force_shutdown("modem");
+	disable_irq_nosync(drv->irq);
+
+	return 0;
+}
+
+static int modem_powerup(const struct subsys_desc *subsys)
+{
+	struct modem_data *drv;
+	int ret;
+
+	drv = container_of(subsys, struct modem_data, subsys_desc);
+	ret = pil_force_boot("modem");
+	enable_irq(drv->irq);
+
+	return ret;
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment modem_segments[] = {
+	{ 0x42F00000, 0x46000000 - 0x42F00000 },
+};
+
+static int modem_ramdump(int enable, const struct subsys_desc *subsys)
+{
+	struct modem_data *drv;
+
+	drv = container_of(subsys, struct modem_data, subsys_desc);
+	if (enable)
+		return do_ramdump(drv->ramdump_dev, modem_segments,
+				ARRAY_SIZE(modem_segments));
+	else
+		return 0;
+}
+
 static int __devinit pil_modem_driver_probe(struct platform_device *pdev)
 {
 	struct modem_data *drv;
 	struct resource *res;
 	struct pil_desc *desc;
+	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -247,6 +420,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;
@@ -259,6 +436,14 @@
 	if (!desc)
 		return -ENOMEM;
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res)
+		return -EINVAL;
+
+	drv->wdog = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->wdog)
+		return -ENOMEM;
+
 	desc->name = "modem";
 	desc->depends_on = "q6";
 	desc->dev = &pdev->dev;
@@ -273,16 +458,61 @@
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
 	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil)) {
+	if (IS_ERR(drv->pil))
 		return PTR_ERR(drv->pil);
+
+	drv->notifier.notifier_call = modem_notif_handler,
+	ret = modem_register_notifier(&drv->notifier);
+	if (ret)
+		goto err_notify;
+
+	drv->subsys_desc.name = "modem";
+	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;
+
+	INIT_WORK(&drv->fatal_work, modem_fatal_fn);
+	INIT_DELAYED_WORK(&drv->unlock_work, modem_unlock_timeout);
+
+	drv->subsys = subsys_register(&drv->subsys_desc);
+	if (IS_ERR(drv->subsys)) {
+		ret = PTR_ERR(drv->subsys);
+		goto err_subsys;
 	}
+
+	drv->ramdump_dev = create_ramdump_device("modem");
+	if (!drv->ramdump_dev) {
+		ret = -ENOMEM;
+		goto err_ramdump;
+	}
+
+	ret = devm_request_irq(&pdev->dev, drv->irq, modem_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, "modem_watchdog", drv);
+	if (ret)
+		goto err_irq;
 	return 0;
+
+err_irq:
+	destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+	subsys_unregister(drv->subsys);
+err_subsys:
+	modem_unregister_notifier(&drv->notifier);
+err_notify:
+	msm_pil_unregister(drv->pil);
+	return ret;
 }
 
 static int __devexit pil_modem_driver_exit(struct platform_device *pdev)
 {
 	struct modem_data *drv = platform_get_drvdata(pdev);
+
+	destroy_ramdump_device(drv->ramdump_dev);
+	subsys_unregister(drv->subsys);
+	modem_unregister_notifier(&drv->notifier);
 	msm_pil_unregister(drv->pil);
+
 	return 0;
 }