| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (c) 2012, Code Aurora Forum. All rights reserved. | 
 | 3 |  * | 
 | 4 |  * This program is free software; you can redistribute it and/or modify | 
 | 5 |  * it under the terms of the GNU General Public License version 2 and | 
 | 6 |  * only version 2 as published by the Free Software Foundation. | 
 | 7 |  * | 
 | 8 |  * This program is distributed in the hope that it will be useful, | 
 | 9 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 10 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 11 |  * GNU General Public License for more details. | 
 | 12 |  */ | 
 | 13 |  | 
 | 14 | #include <linux/kernel.h> | 
 | 15 | #include <linux/err.h> | 
 | 16 | #include <linux/io.h> | 
 | 17 | #include <linux/elf.h> | 
 | 18 | #include <linux/delay.h> | 
 | 19 | #include <linux/module.h> | 
 | 20 | #include <linux/slab.h> | 
 | 21 | #include <linux/platform_device.h> | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 22 | #include <linux/clk.h> | 
| Matt Wagantall | 19ac4fd | 2012-02-03 20:18:23 -0800 | [diff] [blame] | 23 | #include <linux/smp.h> | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 24 |  | 
 | 25 | #include <mach/msm_iomap.h> | 
 | 26 | #include <mach/msm_xo.h> | 
| Matt Wagantall | 556d3f7 | 2012-02-16 17:36:29 -0800 | [diff] [blame] | 27 | #include <mach/socinfo.h> | 
| Matt Wagantall | f3471ef | 2012-03-09 14:21:54 -0800 | [diff] [blame] | 28 | #include <mach/msm_bus_board.h> | 
 | 29 | #include <mach/msm_bus.h> | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 30 |  | 
 | 31 | #include "peripheral-loader.h" | 
 | 32 | #include "scm-pas.h" | 
 | 33 |  | 
 | 34 | #define GSS_CSR_AHB_CLK_SEL	0x0 | 
 | 35 | #define GSS_CSR_RESET		0x4 | 
 | 36 | #define GSS_CSR_CLK_BLK_CONFIG	0x8 | 
 | 37 | #define GSS_CSR_CLK_ENABLE	0xC | 
 | 38 | #define GSS_CSR_BOOT_REMAP	0x14 | 
 | 39 | #define GSS_CSR_POWER_UP_DOWN	0x18 | 
| Matt Wagantall | 19ac4fd | 2012-02-03 20:18:23 -0800 | [diff] [blame] | 40 | #define GSS_CSR_CFG_HID		0x2C | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 41 |  | 
 | 42 | #define GSS_SLP_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2C60) | 
 | 43 | #define GSS_RESET		(MSM_CLK_CTL_BASE + 0x2C64) | 
 | 44 | #define GSS_CLAMP_ENA		(MSM_CLK_CTL_BASE + 0x2C68) | 
 | 45 | #define GSS_CXO_SRC_CTL		(MSM_CLK_CTL_BASE + 0x2C74) | 
 | 46 |  | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 47 | #define PLL5_STATUS		(MSM_CLK_CTL_BASE + 0x30F8) | 
 | 48 | #define PLL_ENA_GSS		(MSM_CLK_CTL_BASE + 0x3480) | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 49 |  | 
 | 50 | #define PLL5_VOTE		BIT(5) | 
 | 51 | #define PLL_STATUS		BIT(16) | 
 | 52 | #define REMAP_ENABLE		BIT(16) | 
 | 53 | #define A5_POWER_STATUS		BIT(4) | 
 | 54 | #define A5_POWER_ENA		BIT(0) | 
 | 55 | #define NAV_POWER_ENA		BIT(1) | 
 | 56 | #define XO_CLK_BRANCH_ENA	BIT(0) | 
 | 57 | #define SLP_CLK_BRANCH_ENA	BIT(4) | 
 | 58 | #define A5_RESET		BIT(0) | 
 | 59 |  | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 60 | struct gss_data { | 
 | 61 | 	void __iomem *base; | 
| Matt Wagantall | 19ac4fd | 2012-02-03 20:18:23 -0800 | [diff] [blame] | 62 | 	void __iomem *qgic2_base; | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 63 | 	unsigned long start_addr; | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 64 | 	struct clk *xo; | 
| Stephen Boyd | 6d67d25 | 2011-09-27 11:50:05 -0700 | [diff] [blame] | 65 | 	struct pil_device *pil; | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 66 | }; | 
 | 67 |  | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 68 | static int pil_gss_init_image(struct pil_desc *pil, const u8 *metadata, | 
 | 69 | 		size_t size) | 
 | 70 | { | 
 | 71 | 	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata; | 
 | 72 | 	struct gss_data *drv = dev_get_drvdata(pil->dev); | 
 | 73 | 	drv->start_addr = ehdr->e_entry; | 
 | 74 | 	return 0; | 
 | 75 | } | 
 | 76 |  | 
