blob: 0b99abc9e1d13feb66d4da44573bb6ee10c73eb1 [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
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
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530182 if (msm_host->ice.vops->config) {
183 err = msm_host->ice.vops->init(msm_host->ice.pdev,
184 msm_host,
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530185 sdhci_msm_ice_error_cb);
186 if (err) {
187 pr_err("%s: ice init err %d\n",
188 mmc_hostname(host->mmc), err);
Dinesh K Garg1e93de82015-10-26 11:40:37 -0700189 sdhci_msm_ice_print_regs(host);
190 goto out;
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530191 }
Dinesh K Garg1e93de82015-10-26 11:40:37 -0700192 msm_host->ice.state = SDHCI_MSM_ICE_STATE_ACTIVE;
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530193 }
194
Dinesh K Garg1e93de82015-10-26 11:40:37 -0700195out:
196 return err;
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530197}
198
Sahitya Tummala9e35aae2015-09-01 16:46:09 +0530199void sdhci_msm_ice_cfg_reset(struct sdhci_host *host, u32 slot)
200{
201 writel_relaxed(SDHCI_MSM_ICE_ENABLE_BYPASS,
202 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot);
203}
204
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530205int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
206 u32 slot)
207{
208 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
209 struct sdhci_msm_host *msm_host = pltfm_host->priv;
210 int err = 0;
211 struct ice_data_setting ice_set;
212 sector_t lba = 0;
213 unsigned int ctrl_info_val = 0;
214 unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS;
215 struct request *req;
216
217 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
218 pr_err("%s: ice is in invalid state %d\n",
219 mmc_hostname(host->mmc), msm_host->ice.state);
220 return -EINVAL;
221 }
222
223 BUG_ON(!mrq);
224 memset(&ice_set, 0, sizeof(struct ice_data_setting));
225 req = mrq->req;
226 if (req) {
227 lba = req->__sector;
228 if (msm_host->ice.vops->config) {
229 err = msm_host->ice.vops->config(msm_host->ice.pdev,
230 req, &ice_set);
231 if (err) {
232 pr_err("%s: ice config failed %d\n",
233 mmc_hostname(host->mmc), err);
234 return err;
235 }
236 }
237 /* if writing data command */
238 if (rq_data_dir(req) == WRITE)
239 bypass = ice_set.encr_bypass ?
240 SDHCI_MSM_ICE_ENABLE_BYPASS :
241 SDHCI_MSM_ICE_DISABLE_BYPASS;
242 /* if reading data command */
243 else if (rq_data_dir(req) == READ)
244 bypass = ice_set.decr_bypass ?
245 SDHCI_MSM_ICE_ENABLE_BYPASS :
246 SDHCI_MSM_ICE_DISABLE_BYPASS;
247 pr_debug("%s: %s: slot %d encr_bypass %d bypass %d decr_bypass %d key_index %d\n",
248 mmc_hostname(host->mmc),
249 (rq_data_dir(req) == WRITE) ? "WRITE" : "READ",
250 slot, ice_set.encr_bypass, bypass,
251 ice_set.decr_bypass,
252 ice_set.crypto_data.key_index);
253 }
254
255 /* Configure ICE index */
256 ctrl_info_val =
257 (ice_set.crypto_data.key_index &
258 MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX)
259 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX;
260
261 /* Configure data unit size of transfer request */
262 ctrl_info_val |=
263 (SDHCI_MSM_ICE_TR_DATA_UNIT_512_B &
264 MASK_SDHCI_MSM_ICE_CTRL_INFO_CDU)
265 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU;
266
267 /* Configure ICE bypass mode */
268 ctrl_info_val |=
269 (bypass & MASK_SDHCI_MSM_ICE_CTRL_INFO_BYPASS)
270 << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_BYPASS;
271
272 writel_relaxed((lba & 0xFFFFFFFF),
273 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_1_n + 16 * slot);
274 writel_relaxed(((lba >> 32) & 0xFFFFFFFF),
275 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_2_n + 16 * slot);
276 writel_relaxed(ctrl_info_val,
277 host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot);
278
279 /* Ensure ICE registers are configured before issuing SDHCI request */
280 mb();
281 return 0;
282}
283
284int sdhci_msm_ice_reset(struct sdhci_host *host)
285{
286 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
287 struct sdhci_msm_host *msm_host = pltfm_host->priv;
288 int err = 0;
289
290 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
291 pr_err("%s: ice is in invalid state before reset %d\n",
292 mmc_hostname(host->mmc), msm_host->ice.state);
293 return -EINVAL;
294 }
295
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530296 if (msm_host->ice.vops->reset) {
297 err = msm_host->ice.vops->reset(msm_host->ice.pdev);
298 if (err) {
299 pr_err("%s: ice reset failed %d\n",
300 mmc_hostname(host->mmc), err);
Dinesh K Garg1e93de82015-10-26 11:40:37 -0700301 sdhci_msm_ice_print_regs(host);
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530302 return err;
303 }
304 }
305
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530306 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
307 pr_err("%s: ice is in invalid state after reset %d\n",
308 mmc_hostname(host->mmc), msm_host->ice.state);
309 return -EINVAL;
310 }
311 return 0;
312}
313
314int sdhci_msm_ice_resume(struct sdhci_host *host)
315{
316 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
317 struct sdhci_msm_host *msm_host = pltfm_host->priv;
318 int err = 0;
319
320 if (msm_host->ice.state !=
321 SDHCI_MSM_ICE_STATE_SUSPENDED) {
322 pr_err("%s: ice is in invalid state before resume %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->resume) {
328 err = msm_host->ice.vops->resume(msm_host->ice.pdev);
329 if (err) {
330 pr_err("%s: ice resume failed %d\n",
331 mmc_hostname(host->mmc), err);
332 return err;
333 }
334 }
335
Dinesh K Garg1e93de82015-10-26 11:40:37 -0700336 msm_host->ice.state = SDHCI_MSM_ICE_STATE_ACTIVE;
Sahitya Tummala719c6b52015-05-21 08:28:19 +0530337 return 0;
338}
339
340int sdhci_msm_ice_suspend(struct sdhci_host *host)
341{
342 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
343 struct sdhci_msm_host *msm_host = pltfm_host->priv;
344 int err = 0;
345
346 if (msm_host->ice.state !=
347 SDHCI_MSM_ICE_STATE_ACTIVE) {
348 pr_err("%s: ice is in invalid state before resume %d\n",
349 mmc_hostname(host->mmc), msm_host->ice.state);
350 return -EINVAL;
351 }
352
353 if (msm_host->ice.vops->suspend) {
354 err = msm_host->ice.vops->suspend(msm_host->ice.pdev);
355 if (err) {
356 pr_err("%s: ice suspend failed %d\n",
357 mmc_hostname(host->mmc), err);
358 return -EINVAL;
359 }
360 }
361 msm_host->ice.state = SDHCI_MSM_ICE_STATE_SUSPENDED;
362 return 0;
363}
364
365int sdhci_msm_ice_get_status(struct sdhci_host *host, int *ice_status)
366{
367 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
368 struct sdhci_msm_host *msm_host = pltfm_host->priv;
369 int stat = -EINVAL;
370
371 if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
372 pr_err("%s: ice is in invalid state %d\n",
373 mmc_hostname(host->mmc), msm_host->ice.state);
374 return -EINVAL;
375 }
376
377 if (msm_host->ice.vops->status) {
378 *ice_status = 0;
379 stat = msm_host->ice.vops->status(msm_host->ice.pdev);
380 if (stat < 0) {
381 pr_err("%s: ice get sts failed %d\n",
382 mmc_hostname(host->mmc), stat);
383 return -EINVAL;
384 }
385 *ice_status = stat;
386 }
387 return 0;
388}
Sahitya Tummalaf4746692015-09-28 15:54:21 +0530389
390void sdhci_msm_ice_print_regs(struct sdhci_host *host)
391{
392 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
393 struct sdhci_msm_host *msm_host = pltfm_host->priv;
394
395 if (msm_host->ice.vops->debug)
396 msm_host->ice.vops->debug(msm_host->ice.pdev);
397}