diff options
author | Tim Yamin <plasm@roo.me.uk> | 2008-12-21 04:54:29 -0500 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2008-12-21 04:54:29 -0500 |
commit | 6b61e69e7bc1cfe80ab54c6321f19061f9487ed3 (patch) | |
tree | 0e3a4f9f8069186b385f1eba379fad6897df7c81 /drivers/ata | |
parent | aaab5e83c2c25d94f7409bdc947a5cc383514e15 (diff) |
powerpc/mpc5200: Add MDMA/UDMA support to MPC5200 ATA driver
This patch adds MDMA/UDMA support using BestComm for DMA on the MPC5200
platform. Based heavily on previous work by Freescale (Bernard Kuhn,
John Rigby) and Domen Puncer.
With this patch, a SanDisk Extreme IV CF card gets read speeds of
approximately 26.70 MB/sec.
Signed-off-by: Tim Yamin <plasm@roo.me.uk>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/Kconfig | 3 | ||||
-rw-r--r-- | drivers/ata/pata_mpc52xx.c | 546 |
2 files changed, 483 insertions, 66 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 421b7c71e72d..1a7be96d627b 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig | |||
@@ -456,7 +456,8 @@ config PATA_MARVELL | |||
456 | 456 | ||
457 | config PATA_MPC52xx | 457 | config PATA_MPC52xx |
458 | tristate "Freescale MPC52xx SoC internal IDE" | 458 | tristate "Freescale MPC52xx SoC internal IDE" |
459 | depends on PPC_MPC52xx | 459 | depends on PPC_MPC52xx && PPC_BESTCOMM |
460 | select PPC_BESTCOMM_ATA | ||
460 | help | 461 | help |
461 | This option enables support for integrated IDE controller | 462 | This option enables support for integrated IDE controller |
462 | of the Freescale MPC52xx SoC. | 463 | of the Freescale MPC52xx SoC. |
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index a9e827356d06..50ae6d13078a 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c | |||
@@ -6,6 +6,9 @@ | |||
6 | * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com> | 6 | * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com> |
7 | * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt | 7 | * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt |
8 | * | 8 | * |
9 | * UDMA support based on patches by Freescale (Bernard Kuhn, John Rigby), | ||
10 | * Domen Puncer and Tim Yamin. | ||
11 | * | ||
9 | * This file is licensed under the terms of the GNU General Public License | 12 | * This file is licensed under the terms of the GNU General Public License |
10 | * version 2. This program is licensed "as is" without any warranty of any | 13 | * version 2. This program is licensed "as is" without any warranty of any |
11 | * kind, whether express or implied. | 14 | * kind, whether express or implied. |
@@ -17,28 +20,46 @@ | |||
17 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
18 | #include <linux/libata.h> | 21 | #include <linux/libata.h> |
19 | #include <linux/of_platform.h> | 22 | #include <linux/of_platform.h> |
23 | #include <linux/types.h> | ||
20 | 24 | ||
21 | #include <asm/types.h> | 25 | #include <asm/cacheflush.h> |
22 | #include <asm/prom.h> | 26 | #include <asm/prom.h> |
23 | #include <asm/mpc52xx.h> | 27 | #include <asm/mpc52xx.h> |
24 | 28 | ||
29 | #include <sysdev/bestcomm/bestcomm.h> | ||
30 | #include <sysdev/bestcomm/bestcomm_priv.h> | ||
31 | #include <sysdev/bestcomm/ata.h> | ||
25 | 32 | ||
26 | #define DRV_NAME "mpc52xx_ata" | 33 | #define DRV_NAME "mpc52xx_ata" |
27 | #define DRV_VERSION "0.1.2" | ||
28 | |||
29 | 34 | ||
30 | /* Private structures used by the driver */ | 35 | /* Private structures used by the driver */ |
31 | struct mpc52xx_ata_timings { | 36 | struct mpc52xx_ata_timings { |
32 | u32 pio1; | 37 | u32 pio1; |
33 | u32 pio2; | 38 | u32 pio2; |
39 | u32 mdma1; | ||
40 | u32 mdma2; | ||
41 | u32 udma1; | ||
42 | u32 udma2; | ||
43 | u32 udma3; | ||
44 | u32 udma4; | ||
45 | u32 udma5; | ||
46 | int using_udma; | ||
34 | }; | 47 | }; |
35 | 48 | ||
36 | struct mpc52xx_ata_priv { | 49 | struct mpc52xx_ata_priv { |
37 | unsigned int ipb_period; | 50 | unsigned int ipb_period; |
38 | struct mpc52xx_ata __iomem * ata_regs; | 51 | struct mpc52xx_ata __iomem *ata_regs; |
52 | phys_addr_t ata_regs_pa; | ||
39 | int ata_irq; | 53 | int ata_irq; |
40 | struct mpc52xx_ata_timings timings[2]; | 54 | struct mpc52xx_ata_timings timings[2]; |
41 | int csel; | 55 | int csel; |
56 | |||
57 | /* DMA */ | ||
58 | struct bcom_task *dmatsk; | ||
59 | const struct udmaspec *udmaspec; | ||
60 | const struct mdmaspec *mdmaspec; | ||
61 | int mpc52xx_ata_dma_last_write; | ||
62 | int waiting_for_dma; | ||
42 | }; | 63 | }; |
43 | 64 | ||
44 | 65 | ||
@@ -53,6 +74,107 @@ static const int ataspec_ta[5] = { 35, 35, 35, 35, 35}; | |||
53 | 74 | ||
54 | #define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c))) | 75 | #define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c))) |
55 | 76 | ||
77 | /* ======================================================================== */ | ||
78 | |||
79 | /* ATAPI-4 MDMA specs (in clocks) */ | ||
80 | struct mdmaspec { | ||
81 | u32 t0M; | ||
82 | u32 td; | ||
83 | u32 th; | ||
84 | u32 tj; | ||
85 | u32 tkw; | ||
86 | u32 tm; | ||
87 | u32 tn; | ||
88 | }; | ||
89 | |||
90 | static const struct mdmaspec mdmaspec66[3] = { | ||
91 | { .t0M = 32, .td = 15, .th = 2, .tj = 2, .tkw = 15, .tm = 4, .tn = 1 }, | ||
92 | { .t0M = 10, .td = 6, .th = 1, .tj = 1, .tkw = 4, .tm = 2, .tn = 1 }, | ||
93 | { .t0M = 8, .td = 5, .th = 1, .tj = 1, .tkw = 2, .tm = 2, .tn = 1 }, | ||
94 | }; | ||
95 | |||
96 | static const struct mdmaspec mdmaspec132[3] = { | ||
97 | { .t0M = 64, .td = 29, .th = 3, .tj = 3, .tkw = 29, .tm = 7, .tn = 2 }, | ||
98 | { .t0M = 20, .td = 11, .th = 2, .tj = 1, .tkw = 7, .tm = 4, .tn = 1 }, | ||
99 | { .t0M = 16, .td = 10, .th = 2, .tj = 1, .tkw = 4, .tm = 4, .tn = 1 }, | ||
100 | }; | ||
101 | |||
102 | /* ATAPI-4 UDMA specs (in clocks) */ | ||
103 | struct udmaspec { | ||
104 | u32 tcyc; | ||
105 | u32 t2cyc; | ||
106 | u32 tds; | ||
107 | u32 tdh; | ||
108 | u32 tdvs; | ||
109 | u32 tdvh; | ||
110 | u32 tfs; | ||
111 | u32 tli; | ||
112 | u32 tmli; | ||
113 | u32 taz; | ||
114 | u32 tzah; | ||
115 | u32 tenv; | ||
116 | u32 tsr; | ||
117 | u32 trfs; | ||
118 | u32 trp; | ||
119 | u32 tack; | ||
120 | u32 tss; | ||
121 | }; | ||
122 | |||
123 | static const struct udmaspec udmaspec66[6] = { | ||
124 | { .tcyc = 8, .t2cyc = 16, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1, | ||
125 | .tfs = 16, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | ||
126 | .tsr = 3, .trfs = 5, .trp = 11, .tack = 2, .tss = 4, | ||
127 | }, | ||
128 | { .tcyc = 5, .t2cyc = 11, .tds = 1, .tdh = 1, .tdvs = 4, .tdvh = 1, | ||
129 | .tfs = 14, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | ||
130 | .tsr = 2, .trfs = 5, .trp = 9, .tack = 2, .tss = 4, | ||
131 | }, | ||
132 | { .tcyc = 4, .t2cyc = 8, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1, | ||
133 | .tfs = 12, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | ||
134 | .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, | ||
135 | }, | ||
136 | { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 2, .tdvh = 1, | ||
137 | .tfs = 9, .tli = 7, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | ||
138 | .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, | ||
139 | }, | ||
140 | { .tcyc = 2, .t2cyc = 4, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, | ||
141 | .tfs = 8, .tli = 8, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | ||
142 | .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, | ||
143 | }, | ||
144 | { .tcyc = 2, .t2cyc = 2, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, | ||
145 | .tfs = 6, .tli = 5, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | ||
146 | .tsr = 2, .trfs = 4, .trp = 6, .tack = 2, .tss = 4, | ||
147 | }, | ||
148 | }; | ||
149 | |||
150 | static const struct udmaspec udmaspec132[6] = { | ||
151 | { .tcyc = 15, .t2cyc = 31, .tds = 2, .tdh = 1, .tdvs = 10, .tdvh = 1, | ||
152 | .tfs = 30, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, | ||
153 | .tsr = 7, .trfs = 10, .trp = 22, .tack = 3, .tss = 7, | ||
154 | }, | ||
155 | { .tcyc = 10, .t2cyc = 21, .tds = 2, .tdh = 1, .tdvs = 7, .tdvh = 1, | ||
156 | .tfs = 27, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, | ||
157 | .tsr = 4, .trfs = 10, .trp = 17, .tack = 3, .tss = 7, | ||
158 | }, | ||
159 | { .tcyc = 6, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1, | ||
160 | .tfs = 23, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, | ||
161 | .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7, | ||
162 | }, | ||
163 | { .tcyc = 7, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1, | ||
164 | .tfs = 15, .tli = 13, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, | ||
165 | .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7, | ||
166 | }, | ||
167 | { .tcyc = 2, .t2cyc = 5, .tds = 0, .tdh = 0, .tdvs = 1, .tdvh = 1, | ||
168 | .tfs = 16, .tli = 14, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | ||
169 | .tsr = 2, .trfs = 7, .trp = 13, .tack = 2, .tss = 6, | ||
170 | }, | ||
171 | { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, | ||
172 | .tfs = 12, .tli = 10, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, | ||
173 | .tsr = 3, .trfs = 7, .trp = 12, .tack = 3, .tss = 7, | ||
174 | }, | ||
175 | }; | ||
176 | |||
177 | /* ======================================================================== */ | ||
56 | 178 | ||
57 | /* Bit definitions inside the registers */ | 179 | /* Bit definitions inside the registers */ |
58 | #define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */ | 180 | #define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */ |
@@ -66,6 +188,7 @@ static const int ataspec_ta[5] = { 35, 35, 35, 35, 35}; | |||
66 | #define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */ | 188 | #define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */ |
67 | 189 | ||
68 | #define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */ | 190 | #define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */ |
191 | #define MPC52xx_ATA_FIFOSTAT_ERROR 0x40 /* FIFO Error */ | ||
69 | 192 | ||
70 | #define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */ | 193 | #define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */ |
71 | #define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */ | 194 | #define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */ |
@@ -75,6 +198,8 @@ static const int ataspec_ta[5] = { 35, 35, 35, 35, 35}; | |||
75 | #define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */ | 198 | #define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */ |
76 | #define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */ | 199 | #define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */ |
77 | 200 | ||
201 | #define MAX_DMA_BUFFERS 128 | ||
202 | #define MAX_DMA_BUFFER_SIZE 0x20000u | ||
78 | 203 | ||
79 | /* Structure of the hardware registers */ | 204 | /* Structure of the hardware registers */ |
80 | struct mpc52xx_ata { | 205 | struct mpc52xx_ata { |
@@ -140,7 +265,6 @@ struct mpc52xx_ata { | |||
140 | 265 | ||
141 | 266 | ||
142 | /* MPC52xx low level hw control */ | 267 | /* MPC52xx low level hw control */ |
143 | |||
144 | static int | 268 | static int |
145 | mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio) | 269 | mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio) |
146 | { | 270 | { |
@@ -148,7 +272,7 @@ mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio) | |||
148 | unsigned int ipb_period = priv->ipb_period; | 272 | unsigned int ipb_period = priv->ipb_period; |
149 | unsigned int t0, t1, t2_8, t2_16, t2i, t4, ta; | 273 | unsigned int t0, t1, t2_8, t2_16, t2i, t4, ta; |
150 | 274 | ||
151 | if ((pio<0) || (pio>4)) | 275 | if ((pio < 0) || (pio > 4)) |
152 | return -EINVAL; | 276 | return -EINVAL; |
153 | 277 | ||
154 | t0 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t0[pio]); | 278 | t0 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t0[pio]); |
@@ -165,6 +289,43 @@ mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio) | |||
165 | return 0; | 289 | return 0; |
166 | } | 290 | } |
167 | 291 | ||
292 | static int | ||
293 | mpc52xx_ata_compute_mdma_timings(struct mpc52xx_ata_priv *priv, int dev, | ||
294 | int speed) | ||
295 | { | ||
296 | struct mpc52xx_ata_timings *t = &priv->timings[dev]; | ||
297 | const struct mdmaspec *s = &priv->mdmaspec[speed]; | ||
298 | |||
299 | if (speed < 0 || speed > 2) | ||
300 | return -EINVAL; | ||
301 | |||
302 | t->mdma1 = (s->t0M << 24) | (s->td << 16) | (s->tkw << 8) | (s->tm); | ||
303 | t->mdma2 = (s->th << 24) | (s->tj << 16) | (s->tn << 8); | ||
304 | t->using_udma = 0; | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int | ||
310 | mpc52xx_ata_compute_udma_timings(struct mpc52xx_ata_priv *priv, int dev, | ||
311 | int speed) | ||
312 | { | ||
313 | struct mpc52xx_ata_timings *t = &priv->timings[dev]; | ||
314 | const struct udmaspec *s = &priv->udmaspec[speed]; | ||
315 | |||
316 | if (speed < 0 || speed > 2) | ||
317 | return -EINVAL; | ||
318 | |||
319 | t->udma1 = (s->t2cyc << 24) | (s->tcyc << 16) | (s->tds << 8) | s->tdh; | ||
320 | t->udma2 = (s->tdvs << 24) | (s->tdvh << 16) | (s->tfs << 8) | s->tli; | ||
321 | t->udma3 = (s->tmli << 24) | (s->taz << 16) | (s->tenv << 8) | s->tsr; | ||
322 | t->udma4 = (s->tss << 24) | (s->trfs << 16) | (s->trp << 8) | s->tack; | ||
323 | t->udma5 = (s->tzah << 24); | ||
324 | t->using_udma = 1; | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
168 | static void | 329 | static void |
169 | mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device) | 330 | mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device) |
170 | { | 331 | { |
@@ -173,14 +334,13 @@ mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device) | |||
173 | 334 | ||
174 | out_be32(®s->pio1, timing->pio1); | 335 | out_be32(®s->pio1, timing->pio1); |
175 | out_be32(®s->pio2, timing->pio2); | 336 | out_be32(®s->pio2, timing->pio2); |
176 | out_be32(®s->mdma1, 0); | 337 | out_be32(®s->mdma1, timing->mdma1); |
177 | out_be32(®s->mdma2, 0); | 338 | out_be32(®s->mdma2, timing->mdma2); |
178 | out_be32(®s->udma1, 0); | 339 | out_be32(®s->udma1, timing->udma1); |
179 | out_be32(®s->udma2, 0); | 340 | out_be32(®s->udma2, timing->udma2); |
180 | out_be32(®s->udma3, 0); | 341 | out_be32(®s->udma3, timing->udma3); |
181 | out_be32(®s->udma4, 0); | 342 | out_be32(®s->udma4, timing->udma4); |
182 | out_be32(®s->udma5, 0); | 343 | out_be32(®s->udma5, timing->udma5); |
183 | |||
184 | priv->csel = device; | 344 | priv->csel = device; |
185 | } | 345 | } |
186 | 346 | ||
@@ -208,7 +368,7 @@ mpc52xx_ata_hw_init(struct mpc52xx_ata_priv *priv) | |||
208 | 368 | ||
209 | /* Set the time slot to 1us */ | 369 | /* Set the time slot to 1us */ |
210 | tslot = CALC_CLKCYC(priv->ipb_period, 1000000); | 370 | tslot = CALC_CLKCYC(priv->ipb_period, 1000000); |
211 | out_be32(®s->share_cnt, tslot << 16 ); | 371 | out_be32(®s->share_cnt, tslot << 16); |
212 | 372 | ||
213 | /* Init timings to PIO0 */ | 373 | /* Init timings to PIO0 */ |
214 | memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings)); | 374 | memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings)); |
@@ -237,13 +397,37 @@ mpc52xx_ata_set_piomode(struct ata_port *ap, struct ata_device *adev) | |||
237 | rv = mpc52xx_ata_compute_pio_timings(priv, adev->devno, pio); | 397 | rv = mpc52xx_ata_compute_pio_timings(priv, adev->devno, pio); |
238 | 398 | ||
239 | if (rv) { | 399 | if (rv) { |
240 | printk(KERN_ERR DRV_NAME | 400 | dev_err(ap->dev, "error: invalid PIO mode: %d\n", pio); |
241 | ": Trying to select invalid PIO mode %d\n", pio); | 401 | return; |
402 | } | ||
403 | |||
404 | mpc52xx_ata_apply_timings(priv, adev->devno); | ||
405 | } | ||
406 | |||
407 | static void | ||
408 | mpc52xx_ata_set_dmamode(struct ata_port *ap, struct ata_device *adev) | ||
409 | { | ||
410 | struct mpc52xx_ata_priv *priv = ap->host->private_data; | ||
411 | int rv; | ||
412 | |||
413 | if (adev->dma_mode >= XFER_UDMA_0) { | ||
414 | int dma = adev->dma_mode - XFER_UDMA_0; | ||
415 | rv = mpc52xx_ata_compute_udma_timings(priv, adev->devno, dma); | ||
416 | } else { | ||
417 | int dma = adev->dma_mode - XFER_MW_DMA_0; | ||
418 | rv = mpc52xx_ata_compute_mdma_timings(priv, adev->devno, dma); | ||
419 | } | ||
420 | |||
421 | if (rv) { | ||
422 | dev_alert(ap->dev, | ||
423 | "Trying to select invalid DMA mode %d\n", | ||
424 | adev->dma_mode); | ||
242 | return; | 425 | return; |
243 | } | 426 | } |
244 | 427 | ||
245 | mpc52xx_ata_apply_timings(priv, adev->devno); | 428 | mpc52xx_ata_apply_timings(priv, adev->devno); |
246 | } | 429 | } |
430 | |||
247 | static void | 431 | static void |
248 | mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device) | 432 | mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device) |
249 | { | 433 | { |
@@ -252,7 +436,173 @@ mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device) | |||
252 | if (device != priv->csel) | 436 | if (device != priv->csel) |
253 | mpc52xx_ata_apply_timings(priv, device); | 437 | mpc52xx_ata_apply_timings(priv, device); |
254 | 438 | ||
255 | ata_sff_dev_select(ap,device); | 439 | ata_sff_dev_select(ap, device); |
440 | } | ||
441 | |||
442 | static int | ||
443 | mpc52xx_ata_build_dmatable(struct ata_queued_cmd *qc) | ||
444 | { | ||
445 | struct ata_port *ap = qc->ap; | ||
446 | struct mpc52xx_ata_priv *priv = ap->host->private_data; | ||
447 | struct bcom_ata_bd *bd; | ||
448 | unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE), si; | ||
449 | struct scatterlist *sg; | ||
450 | int count = 0; | ||
451 | |||
452 | if (read) | ||
453 | bcom_ata_rx_prepare(priv->dmatsk); | ||
454 | else | ||
455 | bcom_ata_tx_prepare(priv->dmatsk); | ||
456 | |||
457 | for_each_sg(qc->sg, sg, qc->n_elem, si) { | ||
458 | dma_addr_t cur_addr = sg_dma_address(sg); | ||
459 | u32 cur_len = sg_dma_len(sg); | ||
460 | |||
461 | while (cur_len) { | ||
462 | unsigned int tc = min(cur_len, MAX_DMA_BUFFER_SIZE); | ||
463 | bd = (struct bcom_ata_bd *) | ||
464 | bcom_prepare_next_buffer(priv->dmatsk); | ||
465 | |||
466 | if (read) { | ||
467 | bd->status = tc; | ||
468 | bd->src_pa = (__force u32) priv->ata_regs_pa + | ||
469 | offsetof(struct mpc52xx_ata, fifo_data); | ||
470 | bd->dst_pa = (__force u32) cur_addr; | ||
471 | } else { | ||
472 | bd->status = tc; | ||
473 | bd->src_pa = (__force u32) cur_addr; | ||
474 | bd->dst_pa = (__force u32) priv->ata_regs_pa + | ||
475 | offsetof(struct mpc52xx_ata, fifo_data); | ||
476 | } | ||
477 | |||
478 | bcom_submit_next_buffer(priv->dmatsk, NULL); | ||
479 | |||
480 | cur_addr += tc; | ||
481 | cur_len -= tc; | ||
482 | count++; | ||
483 | |||
484 | if (count > MAX_DMA_BUFFERS) { | ||
485 | dev_alert(ap->dev, "dma table" | ||
486 | "too small\n"); | ||
487 | goto use_pio_instead; | ||
488 | } | ||
489 | } | ||
490 | } | ||
491 | return 1; | ||
492 | |||
493 | use_pio_instead: | ||
494 | bcom_ata_reset_bd(priv->dmatsk); | ||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | static void | ||
499 | mpc52xx_bmdma_setup(struct ata_queued_cmd *qc) | ||
500 | { | ||
501 | struct ata_port *ap = qc->ap; | ||
502 | struct mpc52xx_ata_priv *priv = ap->host->private_data; | ||
503 | struct mpc52xx_ata __iomem *regs = priv->ata_regs; | ||
504 | |||
505 | unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE); | ||
506 | u8 dma_mode; | ||
507 | |||
508 | if (!mpc52xx_ata_build_dmatable(qc)) | ||
509 | dev_alert(ap->dev, "%s: %i, return 1?\n", | ||
510 | __func__, __LINE__); | ||
511 | |||
512 | /* Check FIFO is OK... */ | ||
513 | if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) | ||
514 | dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n", | ||
515 | __func__, in_8(&priv->ata_regs->fifo_status)); | ||
516 | |||
517 | if (read) { | ||
518 | dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_READ | | ||
519 | MPC52xx_ATA_DMAMODE_FE; | ||
520 | |||
521 | /* Setup FIFO if direction changed */ | ||
522 | if (priv->mpc52xx_ata_dma_last_write != 0) { | ||
523 | priv->mpc52xx_ata_dma_last_write = 0; | ||
524 | |||
525 | /* Configure FIFO with granularity to 7 */ | ||
526 | out_8(®s->fifo_control, 7); | ||
527 | out_be16(®s->fifo_alarm, 128); | ||
528 | |||
529 | /* Set FIFO Reset bit (FR) */ | ||
530 | out_8(®s->dma_mode, MPC52xx_ATA_DMAMODE_FR); | ||
531 | } | ||
532 | } else { | ||
533 | dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_WRITE; | ||
534 | |||
535 | /* Setup FIFO if direction changed */ | ||
536 | if (priv->mpc52xx_ata_dma_last_write != 1) { | ||
537 | priv->mpc52xx_ata_dma_last_write = 1; | ||
538 | |||
539 | /* Configure FIFO with granularity to 4 */ | ||
540 | out_8(®s->fifo_control, 4); | ||
541 | out_be16(®s->fifo_alarm, 128); | ||
542 | } | ||
543 | } | ||
544 | |||
545 | if (priv->timings[qc->dev->devno].using_udma) | ||
546 | dma_mode |= MPC52xx_ATA_DMAMODE_UDMA; | ||
547 | |||
548 | out_8(®s->dma_mode, dma_mode); | ||
549 | priv->waiting_for_dma = ATA_DMA_ACTIVE; | ||
550 | |||
551 | ata_wait_idle(ap); | ||
552 | ap->ops->sff_exec_command(ap, &qc->tf); | ||
553 | } | ||
554 | |||
555 | static void | ||
556 | mpc52xx_bmdma_start(struct ata_queued_cmd *qc) | ||
557 | { | ||
558 | struct ata_port *ap = qc->ap; | ||
559 | struct mpc52xx_ata_priv *priv = ap->host->private_data; | ||
560 | |||
561 | bcom_set_task_auto_start(priv->dmatsk->tasknum, priv->dmatsk->tasknum); | ||
562 | bcom_enable(priv->dmatsk); | ||
563 | } | ||
564 | |||
565 | static void | ||
566 | mpc52xx_bmdma_stop(struct ata_queued_cmd *qc) | ||
567 | { | ||
568 | struct ata_port *ap = qc->ap; | ||
569 | struct mpc52xx_ata_priv *priv = ap->host->private_data; | ||
570 | |||
571 | bcom_disable(priv->dmatsk); | ||
572 | bcom_ata_reset_bd(priv->dmatsk); | ||
573 | priv->waiting_for_dma = 0; | ||
574 | |||
575 | /* Check FIFO is OK... */ | ||
576 | if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) | ||
577 | dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n", | ||
578 | __func__, in_8(&priv->ata_regs->fifo_status)); | ||
579 | } | ||
580 | |||
581 | static u8 | ||
582 | mpc52xx_bmdma_status(struct ata_port *ap) | ||
583 | { | ||
584 | struct mpc52xx_ata_priv *priv = ap->host->private_data; | ||
585 | |||
586 | /* Check FIFO is OK... */ | ||
587 | if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) { | ||
588 | dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n", | ||
589 | __func__, in_8(&priv->ata_regs->fifo_status)); | ||
590 | return priv->waiting_for_dma | ATA_DMA_ERR; | ||
591 | } | ||
592 | |||
593 | return priv->waiting_for_dma; | ||
594 | } | ||
595 | |||
596 | static irqreturn_t | ||
597 | mpc52xx_ata_task_irq(int irq, void *vpriv) | ||
598 | { | ||
599 | struct mpc52xx_ata_priv *priv = vpriv; | ||
600 | while (bcom_buffer_done(priv->dmatsk)) | ||
601 | bcom_retrieve_buffer(priv->dmatsk, NULL, NULL); | ||
602 | |||
603 | priv->waiting_for_dma |= ATA_DMA_INTR; | ||
604 | |||
605 | return IRQ_HANDLED; | ||
256 | } | 606 | } |
257 | 607 | ||
258 | static struct scsi_host_template mpc52xx_ata_sht = { | 608 | static struct scsi_host_template mpc52xx_ata_sht = { |
@@ -262,14 +612,18 @@ static struct scsi_host_template mpc52xx_ata_sht = { | |||
262 | static struct ata_port_operations mpc52xx_ata_port_ops = { | 612 | static struct ata_port_operations mpc52xx_ata_port_ops = { |
263 | .inherits = &ata_sff_port_ops, | 613 | .inherits = &ata_sff_port_ops, |
264 | .sff_dev_select = mpc52xx_ata_dev_select, | 614 | .sff_dev_select = mpc52xx_ata_dev_select, |
265 | .cable_detect = ata_cable_40wire, | ||
266 | .set_piomode = mpc52xx_ata_set_piomode, | 615 | .set_piomode = mpc52xx_ata_set_piomode, |
267 | .post_internal_cmd = ATA_OP_NULL, | 616 | .set_dmamode = mpc52xx_ata_set_dmamode, |
617 | .bmdma_setup = mpc52xx_bmdma_setup, | ||
618 | .bmdma_start = mpc52xx_bmdma_start, | ||
619 | .bmdma_stop = mpc52xx_bmdma_stop, | ||
620 | .bmdma_status = mpc52xx_bmdma_status, | ||
621 | .qc_prep = ata_noop_qc_prep, | ||
268 | }; | 622 | }; |
269 | 623 | ||
270 | static int __devinit | 624 | static int __devinit |
271 | mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv, | 625 | mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv, |
272 | unsigned long raw_ata_regs) | 626 | unsigned long raw_ata_regs, int mwdma_mask, int udma_mask) |
273 | { | 627 | { |
274 | struct ata_host *host; | 628 | struct ata_host *host; |
275 | struct ata_port *ap; | 629 | struct ata_port *ap; |
@@ -281,9 +635,9 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv, | |||
281 | 635 | ||
282 | ap = host->ports[0]; | 636 | ap = host->ports[0]; |
283 | ap->flags |= ATA_FLAG_SLAVE_POSS; | 637 | ap->flags |= ATA_FLAG_SLAVE_POSS; |
284 | ap->pio_mask = 0x1f; /* Up to PIO4 */ | 638 | ap->pio_mask = ATA_PIO4; |
285 | ap->mwdma_mask = 0x00; /* No MWDMA */ | 639 | ap->mwdma_mask = mwdma_mask; |
286 | ap->udma_mask = 0x00; /* No UDMA */ | 640 | ap->udma_mask = udma_mask; |
287 | ap->ops = &mpc52xx_ata_port_ops; | 641 | ap->ops = &mpc52xx_ata_port_ops; |
288 | host->private_data = priv; | 642 | host->private_data = priv; |
289 | 643 | ||
@@ -330,89 +684,139 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match) | |||
330 | { | 684 | { |
331 | unsigned int ipb_freq; | 685 | unsigned int ipb_freq; |
332 | struct resource res_mem; | 686 | struct resource res_mem; |
333 | int ata_irq; | 687 | int ata_irq = 0; |
334 | struct mpc52xx_ata __iomem *ata_regs; | 688 | struct mpc52xx_ata __iomem *ata_regs; |
335 | struct mpc52xx_ata_priv *priv; | 689 | struct mpc52xx_ata_priv *priv = NULL; |
336 | int rv; | 690 | int rv, ret, task_irq = 0; |
691 | int mwdma_mask = 0, udma_mask = 0; | ||
692 | const __be32 *prop; | ||
693 | int proplen; | ||
694 | struct bcom_task *dmatsk = NULL; | ||
337 | 695 | ||
338 | /* Get ipb frequency */ | 696 | /* Get ipb frequency */ |
339 | ipb_freq = mpc52xx_find_ipb_freq(op->node); | 697 | ipb_freq = mpc52xx_find_ipb_freq(op->node); |
340 | if (!ipb_freq) { | 698 | if (!ipb_freq) { |
341 | printk(KERN_ERR DRV_NAME ": " | 699 | dev_err(&op->dev, "could not determine IPB bus frequency\n"); |
342 | "Unable to find IPB Bus frequency\n" ); | ||
343 | return -ENODEV; | 700 | return -ENODEV; |
344 | } | 701 | } |
345 | 702 | ||
346 | /* Get IRQ and register */ | 703 | /* Get device base address from device tree, request the region |
704 | * and ioremap it. */ | ||
347 | rv = of_address_to_resource(op->node, 0, &res_mem); | 705 | rv = of_address_to_resource(op->node, 0, &res_mem); |
348 | if (rv) { | 706 | if (rv) { |
349 | printk(KERN_ERR DRV_NAME ": " | 707 | dev_err(&op->dev, "could not determine device base address\n"); |
350 | "Error while parsing device node resource\n" ); | ||
351 | return rv; | 708 | return rv; |
352 | } | 709 | } |
353 | 710 | ||
354 | ata_irq = irq_of_parse_and_map(op->node, 0); | ||
355 | if (ata_irq == NO_IRQ) { | ||
356 | printk(KERN_ERR DRV_NAME ": " | ||
357 | "Error while mapping the irq\n"); | ||
358 | return -EINVAL; | ||
359 | } | ||
360 | |||
361 | /* Request mem region */ | ||
362 | if (!devm_request_mem_region(&op->dev, res_mem.start, | 711 | if (!devm_request_mem_region(&op->dev, res_mem.start, |
363 | sizeof(struct mpc52xx_ata), DRV_NAME)) { | 712 | sizeof(*ata_regs), DRV_NAME)) { |
364 | printk(KERN_ERR DRV_NAME ": " | 713 | dev_err(&op->dev, "error requesting register region\n"); |
365 | "Error while requesting mem region\n"); | 714 | return -EBUSY; |
366 | rv = -EBUSY; | ||
367 | goto err; | ||
368 | } | 715 | } |
369 | 716 | ||
370 | /* Remap registers */ | 717 | ata_regs = devm_ioremap(&op->dev, res_mem.start, sizeof(*ata_regs)); |
371 | ata_regs = devm_ioremap(&op->dev, res_mem.start, | ||
372 | sizeof(struct mpc52xx_ata)); | ||
373 | if (!ata_regs) { | 718 | if (!ata_regs) { |
374 | printk(KERN_ERR DRV_NAME ": " | 719 | dev_err(&op->dev, "error mapping device registers\n"); |
375 | "Error while mapping register set\n"); | ||
376 | rv = -ENOMEM; | 720 | rv = -ENOMEM; |
377 | goto err; | 721 | goto err; |
378 | } | 722 | } |
379 | 723 | ||
724 | /* | ||
725 | * By default, all DMA modes are disabled for the MPC5200. Some | ||
726 | * boards don't have the required signals routed to make DMA work. | ||
727 | * Also, the MPC5200B has a silicon bug that causes data corruption | ||
728 | * with UDMA if it is used at the same time as the LocalPlus bus. | ||
729 | * | ||
730 | * Instead of trying to guess what modes are usable, check the | ||
731 | * ATA device tree node to find out what DMA modes work on the board. | ||
732 | * UDMA/MWDMA modes can also be forced by adding "libata.force=<mode>" | ||
733 | * to the kernel boot parameters. | ||
734 | * | ||
735 | * The MPC5200 ATA controller supports MWDMA modes 0, 1 and 2 and | ||
736 | * UDMA modes 0, 1 and 2. | ||
737 | */ | ||
738 | prop = of_get_property(op->node, "mwdma-mode", &proplen); | ||
739 | if ((prop) && (proplen >= 4)) | ||
740 | mwdma_mask = 0x7 & ((1 << (*prop + 1)) - 1); | ||
741 | prop = of_get_property(op->node, "udma-mode", &proplen); | ||
742 | if ((prop) && (proplen >= 4)) | ||
743 | udma_mask = 0x7 & ((1 << (*prop + 1)) - 1); | ||
744 | |||
745 | ata_irq = irq_of_parse_and_map(op->node, 0); | ||
746 | if (ata_irq == NO_IRQ) { | ||
747 | dev_err(&op->dev, "error mapping irq\n"); | ||
748 | return -EINVAL; | ||
749 | } | ||
750 | |||
380 | /* Prepare our private structure */ | 751 | /* Prepare our private structure */ |
381 | priv = devm_kzalloc(&op->dev, sizeof(struct mpc52xx_ata_priv), | 752 | priv = devm_kzalloc(&op->dev, sizeof(*priv), GFP_ATOMIC); |
382 | GFP_ATOMIC); | ||
383 | if (!priv) { | 753 | if (!priv) { |
384 | printk(KERN_ERR DRV_NAME ": " | 754 | dev_err(&op->dev, "error allocating private structure\n"); |
385 | "Error while allocating private structure\n"); | ||
386 | rv = -ENOMEM; | 755 | rv = -ENOMEM; |
387 | goto err; | 756 | goto err; |
388 | } | 757 | } |
389 | 758 | ||
390 | priv->ipb_period = 1000000000 / (ipb_freq / 1000); | 759 | priv->ipb_period = 1000000000 / (ipb_freq / 1000); |
391 | priv->ata_regs = ata_regs; | 760 | priv->ata_regs = ata_regs; |
761 | priv->ata_regs_pa = res_mem.start; | ||
392 | priv->ata_irq = ata_irq; | 762 | priv->ata_irq = ata_irq; |
393 | priv->csel = -1; | 763 | priv->csel = -1; |
764 | priv->mpc52xx_ata_dma_last_write = -1; | ||
765 | |||
766 | if (ipb_freq/1000000 == 66) { | ||
767 | priv->mdmaspec = mdmaspec66; | ||
768 | priv->udmaspec = udmaspec66; | ||
769 | } else { | ||
770 | priv->mdmaspec = mdmaspec132; | ||
771 | priv->udmaspec = udmaspec132; | ||
772 | } | ||
773 | |||
774 | /* Allocate a BestComm task for DMA */ | ||
775 | dmatsk = bcom_ata_init(MAX_DMA_BUFFERS, MAX_DMA_BUFFER_SIZE); | ||
776 | if (!dmatsk) { | ||
777 | dev_err(&op->dev, "bestcomm initialization failed\n"); | ||
778 | rv = -ENOMEM; | ||
779 | goto err; | ||
780 | } | ||
781 | |||
782 | task_irq = bcom_get_task_irq(dmatsk); | ||
783 | ret = request_irq(task_irq, &mpc52xx_ata_task_irq, IRQF_DISABLED, | ||
784 | "ATA task", priv); | ||
785 | if (ret) { | ||
786 | dev_err(&op->dev, "error requesting DMA IRQ\n"); | ||
787 | goto err; | ||
788 | } | ||
789 | priv->dmatsk = dmatsk; | ||
394 | 790 | ||
395 | /* Init the hw */ | 791 | /* Init the hw */ |
396 | rv = mpc52xx_ata_hw_init(priv); | 792 | rv = mpc52xx_ata_hw_init(priv); |
397 | if (rv) { | 793 | if (rv) { |
398 | printk(KERN_ERR DRV_NAME ": Error during HW init\n"); | 794 | dev_err(&op->dev, "error initializing hardware\n"); |
399 | goto err; | 795 | goto err; |
400 | } | 796 | } |
401 | 797 | ||
402 | /* Register ourselves to libata */ | 798 | /* Register ourselves to libata */ |
403 | rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start); | 799 | rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start, |
800 | mwdma_mask, udma_mask); | ||
404 | if (rv) { | 801 | if (rv) { |
405 | printk(KERN_ERR DRV_NAME ": " | 802 | dev_err(&op->dev, "error registering with ATA layer\n"); |
406 | "Error while registering to ATA layer\n"); | 803 | goto err; |
407 | return rv; | ||
408 | } | 804 | } |
409 | 805 | ||
410 | /* Done */ | ||
411 | return 0; | 806 | return 0; |
412 | 807 | ||
413 | /* Error path */ | 808 | err: |
414 | err: | 809 | devm_release_mem_region(&op->dev, res_mem.start, sizeof(*ata_regs)); |
415 | irq_dispose_mapping(ata_irq); | 810 | if (ata_irq) |
811 | irq_dispose_mapping(ata_irq); | ||
812 | if (task_irq) | ||
813 | irq_dispose_mapping(task_irq); | ||
814 | if (dmatsk) | ||
815 | bcom_ata_release(dmatsk); | ||
816 | if (ata_regs) | ||
817 | devm_iounmap(&op->dev, ata_regs); | ||
818 | if (priv) | ||
819 | devm_kfree(&op->dev, priv); | ||
416 | return rv; | 820 | return rv; |
417 | } | 821 | } |
418 | 822 | ||
@@ -420,10 +824,23 @@ static int | |||
420 | mpc52xx_ata_remove(struct of_device *op) | 824 | mpc52xx_ata_remove(struct of_device *op) |
421 | { | 825 | { |
422 | struct mpc52xx_ata_priv *priv; | 826 | struct mpc52xx_ata_priv *priv; |
827 | int task_irq; | ||
423 | 828 | ||
829 | /* Deregister the ATA interface */ | ||
424 | priv = mpc52xx_ata_remove_one(&op->dev); | 830 | priv = mpc52xx_ata_remove_one(&op->dev); |
831 | |||
832 | /* Clean up DMA */ | ||
833 | task_irq = bcom_get_task_irq(priv->dmatsk); | ||
834 | irq_dispose_mapping(task_irq); | ||
835 | bcom_ata_release(priv->dmatsk); | ||
425 | irq_dispose_mapping(priv->ata_irq); | 836 | irq_dispose_mapping(priv->ata_irq); |
426 | 837 | ||
838 | /* Clear up IO allocations */ | ||
839 | devm_iounmap(&op->dev, priv->ata_regs); | ||
840 | devm_release_mem_region(&op->dev, priv->ata_regs_pa, | ||
841 | sizeof(*priv->ata_regs)); | ||
842 | devm_kfree(&op->dev, priv); | ||
843 | |||
427 | return 0; | 844 | return 0; |
428 | } | 845 | } |
429 | 846 | ||
@@ -447,7 +864,7 @@ mpc52xx_ata_resume(struct of_device *op) | |||
447 | 864 | ||
448 | rv = mpc52xx_ata_hw_init(priv); | 865 | rv = mpc52xx_ata_hw_init(priv); |
449 | if (rv) { | 866 | if (rv) { |
450 | printk(KERN_ERR DRV_NAME ": Error during HW init\n"); | 867 | dev_err(host->dev, "error initializing hardware\n"); |
451 | return rv; | 868 | return rv; |
452 | } | 869 | } |
453 | 870 | ||
@@ -507,5 +924,4 @@ MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>"); | |||
507 | MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver"); | 924 | MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver"); |
508 | MODULE_LICENSE("GPL"); | 925 | MODULE_LICENSE("GPL"); |
509 | MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match); | 926 | MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match); |
510 | MODULE_VERSION(DRV_VERSION); | ||
511 | 927 | ||