| Stephen Boyd | ab2b907 | 2012-03-22 10:59:22 -0700 | [diff] [blame] | 77 | static int make_gss_proxy_votes(struct pil_desc *pil) | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 78 | { | 
 | 79 | 	int ret; | 
| Stephen Boyd | ab2b907 | 2012-03-22 10:59:22 -0700 | [diff] [blame] | 80 | 	struct gss_data *drv = dev_get_drvdata(pil->dev); | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 81 |  | 
 | 82 | 	ret = clk_prepare_enable(drv->xo); | 
 | 83 | 	if (ret) { | 
| Stephen Boyd | ab2b907 | 2012-03-22 10:59:22 -0700 | [diff] [blame] | 84 | 		dev_err(pil->dev, "Failed to enable XO\n"); | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 85 | 		return ret; | 
 | 86 | 	} | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 87 | 	return 0; | 
 | 88 | } | 
 | 89 |  | 
| Stephen Boyd | ab2b907 | 2012-03-22 10:59:22 -0700 | [diff] [blame] | 90 | static void remove_gss_proxy_votes(struct pil_desc *pil) | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 91 | { | 
| Stephen Boyd | ab2b907 | 2012-03-22 10:59:22 -0700 | [diff] [blame] | 92 | 	struct gss_data *drv = dev_get_drvdata(pil->dev); | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 93 | 	clk_disable_unprepare(drv->xo); | 
 | 94 | } | 
 | 95 |  | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 96 | static void gss_init(struct gss_data *drv) | 
 | 97 | { | 
 | 98 | 	void __iomem *base = drv->base; | 
 | 99 |  | 
 | 100 | 	/* Supply clocks to GSS. */ | 
 | 101 | 	writel_relaxed(XO_CLK_BRANCH_ENA, GSS_CXO_SRC_CTL); | 
 | 102 | 	writel_relaxed(SLP_CLK_BRANCH_ENA, GSS_SLP_CLK_CTL); | 
 | 103 |  | 
 | 104 | 	/* Deassert GSS reset and clamps. */ | 
 | 105 | 	writel_relaxed(0x0, GSS_RESET); | 
 | 106 | 	writel_relaxed(0x0, GSS_CLAMP_ENA); | 
 | 107 | 	mb(); | 
 | 108 |  | 
 | 109 | 	/* | 
 | 110 | 	 * Configure clock source and dividers for 288MHz core, 144MHz AXI and | 
 | 111 | 	 * 72MHz AHB, all derived from the 288MHz PLL. | 
 | 112 | 	 */ | 
 | 113 | 	writel_relaxed(0x341, base + GSS_CSR_CLK_BLK_CONFIG); | 
 | 114 | 	writel_relaxed(0x1, base + GSS_CSR_AHB_CLK_SEL); | 
 | 115 |  | 
 | 116 | 	/* Assert all GSS resets. */ | 
 | 117 | 	writel_relaxed(0x7F, base + GSS_CSR_RESET); | 
 | 118 |  | 
 | 119 | 	/* Enable all bus clocks and wait for resets to propagate. */ | 
 | 120 | 	writel_relaxed(0x1F, base + GSS_CSR_CLK_ENABLE); | 
 | 121 | 	mb(); | 
 | 122 | 	udelay(1); | 
 | 123 |  | 
 | 124 | 	/* Release subsystem from reset, but leave A5 in reset. */ | 
 | 125 | 	writel_relaxed(A5_RESET, base + GSS_CSR_RESET); | 
 | 126 | } | 
 | 127 |  | 
