blob: 3dbddae8ac2219715e67833e5b86dbbad20caa44 [file] [log] [blame]
Deepak Katragadda4118ccc2013-07-05 10:01:19 -07001/* Copyright (c) 2012-2013, 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>
Deepak Katragadda4118ccc2013-07-05 10:01:19 -070020#include <mach/msm_bus_board.h>
Stephen Boyd046013f2012-06-28 20:24:17 -070021
Stephen Boyd7b973de2012-03-09 12:26:16 -080022#include "peripheral-loader.h"
23#include "scm-pas.h"
24
25struct vidc_data {
26 struct clk *smmu_iface;
27 struct clk *core;
Stephen Boyde83a0a22012-06-29 13:51:27 -070028 struct pil_desc pil_desc;
Stephen Boyd046013f2012-06-28 20:24:17 -070029 struct subsys_device *subsys;
30 struct subsys_desc subsys_desc;
Stephen Boyd7b973de2012-03-09 12:26:16 -080031};
32
33static int pil_vidc_init_image(struct pil_desc *pil, const u8 *metadata,
34 size_t size)
35{
36 return pas_init_image(PAS_VIDC, metadata, size);
37}
38
39static int pil_vidc_reset(struct pil_desc *pil)
40{
41 int ret;
42 struct vidc_data *drv = dev_get_drvdata(pil->dev);
43
44 ret = clk_prepare_enable(drv->smmu_iface);
45 if (ret)
46 goto err_smmu;
47 ret = clk_prepare_enable(drv->core);
48 if (ret)
49 goto err_core;
50 ret = pas_auth_and_reset(PAS_VIDC);
51
52 clk_disable_unprepare(drv->core);
53err_core:
54 clk_disable_unprepare(drv->smmu_iface);
55err_smmu:
56 return ret;
57}
58
59static int pil_vidc_shutdown(struct pil_desc *pil)
60{
61 return pas_shutdown(PAS_VIDC);
62}
63
64static struct pil_reset_ops pil_vidc_ops = {
65 .init_image = pil_vidc_init_image,
66 .auth_and_reset = pil_vidc_reset,
67 .shutdown = pil_vidc_shutdown,
68};
69
Stephen Boyd046013f2012-06-28 20:24:17 -070070#define subsys_to_drv(d) container_of(d, struct vidc_data, subsys_desc)
71
72static int vidc_start(const struct subsys_desc *desc)
73{
Stephen Boyde83a0a22012-06-29 13:51:27 -070074 struct vidc_data *drv = subsys_to_drv(desc);
75 return pil_boot(&drv->pil_desc);
Stephen Boyd046013f2012-06-28 20:24:17 -070076}
77
78static void vidc_stop(const struct subsys_desc *desc)
79{
80 struct vidc_data *drv = subsys_to_drv(desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -070081 pil_shutdown(&drv->pil_desc);
Stephen Boyd046013f2012-06-28 20:24:17 -070082}
83
Stephen Boyd7b973de2012-03-09 12:26:16 -080084static int __devinit pil_vidc_driver_probe(struct platform_device *pdev)
85{
86 struct pil_desc *desc;
87 struct vidc_data *drv;
Stephen Boyde83a0a22012-06-29 13:51:27 -070088 int ret;
Stephen Boyd7b973de2012-03-09 12:26:16 -080089
90 if (pas_supported(PAS_VIDC) < 0)
91 return -ENOSYS;
92
Stephen Boyd7b973de2012-03-09 12:26:16 -080093 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
94 if (!drv)
95 return -ENOMEM;
96 platform_set_drvdata(pdev, drv);
Stephen Boyd46e51b52012-06-27 13:29:47 -070097
98 drv->smmu_iface = devm_clk_get(&pdev->dev, "smmu_iface_clk");
99 if (IS_ERR(drv->smmu_iface))
100 return PTR_ERR(drv->smmu_iface);
101
102 drv->core = devm_clk_get(&pdev->dev, "core_clk");
103 if (IS_ERR(drv->core))
104 return PTR_ERR(drv->core);
Stephen Boyd7b973de2012-03-09 12:26:16 -0800105
Stephen Boyde83a0a22012-06-29 13:51:27 -0700106 desc = &drv->pil_desc;
Stephen Boyd7b973de2012-03-09 12:26:16 -0800107 desc->name = "vidc";
108 desc->dev = &pdev->dev;
109 desc->ops = &pil_vidc_ops;
110 desc->owner = THIS_MODULE;
Stephen Boyde83a0a22012-06-29 13:51:27 -0700111 ret = pil_desc_init(desc);
112 if (ret)
113 return ret;
Stephen Boyd046013f2012-06-28 20:24:17 -0700114
115 drv->subsys_desc.name = "vidc";
116 drv->subsys_desc.dev = &pdev->dev;
117 drv->subsys_desc.owner = THIS_MODULE;
118 drv->subsys_desc.start = vidc_start;
119 drv->subsys_desc.stop = vidc_stop;
120
121 drv->subsys = subsys_register(&drv->subsys_desc);
122 if (IS_ERR(drv->subsys)) {
Stephen Boyde83a0a22012-06-29 13:51:27 -0700123 pil_desc_release(desc);
Stephen Boyd046013f2012-06-28 20:24:17 -0700124 return PTR_ERR(drv->subsys);
125 }
Deepak Katragadda4118ccc2013-07-05 10:01:19 -0700126
127 scm_pas_init(MSM_BUS_MASTER_SPS);
128
Stephen Boyd7b973de2012-03-09 12:26:16 -0800129 return 0;
Stephen Boyd7b973de2012-03-09 12:26:16 -0800130}
131
132static int __devexit pil_vidc_driver_exit(struct platform_device *pdev)
133{
134 struct vidc_data *drv = platform_get_drvdata(pdev);
Stephen Boyd046013f2012-06-28 20:24:17 -0700135 subsys_unregister(drv->subsys);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700136 pil_desc_release(&drv->pil_desc);
Stephen Boyd7b973de2012-03-09 12:26:16 -0800137 return 0;
138}
139
140static struct platform_driver pil_vidc_driver = {
141 .probe = pil_vidc_driver_probe,
142 .remove = __devexit_p(pil_vidc_driver_exit),
143 .driver = {
144 .name = "pil_vidc",
145 .owner = THIS_MODULE,
146 },
147};
148
149static int __init pil_vidc_init(void)
150{
151 return platform_driver_register(&pil_vidc_driver);
152}
153module_init(pil_vidc_init);
154
155static void __exit pil_vidc_exit(void)
156{
157 platform_driver_unregister(&pil_vidc_driver);
158}
159module_exit(pil_vidc_exit);
160
161MODULE_DESCRIPTION("Support for secure booting vidc images");
162MODULE_LICENSE("GPL v2");