blob: 2ba882ccbb939b274f867c1f2fd8d5feb81b773e [file] [log] [blame]
Sahitya Tummala719c6b52015-05-21 08:28:19 +05301/*
2 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include "sdhci-msm-ice.h"
15
16static void sdhci_msm_ice_success_cb(void *host_ctrl,
17 enum ice_event_completion evt)
18{
19 struct sdhci_msm_host *msm_host = (struct sdhci_msm_host *)host_ctrl;
20
21 if ((msm_host->ice.state == SDHCI_MSM_ICE_STATE_DISABLED &&
22 evt == ICE_INIT_COMPLETION) || (msm_host->ice.state ==
23 SDHCI_MSM_ICE_STATE_SUSPENDED && evt == ICE_RESUME_COMPLETION))
24 msm_host->ice.state = SDHCI_MSM_ICE_STATE_ACTIVE;
25
26 complete(&msm_host->ice.async_done);
27}
28
29static void sdhci_msm_ice_error_cb(void *host_ctrl, enum ice_error_code evt)
30{
31 struct sdhci_msm_host *msm_host = (struct sdhci_msm_host *)host_ctrl;
32
33 dev_err(&msm_host->pdev->dev, "%s: Error in ice operation %d",
34 __func__, evt);
35
36 if (msm_host->ice.state == SDHCI_MSM_ICE_STATE_ACTIVE)
37 msm_host->ice.state = SDHCI_MSM_ICE_STATE_DISABLED;
38
39 complete(&msm_host->ice.async_done);
40}
41
42static struct platform_device *sdhci_msm_ice_get_pdevice(struct device *dev)
43{
44 struct device_node *node;
45 struct platform_device *ice_pdev = NULL;
46
47 node = of_parse_phandle(dev->of_node, SDHC_MSM_CRYPTO_LABEL, 0);
48 if (!node) {
49 dev_dbg(dev, "%s: sdhc-msm-crypto property not specified\n",
50 __func__);
51 goto out;
52 }
53 ice_pdev = qcom_ice_get_pdevice(node);
54out:
55 return ice_pdev;
56}
57
58static
59struct qcom_ice_variant_ops *sdhci_msm_ice_get_vops(struct device *dev)
60{
61 struct qcom_ice_variant_ops *ice_vops = NULL;
62 struct device_node *node;
63
64 node = of_parse_phandle(dev->of_node, SDHC_MSM_CRYPTO_LABEL, 0);
65 if (!node) {
66 dev_dbg(dev, "%s: sdhc-msm-crypto property not specified\n",
67 __func__);
68 goto out;
69 }
70 ice_vops = qcom_ice_get_variant_ops(node);
71 of_node_put(node);
72out:
73 return ice_vops;
74}
75
76int sdhci_msm_ice_get_dev(struct sdhci_host *host)
77{
78 struct device *sdhc_dev;
79 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
80 struct sdhci_msm_host *msm_host = pltfm_host->priv;
81
82 if (!msm_host || !msm_host->pdev) {
83 pr_err("%s: invalid msm_host %p or msm_host->pdev\n",
84 __func__, msm_host);
85 return -EINVAL;
86 }
87
88 sdhc_dev = &msm_host->pdev->dev;
89 msm_host->ice.vops = sdhci_msm_ice_get_vops(sdhc_dev);
90 msm_host->ice.pdev = sdhci_msm_ice_get_pdevice(sdhc_dev);
91
92 if (msm_host->ice.pdev == ERR_PTR(-EPROBE_DEFER)) {
93 dev_err(sdhc_dev, "%s: ICE device not probed yet\n",
94 __func__);
95 msm_host->ice.pdev = NULL;
96 msm_host->ice.vops = NULL;
97 return -EPROBE_DEFER;
98 }
99
100 if (!msm_host->ice.pdev) {
101 dev_dbg(sdhc_dev, "%s: invalid platform device\n", __func__);
102 msm_host->ice.vops = NULL;
103 return -ENODEV;
104 }
105 if (!msm_host->ice.vops) {
106 dev_dbg(sdhc_dev, "%s: invalid ice vops\n", __func__);
107 msm_host->ice.pdev = NULL;
108 return -ENODEV;
109 }
110 msm_host->ice.state = SDHCI_MSM_ICE_STATE_DISABLED;
111 return 0;
112}
113
114int sdhci_msm_ice_init(struct sdhci_host *host)
115{
116 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
117 struct sdhci_msm_host *msm_host = pltfm_host->priv;
118 int err = 0;
119
120 init_completion(&msm_host->ice.async_done);
121 if (msm_host->ice.vops->config) {
122 err = msm_host->ice.vops->init(msm_host->ice.pdev,
123 msm_host,
124 sdhci_msm_ice_success_cb,
125 sdhci_msm_ice_error_cb);
126 if (err) {
127 pr_err("%s: ice init err %d\n",
128 mmc_hostname(host->mmc), err);
129 return err;
130 }
131 }
132
133 if (!wait_for_completion_timeout(&msm_host->ice.async_done,
134 msecs_to_jiffies(SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS))) {
135 pr_err("%s: ice init timedout after %d ms\n",
136 mmc_hostname(host->mmc),
137 SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS);
138 return -ETIMEDOUT;
139 }
140
141 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
142 pr_err("%s: ice is in invalid state %d\n",
143 mmc_hostname(host->mmc), msm_host->ice.state);
144 return -EINVAL;
145 }
146 return 0;
147}
148
149int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
150 u32 slot)
151{
152 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
153 struct sdhci_msm_host *msm_host = pltfm_host->priv;
154 int err = 0;
155 struct ice_data_setting ice_set;
156 sector_t lba = 0;
157 unsigned int ctrl_info_val = 0;
158 unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS;
159 struct request *req;
160
161 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
162 pr_err("%s: ice is in invalid state %d\n",
163 mmc_hostname(host->mmc), msm_host->ice.state);
164 return -EINVAL;
165 }
166
167 BUG_ON(!mrq);
168 memset(&ice_set, 0, sizeof(struct ice_data_setting));
169 req = mrq->req;
170 if (req) {
171 lba = req->__sector;
172 if (msm_host->ice.vops->config) {
173 err = msm_host->ice.vops->config(msm_host->ice.pdev,
174 req, &ice_set);
175 if (err) {
176 pr_err("%s: ice config failed %d\n",
177 mmc_hostname(host->mmc), err);
178 return err;
179 }
180 }
181 /* if writing data command */
182 if (rq_data_dir(req) == WRITE)
183 bypass = ice_set.encr_bypass ?
184 SDHCI_MSM_ICE_ENABLE_BYPASS :
185 SDHCI_MSM_ICE_DISABLE_BYPASS;
186 /* if reading data command */
187 else if (rq_data_dir(req) == READ)
188 bypass = ice_set.decr_bypass ?
189 SDHCI_MSM_ICE_ENABLE_BYPASS :
190 SDHCI_MSM_ICE_DISABLE_BYPASS;
191 pr_debug("%s: %s: slot %d encr_bypass %d bypass %d decr_bypass %d key_index %d\n",
192 mmc_hostname(host->mmc),
193 (rq_data_dir(req) == WRITE) ? "WRITE" : "READ",
194 slot, ice_set.encr_bypass, bypass,
195 ice_set.decr_bypass,
196 ice_set.crypto_data.key_index);
197 }
198
199 /* Configure ICE index */
200 ctrl_info_val =
201 (ice_set.crypto_data.key_index &
202 MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX)
203 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX;
204
205 /* Configure data unit size of transfer request */
206 ctrl_info_val |=
207 (SDHCI_MSM_ICE_TR_DATA_UNIT_512_B &
208 MASK_SDHCI_MSM_ICE_CTRL_INFO_CDU)
209 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU;
210
211 /* Configure ICE bypass mode */
212 ctrl_info_val |=
213 (bypass & MASK_SDHCI_MSM_ICE_CTRL_INFO_BYPASS)
214 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_BYPASS;
215
216 writel_relaxed((lba & 0xFFFFFFFF),
217 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_1_n + 16 * slot);
218 writel_relaxed(((lba >> 32) & 0xFFFFFFFF),
219 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_2_n + 16 * slot);
220 writel_relaxed(ctrl_info_val,
221 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot);
222
223 /* Ensure ICE registers are configured before issuing SDHCI request */
224 mb();
225 return 0;
226}
227
228int sdhci_msm_ice_reset(struct sdhci_host *host)
229{
230 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
231 struct sdhci_msm_host *msm_host = pltfm_host->priv;
232 int err = 0;
233
234 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
235 pr_err("%s: ice is in invalid state before reset %d\n",
236 mmc_hostname(host->mmc), msm_host->ice.state);
237 return -EINVAL;
238 }
239
240 init_completion(&msm_host->ice.async_done);
241
242 if (msm_host->ice.vops->reset) {
243 err = msm_host->ice.vops->reset(msm_host->ice.pdev);
244 if (err) {
245 pr_err("%s: ice reset failed %d\n",
246 mmc_hostname(host->mmc), err);
247 return err;
248 }
249 }
250
251 if (!wait_for_completion_timeout(&msm_host->ice.async_done,
252 msecs_to_jiffies(SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS))) {
253 pr_err("%s: ice reset timedout after %d ms\n",
254 mmc_hostname(host->mmc),
255 SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS);
256 return -ETIMEDOUT;
257 }
258
259 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
260 pr_err("%s: ice is in invalid state after reset %d\n",
261 mmc_hostname(host->mmc), msm_host->ice.state);
262 return -EINVAL;
263 }
264 return 0;
265}
266
267int sdhci_msm_ice_resume(struct sdhci_host *host)
268{
269 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
270 struct sdhci_msm_host *msm_host = pltfm_host->priv;
271 int err = 0;
272
273 if (msm_host->ice.state !=
274 SDHCI_MSM_ICE_STATE_SUSPENDED) {
275 pr_err("%s: ice is in invalid state before resume %d\n",
276 mmc_hostname(host->mmc), msm_host->ice.state);
277 return -EINVAL;
278 }
279
280 init_completion(&msm_host->ice.async_done);
281
282 if (msm_host->ice.vops->resume) {
283 err = msm_host->ice.vops->resume(msm_host->ice.pdev);
284 if (err) {
285 pr_err("%s: ice resume failed %d\n",
286 mmc_hostname(host->mmc), err);
287 return err;
288 }
289 }
290
291 if (!wait_for_completion_timeout(&msm_host->ice.async_done,
292 msecs_to_jiffies(SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS))) {
293 pr_err("%s: ice resume timedout after %d ms\n",
294 mmc_hostname(host->mmc),
295 SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS);
296 return -ETIMEDOUT;
297 }
298
299 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
300 pr_err("%s: ice is in invalid state after resume %d\n",
301 mmc_hostname(host->mmc), msm_host->ice.state);
302 return -EINVAL;
303 }
304 return 0;
305}
306
307int sdhci_msm_ice_suspend(struct sdhci_host *host)
308{
309 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
310 struct sdhci_msm_host *msm_host = pltfm_host->priv;
311 int err = 0;
312
313 if (msm_host->ice.state !=
314 SDHCI_MSM_ICE_STATE_ACTIVE) {
315 pr_err("%s: ice is in invalid state before resume %d\n",
316 mmc_hostname(host->mmc), msm_host->ice.state);
317 return -EINVAL;
318 }
319
320 if (msm_host->ice.vops->suspend) {
321 err = msm_host->ice.vops->suspend(msm_host->ice.pdev);
322 if (err) {
323 pr_err("%s: ice suspend failed %d\n",
324 mmc_hostname(host->mmc), err);
325 return -EINVAL;
326 }
327 }
328 msm_host->ice.state = SDHCI_MSM_ICE_STATE_SUSPENDED;
329 return 0;
330}
331
332int sdhci_msm_ice_get_status(struct sdhci_host *host, int *ice_status)
333{
334 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
335 struct sdhci_msm_host *msm_host = pltfm_host->priv;
336 int stat = -EINVAL;
337
338 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
339 pr_err("%s: ice is in invalid state %d\n",
340 mmc_hostname(host->mmc), msm_host->ice.state);
341 return -EINVAL;
342 }
343
344 if (msm_host->ice.vops->status) {
345 *ice_status = 0;
346 stat = msm_host->ice.vops->status(msm_host->ice.pdev);
347 if (stat < 0) {
348 pr_err("%s: ice get sts failed %d\n",
349 mmc_hostname(host->mmc), stat);
350 return -EINVAL;
351 }
352 *ice_status = stat;
353 }
354 return 0;
355}