Blame view
drivers/ata/pata_mpc52xx.c
25 KB
155d2916d [PATCH] libata: A... |
1 2 3 4 5 6 7 8 |
/* * drivers/ata/pata_mpc52xx.c * * libata driver for the Freescale MPC52xx on-chip IDE interface * * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com> * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt * |
6b61e69e7 powerpc/mpc5200: ... |
9 10 11 |
* UDMA support based on patches by Freescale (Bernard Kuhn, John Rigby), * Domen Puncer and Tim Yamin. * |
155d2916d [PATCH] libata: A... |
12 13 14 15 16 17 18 |
* This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ #include <linux/kernel.h> #include <linux/module.h> |
5a0e3ad6a include cleanup: ... |
19 |
#include <linux/gfp.h> |
155d2916d [PATCH] libata: A... |
20 21 |
#include <linux/delay.h> #include <linux/libata.h> |
e6a9192d0 powerpc/pata_mpc5... |
22 |
#include <linux/of_platform.h> |
6b61e69e7 powerpc/mpc5200: ... |
23 |
#include <linux/types.h> |
155d2916d [PATCH] libata: A... |
24 |
|
6b61e69e7 powerpc/mpc5200: ... |
25 |
#include <asm/cacheflush.h> |
155d2916d [PATCH] libata: A... |
26 |
#include <asm/prom.h> |
155d2916d [PATCH] libata: A... |
27 |
#include <asm/mpc52xx.h> |
9a3229939 powerpc, dma: mov... |
28 29 30 |
#include <linux/fsl/bestcomm/bestcomm.h> #include <linux/fsl/bestcomm/bestcomm_priv.h> #include <linux/fsl/bestcomm/ata.h> |
155d2916d [PATCH] libata: A... |
31 32 |
#define DRV_NAME "mpc52xx_ata" |
155d2916d [PATCH] libata: A... |
33 34 35 36 37 |
/* Private structures used by the driver */ struct mpc52xx_ata_timings { u32 pio1; u32 pio2; |
6b61e69e7 powerpc/mpc5200: ... |
38 39 40 41 42 43 44 45 |
u32 mdma1; u32 mdma2; u32 udma1; u32 udma2; u32 udma3; u32 udma4; u32 udma5; int using_udma; |
155d2916d [PATCH] libata: A... |
46 47 48 49 |
}; struct mpc52xx_ata_priv { unsigned int ipb_period; |
6b61e69e7 powerpc/mpc5200: ... |
50 51 |
struct mpc52xx_ata __iomem *ata_regs; phys_addr_t ata_regs_pa; |
155d2916d [PATCH] libata: A... |
52 53 54 |
int ata_irq; struct mpc52xx_ata_timings timings[2]; int csel; |
6b61e69e7 powerpc/mpc5200: ... |
55 56 57 58 59 60 61 |
/* DMA */ struct bcom_task *dmatsk; const struct udmaspec *udmaspec; const struct mdmaspec *mdmaspec; int mpc52xx_ata_dma_last_write; int waiting_for_dma; |
155d2916d [PATCH] libata: A... |
62 63 64 65 |
}; /* ATAPI-4 PIO specs (in ns) */ |
ec569af85 pata_mpc52xx: red... |
66 67 68 69 70 71 72 |
static const u16 ataspec_t0[5] = {600, 383, 240, 180, 120}; static const u16 ataspec_t1[5] = { 70, 50, 30, 30, 25}; static const u16 ataspec_t2_8[5] = {290, 290, 290, 80, 70}; static const u16 ataspec_t2_16[5] = {165, 125, 100, 80, 70}; static const u16 ataspec_t2i[5] = { 0, 0, 0, 70, 25}; static const u16 ataspec_t4[5] = { 30, 20, 15, 10, 10}; static const u16 ataspec_ta[5] = { 35, 35, 35, 35, 35}; |
155d2916d [PATCH] libata: A... |
73 74 |
#define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c))) |
6b61e69e7 powerpc/mpc5200: ... |
75 76 77 78 |
/* ======================================================================== */ /* ATAPI-4 MDMA specs (in clocks) */ struct mdmaspec { |
ec569af85 pata_mpc52xx: red... |
79 80 81 82 83 84 85 |
u8 t0M; u8 td; u8 th; u8 tj; u8 tkw; u8 tm; u8 tn; |
6b61e69e7 powerpc/mpc5200: ... |
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
}; static const struct mdmaspec mdmaspec66[3] = { { .t0M = 32, .td = 15, .th = 2, .tj = 2, .tkw = 15, .tm = 4, .tn = 1 }, { .t0M = 10, .td = 6, .th = 1, .tj = 1, .tkw = 4, .tm = 2, .tn = 1 }, { .t0M = 8, .td = 5, .th = 1, .tj = 1, .tkw = 2, .tm = 2, .tn = 1 }, }; static const struct mdmaspec mdmaspec132[3] = { { .t0M = 64, .td = 29, .th = 3, .tj = 3, .tkw = 29, .tm = 7, .tn = 2 }, { .t0M = 20, .td = 11, .th = 2, .tj = 1, .tkw = 7, .tm = 4, .tn = 1 }, { .t0M = 16, .td = 10, .th = 2, .tj = 1, .tkw = 4, .tm = 4, .tn = 1 }, }; /* ATAPI-4 UDMA specs (in clocks) */ struct udmaspec { |
ec569af85 pata_mpc52xx: red... |
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
u8 tcyc; u8 t2cyc; u8 tds; u8 tdh; u8 tdvs; u8 tdvh; u8 tfs; u8 tli; u8 tmli; u8 taz; u8 tzah; u8 tenv; u8 tsr; u8 trfs; u8 trp; u8 tack; u8 tss; |
6b61e69e7 powerpc/mpc5200: ... |
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
}; static const struct udmaspec udmaspec66[6] = { { .tcyc = 8, .t2cyc = 16, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1, .tfs = 16, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, .tsr = 3, .trfs = 5, .trp = 11, .tack = 2, .tss = 4, }, { .tcyc = 5, .t2cyc = 11, .tds = 1, .tdh = 1, .tdvs = 4, .tdvh = 1, .tfs = 14, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, .tsr = 2, .trfs = 5, .trp = 9, .tack = 2, .tss = 4, }, { .tcyc = 4, .t2cyc = 8, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1, .tfs = 12, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, }, { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 2, .tdvh = 1, .tfs = 9, .tli = 7, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, }, { .tcyc = 2, .t2cyc = 4, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, .tfs = 8, .tli = 8, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, }, { .tcyc = 2, .t2cyc = 2, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, .tfs = 6, .tli = 5, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, .tsr = 2, .trfs = 4, .trp = 6, .tack = 2, .tss = 4, }, }; static const struct udmaspec udmaspec132[6] = { { .tcyc = 15, .t2cyc = 31, .tds = 2, .tdh = 1, .tdvs = 10, .tdvh = 1, .tfs = 30, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, .tsr = 7, .trfs = 10, .trp = 22, .tack = 3, .tss = 7, }, { .tcyc = 10, .t2cyc = 21, .tds = 2, .tdh = 1, .tdvs = 7, .tdvh = 1, .tfs = 27, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, .tsr = 4, .trfs = 10, .trp = 17, .tack = 3, .tss = 7, }, { .tcyc = 6, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1, .tfs = 23, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7, }, { .tcyc = 7, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1, .tfs = 15, .tli = 13, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7, }, { .tcyc = 2, .t2cyc = 5, .tds = 0, .tdh = 0, .tdvs = 1, .tdvh = 1, .tfs = 16, .tli = 14, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, .tsr = 2, .trfs = 7, .trp = 13, .tack = 2, .tss = 6, }, { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, .tfs = 12, .tli = 10, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, .tsr = 3, .trfs = 7, .trp = 12, .tack = 3, .tss = 7, }, }; /* ======================================================================== */ |
155d2916d [PATCH] libata: A... |
176 177 178 179 180 181 182 183 184 185 186 187 188 |
/* Bit definitions inside the registers */ #define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */ #define MPC52xx_ATA_HOSTCONF_FR 0x40000000UL /* FIFO Reset */ #define MPC52xx_ATA_HOSTCONF_IE 0x02000000UL /* Enable interrupt in PIO */ #define MPC52xx_ATA_HOSTCONF_IORDY 0x01000000UL /* Drive supports IORDY protocol */ #define MPC52xx_ATA_HOSTSTAT_TIP 0x80000000UL /* Transaction in progress */ #define MPC52xx_ATA_HOSTSTAT_UREP 0x40000000UL /* UDMA Read Extended Pause */ #define MPC52xx_ATA_HOSTSTAT_RERR 0x02000000UL /* Read Error */ #define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */ #define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */ |
6b61e69e7 powerpc/mpc5200: ... |
189 |
#define MPC52xx_ATA_FIFOSTAT_ERROR 0x40 /* FIFO Error */ |
155d2916d [PATCH] libata: A... |
190 191 192 193 194 195 196 197 |
#define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */ #define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */ #define MPC52xx_ATA_DMAMODE_UDMA 0x04 /* UDMA enabled */ #define MPC52xx_ATA_DMAMODE_IE 0x08 /* Enable drive interrupt to CPU in DMA mode */ #define MPC52xx_ATA_DMAMODE_FE 0x10 /* FIFO Flush enable in Rx mode */ #define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */ #define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */ |
6b61e69e7 powerpc/mpc5200: ... |
198 199 |
#define MAX_DMA_BUFFERS 128 #define MAX_DMA_BUFFER_SIZE 0x20000u |
155d2916d [PATCH] libata: A... |
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
/* Structure of the hardware registers */ struct mpc52xx_ata { /* Host interface registers */ u32 config; /* ATA + 0x00 Host configuration */ u32 host_status; /* ATA + 0x04 Host controller status */ u32 pio1; /* ATA + 0x08 PIO Timing 1 */ u32 pio2; /* ATA + 0x0c PIO Timing 2 */ u32 mdma1; /* ATA + 0x10 MDMA Timing 1 */ u32 mdma2; /* ATA + 0x14 MDMA Timing 2 */ u32 udma1; /* ATA + 0x18 UDMA Timing 1 */ u32 udma2; /* ATA + 0x1c UDMA Timing 2 */ u32 udma3; /* ATA + 0x20 UDMA Timing 3 */ u32 udma4; /* ATA + 0x24 UDMA Timing 4 */ u32 udma5; /* ATA + 0x28 UDMA Timing 5 */ u32 share_cnt; /* ATA + 0x2c ATA share counter */ u32 reserved0[3]; /* FIFO registers */ u32 fifo_data; /* ATA + 0x3c */ u8 fifo_status_frame; /* ATA + 0x40 */ u8 fifo_status; /* ATA + 0x41 */ u16 reserved7[1]; u8 fifo_control; /* ATA + 0x44 */ u8 reserved8[5]; u16 fifo_alarm; /* ATA + 0x4a */ u16 reserved9; u16 fifo_rdp; /* ATA + 0x4e */ u16 reserved10; u16 fifo_wrp; /* ATA + 0x52 */ u16 reserved11; u16 fifo_lfrdp; /* ATA + 0x56 */ u16 reserved12; u16 fifo_lfwrp; /* ATA + 0x5a */ /* Drive TaskFile registers */ u8 tf_control; /* ATA + 0x5c TASKFILE Control/Alt Status */ u8 reserved13[3]; u16 tf_data; /* ATA + 0x60 TASKFILE Data */ u16 reserved14; u8 tf_features; /* ATA + 0x64 TASKFILE Features/Error */ u8 reserved15[3]; u8 tf_sec_count; /* ATA + 0x68 TASKFILE Sector Count */ u8 reserved16[3]; u8 tf_sec_num; /* ATA + 0x6c TASKFILE Sector Number */ u8 reserved17[3]; u8 tf_cyl_low; /* ATA + 0x70 TASKFILE Cylinder Low */ u8 reserved18[3]; u8 tf_cyl_high; /* ATA + 0x74 TASKFILE Cylinder High */ u8 reserved19[3]; u8 tf_dev_head; /* ATA + 0x78 TASKFILE Device/Head */ u8 reserved20[3]; u8 tf_command; /* ATA + 0x7c TASKFILE Command/Status */ u8 dma_mode; /* ATA + 0x7d ATA Host DMA Mode configuration */ u8 reserved21[2]; }; /* ======================================================================== */ /* Aux fns */ /* ======================================================================== */ /* MPC52xx low level hw control */ |
155d2916d [PATCH] libata: A... |
265 266 267 268 269 |
static int mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio) { struct mpc52xx_ata_timings *timing = &priv->timings[dev]; unsigned int ipb_period = priv->ipb_period; |
ec569af85 pata_mpc52xx: red... |
270 |
u32 t0, t1, t2_8, t2_16, t2i, t4, ta; |
155d2916d [PATCH] libata: A... |
271 |
|
6b61e69e7 powerpc/mpc5200: ... |
272 |
if ((pio < 0) || (pio > 4)) |
155d2916d [PATCH] libata: A... |
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
return -EINVAL; t0 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t0[pio]); t1 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t1[pio]); t2_8 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_8[pio]); t2_16 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_16[pio]); t2i = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2i[pio]); t4 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t4[pio]); ta = CALC_CLKCYC(ipb_period, 1000 * ataspec_ta[pio]); timing->pio1 = (t0 << 24) | (t2_8 << 16) | (t2_16 << 8) | (t2i); timing->pio2 = (t4 << 24) | (t1 << 16) | (ta << 8); return 0; } |
6b61e69e7 powerpc/mpc5200: ... |
288 289 290 291 292 293 294 295 296 |
static int mpc52xx_ata_compute_mdma_timings(struct mpc52xx_ata_priv *priv, int dev, int speed) { struct mpc52xx_ata_timings *t = &priv->timings[dev]; const struct mdmaspec *s = &priv->mdmaspec[speed]; if (speed < 0 || speed > 2) return -EINVAL; |
ec569af85 pata_mpc52xx: red... |
297 298 |
t->mdma1 = ((u32)s->t0M << 24) | ((u32)s->td << 16) | ((u32)s->tkw << 8) | s->tm; t->mdma2 = ((u32)s->th << 24) | ((u32)s->tj << 16) | ((u32)s->tn << 8); |
6b61e69e7 powerpc/mpc5200: ... |
299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
t->using_udma = 0; return 0; } static int mpc52xx_ata_compute_udma_timings(struct mpc52xx_ata_priv *priv, int dev, int speed) { struct mpc52xx_ata_timings *t = &priv->timings[dev]; const struct udmaspec *s = &priv->udmaspec[speed]; if (speed < 0 || speed > 2) return -EINVAL; |
ec569af85 pata_mpc52xx: red... |
313 314 315 316 317 |
t->udma1 = ((u32)s->t2cyc << 24) | ((u32)s->tcyc << 16) | ((u32)s->tds << 8) | s->tdh; t->udma2 = ((u32)s->tdvs << 24) | ((u32)s->tdvh << 16) | ((u32)s->tfs << 8) | s->tli; t->udma3 = ((u32)s->tmli << 24) | ((u32)s->taz << 16) | ((u32)s->tenv << 8) | s->tsr; t->udma4 = ((u32)s->tss << 24) | ((u32)s->trfs << 16) | ((u32)s->trp << 8) | s->tack; t->udma5 = (u32)s->tzah << 24; |
6b61e69e7 powerpc/mpc5200: ... |
318 319 320 321 |
t->using_udma = 1; return 0; } |
155d2916d [PATCH] libata: A... |
322 323 324 325 326 327 328 329 |
static void mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device) { struct mpc52xx_ata __iomem *regs = priv->ata_regs; struct mpc52xx_ata_timings *timing = &priv->timings[device]; out_be32(®s->pio1, timing->pio1); out_be32(®s->pio2, timing->pio2); |
6b61e69e7 powerpc/mpc5200: ... |
330 331 332 333 334 335 336 |
out_be32(®s->mdma1, timing->mdma1); out_be32(®s->mdma2, timing->mdma2); out_be32(®s->udma1, timing->udma1); out_be32(®s->udma2, timing->udma2); out_be32(®s->udma3, timing->udma3); out_be32(®s->udma4, timing->udma4); out_be32(®s->udma5, timing->udma5); |
155d2916d [PATCH] libata: A... |
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
priv->csel = device; } static int mpc52xx_ata_hw_init(struct mpc52xx_ata_priv *priv) { struct mpc52xx_ata __iomem *regs = priv->ata_regs; int tslot; /* Clear share_cnt (all sample code do this ...) */ out_be32(®s->share_cnt, 0); /* Configure and reset host */ out_be32(®s->config, MPC52xx_ATA_HOSTCONF_IE | MPC52xx_ATA_HOSTCONF_IORDY | MPC52xx_ATA_HOSTCONF_SMR | MPC52xx_ATA_HOSTCONF_FR); udelay(10); out_be32(®s->config, MPC52xx_ATA_HOSTCONF_IE | MPC52xx_ATA_HOSTCONF_IORDY); /* Set the time slot to 1us */ tslot = CALC_CLKCYC(priv->ipb_period, 1000000); |
6b61e69e7 powerpc/mpc5200: ... |
364 |
out_be32(®s->share_cnt, tslot << 16); |
155d2916d [PATCH] libata: A... |
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
/* Init timings to PIO0 */ memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings)); mpc52xx_ata_compute_pio_timings(priv, 0, 0); mpc52xx_ata_compute_pio_timings(priv, 1, 0); mpc52xx_ata_apply_timings(priv, 0); return 0; } /* ======================================================================== */ /* libata driver */ /* ======================================================================== */ static void mpc52xx_ata_set_piomode(struct ata_port *ap, struct ata_device *adev) { struct mpc52xx_ata_priv *priv = ap->host->private_data; int pio, rv; pio = adev->pio_mode - XFER_PIO_0; rv = mpc52xx_ata_compute_pio_timings(priv, adev->devno, pio); if (rv) { |
6b61e69e7 powerpc/mpc5200: ... |
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 |
dev_err(ap->dev, "error: invalid PIO mode: %d ", pio); return; } mpc52xx_ata_apply_timings(priv, adev->devno); } static void mpc52xx_ata_set_dmamode(struct ata_port *ap, struct ata_device *adev) { struct mpc52xx_ata_priv *priv = ap->host->private_data; int rv; if (adev->dma_mode >= XFER_UDMA_0) { int dma = adev->dma_mode - XFER_UDMA_0; rv = mpc52xx_ata_compute_udma_timings(priv, adev->devno, dma); } else { int dma = adev->dma_mode - XFER_MW_DMA_0; rv = mpc52xx_ata_compute_mdma_timings(priv, adev->devno, dma); } if (rv) { dev_alert(ap->dev, "Trying to select invalid DMA mode %d ", adev->dma_mode); |
155d2916d [PATCH] libata: A... |
420 421 422 423 424 |
return; } mpc52xx_ata_apply_timings(priv, adev->devno); } |
6b61e69e7 powerpc/mpc5200: ... |
425 |
|
155d2916d [PATCH] libata: A... |
426 427 428 429 430 431 432 |
static void mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device) { struct mpc52xx_ata_priv *priv = ap->host->private_data; if (device != priv->csel) mpc52xx_ata_apply_timings(priv, device); |
6b61e69e7 powerpc/mpc5200: ... |
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 |
ata_sff_dev_select(ap, device); } static int mpc52xx_ata_build_dmatable(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct mpc52xx_ata_priv *priv = ap->host->private_data; struct bcom_ata_bd *bd; unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE), si; struct scatterlist *sg; int count = 0; if (read) bcom_ata_rx_prepare(priv->dmatsk); else bcom_ata_tx_prepare(priv->dmatsk); for_each_sg(qc->sg, sg, qc->n_elem, si) { dma_addr_t cur_addr = sg_dma_address(sg); u32 cur_len = sg_dma_len(sg); while (cur_len) { unsigned int tc = min(cur_len, MAX_DMA_BUFFER_SIZE); bd = (struct bcom_ata_bd *) bcom_prepare_next_buffer(priv->dmatsk); if (read) { bd->status = tc; bd->src_pa = (__force u32) priv->ata_regs_pa + offsetof(struct mpc52xx_ata, fifo_data); bd->dst_pa = (__force u32) cur_addr; } else { bd->status = tc; bd->src_pa = (__force u32) cur_addr; bd->dst_pa = (__force u32) priv->ata_regs_pa + offsetof(struct mpc52xx_ata, fifo_data); } bcom_submit_next_buffer(priv->dmatsk, NULL); cur_addr += tc; cur_len -= tc; count++; if (count > MAX_DMA_BUFFERS) { dev_alert(ap->dev, "dma table" "too small "); goto use_pio_instead; } } } return 1; use_pio_instead: bcom_ata_reset_bd(priv->dmatsk); return 0; } static void mpc52xx_bmdma_setup(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct mpc52xx_ata_priv *priv = ap->host->private_data; struct mpc52xx_ata __iomem *regs = priv->ata_regs; unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE); u8 dma_mode; if (!mpc52xx_ata_build_dmatable(qc)) dev_alert(ap->dev, "%s: %i, return 1? ", __func__, __LINE__); /* Check FIFO is OK... */ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x! ", __func__, in_8(&priv->ata_regs->fifo_status)); if (read) { dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_READ | MPC52xx_ATA_DMAMODE_FE; /* Setup FIFO if direction changed */ if (priv->mpc52xx_ata_dma_last_write != 0) { priv->mpc52xx_ata_dma_last_write = 0; /* Configure FIFO with granularity to 7 */ out_8(®s->fifo_control, 7); out_be16(®s->fifo_alarm, 128); /* Set FIFO Reset bit (FR) */ out_8(®s->dma_mode, MPC52xx_ATA_DMAMODE_FR); } } else { dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_WRITE; /* Setup FIFO if direction changed */ if (priv->mpc52xx_ata_dma_last_write != 1) { priv->mpc52xx_ata_dma_last_write = 1; /* Configure FIFO with granularity to 4 */ out_8(®s->fifo_control, 4); out_be16(®s->fifo_alarm, 128); } } if (priv->timings[qc->dev->devno].using_udma) dma_mode |= MPC52xx_ATA_DMAMODE_UDMA; out_8(®s->dma_mode, dma_mode); priv->waiting_for_dma = ATA_DMA_ACTIVE; ata_wait_idle(ap); ap->ops->sff_exec_command(ap, &qc->tf); } static void mpc52xx_bmdma_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct mpc52xx_ata_priv *priv = ap->host->private_data; bcom_set_task_auto_start(priv->dmatsk->tasknum, priv->dmatsk->tasknum); bcom_enable(priv->dmatsk); } static void mpc52xx_bmdma_stop(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct mpc52xx_ata_priv *priv = ap->host->private_data; bcom_disable(priv->dmatsk); bcom_ata_reset_bd(priv->dmatsk); priv->waiting_for_dma = 0; /* Check FIFO is OK... */ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x! ", __func__, in_8(&priv->ata_regs->fifo_status)); } static u8 mpc52xx_bmdma_status(struct ata_port *ap) { struct mpc52xx_ata_priv *priv = ap->host->private_data; /* Check FIFO is OK... */ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) { dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x! ", __func__, in_8(&priv->ata_regs->fifo_status)); return priv->waiting_for_dma | ATA_DMA_ERR; } return priv->waiting_for_dma; } static irqreturn_t mpc52xx_ata_task_irq(int irq, void *vpriv) { struct mpc52xx_ata_priv *priv = vpriv; while (bcom_buffer_done(priv->dmatsk)) bcom_retrieve_buffer(priv->dmatsk, NULL, NULL); priv->waiting_for_dma |= ATA_DMA_INTR; return IRQ_HANDLED; |
155d2916d [PATCH] libata: A... |
605 |
} |
155d2916d [PATCH] libata: A... |
606 |
static struct scsi_host_template mpc52xx_ata_sht = { |
68d1d07b5 libata: implement... |
607 |
ATA_PIO_SHT(DRV_NAME), |
155d2916d [PATCH] libata: A... |
608 609 610 |
}; static struct ata_port_operations mpc52xx_ata_port_ops = { |
77c5fd190 pata_mpc52xx: inh... |
611 |
.inherits = &ata_bmdma_port_ops, |
5682ed33a libata: rename SF... |
612 |
.sff_dev_select = mpc52xx_ata_dev_select, |
029cfd6b7 libata: implement... |
613 |
.set_piomode = mpc52xx_ata_set_piomode, |
6b61e69e7 powerpc/mpc5200: ... |
614 615 616 617 618 619 |
.set_dmamode = mpc52xx_ata_set_dmamode, .bmdma_setup = mpc52xx_bmdma_setup, .bmdma_start = mpc52xx_bmdma_start, .bmdma_stop = mpc52xx_bmdma_stop, .bmdma_status = mpc52xx_bmdma_status, .qc_prep = ata_noop_qc_prep, |
155d2916d [PATCH] libata: A... |
620 |
}; |
0ec249146 Drivers: ata: rem... |
621 622 623 624 |
static int mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv, unsigned long raw_ata_regs, int mwdma_mask, int udma_mask) |
155d2916d [PATCH] libata: A... |
625 |
{ |
5d728824e libata: convert t... |
626 627 628 |
struct ata_host *host; struct ata_port *ap; struct ata_ioports *aio; |
5d728824e libata: convert t... |
629 630 631 632 633 634 635 |
host = ata_host_alloc(dev, 1); if (!host) return -ENOMEM; ap = host->ports[0]; ap->flags |= ATA_FLAG_SLAVE_POSS; |
6b61e69e7 powerpc/mpc5200: ... |
636 637 638 |
ap->pio_mask = ATA_PIO4; ap->mwdma_mask = mwdma_mask; ap->udma_mask = udma_mask; |
5d728824e libata: convert t... |
639 640 641 642 |
ap->ops = &mpc52xx_ata_port_ops; host->private_data = priv; aio = &ap->ioaddr; |
89952d133 [PATCH] misc NULL... |
643 |
aio->cmd_addr = NULL; /* Don't have a classic reg block */ |
0d5ff5667 libata: convert t... |
644 645 646 647 648 649 650 651 652 653 654 655 |
aio->altstatus_addr = &priv->ata_regs->tf_control; aio->ctl_addr = &priv->ata_regs->tf_control; aio->data_addr = &priv->ata_regs->tf_data; aio->error_addr = &priv->ata_regs->tf_features; aio->feature_addr = &priv->ata_regs->tf_features; aio->nsect_addr = &priv->ata_regs->tf_sec_count; aio->lbal_addr = &priv->ata_regs->tf_sec_num; aio->lbam_addr = &priv->ata_regs->tf_cyl_low; aio->lbah_addr = &priv->ata_regs->tf_cyl_high; aio->device_addr = &priv->ata_regs->tf_dev_head; aio->status_addr = &priv->ata_regs->tf_command; aio->command_addr = &priv->ata_regs->tf_command; |
155d2916d [PATCH] libata: A... |
656 |
|
cbcdd8759 libata: implement... |
657 |
ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs); |
5d728824e libata: convert t... |
658 |
/* activate host */ |
c3b288942 libata-sff: separ... |
659 |
return ata_host_activate(host, priv->ata_irq, ata_bmdma_interrupt, 0, |
5d728824e libata: convert t... |
660 |
&mpc52xx_ata_sht); |
155d2916d [PATCH] libata: A... |
661 |
} |
155d2916d [PATCH] libata: A... |
662 663 664 |
/* ======================================================================== */ /* OF Platform driver */ /* ======================================================================== */ |
0ec249146 Drivers: ata: rem... |
665 |
static int mpc52xx_ata_probe(struct platform_device *op) |
155d2916d [PATCH] libata: A... |
666 667 668 |
{ unsigned int ipb_freq; struct resource res_mem; |
6b61e69e7 powerpc/mpc5200: ... |
669 |
int ata_irq = 0; |
24dc5f33e libata: update li... |
670 |
struct mpc52xx_ata __iomem *ata_regs; |
6b61e69e7 powerpc/mpc5200: ... |
671 |
struct mpc52xx_ata_priv *priv = NULL; |
d01159dff drivers/ata/pata_... |
672 |
int rv, task_irq; |
6b61e69e7 powerpc/mpc5200: ... |
673 674 675 |
int mwdma_mask = 0, udma_mask = 0; const __be32 *prop; int proplen; |
d01159dff drivers/ata/pata_... |
676 |
struct bcom_task *dmatsk; |
155d2916d [PATCH] libata: A... |
677 678 |
/* Get ipb frequency */ |
61c7a080a of: Always use 's... |
679 |
ipb_freq = mpc5xxx_get_bus_frequency(op->dev.of_node); |
155d2916d [PATCH] libata: A... |
680 |
if (!ipb_freq) { |
6b61e69e7 powerpc/mpc5200: ... |
681 682 |
dev_err(&op->dev, "could not determine IPB bus frequency "); |
155d2916d [PATCH] libata: A... |
683 684 |
return -ENODEV; } |
6b61e69e7 powerpc/mpc5200: ... |
685 686 |
/* Get device base address from device tree, request the region * and ioremap it. */ |
61c7a080a of: Always use 's... |
687 |
rv = of_address_to_resource(op->dev.of_node, 0, &res_mem); |
155d2916d [PATCH] libata: A... |
688 |
if (rv) { |
6b61e69e7 powerpc/mpc5200: ... |
689 690 |
dev_err(&op->dev, "could not determine device base address "); |
155d2916d [PATCH] libata: A... |
691 692 |
return rv; } |
24dc5f33e libata: update li... |
693 |
if (!devm_request_mem_region(&op->dev, res_mem.start, |
6b61e69e7 powerpc/mpc5200: ... |
694 695 696 697 |
sizeof(*ata_regs), DRV_NAME)) { dev_err(&op->dev, "error requesting register region "); return -EBUSY; |
155d2916d [PATCH] libata: A... |
698 |
} |
6b61e69e7 powerpc/mpc5200: ... |
699 |
ata_regs = devm_ioremap(&op->dev, res_mem.start, sizeof(*ata_regs)); |
155d2916d [PATCH] libata: A... |
700 |
if (!ata_regs) { |
6b61e69e7 powerpc/mpc5200: ... |
701 702 |
dev_err(&op->dev, "error mapping device registers "); |
d01159dff drivers/ata/pata_... |
703 |
return -ENOMEM; |
155d2916d [PATCH] libata: A... |
704 |
} |
6b61e69e7 powerpc/mpc5200: ... |
705 706 707 708 709 710 711 712 713 714 715 716 717 718 |
/* * By default, all DMA modes are disabled for the MPC5200. Some * boards don't have the required signals routed to make DMA work. * Also, the MPC5200B has a silicon bug that causes data corruption * with UDMA if it is used at the same time as the LocalPlus bus. * * Instead of trying to guess what modes are usable, check the * ATA device tree node to find out what DMA modes work on the board. * UDMA/MWDMA modes can also be forced by adding "libata.force=<mode>" * to the kernel boot parameters. * * The MPC5200 ATA controller supports MWDMA modes 0, 1 and 2 and * UDMA modes 0, 1 and 2. */ |
61c7a080a of: Always use 's... |
719 |
prop = of_get_property(op->dev.of_node, "mwdma-mode", &proplen); |
6b61e69e7 powerpc/mpc5200: ... |
720 |
if ((prop) && (proplen >= 4)) |
14bdef982 [libata] convert ... |
721 |
mwdma_mask = ATA_MWDMA2 & ((1 << (*prop + 1)) - 1); |
61c7a080a of: Always use 's... |
722 |
prop = of_get_property(op->dev.of_node, "udma-mode", &proplen); |
6b61e69e7 powerpc/mpc5200: ... |
723 |
if ((prop) && (proplen >= 4)) |
14bdef982 [libata] convert ... |
724 |
udma_mask = ATA_UDMA2 & ((1 << (*prop + 1)) - 1); |
6b61e69e7 powerpc/mpc5200: ... |
725 |
|
61c7a080a of: Always use 's... |
726 |
ata_irq = irq_of_parse_and_map(op->dev.of_node, 0); |
6b61e69e7 powerpc/mpc5200: ... |
727 728 729 730 731 |
if (ata_irq == NO_IRQ) { dev_err(&op->dev, "error mapping irq "); return -EINVAL; } |
155d2916d [PATCH] libata: A... |
732 |
/* Prepare our private structure */ |
6b61e69e7 powerpc/mpc5200: ... |
733 |
priv = devm_kzalloc(&op->dev, sizeof(*priv), GFP_ATOMIC); |
155d2916d [PATCH] libata: A... |
734 |
if (!priv) { |
155d2916d [PATCH] libata: A... |
735 |
rv = -ENOMEM; |
d01159dff drivers/ata/pata_... |
736 |
goto err1; |
155d2916d [PATCH] libata: A... |
737 738 739 740 |
} priv->ipb_period = 1000000000 / (ipb_freq / 1000); priv->ata_regs = ata_regs; |
6b61e69e7 powerpc/mpc5200: ... |
741 |
priv->ata_regs_pa = res_mem.start; |
155d2916d [PATCH] libata: A... |
742 743 |
priv->ata_irq = ata_irq; priv->csel = -1; |
6b61e69e7 powerpc/mpc5200: ... |
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 |
priv->mpc52xx_ata_dma_last_write = -1; if (ipb_freq/1000000 == 66) { priv->mdmaspec = mdmaspec66; priv->udmaspec = udmaspec66; } else { priv->mdmaspec = mdmaspec132; priv->udmaspec = udmaspec132; } /* Allocate a BestComm task for DMA */ dmatsk = bcom_ata_init(MAX_DMA_BUFFERS, MAX_DMA_BUFFER_SIZE); if (!dmatsk) { dev_err(&op->dev, "bestcomm initialization failed "); rv = -ENOMEM; |
d01159dff drivers/ata/pata_... |
760 |
goto err1; |
6b61e69e7 powerpc/mpc5200: ... |
761 762 763 |
} task_irq = bcom_get_task_irq(dmatsk); |
d01159dff drivers/ata/pata_... |
764 |
rv = devm_request_irq(&op->dev, task_irq, &mpc52xx_ata_task_irq, 0, |
6b61e69e7 powerpc/mpc5200: ... |
765 |
"ATA task", priv); |
d01159dff drivers/ata/pata_... |
766 |
if (rv) { |
6b61e69e7 powerpc/mpc5200: ... |
767 768 |
dev_err(&op->dev, "error requesting DMA IRQ "); |
d01159dff drivers/ata/pata_... |
769 |
goto err2; |
6b61e69e7 powerpc/mpc5200: ... |
770 771 |
} priv->dmatsk = dmatsk; |
155d2916d [PATCH] libata: A... |
772 773 774 775 |
/* Init the hw */ rv = mpc52xx_ata_hw_init(priv); if (rv) { |
6b61e69e7 powerpc/mpc5200: ... |
776 777 |
dev_err(&op->dev, "error initializing hardware "); |
d01159dff drivers/ata/pata_... |
778 |
goto err2; |
155d2916d [PATCH] libata: A... |
779 780 781 |
} /* Register ourselves to libata */ |
6b61e69e7 powerpc/mpc5200: ... |
782 783 |
rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start, mwdma_mask, udma_mask); |
155d2916d [PATCH] libata: A... |
784 |
if (rv) { |
6b61e69e7 powerpc/mpc5200: ... |
785 786 |
dev_err(&op->dev, "error registering with ATA layer "); |
d01159dff drivers/ata/pata_... |
787 |
goto err2; |
155d2916d [PATCH] libata: A... |
788 |
} |
155d2916d [PATCH] libata: A... |
789 |
return 0; |
d01159dff drivers/ata/pata_... |
790 791 792 793 794 |
err2: irq_dispose_mapping(task_irq); bcom_ata_release(dmatsk); err1: irq_dispose_mapping(ata_irq); |
155d2916d [PATCH] libata: A... |
795 796 797 798 |
return rv; } static int |
2dc115813 of/device: Replac... |
799 |
mpc52xx_ata_remove(struct platform_device *op) |
155d2916d [PATCH] libata: A... |
800 |
{ |
37e1b022b pata_mpc52xx: uti... |
801 802 |
struct ata_host *host = platform_get_drvdata(op); struct mpc52xx_ata_priv *priv = host->private_data; |
6b61e69e7 powerpc/mpc5200: ... |
803 |
int task_irq; |
155d2916d [PATCH] libata: A... |
804 |
|
6b61e69e7 powerpc/mpc5200: ... |
805 |
/* Deregister the ATA interface */ |
37e1b022b pata_mpc52xx: uti... |
806 |
ata_platform_remove_one(op); |
6b61e69e7 powerpc/mpc5200: ... |
807 808 809 810 811 |
/* Clean up DMA */ task_irq = bcom_get_task_irq(priv->dmatsk); irq_dispose_mapping(task_irq); bcom_ata_release(priv->dmatsk); |
155d2916d [PATCH] libata: A... |
812 |
irq_dispose_mapping(priv->ata_irq); |
155d2916d [PATCH] libata: A... |
813 814 |
return 0; } |
58eb8cd56 ata: use CONFIG_P... |
815 |
#ifdef CONFIG_PM_SLEEP |
155d2916d [PATCH] libata: A... |
816 |
static int |
2dc115813 of/device: Replac... |
817 |
mpc52xx_ata_suspend(struct platform_device *op, pm_message_t state) |
155d2916d [PATCH] libata: A... |
818 |
{ |
d89995db5 ata: use platform... |
819 |
struct ata_host *host = platform_get_drvdata(op); |
35142ddbf pata_mpc52xx: sus... |
820 821 |
return ata_host_suspend(host, state); |
155d2916d [PATCH] libata: A... |
822 823 824 |
} static int |
2dc115813 of/device: Replac... |
825 |
mpc52xx_ata_resume(struct platform_device *op) |
155d2916d [PATCH] libata: A... |
826 |
{ |
d89995db5 ata: use platform... |
827 |
struct ata_host *host = platform_get_drvdata(op); |
35142ddbf pata_mpc52xx: sus... |
828 829 830 831 832 |
struct mpc52xx_ata_priv *priv = host->private_data; int rv; rv = mpc52xx_ata_hw_init(priv); if (rv) { |
6b61e69e7 powerpc/mpc5200: ... |
833 834 |
dev_err(host->dev, "error initializing hardware "); |
35142ddbf pata_mpc52xx: sus... |
835 836 837 838 839 840 |
return rv; } ata_host_resume(host); return 0; |
155d2916d [PATCH] libata: A... |
841 |
} |
155d2916d [PATCH] libata: A... |
842 |
#endif |
e3779f6a4 ata: constify of_... |
843 |
static const struct of_device_id mpc52xx_ata_of_match[] = { |
66ffbe490 [POWERPC] mpc5200... |
844 845 |
{ .compatible = "fsl,mpc5200-ata", }, { .compatible = "mpc5200-ata", }, |
155d2916d [PATCH] libata: A... |
846 847 |
{}, }; |
1c48a5c93 dt: Eliminate of_... |
848 |
static struct platform_driver mpc52xx_ata_of_platform_driver = { |
155d2916d [PATCH] libata: A... |
849 850 |
.probe = mpc52xx_ata_probe, .remove = mpc52xx_ata_remove, |
58eb8cd56 ata: use CONFIG_P... |
851 |
#ifdef CONFIG_PM_SLEEP |
155d2916d [PATCH] libata: A... |
852 853 854 855 856 |
.suspend = mpc52xx_ata_suspend, .resume = mpc52xx_ata_resume, #endif .driver = { .name = DRV_NAME, |
4018294b5 of: Remove duplic... |
857 |
.of_match_table = mpc52xx_ata_of_match, |
155d2916d [PATCH] libata: A... |
858 859 |
}, }; |
99c8ea3e5 SATA/PATA: conver... |
860 |
module_platform_driver(mpc52xx_ata_of_platform_driver); |
155d2916d [PATCH] libata: A... |
861 862 863 864 865 |
MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>"); MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match); |
155d2916d [PATCH] libata: A... |
866 |