| Matt Wagantall | 556d3f7 | 2012-02-16 17:36:29 -0800 | [diff] [blame] | 128 | static void cfg_qgic2_bus_access(void *data) | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 129 | { | 
| Matt Wagantall | 19ac4fd | 2012-02-03 20:18:23 -0800 | [diff] [blame] | 130 | 	struct gss_data *drv = data; | 
| Matt Wagantall | 19ac4fd | 2012-02-03 20:18:23 -0800 | [diff] [blame] | 131 | 	int i; | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 132 |  | 
| Matt Wagantall | 556d3f7 | 2012-02-16 17:36:29 -0800 | [diff] [blame] | 133 | 	/* | 
 | 134 | 	 * Apply a 8064 v1.0 workaround to configure QGIC bus access. | 
 | 135 | 	 * This must be done from Krait 0 to configure the Master ID | 
 | 136 | 	 * correctly. | 
 | 137 | 	 */ | 
 | 138 | 	writel_relaxed(0x2, drv->base + GSS_CSR_CFG_HID); | 
| Matt Wagantall | 19ac4fd | 2012-02-03 20:18:23 -0800 | [diff] [blame] | 139 | 	for (i = 0; i <= 3; i++) | 
 | 140 | 		readl_relaxed(drv->qgic2_base); | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 141 | } | 
 | 142 |  | 
 | 143 | static int pil_gss_shutdown(struct pil_desc *pil) | 
 | 144 | { | 
 | 145 | 	struct gss_data *drv = dev_get_drvdata(pil->dev); | 
 | 146 | 	void __iomem *base = drv->base; | 
 | 147 | 	u32 regval; | 
 | 148 | 	int ret; | 
 | 149 |  | 
 | 150 | 	ret = clk_prepare_enable(drv->xo); | 
 | 151 | 	if (ret) { | 
 | 152 | 		dev_err(pil->dev, "Failed to enable XO\n"); | 
 | 153 | 		return ret; | 
 | 154 | 	} | 
 | 155 |  | 
| Matt Wagantall | f3471ef | 2012-03-09 14:21:54 -0800 | [diff] [blame] | 156 | 	/* Make sure bus port is halted. */ | 
 | 157 | 	msm_bus_axi_porthalt(MSM_BUS_MASTER_GSS_NAV); | 
 | 158 |  | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 159 | 	/* | 
 | 160 | 	 * Vote PLL on in GSS's voting register and wait for it to enable. | 
 | 161 | 	 * The PLL must be enable to switch the GFMUX to a low-power source. | 
 | 162 | 	 */ | 
 | 163 | 	writel_relaxed(PLL5_VOTE, PLL_ENA_GSS); | 
 | 164 | 	while ((readl_relaxed(PLL5_STATUS) & PLL_STATUS) == 0) | 
 | 165 | 		cpu_relax(); | 
 | 166 |  | 
 | 167 | 	/* Perform one-time GSS initialization. */ | 
 | 168 | 	gss_init(drv); | 
 | 169 |  | 
 | 170 | 	/* Assert A5 reset. */ | 
 | 171 | 	regval = readl_relaxed(base + GSS_CSR_RESET); | 
 | 172 | 	regval |= A5_RESET; | 
 | 173 | 	writel_relaxed(regval, base + GSS_CSR_RESET); | 
 | 174 |  | 
 | 175 | 	/* Power down A5 and NAV. */ | 
 | 176 | 	regval = readl_relaxed(base + GSS_CSR_POWER_UP_DOWN); | 
 | 177 | 	regval &= ~(A5_POWER_ENA|NAV_POWER_ENA); | 
 | 178 | 	writel_relaxed(regval, base + GSS_CSR_POWER_UP_DOWN); | 
 | 179 |  | 
 | 180 | 	/* Select XO clock source and increase dividers to save power. */ | 
 | 181 | 	regval = readl_relaxed(base + GSS_CSR_CLK_BLK_CONFIG); | 
 | 182 | 	regval |= 0x3FF; | 
 | 183 | 	writel_relaxed(regval, base + GSS_CSR_CLK_BLK_CONFIG); | 
 | 184 |  | 
 | 185 | 	/* Disable bus clocks. */ | 
 | 186 | 	writel_relaxed(0x1F, base + GSS_CSR_CLK_ENABLE); | 
 | 187 |  | 
 | 188 | 	/* Clear GSS PLL votes. */ | 
 | 189 | 	writel_relaxed(0, PLL_ENA_GSS); | 
 | 190 | 	mb(); | 
 | 191 |  | 
 | 192 | 	clk_disable_unprepare(drv->xo); | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 193 |  | 
 | 194 | 	return 0; | 
 | 195 | } | 
 | 196 |  | 
