blob: 1fcd3ba84cea11e65e61d2ece60d7ac0451be995 [file] [log] [blame]
Tianyi Gou828798d2012-05-02 21:12:38 -07001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/err.h>
15#include <linux/io.h>
Tianyi Gou828798d2012-05-02 21:12:38 -070016#include <linux/delay.h>
17#include <linux/module.h>
18#include <linux/slab.h>
19#include <linux/platform_device.h>
20#include <linux/iommu.h>
21#include <linux/iopoll.h>
22#include <linux/of.h>
23#include <linux/regulator/consumer.h>
24
25#include <asm/page.h>
26#include <asm/sizes.h>
27
28#include <mach/iommu.h>
29#include <mach/iommu_domains.h>
Stephen Boyd046013f2012-06-28 20:24:17 -070030#include <mach/subsystem_restart.h>
Tianyi Gouedfa6382012-08-23 10:39:26 -070031#include <mach/msm_bus_board.h>
32#include <mach/msm_bus.h>
Tianyi Gou828798d2012-05-02 21:12:38 -070033
34#include "peripheral-loader.h"
35#include "scm-pas.h"
Vinay Kalia17107ca2012-12-05 14:40:14 -080036#include "ramdump.h"
Tianyi Gou828798d2012-05-02 21:12:38 -070037
38/* VENUS WRAPPER registers */
39#define VENUS_WRAPPER_CLOCK_CONFIG 0x4
40#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR 0x1018
41#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR 0x101C
42#define VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR 0x1020
43#define VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR 0x1024
44#define VENUS_WRAPPER_CPU_CLOCK_CONFIG 0x2000
45#define VENUS_WRAPPER_SW_RESET 0x3000
46
47/* VENUS VBIF registers */
48#define VENUS_VBIF_AXI_HALT_CTRL0 0x0
49#define VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ BIT(0)
50
51#define VENUS_VBIF_AXI_HALT_CTRL1 0x4
52#define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK BIT(0)
53#define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US 500000
54
55/* PIL proxy vote timeout */
56#define VENUS_PROXY_TIMEOUT 10000
57
58/* Poll interval in uS */
59#define POLL_INTERVAL_US 50
60
61static const char * const clk_names[] = {
62 "core_clk",
63 "iface_clk",
64 "bus_clk",
65 "mem_clk",
66};
67
68struct venus_data {
69 void __iomem *venus_wrapper_base;
70 void __iomem *venus_vbif_base;
Stephen Boyde83a0a22012-06-29 13:51:27 -070071 struct pil_desc desc;
Stephen Boyd046013f2012-06-28 20:24:17 -070072 struct subsys_device *subsys;
73 struct subsys_desc subsys_desc;
Tianyi Gou828798d2012-05-02 21:12:38 -070074 struct regulator *gdsc;
Tianyi Gou828798d2012-05-02 21:12:38 -070075 struct clk *clks[ARRAY_SIZE(clk_names)];
76 struct device *iommu_fw_ctx;
77 struct iommu_domain *iommu_fw_domain;
78 int venus_domain_num;
79 bool is_booted;
Vinay Kalia17107ca2012-12-05 14:40:14 -080080 void *ramdump_dev;
Tianyi Gou828798d2012-05-02 21:12:38 -070081 u32 fw_sz;
82 u32 fw_min_paddr;
83 u32 fw_max_paddr;
Tianyi Gouedfa6382012-08-23 10:39:26 -070084 u32 bus_perf_client;
Tianyi Gou828798d2012-05-02 21:12:38 -070085};
86
Stephen Boyd046013f2012-06-28 20:24:17 -070087#define subsys_to_drv(d) container_of(d, struct venus_data, subsys_desc)
88
Tianyi Gou828798d2012-05-02 21:12:38 -070089static int venus_register_domain(u32 fw_max_sz)
90{
91 struct msm_iova_partition venus_fw_partition = {
92 .start = 0,
93 .size = fw_max_sz,
94 };
95 struct msm_iova_layout venus_fw_layout = {
96 .partitions = &venus_fw_partition,
97 .npartitions = 1,
98 .client_name = "pil_venus",
99 .domain_flags = 0,
100 };
101
102 return msm_register_domain(&venus_fw_layout);
103}
104
105/* Get venus clocks and set rates for rate-settable clocks */
106static int venus_clock_setup(struct device *dev)
107{
108 struct venus_data *drv = dev_get_drvdata(dev);
109 int i;
110
111 for (i = 0; i < ARRAY_SIZE(drv->clks); i++) {
112 drv->clks[i] = devm_clk_get(dev, clk_names[i]);
113 if (IS_ERR(drv->clks[i])) {
114 dev_err(dev, "failed to get %s\n",
115 clk_names[i]);
116 return PTR_ERR(drv->clks[i]);
117 }
118 /* Make sure rate-settable clocks' rates are set */
119 if (clk_get_rate(drv->clks[i]) == 0)
120 clk_set_rate(drv->clks[i],
121 clk_round_rate(drv->clks[i], 0));
122 }
123
124 return 0;
125}
126
127static int venus_clock_prepare_enable(struct device *dev)
128{
129 struct venus_data *drv = dev_get_drvdata(dev);
130 int rc, i;
131
132 for (i = 0; i < ARRAY_SIZE(drv->clks); i++) {
133 rc = clk_prepare_enable(drv->clks[i]);
134 if (rc) {
135 dev_err(dev, "failed to enable %s\n",
136 clk_names[i]);
137 for (i--; i >= 0; i--)
138 clk_disable_unprepare(drv->clks[i]);
139 return rc;
140 }
141 }
142
143 return 0;
144}
145
146static void venus_clock_disable_unprepare(struct device *dev)
147{
148 struct venus_data *drv = dev_get_drvdata(dev);
149 int i;
150
151 for (i = 0; i < ARRAY_SIZE(drv->clks); i++)
152 clk_disable_unprepare(drv->clks[i]);
153}
154
Tianyi Gouedfa6382012-08-23 10:39:26 -0700155static struct msm_bus_vectors pil_venus_unvote_bw_vector[] = {
156 {
157 .src = MSM_BUS_MASTER_VIDEO_P0,
158 .dst = MSM_BUS_SLAVE_EBI_CH0,
159 .ab = 0,
160 .ib = 0,
161 },
162};
163
164static struct msm_bus_vectors pil_venus_vote_bw_vector[] = {
165 {
166 .src = MSM_BUS_MASTER_VIDEO_P0,
167 .dst = MSM_BUS_SLAVE_EBI_CH0,
168 .ab = 0,
169 .ib = 16 * 19 * 1000000UL, /* At least 19.2MHz on bus. */
170 },
171};
172
173static struct msm_bus_paths pil_venus_bw_tbl[] = {
174 {
175 .num_paths = ARRAY_SIZE(pil_venus_unvote_bw_vector),
176 .vectors = pil_venus_unvote_bw_vector,
177 },
178 {
179 .num_paths = ARRAY_SIZE(pil_venus_vote_bw_vector),
180 .vectors = pil_venus_vote_bw_vector,
181 },
182};
183
184static struct msm_bus_scale_pdata pil_venus_client_pdata = {
185 .usecase = pil_venus_bw_tbl,
186 .num_usecases = ARRAY_SIZE(pil_venus_bw_tbl),
187 .name = "pil-venus",
188};
189
Tianyi Gou828798d2012-05-02 21:12:38 -0700190static int pil_venus_make_proxy_vote(struct pil_desc *pil)
191{
192 struct venus_data *drv = dev_get_drvdata(pil->dev);
193 int rc;
194
195 /*
196 * Clocks need to be proxy voted to be able to pass control
197 * of clocks from PIL driver to the Venus driver. But GDSC
198 * needs to be turned on before clocks can be turned on. So
199 * enable the GDSC here.
200 */
201 rc = regulator_enable(drv->gdsc);
202 if (rc) {
203 dev_err(pil->dev, "GDSC enable failed\n");
Tianyi Gouedfa6382012-08-23 10:39:26 -0700204 goto err_regulator;
Tianyi Gou828798d2012-05-02 21:12:38 -0700205 }
206
207 rc = venus_clock_prepare_enable(pil->dev);
Tianyi Gouedfa6382012-08-23 10:39:26 -0700208 if (rc) {
209 dev_err(pil->dev, "clock prepare and enable failed\n");
210 goto err_clock;
211 }
Tianyi Gou828798d2012-05-02 21:12:38 -0700212
Tianyi Gouedfa6382012-08-23 10:39:26 -0700213 rc = msm_bus_scale_client_update_request(drv->bus_perf_client, 1);
214 if (rc) {
215 dev_err(pil->dev, "bandwith request failed\n");
216 goto err_bw;
217 }
218
219 return 0;
220
221err_bw:
222 venus_clock_disable_unprepare(pil->dev);
223err_clock:
224 regulator_disable(drv->gdsc);
225err_regulator:
Tianyi Gou828798d2012-05-02 21:12:38 -0700226 return rc;
227}
228
229static void pil_venus_remove_proxy_vote(struct pil_desc *pil)
230{
231 struct venus_data *drv = dev_get_drvdata(pil->dev);
232
Tianyi Gouedfa6382012-08-23 10:39:26 -0700233 msm_bus_scale_client_update_request(drv->bus_perf_client, 0);
234
Tianyi Gou828798d2012-05-02 21:12:38 -0700235 venus_clock_disable_unprepare(pil->dev);
236
237 /* Disable GDSC */
238 regulator_disable(drv->gdsc);
239}
240
Stephen Boyde6477b92012-08-08 18:22:13 -0700241static int pil_venus_mem_setup(struct pil_desc *pil, phys_addr_t addr,
242 size_t size)
Tianyi Gou828798d2012-05-02 21:12:38 -0700243{
Stephen Boyde6477b92012-08-08 18:22:13 -0700244 int domain;
Tianyi Gou828798d2012-05-02 21:12:38 -0700245 struct venus_data *drv = dev_get_drvdata(pil->dev);
246
Stephen Boyde6477b92012-08-08 18:22:13 -0700247 /* TODO: unregister? */
248 if (!drv->venus_domain_num) {
249 size = round_up(size, SZ_4K);
250 domain = venus_register_domain(size);
251 if (domain < 0) {
252 dev_err(pil->dev, "Venus fw iommu domain register failed\n");
253 return -ENODEV;
254 }
255 drv->iommu_fw_domain = msm_get_iommu_domain(domain);
256 if (!drv->iommu_fw_domain) {
257 dev_err(pil->dev, "No iommu fw domain found\n");
258 return -ENODEV;
259 }
260 drv->venus_domain_num = domain;
261 drv->fw_sz = size;
Tianyi Gou828798d2012-05-02 21:12:38 -0700262 }
263
Tianyi Gou828798d2012-05-02 21:12:38 -0700264 return 0;
265}
266
267static int pil_venus_reset(struct pil_desc *pil)
268{
269 int rc;
270 struct venus_data *drv = dev_get_drvdata(pil->dev);
271 void __iomem *wrapper_base = drv->venus_wrapper_base;
Stephen Boyde6477b92012-08-08 18:22:13 -0700272 phys_addr_t pa = pil_get_entry_addr(pil);
Tianyi Gou828798d2012-05-02 21:12:38 -0700273 unsigned long iova;
274
275 /*
276 * GDSC needs to remain on till Venus is shutdown. So, enable
277 * the GDSC here again to make sure it remains on beyond the
278 * expiry of the proxy vote timer.
279 */
280 rc = regulator_enable(drv->gdsc);
281 if (rc) {
282 dev_err(pil->dev, "GDSC enable failed\n");
283 return rc;
284 }
285
286 /* Program CPA start and end address */
287 writel_relaxed(0, wrapper_base +
288 VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR);
289 writel_relaxed(drv->fw_sz, wrapper_base +
290 VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR);
291
292 /* Program FW start and end address */
293 writel_relaxed(0, wrapper_base +
294 VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR);
295 writel_relaxed(drv->fw_sz, wrapper_base +
296 VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR);
297
Tianyi Gou828798d2012-05-02 21:12:38 -0700298 /* Enable all Venus internal clocks */
299 writel_relaxed(0, wrapper_base + VENUS_WRAPPER_CLOCK_CONFIG);
300 writel_relaxed(0, wrapper_base + VENUS_WRAPPER_CPU_CLOCK_CONFIG);
301
302 /* Make sure clocks are enabled */
303 mb();
304
305 /*
306 * Need to wait 10 cycles of internal clocks before bringing ARM9
307 * out of reset.
308 */
309 udelay(1);
310
Tianyi Gou79626242012-08-10 01:04:30 -0700311 rc = iommu_attach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
312 if (rc) {
313 dev_err(pil->dev, "venus fw iommu attach failed\n");
314 goto err_iommu_attach;
315 }
316
Tianyi Gou828798d2012-05-02 21:12:38 -0700317 /* Map virtual addr space 0 - fw_sz to firmware physical addr space */
318 rc = msm_iommu_map_contig_buffer(pa, drv->venus_domain_num, 0,
319 drv->fw_sz, SZ_4K, 0, &iova);
320
321 if (rc || (iova != 0)) {
322 dev_err(pil->dev, "Failed to setup IOMMU\n");
323 goto err_iommu_map;
324 }
325
326 /* Bring Arm9 out of reset */
327 writel_relaxed(0, wrapper_base + VENUS_WRAPPER_SW_RESET);
328
329 drv->is_booted = 1;
330
331 return 0;
332
333err_iommu_map:
334 iommu_detach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
335
336err_iommu_attach:
337 regulator_disable(drv->gdsc);
338
339 return rc;
340}
341
342static int pil_venus_shutdown(struct pil_desc *pil)
343{
344 struct venus_data *drv = dev_get_drvdata(pil->dev);
345 void __iomem *vbif_base = drv->venus_vbif_base;
346 void __iomem *wrapper_base = drv->venus_wrapper_base;
347 u32 reg;
348 int rc;
349
350 if (!drv->is_booted)
351 return 0;
352
353 venus_clock_prepare_enable(pil->dev);
354
Tianyi Gou828798d2012-05-02 21:12:38 -0700355 /* Assert the reset to ARM9 */
356 reg = readl_relaxed(wrapper_base + VENUS_WRAPPER_SW_RESET);
357 reg |= BIT(4);
358 writel_relaxed(reg, wrapper_base + VENUS_WRAPPER_SW_RESET);
359
360 /* Make sure reset is asserted before the mapping is removed */
361 mb();
362
363 msm_iommu_unmap_contig_buffer(0, drv->venus_domain_num,
364 0, drv->fw_sz);
365
366 iommu_detach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
367
Tianyi Gou79626242012-08-10 01:04:30 -0700368 /* Halt AXI and AXI OCMEM VBIF Access */
369 reg = readl_relaxed(vbif_base + VENUS_VBIF_AXI_HALT_CTRL0);
370 reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
371 writel_relaxed(reg, vbif_base + VENUS_VBIF_AXI_HALT_CTRL0);
372
373 /* Request for AXI bus port halt */
374 rc = readl_poll_timeout(vbif_base + VENUS_VBIF_AXI_HALT_CTRL1,
375 reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK,
376 POLL_INTERVAL_US,
377 VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
378 if (rc)
379 dev_err(pil->dev, "Port halt timeout\n");
380
Tianyi Gou828798d2012-05-02 21:12:38 -0700381 venus_clock_disable_unprepare(pil->dev);
382
383 regulator_disable(drv->gdsc);
384
385 drv->is_booted = 0;
386
387 return 0;
388}
389
390static struct pil_reset_ops pil_venus_ops = {
Stephen Boyde6477b92012-08-08 18:22:13 -0700391 .mem_setup = pil_venus_mem_setup,
Tianyi Gou828798d2012-05-02 21:12:38 -0700392 .auth_and_reset = pil_venus_reset,
393 .shutdown = pil_venus_shutdown,
394 .proxy_vote = pil_venus_make_proxy_vote,
395 .proxy_unvote = pil_venus_remove_proxy_vote,
396};
397
Tianyi Gou8d5b8e12012-08-06 16:24:47 -0700398static int pil_venus_init_image_trusted(struct pil_desc *pil,
399 const u8 *metadata, size_t size)
400{
401 return pas_init_image(PAS_VIDC, metadata, size);
402}
403
Stephen Boydc8c5db92012-12-03 11:13:20 -0800404static int pil_venus_mem_setup_trusted(struct pil_desc *pil, phys_addr_t addr,
405 size_t size)
406{
407 return pas_mem_setup(PAS_VIDC, addr, size);
408}
409
Tianyi Gou8d5b8e12012-08-06 16:24:47 -0700410static int pil_venus_reset_trusted(struct pil_desc *pil)
411{
412 int rc;
413 struct venus_data *drv = dev_get_drvdata(pil->dev);
414
415 /*
416 * GDSC needs to remain on till Venus is shutdown. So, enable
417 * the GDSC here again to make sure it remains on beyond the
418 * expiry of the proxy vote timer.
419 */
420 rc = regulator_enable(drv->gdsc);
421 if (rc) {
422 dev_err(pil->dev, "GDSC enable failed\n");
423 return rc;
424 }
425
426 rc = pas_auth_and_reset(PAS_VIDC);
427 if (rc)
428 regulator_disable(drv->gdsc);
429
430 return rc;
431}
432
433static int pil_venus_shutdown_trusted(struct pil_desc *pil)
434{
435 int rc;
436 struct venus_data *drv = dev_get_drvdata(pil->dev);
437
438 venus_clock_prepare_enable(pil->dev);
439
440 rc = pas_shutdown(PAS_VIDC);
441
442 venus_clock_disable_unprepare(pil->dev);
443
444 regulator_disable(drv->gdsc);
445
446 return rc;
447}
448
449static struct pil_reset_ops pil_venus_ops_trusted = {
450 .init_image = pil_venus_init_image_trusted,
Stephen Boydc8c5db92012-12-03 11:13:20 -0800451 .mem_setup = pil_venus_mem_setup_trusted,
Tianyi Gou8d5b8e12012-08-06 16:24:47 -0700452 .auth_and_reset = pil_venus_reset_trusted,
453 .shutdown = pil_venus_shutdown_trusted,
454 .proxy_vote = pil_venus_make_proxy_vote,
455 .proxy_unvote = pil_venus_remove_proxy_vote,
456};
457
Stephen Boyd046013f2012-06-28 20:24:17 -0700458static int venus_start(const struct subsys_desc *desc)
459{
Stephen Boyd046013f2012-06-28 20:24:17 -0700460 struct venus_data *drv = subsys_to_drv(desc);
461
Stephen Boyde83a0a22012-06-29 13:51:27 -0700462 return pil_boot(&drv->desc);
Stephen Boyd046013f2012-06-28 20:24:17 -0700463}
464
465static void venus_stop(const struct subsys_desc *desc)
466{
467 struct venus_data *drv = subsys_to_drv(desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700468 pil_shutdown(&drv->desc);
Stephen Boyd046013f2012-06-28 20:24:17 -0700469}
470
Vinay Kalia17107ca2012-12-05 14:40:14 -0800471static int venus_shutdown(const struct subsys_desc *desc)
472{
473 struct venus_data *drv = subsys_to_drv(desc);
474 pil_shutdown(&drv->desc);
475 return 0;
476}
477
478static int venus_powerup(const struct subsys_desc *desc)
479{
480 struct venus_data *drv = subsys_to_drv(desc);
481 return pil_boot(&drv->desc);
482}
483
484static int venus_ramdump(int enable, const struct subsys_desc *desc)
485{
486 struct venus_data *drv = subsys_to_drv(desc);
487
488 if (!enable)
489 return 0;
490
491 return pil_do_ramdump(&drv->desc, drv->ramdump_dev);
492}
493
Tianyi Gou828798d2012-05-02 21:12:38 -0700494static int __devinit pil_venus_probe(struct platform_device *pdev)
495{
496 struct venus_data *drv;
497 struct resource *res;
498 struct pil_desc *desc;
499 int rc;
500
Tianyi Gou828798d2012-05-02 21:12:38 -0700501 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
502 if (!drv)
503 return -ENOMEM;
504 platform_set_drvdata(pdev, drv);
505
Stephen Boydf8f89282012-07-16 18:05:48 -0700506
507 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
508 "wrapper_base");
509 drv->venus_wrapper_base = devm_request_and_ioremap(&pdev->dev, res);
Tianyi Gou828798d2012-05-02 21:12:38 -0700510 if (!drv->venus_wrapper_base)
511 return -ENOMEM;
512
Matt Wagantall1f168152012-09-25 13:26:47 -0700513 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vbif_base");
Stephen Boydf8f89282012-07-16 18:05:48 -0700514 drv->venus_vbif_base = devm_request_and_ioremap(&pdev->dev, res);
Tianyi Gou828798d2012-05-02 21:12:38 -0700515 if (!drv->venus_vbif_base)
516 return -ENOMEM;
517
518 drv->gdsc = devm_regulator_get(&pdev->dev, "vdd");
519 if (IS_ERR(drv->gdsc)) {
520 dev_err(&pdev->dev, "Failed to get Venus GDSC\n");
521 return -ENODEV;
522 }
523
524 rc = venus_clock_setup(&pdev->dev);
525 if (rc)
526 return rc;
527
Tianyi Gouedfa6382012-08-23 10:39:26 -0700528 drv->bus_perf_client =
529 msm_bus_scale_register_client(&pil_venus_client_pdata);
530 if (!drv->bus_perf_client) {
531 dev_err(&pdev->dev, "Failed to register bus client\n");
532 return -EINVAL;
533 }
534
Tianyi Gou828798d2012-05-02 21:12:38 -0700535 drv->iommu_fw_ctx = msm_iommu_get_ctx("venus_fw");
536 if (!drv->iommu_fw_ctx) {
537 dev_err(&pdev->dev, "No iommu fw context found\n");
538 return -ENODEV;
539 }
540
Stephen Boyde83a0a22012-06-29 13:51:27 -0700541 desc = &drv->desc;
Tianyi Gou828798d2012-05-02 21:12:38 -0700542 rc = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
543 &desc->name);
544 if (rc)
545 return rc;
546
547 desc->dev = &pdev->dev;
548 desc->owner = THIS_MODULE;
549 desc->proxy_timeout = VENUS_PROXY_TIMEOUT;
550
Tianyi Gou8d5b8e12012-08-06 16:24:47 -0700551 if (pas_supported(PAS_VIDC) > 0) {
552 desc->ops = &pil_venus_ops_trusted;
553 dev_info(&pdev->dev, "using secure boot\n");
554 } else {
555 desc->ops = &pil_venus_ops;
556 dev_info(&pdev->dev, "using non-secure boot\n");
557 }
Tianyi Gou828798d2012-05-02 21:12:38 -0700558
Vinay Kalia17107ca2012-12-05 14:40:14 -0800559 drv->ramdump_dev = create_ramdump_device("venus", &pdev->dev);
560 if (!drv->ramdump_dev)
561 return -ENOMEM;
562
Stephen Boyde83a0a22012-06-29 13:51:27 -0700563 rc = pil_desc_init(desc);
564 if (rc)
Vinay Kalia17107ca2012-12-05 14:40:14 -0800565 goto err_ramdump;
Tianyi Gou828798d2012-05-02 21:12:38 -0700566
Stephen Boyd046013f2012-06-28 20:24:17 -0700567 drv->subsys_desc.name = desc->name;
568 drv->subsys_desc.owner = THIS_MODULE;
569 drv->subsys_desc.dev = &pdev->dev;
570 drv->subsys_desc.start = venus_start;
571 drv->subsys_desc.stop = venus_stop;
Vinay Kalia17107ca2012-12-05 14:40:14 -0800572 drv->subsys_desc.shutdown = venus_shutdown;
573 drv->subsys_desc.powerup = venus_powerup;
574 drv->subsys_desc.ramdump = venus_ramdump;
Stephen Boyd046013f2012-06-28 20:24:17 -0700575
576 drv->subsys = subsys_register(&drv->subsys_desc);
577 if (IS_ERR(drv->subsys)) {
Vinay Kalia17107ca2012-12-05 14:40:14 -0800578 rc = PTR_ERR(drv->subsys);
579 goto err_subsys;
Stephen Boyd046013f2012-06-28 20:24:17 -0700580 }
Vinay Kalia17107ca2012-12-05 14:40:14 -0800581 return rc;
582err_subsys:
583 pil_desc_release(desc);
584err_ramdump:
585 destroy_ramdump_device(drv->ramdump_dev);
586 return rc;
Tianyi Gou828798d2012-05-02 21:12:38 -0700587}
588
589static int __devexit pil_venus_remove(struct platform_device *pdev)
590{
591 struct venus_data *drv = platform_get_drvdata(pdev);
Stephen Boyd046013f2012-06-28 20:24:17 -0700592 subsys_unregister(drv->subsys);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700593 pil_desc_release(&drv->desc);
Tianyi Gou828798d2012-05-02 21:12:38 -0700594
595 return 0;
596}
597
598#ifdef CONFIG_OF
599static const struct of_device_id msm_pil_venus_match[] = {
600 {.compatible = "qcom,pil-venus"},
601 {}
602};
603#endif
604
605static struct platform_driver pil_venus_driver = {
606 .probe = pil_venus_probe,
607 .remove = __devexit_p(pil_venus_remove),
608 .driver = {
609 .name = "pil_venus",
610 .owner = THIS_MODULE,
611 .of_match_table = of_match_ptr(msm_pil_venus_match),
612 },
613};
614
615module_platform_driver(pil_venus_driver);
616
617MODULE_DESCRIPTION("Support for booting VENUS processors");
618MODULE_LICENSE("GPL v2");