]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/mmc/host/sdhci-of-esdhc.c
Merge branch 'late/fixes' into fixes
[karo-tx-linux.git] / drivers / mmc / host / sdhci-of-esdhc.c
1 /*
2  * Freescale eSDHC controller driver.
3  *
4  * Copyright (c) 2007, 2010, 2012 Freescale Semiconductor, Inc.
5  * Copyright (c) 2009 MontaVista Software, Inc.
6  *
7  * Authors: Xiaobo Xie <X.Xie@freescale.com>
8  *          Anton Vorontsov <avorontsov@ru.mvista.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or (at
13  * your option) any later version.
14  */
15
16 #include <linux/io.h>
17 #include <linux/of.h>
18 #include <linux/delay.h>
19 #include <linux/module.h>
20 #include <linux/mmc/host.h>
21 #include "sdhci-pltfm.h"
22 #include "sdhci-esdhc.h"
23
24 #define VENDOR_V_22     0x12
25 #define VENDOR_V_23     0x13
26 static u32 esdhc_readl(struct sdhci_host *host, int reg)
27 {
28         u32 ret;
29
30         ret = in_be32(host->ioaddr + reg);
31         /*
32          * The bit of ADMA flag in eSDHC is not compatible with standard
33          * SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is
34          * supported by eSDHC.
35          * And for many FSL eSDHC controller, the reset value of field
36          * SDHCI_CAN_DO_ADMA1 is one, but some of them can't support ADMA,
37          * only these vendor version is greater than 2.2/0x12 support ADMA.
38          * For FSL eSDHC, must aligned 4-byte, so use 0xFC to read the
39          * the verdor version number, oxFE is SDHCI_HOST_VERSION.
40          */
41         if ((reg == SDHCI_CAPABILITIES) && (ret & SDHCI_CAN_DO_ADMA1)) {
42                 u32 tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
43                 tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
44                 if (tmp > VENDOR_V_22)
45                         ret |= SDHCI_CAN_DO_ADMA2;
46         }
47
48         return ret;
49 }
50
51 static u16 esdhc_readw(struct sdhci_host *host, int reg)
52 {
53         u16 ret;
54         int base = reg & ~0x3;
55         int shift = (reg & 0x2) * 8;
56
57         if (unlikely(reg == SDHCI_HOST_VERSION))
58                 ret = in_be32(host->ioaddr + base) & 0xffff;
59         else
60                 ret = (in_be32(host->ioaddr + base) >> shift) & 0xffff;
61         return ret;
62 }
63
64 static u8 esdhc_readb(struct sdhci_host *host, int reg)
65 {
66         int base = reg & ~0x3;
67         int shift = (reg & 0x3) * 8;
68         u8 ret = (in_be32(host->ioaddr + base) >> shift) & 0xff;
69
70         /*
71          * "DMA select" locates at offset 0x28 in SD specification, but on
72          * P5020 or P3041, it locates at 0x29.
73          */
74         if (reg == SDHCI_HOST_CONTROL) {
75                 u32 dma_bits;
76
77                 dma_bits = in_be32(host->ioaddr + reg);
78                 /* DMA select is 22,23 bits in Protocol Control Register */
79                 dma_bits = (dma_bits >> 5) & SDHCI_CTRL_DMA_MASK;
80
81                 /* fixup the result */
82                 ret &= ~SDHCI_CTRL_DMA_MASK;
83                 ret |= dma_bits;
84         }
85
86         return ret;
87 }
88
89 static void esdhc_writel(struct sdhci_host *host, u32 val, int reg)
90 {
91         /*
92          * Enable IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE]
93          * when SYSCTL[RSTD]) is set for some special operations.
94          * No any impact other operation.
95          */
96         if (reg == SDHCI_INT_ENABLE)
97                 val |= SDHCI_INT_BLK_GAP;
98         sdhci_be32bs_writel(host, val, reg);
99 }
100
101 static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
102 {
103         if (reg == SDHCI_BLOCK_SIZE) {
104                 /*
105                  * Two last DMA bits are reserved, and first one is used for
106                  * non-standard blksz of 4096 bytes that we don't support
107                  * yet. So clear the DMA boundary bits.
108                  */
109                 val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
110         }
111         sdhci_be32bs_writew(host, val, reg);
112 }
113
114 static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
115 {
116         /*
117          * "DMA select" location is offset 0x28 in SD specification, but on
118          * P5020 or P3041, it's located at 0x29.
119          */
120         if (reg == SDHCI_HOST_CONTROL) {
121                 u32 dma_bits;
122
123                 /* DMA select is 22,23 bits in Protocol Control Register */
124                 dma_bits = (val & SDHCI_CTRL_DMA_MASK) << 5;
125                 clrsetbits_be32(host->ioaddr + reg , SDHCI_CTRL_DMA_MASK << 5,
126                         dma_bits);
127                 val &= ~SDHCI_CTRL_DMA_MASK;
128                 val |= in_be32(host->ioaddr + reg) & SDHCI_CTRL_DMA_MASK;
129         }
130
131         /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
132         if (reg == SDHCI_HOST_CONTROL)
133                 val &= ~ESDHC_HOST_CONTROL_RES;
134         sdhci_be32bs_writeb(host, val, reg);
135 }
136
137 /*
138  * For Abort or Suspend after Stop at Block Gap, ignore the ADMA
139  * error(IRQSTAT[ADMAE]) if both Transfer Complete(IRQSTAT[TC])
140  * and Block Gap Event(IRQSTAT[BGE]) are also set.
141  * For Continue, apply soft reset for data(SYSCTL[RSTD]);
142  * and re-issue the entire read transaction from beginning.
143  */
144 static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask)
145 {
146         u32 tmp;
147         bool applicable;
148         dma_addr_t dmastart;
149         dma_addr_t dmanow;
150
151         tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
152         tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
153
154         applicable = (intmask & SDHCI_INT_DATA_END) &&
155                 (intmask & SDHCI_INT_BLK_GAP) &&
156                 (tmp == VENDOR_V_23);
157         if (!applicable)
158                 return;
159
160         host->data->error = 0;
161         dmastart = sg_dma_address(host->data->sg);
162         dmanow = dmastart + host->data->bytes_xfered;
163         /*
164          * Force update to the next DMA block boundary.
165          */
166         dmanow = (dmanow & ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
167                 SDHCI_DEFAULT_BOUNDARY_SIZE;
168         host->data->bytes_xfered = dmanow - dmastart;
169         sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
170 }
171
172 static int esdhc_of_enable_dma(struct sdhci_host *host)
173 {
174         setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
175         return 0;
176 }
177
178 static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host)
179 {
180         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
181
182         return pltfm_host->clock;
183 }
184
185 static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
186 {
187         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
188
189         return pltfm_host->clock / 256 / 16;
190 }
191
192 static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
193 {
194         /* Workaround to reduce the clock frequency for p1010 esdhc */
195         if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
196                 if (clock > 20000000)
197                         clock -= 5000000;
198                 if (clock > 40000000)
199                         clock -= 5000000;
200         }
201
202         /* Set the clock */
203         esdhc_set_clock(host, clock);
204 }
205
206 #ifdef CONFIG_PM
207 static u32 esdhc_proctl;
208 static void esdhc_of_suspend(struct sdhci_host *host)
209 {
210         esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
211 }
212
213 static void esdhc_of_resume(struct sdhci_host *host)
214 {
215         esdhc_of_enable_dma(host);
216         sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
217 }
218 #endif
219
220 static void esdhc_of_platform_init(struct sdhci_host *host)
221 {
222         u32 vvn;
223
224         vvn = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
225         vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
226         if (vvn == VENDOR_V_22)
227                 host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
228
229         if (vvn > VENDOR_V_22)
230                 host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
231 }
232
233 static const struct sdhci_ops sdhci_esdhc_ops = {
234         .read_l = esdhc_readl,
235         .read_w = esdhc_readw,
236         .read_b = esdhc_readb,
237         .write_l = esdhc_writel,
238         .write_w = esdhc_writew,
239         .write_b = esdhc_writeb,
240         .set_clock = esdhc_of_set_clock,
241         .enable_dma = esdhc_of_enable_dma,
242         .get_max_clock = esdhc_of_get_max_clock,
243         .get_min_clock = esdhc_of_get_min_clock,
244         .platform_init = esdhc_of_platform_init,
245 #ifdef CONFIG_PM
246         .platform_suspend = esdhc_of_suspend,
247         .platform_resume = esdhc_of_resume,
248 #endif
249         .adma_workaround = esdhci_of_adma_workaround,
250 };
251
252 static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
253         /*
254          * card detection could be handled via GPIO
255          * eSDHC cannot support End Attribute in NOP ADMA descriptor
256          */
257         .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
258                 | SDHCI_QUIRK_NO_CARD_NO_RESET
259                 | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
260         .ops = &sdhci_esdhc_ops,
261 };
262
263 static int sdhci_esdhc_probe(struct platform_device *pdev)
264 {
265         return sdhci_pltfm_register(pdev, &sdhci_esdhc_pdata);
266 }
267
268 static int sdhci_esdhc_remove(struct platform_device *pdev)
269 {
270         return sdhci_pltfm_unregister(pdev);
271 }
272
273 static const struct of_device_id sdhci_esdhc_of_match[] = {
274         { .compatible = "fsl,mpc8379-esdhc" },
275         { .compatible = "fsl,mpc8536-esdhc" },
276         { .compatible = "fsl,esdhc" },
277         { }
278 };
279 MODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match);
280
281 static struct platform_driver sdhci_esdhc_driver = {
282         .driver = {
283                 .name = "sdhci-esdhc",
284                 .owner = THIS_MODULE,
285                 .of_match_table = sdhci_esdhc_of_match,
286                 .pm = SDHCI_PLTFM_PMOPS,
287         },
288         .probe = sdhci_esdhc_probe,
289         .remove = sdhci_esdhc_remove,
290 };
291
292 module_platform_driver(sdhci_esdhc_driver);
293
294 MODULE_DESCRIPTION("SDHCI OF driver for Freescale MPC eSDHC");
295 MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, "
296               "Anton Vorontsov <avorontsov@ru.mvista.com>");
297 MODULE_LICENSE("GPL v2");