| Matt Wagantall | 19ac4fd | 2012-02-03 20:18:23 -0800 | [diff] [blame] | 197 | static int pil_gss_reset(struct pil_desc *pil) | 
 | 198 | { | 
 | 199 | 	struct gss_data *drv = dev_get_drvdata(pil->dev); | 
 | 200 | 	void __iomem *base = drv->base; | 
 | 201 | 	unsigned long start_addr = drv->start_addr; | 
 | 202 | 	int ret; | 
 | 203 |  | 
| Matt Wagantall | f3471ef | 2012-03-09 14:21:54 -0800 | [diff] [blame] | 204 | 	/* Unhalt bus port. */ | 
 | 205 | 	ret = msm_bus_axi_portunhalt(MSM_BUS_MASTER_GSS_NAV); | 
 | 206 | 	if (ret) { | 
 | 207 | 		dev_err(pil->dev, "Failed to unhalt bus port\n"); | 
| Matt Wagantall | f3471ef | 2012-03-09 14:21:54 -0800 | [diff] [blame] | 208 | 		return ret; | 
 | 209 | 	} | 
 | 210 |  | 
| Matt Wagantall | 19ac4fd | 2012-02-03 20:18:23 -0800 | [diff] [blame] | 211 | 	/* Vote PLL on in GSS's voting register and wait for it to enable. */ | 
 | 212 | 	writel_relaxed(PLL5_VOTE, PLL_ENA_GSS); | 
 | 213 | 	while ((readl_relaxed(PLL5_STATUS) & PLL_STATUS) == 0) | 
 | 214 | 		cpu_relax(); | 
 | 215 |  | 
 | 216 | 	/* Perform GSS initialization. */ | 
 | 217 | 	gss_init(drv); | 
 | 218 |  | 
 | 219 | 	/* Configure boot address and enable remap. */ | 
 | 220 | 	writel_relaxed(REMAP_ENABLE | (start_addr >> 16), | 
 | 221 | 			base + GSS_CSR_BOOT_REMAP); | 
 | 222 |  | 
 | 223 | 	/* Power up A5 core. */ | 
 | 224 | 	writel_relaxed(A5_POWER_ENA, base + GSS_CSR_POWER_UP_DOWN); | 
 | 225 | 	while (!(readl_relaxed(base + GSS_CSR_POWER_UP_DOWN) & A5_POWER_STATUS)) | 
 | 226 | 		cpu_relax(); | 
 | 227 |  | 
| Matt Wagantall | 556d3f7 | 2012-02-16 17:36:29 -0800 | [diff] [blame] | 228 | 	if (cpu_is_apq8064() && | 
 | 229 | 	    ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) && | 
 | 230 | 	     (SOCINFO_VERSION_MINOR(socinfo_get_version()) == 0))) { | 
 | 231 | 		ret = smp_call_function_single(0, cfg_qgic2_bus_access, drv, 1); | 
 | 232 | 		if (ret) { | 
 | 233 | 			pr_err("Failed to configure QGIC2 bus access\n"); | 
 | 234 | 			pil_gss_shutdown(pil); | 
 | 235 | 			return ret; | 
 | 236 | 		} | 
| Matt Wagantall | 19ac4fd | 2012-02-03 20:18:23 -0800 | [diff] [blame] | 237 | 	} | 
 | 238 |  | 
 | 239 | 	/* Release A5 from reset. */ | 
 | 240 | 	writel_relaxed(0x0, base + GSS_CSR_RESET); | 
 | 241 |  | 
 | 242 | 	return 0; | 
 | 243 | } | 
 | 244 |  | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 245 | static struct pil_reset_ops pil_gss_ops = { | 
 | 246 | 	.init_image = pil_gss_init_image, | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 247 | 	.auth_and_reset = pil_gss_reset, | 
 | 248 | 	.shutdown = pil_gss_shutdown, | 
| Stephen Boyd | ab2b907 | 2012-03-22 10:59:22 -0700 | [diff] [blame] | 249 | 	.proxy_vote = make_gss_proxy_votes, | 
 | 250 | 	.proxy_unvote = remove_gss_proxy_votes, | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 251 | }; | 
 | 252 |  | 
