blob: d624b4841162d58c1efb9c8b150547fac1557a63 [file] [log] [blame]
Sahitya Tummala719c6b52015-05-21 08:28:19 +05301/*
Veerabhadrarao Badigantie8d1e5d2017-01-09 15:50:04 +05302 * Copyright (c) 2015, 2017, The Linux Foundation. All rights reserved.
Sahitya Tummala719c6b52015-05-21 08:28:19 +05303 *
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
Gilad Bronercdc4f782015-10-28 17:57:14 +020016static void sdhci_msm_ice_error_cb(void *host_ctrl, u32 error)
Sahitya Tummala719c6b52015-05-21 08:28:19 +053017{
18 struct sdhci_msm_host *msm_host = (struct sdhci_msm_host *)host_ctrl;
19
Gilad Bronercdc4f782015-10-28 17:57:14 +020020 dev_err(&msm_host->pdev->dev, "%s: Error in ice operation 0x%x",
21 __func__, error);
Sahitya Tummala719c6b52015-05-21 08:28:19 +053022
23 if (msm_host->ice.state == SDHCI_MSM_ICE_STATE_ACTIVE)
24 msm_host->ice.state = SDHCI_MSM_ICE_STATE_DISABLED;
Sahitya Tummala719c6b52015-05-21 08:28:19 +053025}
26
27static struct platform_device *sdhci_msm_ice_get_pdevice(struct device *dev)
28{
29 struct device_node *node;
30 struct platform_device *ice_pdev = NULL;
31
32 node = of_parse_phandle(dev->of_node, SDHC_MSM_CRYPTO_LABEL, 0);
33 if (!node) {
34 dev_dbg(dev, "%s: sdhc-msm-crypto property not specified\n",
35 __func__);
36 goto out;
37 }
38 ice_pdev = qcom_ice_get_pdevice(node);
39out:
40 return ice_pdev;
41}
42
43static
44struct qcom_ice_variant_ops *sdhci_msm_ice_get_vops(struct device *dev)
45{
46 struct qcom_ice_variant_ops *ice_vops = NULL;
47 struct device_node *node;
48
49 node = of_parse_phandle(dev->of_node, SDHC_MSM_CRYPTO_LABEL, 0);
50 if (!node) {
51 dev_dbg(dev, "%s: sdhc-msm-crypto property not specified\n",
52 __func__);
53 goto out;
54 }
55 ice_vops = qcom_ice_get_variant_ops(node);
56 of_node_put(node);
57out:
58 return ice_vops;
59}
60
Ritesh Harjani82124772014-11-04 15:34:00 +053061static
62void sdhci_msm_enable_ice_hci(struct sdhci_host *host, bool enable)
63{
64 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
65 struct sdhci_msm_host *msm_host = pltfm_host->priv;
66 u32 config = 0;
67 u32 ice_cap = 0;
68
69 /*
70 * Enable the cryptographic support inside SDHC.
71 * This is a global config which needs to be enabled
72 * all the time.
73 * Only when it it is enabled, the ICE_HCI capability
74 * will get reflected in CQCAP register.
75 */
76 config = readl_relaxed(host->ioaddr + HC_VENDOR_SPECIFIC_FUNC4);
77
78 if (enable)
79 config &= ~DISABLE_CRYPTO;
80 else
81 config |= DISABLE_CRYPTO;
82 writel_relaxed(config, host->ioaddr + HC_VENDOR_SPECIFIC_FUNC4);
83
84 /*
85 * CQCAP register is in different register space from above
86 * ice global enable register. So a mb() is required to ensure
87 * above write gets completed before reading the CQCAP register.
88 */
89 mb();
90
91 /*
92 * Check if ICE HCI capability support is present
93 * If present, enable it.
94 */
95 ice_cap = readl_relaxed(msm_host->cryptoio + ICE_CQ_CAPABILITIES);
96 if (ice_cap & ICE_HCI_SUPPORT) {
97 config = readl_relaxed(msm_host->cryptoio + ICE_CQ_CONFIG);
98
99 if (enable)
100 config |= CRYPTO_GENERAL_ENABLE;
101 else
102 config &= ~CRYPTO_GENERAL_ENABLE;
103 writel_relaxed(config, msm_host->cryptoio + ICE_CQ_CONFIG);
104 }
105}
106
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530107int sdhci_msm_ice_get_dev(struct sdhci_host *host)
108{
109 struct device *sdhc_dev;
110 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
111 struct sdhci_msm_host *msm_host = pltfm_host->priv;
112
113 if (!msm_host || !msm_host->pdev) {
114 pr_err("%s: invalid msm_host %p or msm_host->pdev\n",
115 __func__, msm_host);
116 return -EINVAL;
117 }
118
119 sdhc_dev = &msm_host->pdev->dev;
120 msm_host->ice.vops = sdhci_msm_ice_get_vops(sdhc_dev);
121 msm_host->ice.pdev = sdhci_msm_ice_get_pdevice(sdhc_dev);
122
123 if (msm_host->ice.pdev == ERR_PTR(-EPROBE_DEFER)) {
124 dev_err(sdhc_dev, "%s: ICE device not probed yet\n",
125 __func__);
126 msm_host->ice.pdev = NULL;
127 msm_host->ice.vops = NULL;
128 return -EPROBE_DEFER;
129 }
130
131 if (!msm_host->ice.pdev) {
132 dev_dbg(sdhc_dev, "%s: invalid platform device\n", __func__);
133 msm_host->ice.vops = NULL;
134 return -ENODEV;
135 }
136 if (!msm_host->ice.vops) {
137 dev_dbg(sdhc_dev, "%s: invalid ice vops\n", __func__);
138 msm_host->ice.pdev = NULL;
139 return -ENODEV;
140 }
141 msm_host->ice.state = SDHCI_MSM_ICE_STATE_DISABLED;
142 return 0;
143}
144
Ritesh Harjani82124772014-11-04 15:34:00 +0530145static
146int sdhci_msm_ice_pltfm_init(struct sdhci_msm_host *msm_host)
147{
148 struct resource *ice_memres = NULL;
149 struct platform_device *pdev = msm_host->pdev;
150 int err = 0;
151
152 if (!msm_host->ice_hci_support)
153 goto out;
154 /*
155 * ICE HCI registers are present in cmdq register space.
156 * So map the cmdq mem for accessing ICE HCI registers.
157 */
158 ice_memres = platform_get_resource_byname(pdev,
159 IORESOURCE_MEM, "cmdq_mem");
160 if (!ice_memres) {
161 dev_err(&pdev->dev, "Failed to get iomem resource for ice\n");
162 err = -EINVAL;
163 goto out;
164 }
165 msm_host->cryptoio = devm_ioremap(&pdev->dev,
166 ice_memres->start,
167 resource_size(ice_memres));
168 if (!msm_host->cryptoio) {
169 dev_err(&pdev->dev, "Failed to remap registers\n");
170 err = -ENOMEM;
171 }
172out:
173 return err;
174}
175
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530176int sdhci_msm_ice_init(struct sdhci_host *host)
177{
178 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
179 struct sdhci_msm_host *msm_host = pltfm_host->priv;
180 int err = 0;
181
Veerabhadrarao Badigantie8d1e5d2017-01-09 15:50:04 +0530182 if (msm_host->ice.vops->init) {
Veerabhadrarao Badiganti81203502016-12-11 17:04:56 +0530183 err = sdhci_msm_ice_pltfm_init(msm_host);
184 if (err)
185 goto out;
186
187 if (msm_host->ice_hci_support)
188 sdhci_msm_enable_ice_hci(host, true);
189
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530190 err = msm_host->ice.vops->init(msm_host->ice.pdev,
191 msm_host,
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530192 sdhci_msm_ice_error_cb);
193 if (err) {
194 pr_err("%s: ice init err %d\n",
195 mmc_hostname(host->mmc), err);
Dinesh K Garg1e93de82015-10-26 11:40:37 -0700196 sdhci_msm_ice_print_regs(host);
Veerabhadrarao Badiganti81203502016-12-11 17:04:56 +0530197 if (msm_host->ice_hci_support)
198 sdhci_msm_enable_ice_hci(host, false);
Dinesh K Garg1e93de82015-10-26 11:40:37 -0700199 goto out;
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530200 }
Dinesh K Garg1e93de82015-10-26 11:40:37 -0700201 msm_host->ice.state = SDHCI_MSM_ICE_STATE_ACTIVE;
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530202 }
203
Dinesh K Garg1e93de82015-10-26 11:40:37 -0700204out:
205 return err;
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530206}
207
Sahitya Tummala9e35aae2015-09-01 16:46:09 +0530208void sdhci_msm_ice_cfg_reset(struct sdhci_host *host, u32 slot)
209{
210 writel_relaxed(SDHCI_MSM_ICE_ENABLE_BYPASS,
211 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot);
212}
213
Veerabhadrarao Badiganti86c7a7f2017-01-31 07:33:29 +0530214static
Veerabhadrarao Badigantib82fd332017-01-31 15:17:39 +0530215int sdhci_msm_ice_get_cfg(struct sdhci_msm_host *msm_host, struct request *req,
216 unsigned int *bypass, short *key_index)
217{
218 int err = 0;
219 struct ice_data_setting ice_set;
220
221 memset(&ice_set, 0, sizeof(struct ice_data_setting));
222 if (msm_host->ice.vops->config_start) {
223 err = msm_host->ice.vops->config_start(
224 msm_host->ice.pdev,
225 req, &ice_set, false);
226 if (err) {
227 pr_err("%s: ice config failed %d\n",
228 mmc_hostname(msm_host->mmc), err);
229 return err;
230 }
231 }
232 /* if writing data command */
233 if (rq_data_dir(req) == WRITE)
234 *bypass = ice_set.encr_bypass ?
235 SDHCI_MSM_ICE_ENABLE_BYPASS :
236 SDHCI_MSM_ICE_DISABLE_BYPASS;
237 /* if reading data command */
238 else if (rq_data_dir(req) == READ)
239 *bypass = ice_set.decr_bypass ?
240 SDHCI_MSM_ICE_ENABLE_BYPASS :
241 SDHCI_MSM_ICE_DISABLE_BYPASS;
242 *key_index = ice_set.crypto_data.key_index;
243 return err;
244}
245
246static
Veerabhadrarao Badiganti86c7a7f2017-01-31 07:33:29 +0530247void sdhci_msm_ice_update_cfg(struct sdhci_host *host, u64 lba,
248 u32 slot, unsigned int bypass, short key_index)
249{
250 unsigned int ctrl_info_val = 0;
251
252 /* Configure ICE index */
253 ctrl_info_val =
254 (key_index &
255 MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX)
256 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX;
257
258 /* Configure data unit size of transfer request */
259 ctrl_info_val |=
260 (SDHCI_MSM_ICE_TR_DATA_UNIT_512_B &
261 MASK_SDHCI_MSM_ICE_CTRL_INFO_CDU)
262 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU;
263
264 /* Configure ICE bypass mode */
265 ctrl_info_val |=
266 (bypass & MASK_SDHCI_MSM_ICE_CTRL_INFO_BYPASS)
267 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_BYPASS;
268
269 writel_relaxed((lba & 0xFFFFFFFF),
270 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_1_n + 16 * slot);
271 writel_relaxed(((lba >> 32) & 0xFFFFFFFF),
272 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_2_n + 16 * slot);
273 writel_relaxed(ctrl_info_val,
274 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot);
275 /* Ensure ICE registers are configured before issuing SDHCI request */
276 mb();
277}
278
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530279int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
280 u32 slot)
281{
282 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
283 struct sdhci_msm_host *msm_host = pltfm_host->priv;
284 int err = 0;
Veerabhadrarao Badigantib82fd332017-01-31 15:17:39 +0530285 short key_index = 0;
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530286 sector_t lba = 0;
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530287 unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS;
288 struct request *req;
289
290 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
291 pr_err("%s: ice is in invalid state %d\n",
292 mmc_hostname(host->mmc), msm_host->ice.state);
293 return -EINVAL;
294 }
295
Veerabhadrarao Badigantib82fd332017-01-31 15:17:39 +0530296 WARN_ON(!mrq);
297 if (!mrq)
298 return -EINVAL;
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530299 req = mrq->req;
300 if (req) {
301 lba = req->__sector;
Veerabhadrarao Badigantib82fd332017-01-31 15:17:39 +0530302 err = sdhci_msm_ice_get_cfg(msm_host, req, &bypass, &key_index);
303 if (err)
304 return err;
305 pr_debug("%s: %s: slot %d bypass %d key_index %d\n",
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530306 mmc_hostname(host->mmc),
307 (rq_data_dir(req) == WRITE) ? "WRITE" : "READ",
Veerabhadrarao Badigantib82fd332017-01-31 15:17:39 +0530308 slot, bypass, key_index);
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530309 }
310
Veerabhadrarao Badigantib82fd332017-01-31 15:17:39 +0530311 sdhci_msm_ice_update_cfg(host, lba, slot, bypass, key_index);
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530312 return 0;
313}
314
315int sdhci_msm_ice_reset(struct sdhci_host *host)
316{
317 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
318 struct sdhci_msm_host *msm_host = pltfm_host->priv;
319 int err = 0;
320
321 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
322 pr_err("%s: ice is in invalid state before reset %d\n",
323 mmc_hostname(host->mmc), msm_host->ice.state);
324 return -EINVAL;
325 }
326
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530327 if (msm_host->ice.vops->reset) {
328 err = msm_host->ice.vops->reset(msm_host->ice.pdev);
329 if (err) {
330 pr_err("%s: ice reset failed %d\n",
331 mmc_hostname(host->mmc), err);
Dinesh K Garg1e93de82015-10-26 11:40:37 -0700332 sdhci_msm_ice_print_regs(host);
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530333 return err;
334 }
335 }
336
Veerabhadrarao Badiganti81203502016-12-11 17:04:56 +0530337 /* If ICE HCI support is present then re-enable it */
338 if (msm_host->ice_hci_support)
339 sdhci_msm_enable_ice_hci(host, true);
340
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530341 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
342 pr_err("%s: ice is in invalid state after reset %d\n",
343 mmc_hostname(host->mmc), msm_host->ice.state);
344 return -EINVAL;
345 }
346 return 0;
347}
348
349int sdhci_msm_ice_resume(struct sdhci_host *host)
350{
351 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
352 struct sdhci_msm_host *msm_host = pltfm_host->priv;
353 int err = 0;
354
355 if (msm_host->ice.state !=
356 SDHCI_MSM_ICE_STATE_SUSPENDED) {
357 pr_err("%s: ice is in invalid state before resume %d\n",
358 mmc_hostname(host->mmc), msm_host->ice.state);
359 return -EINVAL;
360 }
361
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530362 if (msm_host->ice.vops->resume) {
363 err = msm_host->ice.vops->resume(msm_host->ice.pdev);
364 if (err) {
365 pr_err("%s: ice resume failed %d\n",
366 mmc_hostname(host->mmc), err);
367 return err;
368 }
369 }
370
Dinesh K Garg1e93de82015-10-26 11:40:37 -0700371 msm_host->ice.state = SDHCI_MSM_ICE_STATE_ACTIVE;
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530372 return 0;
373}
374
375int sdhci_msm_ice_suspend(struct sdhci_host *host)
376{
377 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
378 struct sdhci_msm_host *msm_host = pltfm_host->priv;
379 int err = 0;
380
381 if (msm_host->ice.state !=
382 SDHCI_MSM_ICE_STATE_ACTIVE) {
383 pr_err("%s: ice is in invalid state before resume %d\n",
384 mmc_hostname(host->mmc), msm_host->ice.state);
385 return -EINVAL;
386 }
387
388 if (msm_host->ice.vops->suspend) {
389 err = msm_host->ice.vops->suspend(msm_host->ice.pdev);
390 if (err) {
391 pr_err("%s: ice suspend failed %d\n",
392 mmc_hostname(host->mmc), err);
393 return -EINVAL;
394 }
395 }
396 msm_host->ice.state = SDHCI_MSM_ICE_STATE_SUSPENDED;
397 return 0;
398}
399
400int sdhci_msm_ice_get_status(struct sdhci_host *host, int *ice_status)
401{
402 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
403 struct sdhci_msm_host *msm_host = pltfm_host->priv;
404 int stat = -EINVAL;
405
406 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
407 pr_err("%s: ice is in invalid state %d\n",
408 mmc_hostname(host->mmc), msm_host->ice.state);
409 return -EINVAL;
410 }
411
412 if (msm_host->ice.vops->status) {
413 *ice_status = 0;
414 stat = msm_host->ice.vops->status(msm_host->ice.pdev);
415 if (stat < 0) {
416 pr_err("%s: ice get sts failed %d\n",
417 mmc_hostname(host->mmc), stat);
418 return -EINVAL;
419 }
420 *ice_status = stat;
421 }
422 return 0;
423}
Sahitya Tummalaf4746692015-09-28 15:54:21 +0530424
425void sdhci_msm_ice_print_regs(struct sdhci_host *host)
426{
427 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
428 struct sdhci_msm_host *msm_host = pltfm_host->priv;
429
430 if (msm_host->ice.vops->debug)
431 msm_host->ice.vops->debug(msm_host->ice.pdev);
432}