diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig index 9b80cd49e12..905dde24d3a 100644 --- a/arch/arm/configs/msm8660-perf_defconfig +++ b/arch/arm/configs/msm8660-perf_defconfig @@ -62,6 +62,7 @@ CONFIG_MSM_ONCRPCROUTER=y CONFIG_MSM_RMT_STORAGE_CLIENT=y CONFIG_MSM_SDIO_SMEM=y # CONFIG_MSM_HW3D is not set +CONFIG_MSM_PIL_MODEM=y CONFIG_MSM_PIL_QDSP6V3=y CONFIG_MSM_PIL_TZAPPS=y CONFIG_MSM_SUBSYSTEM_RESTART=y diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig index deac0139f88..ec6f5829b00 100644 --- a/arch/arm/configs/msm8660_defconfig +++ b/arch/arm/configs/msm8660_defconfig @@ -54,6 +54,7 @@ CONFIG_MSM_ONCRPCROUTER=y # CONFIG_MSM_RPCSERVER_HANDSET is not set CONFIG_MSM_RMT_STORAGE_CLIENT=y # CONFIG_MSM_HW3D is not set +CONFIG_MSM_PIL_MODEM=y CONFIG_MSM_PIL_QDSP6V3=y CONFIG_MSM_PIL_TZAPPS=y CONFIG_MSM_SUBSYSTEM_RESTART=y diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 66c3af3fcdf..ffaa6060013 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -1596,6 +1596,12 @@ config MSM_PIL Say yes to support these devices. +config MSM_PIL_MODEM + tristate "Modem (ARM11) Boot Support" + depends on MSM_PIL + help + Support for booting and shutting down ARM11 Modem processors. + config MSM_PIL_QDSP6V3 tristate "QDSP6v3 (Hexagon) Boot Support" depends on MSM_PIL diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index e09e861b525..8bc0092610f 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_MSM_PIL_QDSP6V3) += pil-q6v3.o obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o obj-$(CONFIG_MSM_PIL_RIVA) += pil-riva.o obj-$(CONFIG_MSM_PIL_TZAPPS) += pil-tzapps.o +obj-$(CONFIG_MSM_PIL_MODEM) += pil-modem.o obj-$(CONFIG_ARCH_QSD8X50) += sirc.o obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c index 5acb83d84b0..60b8771bf64 100644 --- a/arch/arm/mach-msm/board-msm8x60.c +++ b/arch/arm/mach-msm/board-msm8x60.c @@ -5088,6 +5088,7 @@ static struct platform_device *surf_devices[] __initdata = { &msm_device_smd, &msm_device_uart_dm12, &msm_pil_q6v3, + &msm_pil_modem, &msm_pil_tzapps, #ifdef CONFIG_I2C_QUP &msm_gsbi3_qup_i2c_device, diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c index f1f6e64eb2e..8f1709bbd3d 100644 --- a/arch/arm/mach-msm/devices-msm8x60.c +++ b/arch/arm/mach-msm/devices-msm8x60.c @@ -194,6 +194,23 @@ struct platform_device msm_pil_q6v3 = { .resource = msm_8660_q6_resources, }; +#define MSM_MSS_REGS_PHYS 0x10200000 + +static struct resource msm_8660_modem_resources[] = { + { + .start = MSM_MSS_REGS_PHYS, + .end = MSM_MSS_REGS_PHYS + SZ_256 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device msm_pil_modem = { + .name = "pil_modem", + .id = -1, + .num_resources = ARRAY_SIZE(msm_8660_modem_resources), + .resource = msm_8660_modem_resources, +}; + struct platform_device msm_pil_tzapps = { .name = "pil_tzapps", .id = -1, diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h index 00ff5e8835d..0de06944638 100644 --- a/arch/arm/mach-msm/devices.h +++ b/arch/arm/mach-msm/devices.h @@ -178,6 +178,7 @@ extern struct platform_device msm_cpudai_incall_record_rx; extern struct platform_device msm_cpudai_incall_record_tx; extern struct platform_device msm_pil_q6v3; +extern struct platform_device msm_pil_modem; extern struct platform_device msm_pil_tzapps; extern struct platform_device msm_8960_q6_lpass; extern struct platform_device msm_8960_q6_mss_fw; diff --git a/arch/arm/mach-msm/peripheral-reset.c b/arch/arm/mach-msm/peripheral-reset.c index 20ac4294cda..177c80d152f 100644 --- a/arch/arm/mach-msm/peripheral-reset.c +++ b/arch/arm/mach-msm/peripheral-reset.c @@ -26,57 +26,15 @@ #include #include -#include #include "peripheral-loader.h" #include "scm-pas.h" -#define PROXY_VOTE_TIMEOUT 10000 - -#define MSM_MMS_REGS_BASE 0x10200000 - -#define MARM_RESET (MSM_CLK_CTL_BASE + 0x2BD4) -#define MARM_BOOT_CONTROL (msm_mms_regs_base + 0x0010) -#define MAHB0_SFAB_PORT_RESET (MSM_CLK_CTL_BASE + 0x2304) -#define MARM_CLK_BRANCH_ENA_VOTE (MSM_CLK_CTL_BASE + 0x3000) -#define MARM_CLK_SRC0_NS (MSM_CLK_CTL_BASE + 0x2BC0) -#define MARM_CLK_SRC1_NS (MSM_CLK_CTL_BASE + 0x2BC4) -#define MARM_CLK_SRC_CTL (MSM_CLK_CTL_BASE + 0x2BC8) -#define MARM_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BCC) -#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00) -#define MSS_MODEM_CXO_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C44) -#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60) -#define MSS_MARM_SYS_REF_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C64) -#define MAHB0_CLK_CTL (MSM_CLK_CTL_BASE + 0x2300) -#define MAHB1_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BE4) -#define MAHB2_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C20) -#define MAHB1_NS (MSM_CLK_CTL_BASE + 0x2BE0) -#define MARM_CLK_FS (MSM_CLK_CTL_BASE + 0x2BD0) -#define MAHB2_CLK_FS (MSM_CLK_CTL_BASE + 0x2C24) -#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 PPSS_RESET (MSM_CLK_CTL_BASE + 0x2594) #define PPSS_PROC_CLK_CTL (MSM_CLK_CTL_BASE + 0x2588) #define CLK_HALT_DFAB_STATE (MSM_CLK_CTL_BASE + 0x2FC8) -static int modem_start, dsps_start; -static void __iomem *msm_mms_regs_base; - -static int init_image_modem_trusted(struct pil_desc *pil, const u8 *metadata, - size_t size) -{ - return pas_init_image(PAS_MODEM, metadata, size); -} - -static int init_image_modem_untrusted(struct pil_desc *pil, - const u8 *metadata, size_t size) -{ - struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata; - modem_start = ehdr->e_entry; - return 0; -} +static int dsps_start; static int init_image_dsps_trusted(struct pil_desc *pil, const u8 *metadata, size_t size) @@ -100,176 +58,6 @@ static int verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size) return 0; } -static struct msm_xo_voter *pxo; -static void remove_modem_proxy_votes(unsigned long data) -{ - msm_xo_mode_vote(pxo, MSM_XO_MODE_OFF); -} -static DEFINE_TIMER(modem_timer, remove_modem_proxy_votes, 0, 0); - -static void make_modem_proxy_votes(void) -{ - /* Make proxy votes for modem and set up timer to disable it. */ - msm_xo_mode_vote(pxo, MSM_XO_MODE_ON); - mod_timer(&modem_timer, jiffies + msecs_to_jiffies(PROXY_VOTE_TIMEOUT)); -} - -static void remove_modem_proxy_votes_now(void) -{ - /* - * If the modem proxy vote hasn't been removed yet, them remove the - * votes immediately. - */ - if (del_timer(&modem_timer)) - remove_modem_proxy_votes(0); -} - -static int reset_modem_untrusted(struct pil_desc *pil) -{ - u32 reg; - - make_modem_proxy_votes(); - - /* Put modem AHB0,1,2 clocks into reset */ - __raw_writel(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET); - __raw_writel(BIT(7), MAHB1_CLK_CTL); - __raw_writel(BIT(7), MAHB2_CLK_CTL); - - /* Vote for pll8 on behalf of the modem */ - reg = __raw_readl(PLL_ENA_MARM); - reg |= BIT(8); - __raw_writel(reg, PLL_ENA_MARM); - - /* Wait for PLL8 to enable */ - while (!(__raw_readl(PLL8_STATUS) & BIT(16))) - cpu_relax(); - - /* Set MAHB1 divider to Div-5 to run MAHB1,2 and sfab at 79.8 Mhz*/ - __raw_writel(0x4, MAHB1_NS); - - /* Vote for modem AHB1 and 2 clocks to be on on behalf of the modem */ - reg = __raw_readl(MARM_CLK_BRANCH_ENA_VOTE); - reg |= BIT(0) | BIT(1); - __raw_writel(reg, MARM_CLK_BRANCH_ENA_VOTE); - - /* Source marm_clk off of PLL8 */ - reg = __raw_readl(MARM_CLK_SRC_CTL); - if ((reg & 0x1) == 0) { - __raw_writel(0x3, MARM_CLK_SRC1_NS); - reg |= 0x1; - } else { - __raw_writel(0x3, MARM_CLK_SRC0_NS); - reg &= ~0x1; - } - __raw_writel(reg | 0x2, MARM_CLK_SRC_CTL); - - /* - * Force core on and periph on signals to remain active during halt - * for marm_clk and mahb2_clk - */ - __raw_writel(0x6F, MARM_CLK_FS); - __raw_writel(0x6F, MAHB2_CLK_FS); - - /* - * Enable all of the marm_clk branches, cxo sourced marm branches, - * and sleep clock branches - */ - __raw_writel(0x10, MARM_CLK_CTL); - __raw_writel(0x10, MAHB0_CLK_CTL); - __raw_writel(0x10, SFAB_MSS_S_HCLK_CTL); - __raw_writel(0x10, MSS_MODEM_CXO_CLK_CTL); - __raw_writel(0x10, MSS_SLP_CLK_CTL); - __raw_writel(0x10, MSS_MARM_SYS_REF_CLK_CTL); - - /* Wait for above clocks to be turned on */ - while (__raw_readl(CLK_HALT_MSS_SMPSS_MISC_STATE) & (BIT(7) | BIT(8) | - BIT(9) | BIT(10) | BIT(4) | BIT(6))) - cpu_relax(); - - /* Take MAHB0,1,2 clocks out of reset */ - __raw_writel(0x0, MAHB2_CLK_CTL); - __raw_writel(0x0, MAHB1_CLK_CTL); - __raw_writel(0x0, MAHB0_SFAB_PORT_RESET); - - /* Setup exception vector table base address */ - __raw_writel(modem_start | 0x1, MARM_BOOT_CONTROL); - - /* Wait for vector table to be setup */ - mb(); - - /* Bring modem out of reset */ - __raw_writel(0x0, MARM_RESET); - - return 0; -} - -static int reset_modem_trusted(struct pil_desc *pil) -{ - int ret; - - make_modem_proxy_votes(); - - ret = pas_auth_and_reset(PAS_MODEM); - if (ret) - remove_modem_proxy_votes_now(); - - return ret; -} - -static int shutdown_modem_untrusted(struct pil_desc *pil) -{ - u32 reg; - - /* Put modem into reset */ - __raw_writel(0x1, MARM_RESET); - mb(); - - /* Put modem AHB0,1,2 clocks into reset */ - __raw_writel(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET); - __raw_writel(BIT(7), MAHB1_CLK_CTL); - __raw_writel(BIT(7), MAHB2_CLK_CTL); - mb(); - - /* - * Disable all of the marm_clk branches, cxo sourced marm branches, - * and sleep clock branches - */ - __raw_writel(0x0, MARM_CLK_CTL); - __raw_writel(0x0, MAHB0_CLK_CTL); - __raw_writel(0x0, SFAB_MSS_S_HCLK_CTL); - __raw_writel(0x0, MSS_MODEM_CXO_CLK_CTL); - __raw_writel(0x0, MSS_SLP_CLK_CTL); - __raw_writel(0x0, MSS_MARM_SYS_REF_CLK_CTL); - - /* Disable marm_clk */ - reg = __raw_readl(MARM_CLK_SRC_CTL); - reg &= ~0x2; - __raw_writel(reg, MARM_CLK_SRC_CTL); - - /* Clear modem's votes for ahb clocks */ - __raw_writel(0x0, MARM_CLK_BRANCH_ENA_VOTE); - - /* Clear modem's votes for PLLs */ - __raw_writel(0x0, PLL_ENA_MARM); - - remove_modem_proxy_votes_now(); - - return 0; -} - -static int shutdown_modem_trusted(struct pil_desc *pil) -{ - int ret; - - ret = pas_shutdown(PAS_MODEM); - if (ret) - return ret; - - remove_modem_proxy_votes_now(); - - return 0; -} - static int reset_dsps_untrusted(struct pil_desc *pil) { __raw_writel(0x10, PPSS_PROC_CLK_CTL); @@ -298,13 +86,6 @@ static int shutdown_dsps_untrusted(struct pil_desc *pil) return 0; } -struct pil_reset_ops pil_modem_ops = { - .init_image = init_image_modem_untrusted, - .verify_blob = verify_blob, - .auth_and_reset = reset_modem_untrusted, - .shutdown = shutdown_modem_untrusted, -}; - struct pil_reset_ops pil_dsps_ops = { .init_image = init_image_dsps_untrusted, .verify_blob = verify_blob, @@ -312,17 +93,6 @@ struct pil_reset_ops pil_dsps_ops = { .shutdown = shutdown_dsps_untrusted, }; -static struct platform_device pil_modem = { - .name = "pil_modem", -}; - -static struct pil_desc pil_modem_desc = { - .name = "modem", - .depends_on = "q6", - .dev = &pil_modem.dev, - .ops = &pil_modem_ops, -}; - static struct platform_device pil_dsps = { .name = "pil_dsps", }; @@ -335,49 +105,21 @@ static struct pil_desc pil_dsps_desc = { static int __init msm_peripheral_reset_init(void) { - msm_mms_regs_base = ioremap(MSM_MMS_REGS_BASE, SZ_256); - if (!msm_mms_regs_base) - goto err; - - pxo = msm_xo_get(MSM_XO_PXO, "pil"); - if (IS_ERR(pxo)) - goto err_pxo; - - if (pas_supported(PAS_MODEM) > 0) { - pil_modem_ops.init_image = init_image_modem_trusted; - pil_modem_ops.auth_and_reset = reset_modem_trusted; - pil_modem_ops.shutdown = shutdown_modem_trusted; - } - if (pas_supported(PAS_DSPS) > 0) { pil_dsps_ops.init_image = init_image_dsps_trusted; pil_dsps_ops.auth_and_reset = reset_dsps_trusted; pil_dsps_ops.shutdown = shutdown_dsps_trusted; } - BUG_ON(platform_device_register(&pil_modem)); - BUG_ON(msm_pil_register(&pil_modem_desc)); - if (machine_is_msm8x60_fluid()) pil_dsps_desc.name = "dsps_fluid"; BUG_ON(platform_device_register(&pil_dsps)); BUG_ON(msm_pil_register(&pil_dsps_desc)); return 0; - -err_pxo: - iounmap(msm_mms_regs_base); -err: - return -ENOMEM; -} - -static void __exit msm_peripheral_reset_exit(void) -{ - iounmap(msm_mms_regs_base); } arch_initcall(msm_peripheral_reset_init); -module_exit(msm_peripheral_reset_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Validate and bring peripherals out of reset"); diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c new file mode 100644 index 00000000000..5aa383456c1 --- /dev/null +++ b/arch/arm/mach-msm/pil-modem.c @@ -0,0 +1,344 @@ +/* Copyright (c) 2010-2011, 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "peripheral-loader.h" +#include "scm-pas.h" + +#define MARM_BOOT_CONTROL 0x0010 +#define MARM_RESET (MSM_CLK_CTL_BASE + 0x2BD4) +#define MAHB0_SFAB_PORT_RESET (MSM_CLK_CTL_BASE + 0x2304) +#define MARM_CLK_BRANCH_ENA_VOTE (MSM_CLK_CTL_BASE + 0x3000) +#define MARM_CLK_SRC0_NS (MSM_CLK_CTL_BASE + 0x2BC0) +#define MARM_CLK_SRC1_NS (MSM_CLK_CTL_BASE + 0x2BC4) +#define MARM_CLK_SRC_CTL (MSM_CLK_CTL_BASE + 0x2BC8) +#define MARM_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BCC) +#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00) +#define MSS_MODEM_CXO_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C44) +#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60) +#define MSS_MARM_SYS_REF_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C64) +#define MAHB0_CLK_CTL (MSM_CLK_CTL_BASE + 0x2300) +#define MAHB1_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BE4) +#define MAHB2_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C20) +#define MAHB1_NS (MSM_CLK_CTL_BASE + 0x2BE0) +#define MARM_CLK_FS (MSM_CLK_CTL_BASE + 0x2BD0) +#define MAHB2_CLK_FS (MSM_CLK_CTL_BASE + 0x2C24) +#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 PROXY_VOTE_TIMEOUT 10000 + +struct modem_data { + void __iomem *base; + unsigned long start_addr; + struct msm_xo_voter *pxo; + struct timer_list timer; +}; + +static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size) +{ + return 0; +} + +static void remove_proxy_votes(unsigned long data) +{ + struct modem_data *drv = (struct modem_data *)data; + msm_xo_mode_vote(drv->pxo, MSM_XO_MODE_OFF); +} + +static void make_modem_proxy_votes(struct device *dev) +{ + int ret; + struct modem_data *drv = dev_get_drvdata(dev); + + ret = msm_xo_mode_vote(drv->pxo, MSM_XO_MODE_ON); + if (ret) + dev_err(dev, "Failed to enable PXO\n"); + mod_timer(&drv->timer, jiffies + msecs_to_jiffies(PROXY_VOTE_TIMEOUT)); +} + +static void remove_modem_proxy_votes_now(struct modem_data *drv) +{ + /* If the proxy vote hasn't been removed yet, remove it immediately. */ + if (del_timer(&drv->timer)) + remove_proxy_votes((unsigned long)drv); +} + +static int modem_init_image(struct pil_desc *pil, const u8 *metadata, + size_t size) +{ + const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata; + struct modem_data *drv = dev_get_drvdata(pil->dev); + drv->start_addr = ehdr->e_entry; + return 0; +} + +static int modem_reset(struct pil_desc *pil) +{ + u32 reg; + const struct modem_data *drv = dev_get_drvdata(pil->dev); + + make_modem_proxy_votes(pil->dev); + + /* Put modem AHB0,1,2 clocks into reset */ + writel_relaxed(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET); + writel_relaxed(BIT(7), MAHB1_CLK_CTL); + writel_relaxed(BIT(7), MAHB2_CLK_CTL); + + /* Vote for pll8 on behalf of the modem */ + reg = readl_relaxed(PLL_ENA_MARM); + reg |= BIT(8); + writel_relaxed(reg, PLL_ENA_MARM); + + /* Wait for PLL8 to enable */ + while (!(readl_relaxed(PLL8_STATUS) & BIT(16))) + cpu_relax(); + + /* Set MAHB1 divider to Div-5 to run MAHB1,2 and sfab at 79.8 Mhz*/ + writel_relaxed(0x4, MAHB1_NS); + + /* Vote for modem AHB1 and 2 clocks to be on on behalf of the modem */ + reg = readl_relaxed(MARM_CLK_BRANCH_ENA_VOTE); + reg |= BIT(0) | BIT(1); + writel_relaxed(reg, MARM_CLK_BRANCH_ENA_VOTE); + + /* Source marm_clk off of PLL8 */ + reg = readl_relaxed(MARM_CLK_SRC_CTL); + if ((reg & 0x1) == 0) { + writel_relaxed(0x3, MARM_CLK_SRC1_NS); + reg |= 0x1; + } else { + writel_relaxed(0x3, MARM_CLK_SRC0_NS); + reg &= ~0x1; + } + writel_relaxed(reg | 0x2, MARM_CLK_SRC_CTL); + + /* + * Force core on and periph on signals to remain active during halt + * for marm_clk and mahb2_clk + */ + writel_relaxed(0x6F, MARM_CLK_FS); + writel_relaxed(0x6F, MAHB2_CLK_FS); + + /* + * Enable all of the marm_clk branches, cxo sourced marm branches, + * and sleep clock branches + */ + writel_relaxed(0x10, MARM_CLK_CTL); + writel_relaxed(0x10, MAHB0_CLK_CTL); + writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL); + writel_relaxed(0x10, MSS_MODEM_CXO_CLK_CTL); + writel_relaxed(0x10, MSS_SLP_CLK_CTL); + writel_relaxed(0x10, MSS_MARM_SYS_REF_CLK_CTL); + + /* Wait for above clocks to be turned on */ + while (readl_relaxed(CLK_HALT_MSS_SMPSS_MISC_STATE) & (BIT(7) | BIT(8) | + BIT(9) | BIT(10) | BIT(4) | BIT(6))) + cpu_relax(); + + /* Take MAHB0,1,2 clocks out of reset */ + writel_relaxed(0x0, MAHB2_CLK_CTL); + writel_relaxed(0x0, MAHB1_CLK_CTL); + writel_relaxed(0x0, MAHB0_SFAB_PORT_RESET); + mb(); + + /* Setup exception vector table base address */ + writel_relaxed(drv->start_addr | 0x1, drv->base + MARM_BOOT_CONTROL); + + /* Wait for vector table to be setup */ + mb(); + + /* Bring modem out of reset */ + writel_relaxed(0x0, MARM_RESET); + + return 0; +} + +static int modem_shutdown(struct pil_desc *pil) +{ + u32 reg; + struct modem_data *drv = dev_get_drvdata(pil->dev); + + /* Put modem into reset */ + writel_relaxed(0x1, MARM_RESET); + mb(); + + /* Put modem AHB0,1,2 clocks into reset */ + writel_relaxed(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET); + writel_relaxed(BIT(7), MAHB1_CLK_CTL); + writel_relaxed(BIT(7), MAHB2_CLK_CTL); + mb(); + + /* + * Disable all of the marm_clk branches, cxo sourced marm branches, + * and sleep clock branches + */ + writel_relaxed(0x0, MARM_CLK_CTL); + writel_relaxed(0x0, MAHB0_CLK_CTL); + writel_relaxed(0x0, SFAB_MSS_S_HCLK_CTL); + writel_relaxed(0x0, MSS_MODEM_CXO_CLK_CTL); + writel_relaxed(0x0, MSS_SLP_CLK_CTL); + writel_relaxed(0x0, MSS_MARM_SYS_REF_CLK_CTL); + + /* Disable marm_clk */ + reg = readl_relaxed(MARM_CLK_SRC_CTL); + reg &= ~0x2; + writel_relaxed(reg, MARM_CLK_SRC_CTL); + + /* Clear modem's votes for ahb clocks */ + writel_relaxed(0x0, MARM_CLK_BRANCH_ENA_VOTE); + + /* Clear modem's votes for PLLs */ + writel_relaxed(0x0, PLL_ENA_MARM); + + remove_modem_proxy_votes_now(drv); + + return 0; +} + +static struct pil_reset_ops pil_modem_ops = { + .init_image = modem_init_image, + .verify_blob = nop_verify_blob, + .auth_and_reset = modem_reset, + .shutdown = modem_shutdown, +}; + +static int modem_init_image_trusted(struct pil_desc *pil, const u8 *metadata, + size_t size) +{ + return pas_init_image(PAS_MODEM, metadata, size); +} + +static int modem_reset_trusted(struct pil_desc *pil) +{ + int ret; + struct modem_data *drv = dev_get_drvdata(pil->dev); + + make_modem_proxy_votes(pil->dev); + + ret = pas_auth_and_reset(PAS_MODEM); + if (ret) + remove_modem_proxy_votes_now(drv); + + return ret; +} + +static int modem_shutdown_trusted(struct pil_desc *pil) +{ + int ret; + struct modem_data *drv = dev_get_drvdata(pil->dev); + + ret = pas_shutdown(PAS_MODEM); + if (ret) + return ret; + + remove_modem_proxy_votes_now(drv); + return 0; +} + +static struct pil_reset_ops pil_modem_ops_trusted = { + .init_image = modem_init_image_trusted, + .verify_blob = nop_verify_blob, + .auth_and_reset = modem_reset_trusted, + .shutdown = modem_shutdown_trusted, +}; + +static int __devinit pil_modem_driver_probe(struct platform_device *pdev) +{ + struct modem_data *drv; + struct resource *res; + struct pil_desc *desc; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); + if (!drv) + return -ENOMEM; + platform_set_drvdata(pdev, drv); + + drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!drv->base) + return -ENOMEM; + + drv->pxo = msm_xo_get(MSM_XO_PXO, dev_name(&pdev->dev)); + if (IS_ERR(drv->pxo)) + return PTR_ERR(drv->pxo); + + desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL); + if (!desc) + return -ENOMEM; + + setup_timer(&drv->timer, remove_proxy_votes, (unsigned long)drv); + desc->name = "modem"; + desc->depends_on = "q6"; + desc->dev = &pdev->dev; + + if (pas_supported(PAS_MODEM) > 0) { + desc->ops = &pil_modem_ops_trusted; + dev_info(&pdev->dev, "using secure boot\n"); + } else { + desc->ops = &pil_modem_ops; + dev_info(&pdev->dev, "using non-secure boot\n"); + } + + if (msm_pil_register(desc)) { + msm_xo_put(drv->pxo); + return -EINVAL; + } + return 0; +} + +static int __devexit pil_modem_driver_exit(struct platform_device *pdev) +{ + struct modem_data *drv = platform_get_drvdata(pdev); + del_timer_sync(&drv->timer); + msm_xo_put(drv->pxo); + return 0; +} + +static struct platform_driver pil_modem_driver = { + .probe = pil_modem_driver_probe, + .remove = __devexit_p(pil_modem_driver_exit), + .driver = { + .name = "pil_modem", + .owner = THIS_MODULE, + }, +}; + +static int __init pil_modem_init(void) +{ + return platform_driver_register(&pil_modem_driver); +} +module_init(pil_modem_init); + +static void __exit pil_modem_exit(void) +{ + platform_driver_unregister(&pil_modem_driver); +} +module_exit(pil_modem_exit); + +MODULE_DESCRIPTION("Support for booting modem processors"); +MODULE_LICENSE("GPL v2");