| Matt Wagantall | 11afeee | 2012-02-07 18:38:59 -0800 | [diff] [blame] | 253 | static int pil_gss_init_image_trusted(struct pil_desc *pil, | 
 | 254 | 		const u8 *metadata, size_t size) | 
 | 255 | { | 
 | 256 | 	return pas_init_image(PAS_GSS, metadata, size); | 
 | 257 | } | 
 | 258 |  | 
| Matt Wagantall | 556d3f7 | 2012-02-16 17:36:29 -0800 | [diff] [blame] | 259 | static int pil_gss_shutdown_trusted(struct pil_desc *pil) | 
 | 260 | { | 
 | 261 | 	struct gss_data *drv = dev_get_drvdata(pil->dev); | 
 | 262 | 	int ret; | 
 | 263 |  | 
| Stephen Boyd | 7663ccc | 2012-02-21 19:34:55 -0800 | [diff] [blame] | 264 | 	/* | 
 | 265 | 	 * CXO is used in the secure shutdown code to configure the processor | 
 | 266 | 	 * for low power mode. | 
 | 267 | 	 */ | 
 | 268 | 	ret = clk_prepare_enable(drv->xo); | 
 | 269 | 	if (ret) { | 
 | 270 | 		dev_err(pil->dev, "Failed to enable XO\n"); | 
| Matt Wagantall | 556d3f7 | 2012-02-16 17:36:29 -0800 | [diff] [blame] | 271 | 		return ret; | 
| Stephen Boyd | 7663ccc | 2012-02-21 19:34:55 -0800 | [diff] [blame] | 272 | 	} | 
| Matt Wagantall | 556d3f7 | 2012-02-16 17:36:29 -0800 | [diff] [blame] | 273 |  | 
| Matt Wagantall | f3471ef | 2012-03-09 14:21:54 -0800 | [diff] [blame] | 274 | 	msm_bus_axi_porthalt(MSM_BUS_MASTER_GSS_NAV); | 
| Stephen Boyd | 7663ccc | 2012-02-21 19:34:55 -0800 | [diff] [blame] | 275 | 	ret = pas_shutdown(PAS_GSS); | 
 | 276 | 	clk_disable_unprepare(drv->xo); | 
| Matt Wagantall | 556d3f7 | 2012-02-16 17:36:29 -0800 | [diff] [blame] | 277 |  | 
 | 278 | 	return ret; | 
 | 279 | } | 
 | 280 |  | 
