blob: f73055eb5fbad33edfc030d953153abf42ac24b8 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
Stephen Boyde44ec392011-08-29 12:03:24 -07002 *
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
Stephen Boydef5d1c42011-12-15 20:47:14 -080013#define pr_fmt(fmt) "scm-pas: " fmt
14
Stephen Boyde44ec392011-08-29 12:03:24 -070015#include <linux/module.h>
16#include <linux/slab.h>
17#include <linux/string.h>
Stephen Boydef5d1c42011-12-15 20:47:14 -080018#include <linux/clk.h>
Stephen Boyde44ec392011-08-29 12:03:24 -070019
20#include <mach/scm.h>
21#include <mach/socinfo.h>
Stephen Boydef5d1c42011-12-15 20:47:14 -080022#include <mach/msm_bus.h>
23#include <mach/msm_bus_board.h>
Stephen Boyde44ec392011-08-29 12:03:24 -070024#include "scm-pas.h"
25
26#define PAS_INIT_IMAGE_CMD 1
Stephen Boydb16e0162012-07-30 17:10:54 -070027#define PAS_MEM_SETUP_CMD 2
Stephen Boyde44ec392011-08-29 12:03:24 -070028#define PAS_AUTH_AND_RESET_CMD 5
29#define PAS_SHUTDOWN_CMD 6
30#define PAS_IS_SUPPORTED_CMD 7
31
32int pas_init_image(enum pas_id id, const u8 *metadata, size_t size)
33{
34 int ret;
35 struct pas_init_image_req {
36 u32 proc;
37 u32 image_addr;
38 } request;
39 u32 scm_ret = 0;
40 /* Make memory physically contiguous */
41 void *mdata_buf = kmemdup(metadata, size, GFP_KERNEL);
42
43 if (!mdata_buf)
44 return -ENOMEM;
45
46 request.proc = id;
47 request.image_addr = virt_to_phys(mdata_buf);
48
49 ret = scm_call(SCM_SVC_PIL, PAS_INIT_IMAGE_CMD, &request,
50 sizeof(request), &scm_ret, sizeof(scm_ret));
51 kfree(mdata_buf);
52
53 if (ret)
54 return ret;
55 return scm_ret;
56}
57EXPORT_SYMBOL(pas_init_image);
58
Stephen Boydb16e0162012-07-30 17:10:54 -070059int pas_mem_setup(enum pas_id id, u32 start_addr, u32 len)
60{
61 int ret;
62 struct pas_init_image_req {
63 u32 proc;
64 u32 start_addr;
65 u32 len;
66 } request;
67 u32 scm_ret = 0;
68
69 request.proc = id;
70 request.start_addr = start_addr;
71 request.len = len;
72
73 ret = scm_call(SCM_SVC_PIL, PAS_MEM_SETUP_CMD, &request,
74 sizeof(request), &scm_ret, sizeof(scm_ret));
75 if (ret)
76 return ret;
77 return scm_ret;
78}
79EXPORT_SYMBOL(pas_mem_setup);
80
Stephen Boydef5d1c42011-12-15 20:47:14 -080081static struct msm_bus_paths scm_pas_bw_tbl[] = {
82 {
83 .vectors = (struct msm_bus_vectors[]){
84 {
85 .src = MSM_BUS_MASTER_SPS,
86 .dst = MSM_BUS_SLAVE_EBI_CH0,
87 },
88 },
89 .num_paths = 1,
90 },
91 {
92 .vectors = (struct msm_bus_vectors[]){
93 {
94 .src = MSM_BUS_MASTER_SPS,
95 .dst = MSM_BUS_SLAVE_EBI_CH0,
96 .ib = 492 * 8 * 1000000UL,
97 .ab = 492 * 8 * 100000UL,
98 },
99 },
100 .num_paths = 1,
101 },
102};
103
104static struct msm_bus_scale_pdata scm_pas_bus_pdata = {
105 .usecase = scm_pas_bw_tbl,
106 .num_usecases = ARRAY_SIZE(scm_pas_bw_tbl),
107 .name = "scm_pas",
108};
109
110static uint32_t scm_perf_client;
111static struct clk *scm_bus_clk;
112
113static DEFINE_MUTEX(scm_pas_bw_mutex);
114static int scm_pas_bw_count;
115
116static int scm_pas_enable_bw(void)
117{
118 int ret = 0;
119
Matt Wagantall8873e202012-07-26 14:34:34 -0700120 if (!scm_perf_client)
Stephen Boydef5d1c42011-12-15 20:47:14 -0800121 return -EINVAL;
122
123 mutex_lock(&scm_pas_bw_mutex);
124 if (!scm_pas_bw_count) {
125 ret = msm_bus_scale_client_update_request(scm_perf_client, 1);
126 if (ret) {
127 pr_err("bandwidth request failed (%d)\n", ret);
Matt Wagantall8873e202012-07-26 14:34:34 -0700128 } else if (scm_bus_clk) {
Stephen Boyd12363752012-03-26 17:21:12 -0700129 ret = clk_prepare_enable(scm_bus_clk);
Stephen Boydef5d1c42011-12-15 20:47:14 -0800130 if (ret)
131 pr_err("clock enable failed\n");
132 }
133 }
134 if (ret)
135 msm_bus_scale_client_update_request(scm_perf_client, 0);
136 else
137 scm_pas_bw_count++;
138 mutex_unlock(&scm_pas_bw_mutex);
139 return ret;
140}
141
142static void scm_pas_disable_bw(void)
143{
144 mutex_lock(&scm_pas_bw_mutex);
145 if (scm_pas_bw_count-- == 1) {
146 msm_bus_scale_client_update_request(scm_perf_client, 0);
Matt Wagantall8873e202012-07-26 14:34:34 -0700147 if (scm_bus_clk)
148 clk_disable_unprepare(scm_bus_clk);
Stephen Boydef5d1c42011-12-15 20:47:14 -0800149 }
150 mutex_unlock(&scm_pas_bw_mutex);
151}
152
Stephen Boyde44ec392011-08-29 12:03:24 -0700153int pas_auth_and_reset(enum pas_id id)
154{
Stephen Boydef5d1c42011-12-15 20:47:14 -0800155 int ret, bus_ret;
Stephen Boyde44ec392011-08-29 12:03:24 -0700156 u32 proc = id, scm_ret = 0;
157
Stephen Boydef5d1c42011-12-15 20:47:14 -0800158 bus_ret = scm_pas_enable_bw();
Stephen Boyde44ec392011-08-29 12:03:24 -0700159 ret = scm_call(SCM_SVC_PIL, PAS_AUTH_AND_RESET_CMD, &proc,
160 sizeof(proc), &scm_ret, sizeof(scm_ret));
161 if (ret)
Stephen Boydef5d1c42011-12-15 20:47:14 -0800162 scm_ret = ret;
163 if (!bus_ret)
164 scm_pas_disable_bw();
Stephen Boyde44ec392011-08-29 12:03:24 -0700165
166 return scm_ret;
167}
168EXPORT_SYMBOL(pas_auth_and_reset);
169
170int pas_shutdown(enum pas_id id)
171{
172 int ret;
173 u32 proc = id, scm_ret = 0;
174
175 ret = scm_call(SCM_SVC_PIL, PAS_SHUTDOWN_CMD, &proc, sizeof(proc),
176 &scm_ret, sizeof(scm_ret));
177 if (ret)
178 return ret;
179
180 return scm_ret;
181}
182EXPORT_SYMBOL(pas_shutdown);
183
184static bool secure_pil = true;
185module_param(secure_pil, bool, S_IRUGO);
186MODULE_PARM_DESC(secure_pil, "Use secure PIL");
187
188int pas_supported(enum pas_id id)
189{
190 int ret;
191 u32 periph = id, ret_val = 0;
192
193 if (!secure_pil)
194 return 0;
195
196 /*
197 * 8660 SCM doesn't support querying secure PIL support so just return
198 * true if not overridden on the command line.
199 */
200 if (cpu_is_msm8x60())
201 return 1;
202
203 if (scm_is_call_available(SCM_SVC_PIL, PAS_IS_SUPPORTED_CMD) <= 0)
204 return 0;
205
206 ret = scm_call(SCM_SVC_PIL, PAS_IS_SUPPORTED_CMD, &periph,
207 sizeof(periph), &ret_val, sizeof(ret_val));
208 if (ret)
209 return ret;
210
211 return ret_val;
212}
213EXPORT_SYMBOL(pas_supported);
Stephen Boydef5d1c42011-12-15 20:47:14 -0800214
215static int __init scm_pas_init(void)
216{
Matt Wagantall8873e202012-07-26 14:34:34 -0700217 if (cpu_is_msm8974()) {
218 scm_pas_bw_tbl[0].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
219 scm_pas_bw_tbl[1].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
220 } else {
221 scm_bus_clk = clk_get_sys("scm", "bus_clk");
222 if (!IS_ERR(scm_bus_clk)) {
223 clk_set_rate(scm_bus_clk, 64000000);
224 } else {
225 scm_bus_clk = NULL;
226 pr_warn("unable to get bus clock\n");
227 }
228 }
229
Syed Rameez Mustafa3c8353d2012-10-18 17:28:57 -0700230 scm_perf_client = msm_bus_scale_register_client(&scm_pas_bus_pdata);
Stephen Boydef5d1c42011-12-15 20:47:14 -0800231 if (!scm_perf_client)
232 pr_warn("unable to register bus client\n");
Matt Wagantall8873e202012-07-26 14:34:34 -0700233
Stephen Boydef5d1c42011-12-15 20:47:14 -0800234 return 0;
235}
236module_init(scm_pas_init);