blob: 286c7454055c1d448fbd07cb0bec75ae47c051ae [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);
Sahitya Tummalaf4746692015-09-28 15:54:21 +0530138 sdhci_msm_ice_print_regs(host);
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530139 return -ETIMEDOUT;
140 }
141
142 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
143 pr_err("%s: ice is in invalid state %d\n",
144 mmc_hostname(host->mmc), msm_host->ice.state);
145 return -EINVAL;
146 }
147 return 0;
148}
149
150int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
151 u32 slot)
152{
153 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
154 struct sdhci_msm_host *msm_host = pltfm_host->priv;
155 int err = 0;
156 struct ice_data_setting ice_set;
157 sector_t lba = 0;
158 unsigned int ctrl_info_val = 0;
159 unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS;
160 struct request *req;
161
162 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
163 pr_err("%s: ice is in invalid state %d\n",
164 mmc_hostname(host->mmc), msm_host->ice.state);
165 return -EINVAL;
166 }
167
168 BUG_ON(!mrq);
169 memset(&ice_set, 0, sizeof(struct ice_data_setting));
170 req = mrq->req;
171 if (req) {
172 lba = req->__sector;
173 if (msm_host->ice.vops->config) {
174 err = msm_host->ice.vops->config(msm_host->ice.pdev,
175 req, &ice_set);
176 if (err) {
177 pr_err("%s: ice config failed %d\n",
178 mmc_hostname(host->mmc), err);
179 return err;
180 }
181 }
182 /* if writing data command */
183 if (rq_data_dir(req) == WRITE)
184 bypass = ice_set.encr_bypass ?
185 SDHCI_MSM_ICE_ENABLE_BYPASS :
186 SDHCI_MSM_ICE_DISABLE_BYPASS;
187 /* if reading data command */
188 else if (rq_data_dir(req) == READ)
189 bypass = ice_set.decr_bypass ?
190 SDHCI_MSM_ICE_ENABLE_BYPASS :
191 SDHCI_MSM_ICE_DISABLE_BYPASS;
192 pr_debug("%s: %s: slot %d encr_bypass %d bypass %d decr_bypass %d key_index %d\n",
193 mmc_hostname(host->mmc),
194 (rq_data_dir(req) == WRITE) ? "WRITE" : "READ",
195 slot, ice_set.encr_bypass, bypass,
196 ice_set.decr_bypass,
197 ice_set.crypto_data.key_index);
198 }
199
200 /* Configure ICE index */
201 ctrl_info_val =
202 (ice_set.crypto_data.key_index &
203 MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX)
204 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX;
205
206 /* Configure data unit size of transfer request */
207 ctrl_info_val |=
208 (SDHCI_MSM_ICE_TR_DATA_UNIT_512_B &
209 MASK_SDHCI_MSM_ICE_CTRL_INFO_CDU)
210 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU;
211
212 /* Configure ICE bypass mode */
213 ctrl_info_val |=
214 (bypass & MASK_SDHCI_MSM_ICE_CTRL_INFO_BYPASS)
215 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_BYPASS;
216
217 writel_relaxed((lba & 0xFFFFFFFF),
218 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_1_n + 16 * slot);
219 writel_relaxed(((lba >> 32) & 0xFFFFFFFF),
220 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_2_n + 16 * slot);
221 writel_relaxed(ctrl_info_val,
222 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot);
223
224 /* Ensure ICE registers are configured before issuing SDHCI request */
225 mb();
226 return 0;
227}
228
229int sdhci_msm_ice_reset(struct sdhci_host *host)
230{
231 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
232 struct sdhci_msm_host *msm_host = pltfm_host->priv;
233 int err = 0;
234
235 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
236 pr_err("%s: ice is in invalid state before reset %d\n",
237 mmc_hostname(host->mmc), msm_host->ice.state);
238 return -EINVAL;
239 }
240
241 init_completion(&msm_host->ice.async_done);
242
243 if (msm_host->ice.vops->reset) {
244 err = msm_host->ice.vops->reset(msm_host->ice.pdev);
245 if (err) {
246 pr_err("%s: ice reset failed %d\n",
247 mmc_hostname(host->mmc), err);
248 return err;
249 }
250 }
251
252 if (!wait_for_completion_timeout(&msm_host->ice.async_done,
253 msecs_to_jiffies(SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS))) {
254 pr_err("%s: ice reset timedout after %d ms\n",
255 mmc_hostname(host->mmc),
256 SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS);
Sahitya Tummalaf4746692015-09-28 15:54:21 +0530257 sdhci_msm_ice_print_regs(host);
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530258 return -ETIMEDOUT;
259 }
260
261 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
262 pr_err("%s: ice is in invalid state after reset %d\n",
263 mmc_hostname(host->mmc), msm_host->ice.state);
264 return -EINVAL;
265 }
266 return 0;
267}
268
269int sdhci_msm_ice_resume(struct sdhci_host *host)
270{
271 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
272 struct sdhci_msm_host *msm_host = pltfm_host->priv;
273 int err = 0;
274
275 if (msm_host->ice.state !=
276 SDHCI_MSM_ICE_STATE_SUSPENDED) {
277 pr_err("%s: ice is in invalid state before resume %d\n",
278 mmc_hostname(host->mmc), msm_host->ice.state);
279 return -EINVAL;
280 }
281
282 init_completion(&msm_host->ice.async_done);
283
284 if (msm_host->ice.vops->resume) {
285 err = msm_host->ice.vops->resume(msm_host->ice.pdev);
286 if (err) {
287 pr_err("%s: ice resume failed %d\n",
288 mmc_hostname(host->mmc), err);
289 return err;
290 }
291 }
292
293 if (!wait_for_completion_timeout(&msm_host->ice.async_done,
294 msecs_to_jiffies(SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS))) {
295 pr_err("%s: ice resume timedout after %d ms\n",
296 mmc_hostname(host->mmc),
297 SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS);
Sahitya Tummalaf4746692015-09-28 15:54:21 +0530298 sdhci_msm_ice_print_regs(host);
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530299 return -ETIMEDOUT;
300 }
301
302 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
303 pr_err("%s: ice is in invalid state after resume %d\n",
304 mmc_hostname(host->mmc), msm_host->ice.state);
305 return -EINVAL;
306 }
307 return 0;
308}
309
310int sdhci_msm_ice_suspend(struct sdhci_host *host)
311{
312 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
313 struct sdhci_msm_host *msm_host = pltfm_host->priv;
314 int err = 0;
315
316 if (msm_host->ice.state !=
317 SDHCI_MSM_ICE_STATE_ACTIVE) {
318 pr_err("%s: ice is in invalid state before resume %d\n",
319 mmc_hostname(host->mmc), msm_host->ice.state);
320 return -EINVAL;
321 }
322
323 if (msm_host->ice.vops->suspend) {
324 err = msm_host->ice.vops->suspend(msm_host->ice.pdev);
325 if (err) {
326 pr_err("%s: ice suspend failed %d\n",
327 mmc_hostname(host->mmc), err);
328 return -EINVAL;
329 }
330 }
331 msm_host->ice.state = SDHCI_MSM_ICE_STATE_SUSPENDED;
332 return 0;
333}
334
335int sdhci_msm_ice_get_status(struct sdhci_host *host, int *ice_status)
336{
337 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
338 struct sdhci_msm_host *msm_host = pltfm_host->priv;
339 int stat = -EINVAL;
340
341 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
342 pr_err("%s: ice is in invalid state %d\n",
343 mmc_hostname(host->mmc), msm_host->ice.state);
344 return -EINVAL;
345 }
346
347 if (msm_host->ice.vops->status) {
348 *ice_status = 0;
349 stat = msm_host->ice.vops->status(msm_host->ice.pdev);
350 if (stat < 0) {
351 pr_err("%s: ice get sts failed %d\n",
352 mmc_hostname(host->mmc), stat);
353 return -EINVAL;
354 }
355 *ice_status = stat;
356 }
357 return 0;
358}
Sahitya Tummalaf4746692015-09-28 15:54:21 +0530359
360void sdhci_msm_ice_print_regs(struct sdhci_host *host)
361{
362 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
363 struct sdhci_msm_host *msm_host = pltfm_host->priv;
364
365 if (msm_host->ice.vops->debug)
366 msm_host->ice.vops->debug(msm_host->ice.pdev);
367}