| Matt Wagantall | 11afeee | 2012-02-07 18:38:59 -0800 | [diff] [blame] | 281 | static int pil_gss_reset_trusted(struct pil_desc *pil) | 
 | 282 | { | 
| Matt Wagantall | 11afeee | 2012-02-07 18:38:59 -0800 | [diff] [blame] | 283 | 	int err; | 
 | 284 |  | 
| Matt Wagantall | f3471ef | 2012-03-09 14:21:54 -0800 | [diff] [blame] | 285 | 	err = msm_bus_axi_portunhalt(MSM_BUS_MASTER_GSS_NAV); | 
 | 286 | 	if (err) { | 
 | 287 | 		dev_err(pil->dev, "Failed to unhalt bus port\n"); | 
| Stephen Boyd | ab2b907 | 2012-03-22 10:59:22 -0700 | [diff] [blame] | 288 | 		goto out; | 
| Matt Wagantall | f3471ef | 2012-03-09 14:21:54 -0800 | [diff] [blame] | 289 | 	} | 
| Matt Wagantall | 11afeee | 2012-02-07 18:38:59 -0800 | [diff] [blame] | 290 |  | 
 | 291 | 	err =  pas_auth_and_reset(PAS_GSS); | 
 | 292 | 	if (err) | 
| Matt Wagantall | f3471ef | 2012-03-09 14:21:54 -0800 | [diff] [blame] | 293 | 		goto halt_port; | 
| Matt Wagantall | 11afeee | 2012-02-07 18:38:59 -0800 | [diff] [blame] | 294 |  | 
| Matt Wagantall | f3471ef | 2012-03-09 14:21:54 -0800 | [diff] [blame] | 295 | 	return 0; | 
| Matt Wagantall | 556d3f7 | 2012-02-16 17:36:29 -0800 | [diff] [blame] | 296 |  | 
| Matt Wagantall | f3471ef | 2012-03-09 14:21:54 -0800 | [diff] [blame] | 297 | halt_port: | 
 | 298 | 	msm_bus_axi_porthalt(MSM_BUS_MASTER_GSS_NAV); | 
| Matt Wagantall | f3471ef | 2012-03-09 14:21:54 -0800 | [diff] [blame] | 299 | out: | 
| Matt Wagantall | 11afeee | 2012-02-07 18:38:59 -0800 | [diff] [blame] | 300 | 	return err; | 
 | 301 | } | 
 | 302 |  | 
| Matt Wagantall | 11afeee | 2012-02-07 18:38:59 -0800 | [diff] [blame] | 303 | static struct pil_reset_ops pil_gss_ops_trusted = { | 
 | 304 | 	.init_image = pil_gss_init_image_trusted, | 
| Matt Wagantall | 11afeee | 2012-02-07 18:38:59 -0800 | [diff] [blame] | 305 | 	.auth_and_reset = pil_gss_reset_trusted, | 
 | 306 | 	.shutdown = pil_gss_shutdown_trusted, | 
| Stephen Boyd | ab2b907 | 2012-03-22 10:59:22 -0700 | [diff] [blame] | 307 | 	.proxy_vote = make_gss_proxy_votes, | 
 | 308 | 	.proxy_unvote = remove_gss_proxy_votes, | 
| Matt Wagantall | 11afeee | 2012-02-07 18:38:59 -0800 | [diff] [blame] | 309 | }; | 
 | 310 |  | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 311 | static int __devinit pil_gss_probe(struct platform_device *pdev) | 
 | 312 | { | 
 | 313 | 	struct gss_data *drv; | 
 | 314 | 	struct resource *res; | 
 | 315 | 	struct pil_desc *desc; | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 316 |  | 
 | 317 | 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 
 | 318 | 	if (!res) | 
 | 319 | 		return -EINVAL; | 
 | 320 |  | 
 | 321 | 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); | 
 | 322 | 	if (!drv) | 
 | 323 | 		return -ENOMEM; | 
 | 324 | 	platform_set_drvdata(pdev, drv); | 
 | 325 |  | 
 | 326 | 	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); | 
 | 327 | 	if (!drv->base) | 
 | 328 | 		return -ENOMEM; | 
 | 329 |  | 
 | 330 | 	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL); | 
 | 331 | 	if (!desc) | 
 | 332 | 		return -ENOMEM; | 
 | 333 |  | 
| Matt Wagantall | 19ac4fd | 2012-02-03 20:18:23 -0800 | [diff] [blame] | 334 | 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 
 | 335 | 	if (!res) | 
 | 336 | 		return -EINVAL; | 
 | 337 |  | 
 | 338 | 	drv->qgic2_base = devm_ioremap(&pdev->dev, res->start, | 
 | 339 | 					resource_size(res)); | 
 | 340 | 	if (!drv->qgic2_base) | 
 | 341 | 		return -ENOMEM; | 
 | 342 |  | 
