blob: dc8d865cfabc639d98690e3b773a557b1766166c [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
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530214int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
215 u32 slot)
216{
217 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
218 struct sdhci_msm_host *msm_host = pltfm_host->priv;
219 int err = 0;
220 struct ice_data_setting ice_set;
221 sector_t lba = 0;
222 unsigned int ctrl_info_val = 0;
223 unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS;
224 struct request *req;
225
226 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
227 pr_err("%s: ice is in invalid state %d\n",
228 mmc_hostname(host->mmc), msm_host->ice.state);
229 return -EINVAL;
230 }
231
232 BUG_ON(!mrq);
233 memset(&ice_set, 0, sizeof(struct ice_data_setting));
234 req = mrq->req;
235 if (req) {
236 lba = req->__sector;
Veerabhadrarao Badigantie8d1e5d2017-01-09 15:50:04 +0530237 if (msm_host->ice.vops->config_start) {
238 err = msm_host->ice.vops->config_start(
239 msm_host->ice.pdev,
240 req, &ice_set, false);
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530241 if (err) {
242 pr_err("%s: ice config failed %d\n",
243 mmc_hostname(host->mmc), err);
244 return err;
245 }
246 }
247 /* if writing data command */
248 if (rq_data_dir(req) == WRITE)
249 bypass = ice_set.encr_bypass ?
250 SDHCI_MSM_ICE_ENABLE_BYPASS :
251 SDHCI_MSM_ICE_DISABLE_BYPASS;
252 /* if reading data command */
253 else if (rq_data_dir(req) == READ)
254 bypass = ice_set.decr_bypass ?
255 SDHCI_MSM_ICE_ENABLE_BYPASS :
256 SDHCI_MSM_ICE_DISABLE_BYPASS;
257 pr_debug("%s: %s: slot %d encr_bypass %d bypass %d decr_bypass %d key_index %d\n",
258 mmc_hostname(host->mmc),
259 (rq_data_dir(req) == WRITE) ? "WRITE" : "READ",
260 slot, ice_set.encr_bypass, bypass,
261 ice_set.decr_bypass,
262 ice_set.crypto_data.key_index);
263 }
264
265 /* Configure ICE index */
266 ctrl_info_val =
267 (ice_set.crypto_data.key_index &
268 MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX)
269 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX;
270
271 /* Configure data unit size of transfer request */
272 ctrl_info_val |=
273 (SDHCI_MSM_ICE_TR_DATA_UNIT_512_B &
274 MASK_SDHCI_MSM_ICE_CTRL_INFO_CDU)
275 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU;
276
277 /* Configure ICE bypass mode */
278 ctrl_info_val |=
279 (bypass & MASK_SDHCI_MSM_ICE_CTRL_INFO_BYPASS)
280 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_BYPASS;
281
282 writel_relaxed((lba & 0xFFFFFFFF),
283 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_1_n + 16 * slot);
284 writel_relaxed(((lba >> 32) & 0xFFFFFFFF),
285 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_2_n + 16 * slot);
286 writel_relaxed(ctrl_info_val,
287 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot);
288
289 /* Ensure ICE registers are configured before issuing SDHCI request */
290 mb();
291 return 0;
292}
293
294int sdhci_msm_ice_reset(struct sdhci_host *host)
295{
296 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
297 struct sdhci_msm_host *msm_host = pltfm_host->priv;
298 int err = 0;
299
300 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
301 pr_err("%s: ice is in invalid state before reset %d\n",
302 mmc_hostname(host->mmc), msm_host->ice.state);
303 return -EINVAL;
304 }
305
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530306 if (msm_host->ice.vops->reset) {
307 err = msm_host->ice.vops->reset(msm_host->ice.pdev);
308 if (err) {
309 pr_err("%s: ice reset failed %d\n",
310 mmc_hostname(host->mmc), err);
Dinesh K Garg1e93de82015-10-26 11:40:37 -0700311 sdhci_msm_ice_print_regs(host);
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530312 return err;
313 }
314 }
315
Veerabhadrarao Badiganti81203502016-12-11 17:04:56 +0530316 /* If ICE HCI support is present then re-enable it */
317 if (msm_host->ice_hci_support)
318 sdhci_msm_enable_ice_hci(host, true);
319
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530320 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
321 pr_err("%s: ice is in invalid state after reset %d\n",
322 mmc_hostname(host->mmc), msm_host->ice.state);
323 return -EINVAL;
324 }
325 return 0;
326}
327
328int sdhci_msm_ice_resume(struct sdhci_host *host)
329{
330 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
331 struct sdhci_msm_host *msm_host = pltfm_host->priv;
332 int err = 0;
333
334 if (msm_host->ice.state !=
335 SDHCI_MSM_ICE_STATE_SUSPENDED) {
336 pr_err("%s: ice is in invalid state before resume %d\n",
337 mmc_hostname(host->mmc), msm_host->ice.state);
338 return -EINVAL;
339 }
340
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530341 if (msm_host->ice.vops->resume) {
342 err = msm_host->ice.vops->resume(msm_host->ice.pdev);
343 if (err) {
344 pr_err("%s: ice resume failed %d\n",
345 mmc_hostname(host->mmc), err);
346 return err;
347 }
348 }
349
Dinesh K Garg1e93de82015-10-26 11:40:37 -0700350 msm_host->ice.state = SDHCI_MSM_ICE_STATE_ACTIVE;
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530351 return 0;
352}
353
354int sdhci_msm_ice_suspend(struct sdhci_host *host)
355{
356 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
357 struct sdhci_msm_host *msm_host = pltfm_host->priv;
358 int err = 0;
359
360 if (msm_host->ice.state !=
361 SDHCI_MSM_ICE_STATE_ACTIVE) {
362 pr_err("%s: ice is in invalid state before resume %d\n",
363 mmc_hostname(host->mmc), msm_host->ice.state);
364 return -EINVAL;
365 }
366
367 if (msm_host->ice.vops->suspend) {
368 err = msm_host->ice.vops->suspend(msm_host->ice.pdev);
369 if (err) {
370 pr_err("%s: ice suspend failed %d\n",
371 mmc_hostname(host->mmc), err);
372 return -EINVAL;
373 }
374 }
375 msm_host->ice.state = SDHCI_MSM_ICE_STATE_SUSPENDED;
376 return 0;
377}
378
379int sdhci_msm_ice_get_status(struct sdhci_host *host, int *ice_status)
380{
381 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
382 struct sdhci_msm_host *msm_host = pltfm_host->priv;
383 int stat = -EINVAL;
384
385 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
386 pr_err("%s: ice is in invalid state %d\n",
387 mmc_hostname(host->mmc), msm_host->ice.state);
388 return -EINVAL;
389 }
390
391 if (msm_host->ice.vops->status) {
392 *ice_status = 0;
393 stat = msm_host->ice.vops->status(msm_host->ice.pdev);
394 if (stat < 0) {
395 pr_err("%s: ice get sts failed %d\n",
396 mmc_hostname(host->mmc), stat);
397 return -EINVAL;
398 }
399 *ice_status = stat;
400 }
401 return 0;
402}
Sahitya Tummalaf4746692015-09-28 15:54:21 +0530403
404void sdhci_msm_ice_print_regs(struct sdhci_host *host)
405{
406 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
407 struct sdhci_msm_host *msm_host = pltfm_host->priv;
408
409 if (msm_host->ice.vops->debug)
410 msm_host->ice.vops->debug(msm_host->ice.pdev);
411}