blob: 629907f9ed244d1b46093ae5513f9ccd7816464b [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
Stephen Boyd7b973de2012-03-09 12:26:16 -08002 *
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/init.h>
14#include <linux/module.h>
15#include <linux/platform_device.h>
Stephen Boyd7b973de2012-03-09 12:26:16 -080016#include <linux/err.h>
17#include <linux/clk.h>
18
Stephen Boyd046013f2012-06-28 20:24:17 -070019#include <mach/subsystem_restart.h>
20
Stephen Boyd7b973de2012-03-09 12:26:16 -080021#include "peripheral-loader.h"
22#include "scm-pas.h"
23
24struct vidc_data {
25 struct clk *smmu_iface;
26 struct clk *core;
Stephen Boyde83a0a22012-06-29 13:51:27 -070027 struct pil_desc pil_desc;
Stephen Boyd046013f2012-06-28 20:24:17 -070028 struct subsys_device *subsys;
29 struct subsys_desc subsys_desc;
Stephen Boyd7b973de2012-03-09 12:26:16 -080030};
31
32static int pil_vidc_init_image(struct pil_desc *pil, const u8 *metadata,
33 size_t size)
34{
35 return pas_init_image(PAS_VIDC, metadata, size);
36}
37
38static int pil_vidc_reset(struct pil_desc *pil)
39{
40 int ret;
41 struct vidc_data *drv = dev_get_drvdata(pil->dev);
42
43 ret = clk_prepare_enable(drv->smmu_iface);
44 if (ret)
45 goto err_smmu;
46 ret = clk_prepare_enable(drv->core);
47 if (ret)
48 goto err_core;
49 ret = pas_auth_and_reset(PAS_VIDC);
50
51 clk_disable_unprepare(drv->core);
52err_core:
53 clk_disable_unprepare(drv->smmu_iface);
54err_smmu:
55 return ret;
56}
57
58static int pil_vidc_shutdown(struct pil_desc *pil)
59{
60 return pas_shutdown(PAS_VIDC);
61}
62
63static struct pil_reset_ops pil_vidc_ops = {
64 .init_image = pil_vidc_init_image,
65 .auth_and_reset = pil_vidc_reset,
66 .shutdown = pil_vidc_shutdown,
67};
68
Stephen Boyd046013f2012-06-28 20:24:17 -070069#define subsys_to_drv(d) container_of(d, struct vidc_data, subsys_desc)
70
71static int vidc_start(const struct subsys_desc *desc)
72{
Stephen Boyde83a0a22012-06-29 13:51:27 -070073 struct vidc_data *drv = subsys_to_drv(desc);
74 return pil_boot(&drv->pil_desc);
Stephen Boyd046013f2012-06-28 20:24:17 -070075}
76
77static void vidc_stop(const struct subsys_desc *desc)
78{
79 struct vidc_data *drv = subsys_to_drv(desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -070080 pil_shutdown(&drv->pil_desc);
Stephen Boyd046013f2012-06-28 20:24:17 -070081}
82
Stephen Boyd7b973de2012-03-09 12:26:16 -080083static int __devinit pil_vidc_driver_probe(struct platform_device *pdev)
84{
85 struct pil_desc *desc;
86 struct vidc_data *drv;
Stephen Boyde83a0a22012-06-29 13:51:27 -070087 int ret;
Stephen Boyd7b973de2012-03-09 12:26:16 -080088
89 if (pas_supported(PAS_VIDC) < 0)
90 return -ENOSYS;
91
Stephen Boyd7b973de2012-03-09 12:26:16 -080092 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
93 if (!drv)
94 return -ENOMEM;
95 platform_set_drvdata(pdev, drv);
Stephen Boyd46e51b52012-06-27 13:29:47 -070096
97 drv->smmu_iface = devm_clk_get(&pdev->dev, "smmu_iface_clk");
98 if (IS_ERR(drv->smmu_iface))
99 return PTR_ERR(drv->smmu_iface);
100
101 drv->core = devm_clk_get(&pdev->dev, "core_clk");
102 if (IS_ERR(drv->core))
103 return PTR_ERR(drv->core);
Stephen Boyd7b973de2012-03-09 12:26:16 -0800104
Stephen Boyde83a0a22012-06-29 13:51:27 -0700105 desc = &drv->pil_desc;
Stephen Boyd7b973de2012-03-09 12:26:16 -0800106 desc->name = "vidc";
107 desc->dev = &pdev->dev;
108 desc->ops = &pil_vidc_ops;
109 desc->owner = THIS_MODULE;
Stephen Boyde83a0a22012-06-29 13:51:27 -0700110 ret = pil_desc_init(desc);
111 if (ret)
112 return ret;
Stephen Boyd046013f2012-06-28 20:24:17 -0700113
114 drv->subsys_desc.name = "vidc";
115 drv->subsys_desc.dev = &pdev->dev;
116 drv->subsys_desc.owner = THIS_MODULE;
117 drv->subsys_desc.start = vidc_start;
118 drv->subsys_desc.stop = vidc_stop;
119
120 drv->subsys = subsys_register(&drv->subsys_desc);
121 if (IS_ERR(drv->subsys)) {
Stephen Boyde83a0a22012-06-29 13:51:27 -0700122 pil_desc_release(desc);
Stephen Boyd046013f2012-06-28 20:24:17 -0700123 return PTR_ERR(drv->subsys);
124 }
Stephen Boyd7b973de2012-03-09 12:26:16 -0800125 return 0;
Stephen Boyd7b973de2012-03-09 12:26:16 -0800126}
127
128static int __devexit pil_vidc_driver_exit(struct platform_device *pdev)
129{
130 struct vidc_data *drv = platform_get_drvdata(pdev);
Stephen Boyd046013f2012-06-28 20:24:17 -0700131 subsys_unregister(drv->subsys);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700132 pil_desc_release(&drv->pil_desc);
Stephen Boyd7b973de2012-03-09 12:26:16 -0800133 return 0;
134}
135
136static struct platform_driver pil_vidc_driver = {
137 .probe = pil_vidc_driver_probe,
138 .remove = __devexit_p(pil_vidc_driver_exit),
139 .driver = {
140 .name = "pil_vidc",
141 .owner = THIS_MODULE,
142 },
143};
144
145static int __init pil_vidc_init(void)
146{
147 return platform_driver_register(&pil_vidc_driver);
148}
149module_init(pil_vidc_init);
150
151static void __exit pil_vidc_exit(void)
152{
153 platform_driver_unregister(&pil_vidc_driver);
154}
155module_exit(pil_vidc_exit);
156
157MODULE_DESCRIPTION("Support for secure booting vidc images");
158MODULE_LICENSE("GPL v2");