blob: 9eb04e03338b15336c0f5db812e41ff53e1cc2fa [file] [log] [blame]
Duy Truonge833aca2013-02-12 13:35:08 -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
27#define PAS_AUTH_AND_RESET_CMD 5
28#define PAS_SHUTDOWN_CMD 6
29#define PAS_IS_SUPPORTED_CMD 7
30
31int pas_init_image(enum pas_id id, const u8 *metadata, size_t size)
32{
33 int ret;
34 struct pas_init_image_req {
35 u32 proc;
36 u32 image_addr;
37 } request;
38 u32 scm_ret = 0;
39 /* Make memory physically contiguous */
40 void *mdata_buf = kmemdup(metadata, size, GFP_KERNEL);
41
42 if (!mdata_buf)
43 return -ENOMEM;
44
45 request.proc = id;
46 request.image_addr = virt_to_phys(mdata_buf);
47
48 ret = scm_call(SCM_SVC_PIL, PAS_INIT_IMAGE_CMD, &request,
49 sizeof(request), &scm_ret, sizeof(scm_ret));
50 kfree(mdata_buf);
51
52 if (ret)
53 return ret;
54 return scm_ret;
55}
56EXPORT_SYMBOL(pas_init_image);
57
Stephen Boydef5d1c42011-12-15 20:47:14 -080058static struct msm_bus_paths scm_pas_bw_tbl[] = {
59 {
60 .vectors = (struct msm_bus_vectors[]){
61 {
62 .src = MSM_BUS_MASTER_SPS,
63 .dst = MSM_BUS_SLAVE_EBI_CH0,
64 },
65 },
66 .num_paths = 1,
67 },
68 {
69 .vectors = (struct msm_bus_vectors[]){
70 {
71 .src = MSM_BUS_MASTER_SPS,
72 .dst = MSM_BUS_SLAVE_EBI_CH0,
73 .ib = 492 * 8 * 1000000UL,
74 .ab = 492 * 8 * 100000UL,
75 },
76 },
77 .num_paths = 1,
78 },
79};
80
81static struct msm_bus_scale_pdata scm_pas_bus_pdata = {
82 .usecase = scm_pas_bw_tbl,
83 .num_usecases = ARRAY_SIZE(scm_pas_bw_tbl),
84 .name = "scm_pas",
85};
86
87static uint32_t scm_perf_client;
88static struct clk *scm_bus_clk;
89
90static DEFINE_MUTEX(scm_pas_bw_mutex);
91static int scm_pas_bw_count;
92
93static int scm_pas_enable_bw(void)
94{
95 int ret = 0;
96
Matt Wagantall8873e202012-07-26 14:34:34 -070097 if (!scm_perf_client)
Stephen Boydef5d1c42011-12-15 20:47:14 -080098 return -EINVAL;
99
100 mutex_lock(&scm_pas_bw_mutex);
101 if (!scm_pas_bw_count) {
102 ret = msm_bus_scale_client_update_request(scm_perf_client, 1);
103 if (ret) {
104 pr_err("bandwidth request failed (%d)\n", ret);
Matt Wagantall8873e202012-07-26 14:34:34 -0700105 } else if (scm_bus_clk) {
Stephen Boyd12363752012-03-26 17:21:12 -0700106 ret = clk_prepare_enable(scm_bus_clk);
Stephen Boydef5d1c42011-12-15 20:47:14 -0800107 if (ret)
108 pr_err("clock enable failed\n");
109 }
110 }
111 if (ret)
112 msm_bus_scale_client_update_request(scm_perf_client, 0);
113 else
114 scm_pas_bw_count++;
115 mutex_unlock(&scm_pas_bw_mutex);
116 return ret;
117}
118
119static void scm_pas_disable_bw(void)
120{
121 mutex_lock(&scm_pas_bw_mutex);
122 if (scm_pas_bw_count-- == 1) {
123 msm_bus_scale_client_update_request(scm_perf_client, 0);
Matt Wagantall8873e202012-07-26 14:34:34 -0700124 if (scm_bus_clk)
125 clk_disable_unprepare(scm_bus_clk);
Stephen Boydef5d1c42011-12-15 20:47:14 -0800126 }
127 mutex_unlock(&scm_pas_bw_mutex);
128}
129
Stephen Boyde44ec392011-08-29 12:03:24 -0700130int pas_auth_and_reset(enum pas_id id)
131{
Stephen Boydef5d1c42011-12-15 20:47:14 -0800132 int ret, bus_ret;
Stephen Boyde44ec392011-08-29 12:03:24 -0700133 u32 proc = id, scm_ret = 0;
134
Stephen Boydef5d1c42011-12-15 20:47:14 -0800135 bus_ret = scm_pas_enable_bw();
Stephen Boyde44ec392011-08-29 12:03:24 -0700136 ret = scm_call(SCM_SVC_PIL, PAS_AUTH_AND_RESET_CMD, &proc,
137 sizeof(proc), &scm_ret, sizeof(scm_ret));
138 if (ret)
Stephen Boydef5d1c42011-12-15 20:47:14 -0800139 scm_ret = ret;
140 if (!bus_ret)
141 scm_pas_disable_bw();
Stephen Boyde44ec392011-08-29 12:03:24 -0700142
143 return scm_ret;
144}
145EXPORT_SYMBOL(pas_auth_and_reset);
146
147int pas_shutdown(enum pas_id id)
148{
149 int ret;
150 u32 proc = id, scm_ret = 0;
151
152 ret = scm_call(SCM_SVC_PIL, PAS_SHUTDOWN_CMD, &proc, sizeof(proc),
153 &scm_ret, sizeof(scm_ret));
154 if (ret)
155 return ret;
156
157 return scm_ret;
158}
159EXPORT_SYMBOL(pas_shutdown);
160
161static bool secure_pil = true;
162module_param(secure_pil, bool, S_IRUGO);
163MODULE_PARM_DESC(secure_pil, "Use secure PIL");
164
165int pas_supported(enum pas_id id)
166{
167 int ret;
168 u32 periph = id, ret_val = 0;
169
170 if (!secure_pil)
171 return 0;
172
173 /*
174 * 8660 SCM doesn't support querying secure PIL support so just return
175 * true if not overridden on the command line.
176 */
177 if (cpu_is_msm8x60())
178 return 1;
179
180 if (scm_is_call_available(SCM_SVC_PIL, PAS_IS_SUPPORTED_CMD) <= 0)
181 return 0;
182
183 ret = scm_call(SCM_SVC_PIL, PAS_IS_SUPPORTED_CMD, &periph,
184 sizeof(periph), &ret_val, sizeof(ret_val));
185 if (ret)
186 return ret;
187
188 return ret_val;
189}
190EXPORT_SYMBOL(pas_supported);
Stephen Boydef5d1c42011-12-15 20:47:14 -0800191
192static int __init scm_pas_init(void)
193{
Matt Wagantall8873e202012-07-26 14:34:34 -0700194 if (cpu_is_msm8974()) {
195 scm_pas_bw_tbl[0].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
196 scm_pas_bw_tbl[1].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
197 } else {
198 scm_bus_clk = clk_get_sys("scm", "bus_clk");
199 if (!IS_ERR(scm_bus_clk)) {
200 clk_set_rate(scm_bus_clk, 64000000);
201 } else {
202 scm_bus_clk = NULL;
203 pr_warn("unable to get bus clock\n");
204 }
205 }
206
Stephen Boyd6dd4b352012-02-10 14:54:02 -0800207 scm_perf_client = msm_bus_scale_register_client(&scm_pas_bus_pdata);
Stephen Boydef5d1c42011-12-15 20:47:14 -0800208 if (!scm_perf_client)
209 pr_warn("unable to register bus client\n");
Matt Wagantall8873e202012-07-26 14:34:34 -0700210
Stephen Boydef5d1c42011-12-15 20:47:14 -0800211 return 0;
212}
213module_init(scm_pas_init);