| Stephen Boyd | 22b0447 | 2012-03-23 15:23:10 -0700 | [diff] [blame] | 343 | 	drv->xo = devm_clk_get(&pdev->dev, "xo"); | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 344 | 	if (IS_ERR(drv->xo)) | 
 | 345 | 		return PTR_ERR(drv->xo); | 
 | 346 |  | 
 | 347 | 	desc->name = "gss"; | 
 | 348 | 	desc->dev = &pdev->dev; | 
| Stephen Boyd | 6d67d25 | 2011-09-27 11:50:05 -0700 | [diff] [blame] | 349 | 	desc->owner = THIS_MODULE; | 
| Stephen Boyd | ab2b907 | 2012-03-22 10:59:22 -0700 | [diff] [blame] | 350 | 	desc->proxy_timeout = 10000; | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 351 |  | 
| Matt Wagantall | 11afeee | 2012-02-07 18:38:59 -0800 | [diff] [blame] | 352 | 	if (pas_supported(PAS_GSS) > 0) { | 
 | 353 | 		desc->ops = &pil_gss_ops_trusted; | 
 | 354 | 		dev_info(&pdev->dev, "using secure boot\n"); | 
 | 355 | 	} else { | 
 | 356 | 		desc->ops = &pil_gss_ops; | 
 | 357 | 		dev_info(&pdev->dev, "using non-secure boot\n"); | 
 | 358 | 	} | 
| Stephen Boyd | 95a1c54 | 2012-06-21 12:45:11 -0700 | [diff] [blame] | 359 | 	/* Force into low power mode because hardware doesn't do this */ | 
 | 360 | 	desc->ops->shutdown(desc); | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 361 |  | 
| Stephen Boyd | 6d67d25 | 2011-09-27 11:50:05 -0700 | [diff] [blame] | 362 | 	drv->pil = msm_pil_register(desc); | 
 | 363 | 	if (IS_ERR(drv->pil)) { | 
| Stephen Boyd | 6d67d25 | 2011-09-27 11:50:05 -0700 | [diff] [blame] | 364 | 		return PTR_ERR(drv->pil); | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 365 | 	} | 
| Stephen Boyd | 6d67d25 | 2011-09-27 11:50:05 -0700 | [diff] [blame] | 366 | 	return 0; | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 367 | } | 
 | 368 |  | 
 | 369 | static int __devexit pil_gss_remove(struct platform_device *pdev) | 
 | 370 | { | 
 | 371 | 	struct gss_data *drv = platform_get_drvdata(pdev); | 
| Stephen Boyd | 6d67d25 | 2011-09-27 11:50:05 -0700 | [diff] [blame] | 372 | 	msm_pil_unregister(drv->pil); | 
| Matt Wagantall | 292aace | 2012-01-26 19:12:34 -0800 | [diff] [blame] | 373 | 	return 0; | 
 | 374 | } | 
 | 375 |  | 
 | 376 | static struct platform_driver pil_gss_driver = { | 
 | 377 | 	.probe = pil_gss_probe, | 
 | 378 | 	.remove = __devexit_p(pil_gss_remove), | 
 | 379 | 	.driver = { | 
 | 380 | 		.name = "pil_gss", | 
 | 381 | 		.owner = THIS_MODULE, | 
 | 382 | 	}, | 
 | 383 | }; | 
 | 384 |  | 
 | 385 | static int __init pil_gss_init(void) | 
 | 386 | { | 
 | 387 | 	return platform_driver_register(&pil_gss_driver); | 
 | 388 | } | 
 | 389 | module_init(pil_gss_init); | 
 | 390 |  | 
 | 391 | static void __exit pil_gss_exit(void) | 
 | 392 | { | 
 | 393 | 	platform_driver_unregister(&pil_gss_driver); | 
 | 394 | } | 
 | 395 | module_exit(pil_gss_exit); | 
 | 396 |  | 
 | 397 | MODULE_DESCRIPTION("Support for booting the GSS processor"); | 
 | 398 | MODULE_LICENSE("GPL v2"); |