| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 | * Support for IDE interfaces on PowerMacs. | 
| Bartlomiej Zolnierkiewicz | 58f189f | 2008-02-01 23:09:33 +0100 | [diff] [blame] | 3 | * | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4 | * These IDE interfaces are memory-mapped and have a DBDMA channel | 
|  | 5 | * for doing DMA. | 
|  | 6 | * | 
|  | 7 | *  Copyright (C) 1998-2003 Paul Mackerras & Ben. Herrenschmidt | 
| Bartlomiej Zolnierkiewicz | c15d5d4 | 2007-10-11 23:54:01 +0200 | [diff] [blame] | 8 | *  Copyright (C)      2007 Bartlomiej Zolnierkiewicz | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 9 | * | 
|  | 10 | *  This program is free software; you can redistribute it and/or | 
|  | 11 | *  modify it under the terms of the GNU General Public License | 
|  | 12 | *  as published by the Free Software Foundation; either version | 
|  | 13 | *  2 of the License, or (at your option) any later version. | 
|  | 14 | * | 
|  | 15 | * Some code taken from drivers/ide/ide-dma.c: | 
|  | 16 | * | 
|  | 17 | *  Copyright (c) 1995-1998  Mark Lord | 
|  | 18 | * | 
|  | 19 | * TODO: - Use pre-calculated (kauai) timing tables all the time and | 
|  | 20 | * get rid of the "rounded" tables used previously, so we have the | 
|  | 21 | * same table format for all controllers and can then just have one | 
|  | 22 | * big table | 
|  | 23 | * | 
|  | 24 | */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 25 | #include <linux/types.h> | 
|  | 26 | #include <linux/kernel.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 27 | #include <linux/init.h> | 
|  | 28 | #include <linux/delay.h> | 
|  | 29 | #include <linux/ide.h> | 
|  | 30 | #include <linux/notifier.h> | 
|  | 31 | #include <linux/reboot.h> | 
|  | 32 | #include <linux/pci.h> | 
|  | 33 | #include <linux/adb.h> | 
|  | 34 | #include <linux/pmu.h> | 
|  | 35 | #include <linux/scatterlist.h> | 
|  | 36 |  | 
|  | 37 | #include <asm/prom.h> | 
|  | 38 | #include <asm/io.h> | 
|  | 39 | #include <asm/dbdma.h> | 
|  | 40 | #include <asm/ide.h> | 
|  | 41 | #include <asm/pci-bridge.h> | 
|  | 42 | #include <asm/machdep.h> | 
|  | 43 | #include <asm/pmac_feature.h> | 
|  | 44 | #include <asm/sections.h> | 
|  | 45 | #include <asm/irq.h> | 
|  | 46 |  | 
|  | 47 | #ifndef CONFIG_PPC64 | 
|  | 48 | #include <asm/mediabay.h> | 
|  | 49 | #endif | 
|  | 50 |  | 
| Andrew Morton | 9e5755b | 2007-03-03 17:48:54 +0100 | [diff] [blame] | 51 | #include "../ide-timing.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 |  | 
|  | 53 | #undef IDE_PMAC_DEBUG | 
|  | 54 |  | 
|  | 55 | #define DMA_WAIT_TIMEOUT	50 | 
|  | 56 |  | 
|  | 57 | typedef struct pmac_ide_hwif { | 
|  | 58 | unsigned long			regbase; | 
|  | 59 | int				irq; | 
|  | 60 | int				kind; | 
|  | 61 | int				aapl_bus_id; | 
|  | 62 | unsigned			cable_80 : 1; | 
|  | 63 | unsigned			mediabay : 1; | 
|  | 64 | unsigned			broken_dma : 1; | 
|  | 65 | unsigned			broken_dma_warn : 1; | 
|  | 66 | struct device_node*		node; | 
|  | 67 | struct macio_dev		*mdev; | 
|  | 68 | u32				timings[4]; | 
|  | 69 | volatile u32 __iomem *		*kauai_fcr; | 
|  | 70 | #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC | 
|  | 71 | /* Those fields are duplicating what is in hwif. We currently | 
|  | 72 | * can't use the hwif ones because of some assumptions that are | 
|  | 73 | * beeing done by the generic code about the kind of dma controller | 
|  | 74 | * and format of the dma table. This will have to be fixed though. | 
|  | 75 | */ | 
|  | 76 | volatile struct dbdma_regs __iomem *	dma_regs; | 
|  | 77 | struct dbdma_cmd*		dma_table_cpu; | 
|  | 78 | #endif | 
|  | 79 |  | 
|  | 80 | } pmac_ide_hwif_t; | 
|  | 81 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 82 | static pmac_ide_hwif_t pmac_ide[MAX_HWIFS]; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 83 | static int pmac_ide_count; | 
|  | 84 |  | 
|  | 85 | enum { | 
|  | 86 | controller_ohare,	/* OHare based */ | 
|  | 87 | controller_heathrow,	/* Heathrow/Paddington */ | 
|  | 88 | controller_kl_ata3,	/* KeyLargo ATA-3 */ | 
|  | 89 | controller_kl_ata4,	/* KeyLargo ATA-4 */ | 
|  | 90 | controller_un_ata6,	/* UniNorth2 ATA-6 */ | 
|  | 91 | controller_k2_ata6,	/* K2 ATA-6 */ | 
|  | 92 | controller_sh_ata6,	/* Shasta ATA-6 */ | 
|  | 93 | }; | 
|  | 94 |  | 
|  | 95 | static const char* model_name[] = { | 
|  | 96 | "OHare ATA",		/* OHare based */ | 
|  | 97 | "Heathrow ATA",		/* Heathrow/Paddington */ | 
|  | 98 | "KeyLargo ATA-3",	/* KeyLargo ATA-3 (MDMA only) */ | 
|  | 99 | "KeyLargo ATA-4",	/* KeyLargo ATA-4 (UDMA/66) */ | 
|  | 100 | "UniNorth ATA-6",	/* UniNorth2 ATA-6 (UDMA/100) */ | 
|  | 101 | "K2 ATA-6",		/* K2 ATA-6 (UDMA/100) */ | 
|  | 102 | "Shasta ATA-6",		/* Shasta ATA-6 (UDMA/133) */ | 
|  | 103 | }; | 
|  | 104 |  | 
|  | 105 | /* | 
|  | 106 | * Extra registers, both 32-bit little-endian | 
|  | 107 | */ | 
|  | 108 | #define IDE_TIMING_CONFIG	0x200 | 
|  | 109 | #define IDE_INTERRUPT		0x300 | 
|  | 110 |  | 
|  | 111 | /* Kauai (U2) ATA has different register setup */ | 
|  | 112 | #define IDE_KAUAI_PIO_CONFIG	0x200 | 
|  | 113 | #define IDE_KAUAI_ULTRA_CONFIG	0x210 | 
|  | 114 | #define IDE_KAUAI_POLL_CONFIG	0x220 | 
|  | 115 |  | 
|  | 116 | /* | 
|  | 117 | * Timing configuration register definitions | 
|  | 118 | */ | 
|  | 119 |  | 
|  | 120 | /* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */ | 
|  | 121 | #define SYSCLK_TICKS(t)		(((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS) | 
|  | 122 | #define SYSCLK_TICKS_66(t)	(((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS) | 
|  | 123 | #define IDE_SYSCLK_NS		30	/* 33Mhz cell */ | 
|  | 124 | #define IDE_SYSCLK_66_NS	15	/* 66Mhz cell */ | 
|  | 125 |  | 
|  | 126 | /* 133Mhz cell, found in shasta. | 
|  | 127 | * See comments about 100 Mhz Uninorth 2... | 
|  | 128 | * Note that PIO_MASK and MDMA_MASK seem to overlap | 
|  | 129 | */ | 
|  | 130 | #define TR_133_PIOREG_PIO_MASK		0xff000fff | 
|  | 131 | #define TR_133_PIOREG_MDMA_MASK		0x00fff800 | 
|  | 132 | #define TR_133_UDMAREG_UDMA_MASK	0x0003ffff | 
|  | 133 | #define TR_133_UDMAREG_UDMA_EN		0x00000001 | 
|  | 134 |  | 
|  | 135 | /* 100Mhz cell, found in Uninorth 2. I don't have much infos about | 
|  | 136 | * this one yet, it appears as a pci device (106b/0033) on uninorth | 
|  | 137 | * internal PCI bus and it's clock is controlled like gem or fw. It | 
|  | 138 | * appears to be an evolution of keylargo ATA4 with a timing register | 
|  | 139 | * extended to 2 32bits registers and a similar DBDMA channel. Other | 
|  | 140 | * registers seem to exist but I can't tell much about them. | 
|  | 141 | * | 
|  | 142 | * So far, I'm using pre-calculated tables for this extracted from | 
|  | 143 | * the values used by the MacOS X driver. | 
|  | 144 | * | 
|  | 145 | * The "PIO" register controls PIO and MDMA timings, the "ULTRA" | 
|  | 146 | * register controls the UDMA timings. At least, it seems bit 0 | 
|  | 147 | * of this one enables UDMA vs. MDMA, and bits 4..7 are the | 
|  | 148 | * cycle time in units of 10ns. Bits 8..15 are used by I don't | 
|  | 149 | * know their meaning yet | 
|  | 150 | */ | 
|  | 151 | #define TR_100_PIOREG_PIO_MASK		0xff000fff | 
|  | 152 | #define TR_100_PIOREG_MDMA_MASK		0x00fff000 | 
|  | 153 | #define TR_100_UDMAREG_UDMA_MASK	0x0000ffff | 
|  | 154 | #define TR_100_UDMAREG_UDMA_EN		0x00000001 | 
|  | 155 |  | 
|  | 156 |  | 
|  | 157 | /* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on | 
|  | 158 | * 40 connector cable and to 4 on 80 connector one. | 
|  | 159 | * Clock unit is 15ns (66Mhz) | 
|  | 160 | * | 
|  | 161 | * 3 Values can be programmed: | 
|  | 162 | *  - Write data setup, which appears to match the cycle time. They | 
|  | 163 | *    also call it DIOW setup. | 
|  | 164 | *  - Ready to pause time (from spec) | 
|  | 165 | *  - Address setup. That one is weird. I don't see where exactly | 
|  | 166 | *    it fits in UDMA cycles, I got it's name from an obscure piece | 
|  | 167 | *    of commented out code in Darwin. They leave it to 0, we do as | 
|  | 168 | *    well, despite a comment that would lead to think it has a | 
|  | 169 | *    min value of 45ns. | 
|  | 170 | * Apple also add 60ns to the write data setup (or cycle time ?) on | 
|  | 171 | * reads. | 
|  | 172 | */ | 
|  | 173 | #define TR_66_UDMA_MASK			0xfff00000 | 
|  | 174 | #define TR_66_UDMA_EN			0x00100000 /* Enable Ultra mode for DMA */ | 
|  | 175 | #define TR_66_UDMA_ADDRSETUP_MASK	0xe0000000 /* Address setup */ | 
|  | 176 | #define TR_66_UDMA_ADDRSETUP_SHIFT	29 | 
|  | 177 | #define TR_66_UDMA_RDY2PAUS_MASK	0x1e000000 /* Ready 2 pause time */ | 
|  | 178 | #define TR_66_UDMA_RDY2PAUS_SHIFT	25 | 
|  | 179 | #define TR_66_UDMA_WRDATASETUP_MASK	0x01e00000 /* Write data setup time */ | 
|  | 180 | #define TR_66_UDMA_WRDATASETUP_SHIFT	21 | 
|  | 181 | #define TR_66_MDMA_MASK			0x000ffc00 | 
|  | 182 | #define TR_66_MDMA_RECOVERY_MASK	0x000f8000 | 
|  | 183 | #define TR_66_MDMA_RECOVERY_SHIFT	15 | 
|  | 184 | #define TR_66_MDMA_ACCESS_MASK		0x00007c00 | 
|  | 185 | #define TR_66_MDMA_ACCESS_SHIFT		10 | 
|  | 186 | #define TR_66_PIO_MASK			0x000003ff | 
|  | 187 | #define TR_66_PIO_RECOVERY_MASK		0x000003e0 | 
|  | 188 | #define TR_66_PIO_RECOVERY_SHIFT	5 | 
|  | 189 | #define TR_66_PIO_ACCESS_MASK		0x0000001f | 
|  | 190 | #define TR_66_PIO_ACCESS_SHIFT		0 | 
|  | 191 |  | 
|  | 192 | /* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo | 
|  | 193 | * Can do pio & mdma modes, clock unit is 30ns (33Mhz) | 
|  | 194 | * | 
|  | 195 | * The access time and recovery time can be programmed. Some older | 
|  | 196 | * Darwin code base limit OHare to 150ns cycle time. I decided to do | 
|  | 197 | * the same here fore safety against broken old hardware ;) | 
|  | 198 | * The HalfTick bit, when set, adds half a clock (15ns) to the access | 
|  | 199 | * time and removes one from recovery. It's not supported on KeyLargo | 
|  | 200 | * implementation afaik. The E bit appears to be set for PIO mode 0 and | 
|  | 201 | * is used to reach long timings used in this mode. | 
|  | 202 | */ | 
|  | 203 | #define TR_33_MDMA_MASK			0x003ff800 | 
|  | 204 | #define TR_33_MDMA_RECOVERY_MASK	0x001f0000 | 
|  | 205 | #define TR_33_MDMA_RECOVERY_SHIFT	16 | 
|  | 206 | #define TR_33_MDMA_ACCESS_MASK		0x0000f800 | 
|  | 207 | #define TR_33_MDMA_ACCESS_SHIFT		11 | 
|  | 208 | #define TR_33_MDMA_HALFTICK		0x00200000 | 
|  | 209 | #define TR_33_PIO_MASK			0x000007ff | 
|  | 210 | #define TR_33_PIO_E			0x00000400 | 
|  | 211 | #define TR_33_PIO_RECOVERY_MASK		0x000003e0 | 
|  | 212 | #define TR_33_PIO_RECOVERY_SHIFT	5 | 
|  | 213 | #define TR_33_PIO_ACCESS_MASK		0x0000001f | 
|  | 214 | #define TR_33_PIO_ACCESS_SHIFT		0 | 
|  | 215 |  | 
|  | 216 | /* | 
|  | 217 | * Interrupt register definitions | 
|  | 218 | */ | 
|  | 219 | #define IDE_INTR_DMA			0x80000000 | 
|  | 220 | #define IDE_INTR_DEVICE			0x40000000 | 
|  | 221 |  | 
|  | 222 | /* | 
|  | 223 | * FCR Register on Kauai. Not sure what bit 0x4 is  ... | 
|  | 224 | */ | 
|  | 225 | #define KAUAI_FCR_UATA_MAGIC		0x00000004 | 
|  | 226 | #define KAUAI_FCR_UATA_RESET_N		0x00000002 | 
|  | 227 | #define KAUAI_FCR_UATA_ENABLE		0x00000001 | 
|  | 228 |  | 
|  | 229 | #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC | 
|  | 230 |  | 
|  | 231 | /* Rounded Multiword DMA timings | 
|  | 232 | * | 
|  | 233 | * I gave up finding a generic formula for all controller | 
|  | 234 | * types and instead, built tables based on timing values | 
|  | 235 | * used by Apple in Darwin's implementation. | 
|  | 236 | */ | 
|  | 237 | struct mdma_timings_t { | 
|  | 238 | int	accessTime; | 
|  | 239 | int	recoveryTime; | 
|  | 240 | int	cycleTime; | 
|  | 241 | }; | 
|  | 242 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 243 | struct mdma_timings_t mdma_timings_33[] = | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 244 | { | 
|  | 245 | { 240, 240, 480 }, | 
|  | 246 | { 180, 180, 360 }, | 
|  | 247 | { 135, 135, 270 }, | 
|  | 248 | { 120, 120, 240 }, | 
|  | 249 | { 105, 105, 210 }, | 
|  | 250 | {  90,  90, 180 }, | 
|  | 251 | {  75,  75, 150 }, | 
|  | 252 | {  75,  45, 120 }, | 
|  | 253 | {   0,   0,   0 } | 
|  | 254 | }; | 
|  | 255 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 256 | struct mdma_timings_t mdma_timings_33k[] = | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 257 | { | 
|  | 258 | { 240, 240, 480 }, | 
|  | 259 | { 180, 180, 360 }, | 
|  | 260 | { 150, 150, 300 }, | 
|  | 261 | { 120, 120, 240 }, | 
|  | 262 | {  90, 120, 210 }, | 
|  | 263 | {  90,  90, 180 }, | 
|  | 264 | {  90,  60, 150 }, | 
|  | 265 | {  90,  30, 120 }, | 
|  | 266 | {   0,   0,   0 } | 
|  | 267 | }; | 
|  | 268 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 269 | struct mdma_timings_t mdma_timings_66[] = | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 270 | { | 
|  | 271 | { 240, 240, 480 }, | 
|  | 272 | { 180, 180, 360 }, | 
|  | 273 | { 135, 135, 270 }, | 
|  | 274 | { 120, 120, 240 }, | 
|  | 275 | { 105, 105, 210 }, | 
|  | 276 | {  90,  90, 180 }, | 
|  | 277 | {  90,  75, 165 }, | 
|  | 278 | {  75,  45, 120 }, | 
|  | 279 | {   0,   0,   0 } | 
|  | 280 | }; | 
|  | 281 |  | 
|  | 282 | /* KeyLargo ATA-4 Ultra DMA timings (rounded) */ | 
|  | 283 | struct { | 
|  | 284 | int	addrSetup; /* ??? */ | 
|  | 285 | int	rdy2pause; | 
|  | 286 | int	wrDataSetup; | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 287 | } kl66_udma_timings[] = | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 288 | { | 
|  | 289 | {   0, 180,  120 },	/* Mode 0 */ | 
|  | 290 | {   0, 150,  90 },	/*      1 */ | 
|  | 291 | {   0, 120,  60 },	/*      2 */ | 
|  | 292 | {   0, 90,   45 },	/*      3 */ | 
|  | 293 | {   0, 90,   30 }	/*      4 */ | 
|  | 294 | }; | 
|  | 295 |  | 
|  | 296 | /* UniNorth 2 ATA/100 timings */ | 
|  | 297 | struct kauai_timing { | 
|  | 298 | int	cycle_time; | 
|  | 299 | u32	timing_reg; | 
|  | 300 | }; | 
|  | 301 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 302 | static struct kauai_timing	kauai_pio_timings[] = | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 303 | { | 
|  | 304 | { 930	, 0x08000fff }, | 
|  | 305 | { 600	, 0x08000a92 }, | 
|  | 306 | { 383	, 0x0800060f }, | 
|  | 307 | { 360	, 0x08000492 }, | 
|  | 308 | { 330	, 0x0800048f }, | 
|  | 309 | { 300	, 0x080003cf }, | 
|  | 310 | { 270	, 0x080003cc }, | 
|  | 311 | { 240	, 0x0800038b }, | 
|  | 312 | { 239	, 0x0800030c }, | 
|  | 313 | { 180	, 0x05000249 }, | 
| Bartlomiej Zolnierkiewicz | c15d5d4 | 2007-10-11 23:54:01 +0200 | [diff] [blame] | 314 | { 120	, 0x04000148 }, | 
|  | 315 | { 0	, 0 }, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 316 | }; | 
|  | 317 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 318 | static struct kauai_timing	kauai_mdma_timings[] = | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 319 | { | 
|  | 320 | { 1260	, 0x00fff000 }, | 
|  | 321 | { 480	, 0x00618000 }, | 
|  | 322 | { 360	, 0x00492000 }, | 
|  | 323 | { 270	, 0x0038e000 }, | 
|  | 324 | { 240	, 0x0030c000 }, | 
|  | 325 | { 210	, 0x002cb000 }, | 
|  | 326 | { 180	, 0x00249000 }, | 
|  | 327 | { 150	, 0x00209000 }, | 
|  | 328 | { 120	, 0x00148000 }, | 
|  | 329 | { 0	, 0 }, | 
|  | 330 | }; | 
|  | 331 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 332 | static struct kauai_timing	kauai_udma_timings[] = | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 333 | { | 
|  | 334 | { 120	, 0x000070c0 }, | 
|  | 335 | { 90	, 0x00005d80 }, | 
|  | 336 | { 60	, 0x00004a60 }, | 
|  | 337 | { 45	, 0x00003a50 }, | 
|  | 338 | { 30	, 0x00002a30 }, | 
|  | 339 | { 20	, 0x00002921 }, | 
|  | 340 | { 0	, 0 }, | 
|  | 341 | }; | 
|  | 342 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 343 | static struct kauai_timing	shasta_pio_timings[] = | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 344 | { | 
|  | 345 | { 930	, 0x08000fff }, | 
|  | 346 | { 600	, 0x0A000c97 }, | 
|  | 347 | { 383	, 0x07000712 }, | 
|  | 348 | { 360	, 0x040003cd }, | 
|  | 349 | { 330	, 0x040003cd }, | 
|  | 350 | { 300	, 0x040003cd }, | 
|  | 351 | { 270	, 0x040003cd }, | 
|  | 352 | { 240	, 0x040003cd }, | 
|  | 353 | { 239	, 0x040003cd }, | 
|  | 354 | { 180	, 0x0400028b }, | 
| Bartlomiej Zolnierkiewicz | c15d5d4 | 2007-10-11 23:54:01 +0200 | [diff] [blame] | 355 | { 120	, 0x0400010a }, | 
|  | 356 | { 0	, 0 }, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 357 | }; | 
|  | 358 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 359 | static struct kauai_timing	shasta_mdma_timings[] = | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 360 | { | 
|  | 361 | { 1260	, 0x00fff000 }, | 
|  | 362 | { 480	, 0x00820800 }, | 
|  | 363 | { 360	, 0x00820800 }, | 
|  | 364 | { 270	, 0x00820800 }, | 
|  | 365 | { 240	, 0x00820800 }, | 
|  | 366 | { 210	, 0x00820800 }, | 
|  | 367 | { 180	, 0x00820800 }, | 
|  | 368 | { 150	, 0x0028b000 }, | 
|  | 369 | { 120	, 0x001ca000 }, | 
|  | 370 | { 0	, 0 }, | 
|  | 371 | }; | 
|  | 372 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 373 | static struct kauai_timing	shasta_udma133_timings[] = | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 374 | { | 
|  | 375 | { 120   , 0x00035901, }, | 
|  | 376 | { 90    , 0x000348b1, }, | 
|  | 377 | { 60    , 0x00033881, }, | 
|  | 378 | { 45    , 0x00033861, }, | 
|  | 379 | { 30    , 0x00033841, }, | 
|  | 380 | { 20    , 0x00033031, }, | 
|  | 381 | { 15    , 0x00033021, }, | 
|  | 382 | { 0	, 0 }, | 
|  | 383 | }; | 
|  | 384 |  | 
|  | 385 |  | 
|  | 386 | static inline u32 | 
|  | 387 | kauai_lookup_timing(struct kauai_timing* table, int cycle_time) | 
|  | 388 | { | 
|  | 389 | int i; | 
|  | 390 |  | 
|  | 391 | for (i=0; table[i].cycle_time; i++) | 
|  | 392 | if (cycle_time > table[i+1].cycle_time) | 
|  | 393 | return table[i].timing_reg; | 
| Bartlomiej Zolnierkiewicz | 90a87ea | 2007-10-13 17:47:48 +0200 | [diff] [blame] | 394 | BUG(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 395 | return 0; | 
|  | 396 | } | 
|  | 397 |  | 
|  | 398 | /* allow up to 256 DBDMA commands per xfer */ | 
|  | 399 | #define MAX_DCMDS		256 | 
|  | 400 |  | 
|  | 401 | /* | 
|  | 402 | * Wait 1s for disk to answer on IDE bus after a hard reset | 
|  | 403 | * of the device (via GPIO/FCR). | 
|  | 404 | * | 
|  | 405 | * Some devices seem to "pollute" the bus even after dropping | 
|  | 406 | * the BSY bit (typically some combo drives slave on the UDMA | 
|  | 407 | * bus) after a hard reset. Since we hard reset all drives on | 
|  | 408 | * KeyLargo ATA66, we have to keep that delay around. I may end | 
|  | 409 | * up not hard resetting anymore on these and keep the delay only | 
|  | 410 | * for older interfaces instead (we have to reset when coming | 
|  | 411 | * from MacOS...) --BenH. | 
|  | 412 | */ | 
|  | 413 | #define IDE_WAKEUP_DELAY	(1*HZ) | 
|  | 414 |  | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 415 | static int pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 416 | static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 417 | static void pmac_ide_selectproc(ide_drive_t *drive); | 
|  | 418 | static void pmac_ide_kauai_selectproc(ide_drive_t *drive); | 
|  | 419 |  | 
|  | 420 | #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ | 
|  | 421 |  | 
|  | 422 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 423 | * N.B. this can't be an initfunc, because the media-bay task can | 
|  | 424 | * call ide_[un]register at any time. | 
|  | 425 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 426 | void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 427 | pmac_ide_init_hwif_ports(hw_regs_t *hw, | 
|  | 428 | unsigned long data_port, unsigned long ctrl_port, | 
|  | 429 | int *irq) | 
|  | 430 | { | 
|  | 431 | int i, ix; | 
|  | 432 |  | 
|  | 433 | if (data_port == 0) | 
|  | 434 | return; | 
|  | 435 |  | 
|  | 436 | for (ix = 0; ix < MAX_HWIFS; ++ix) | 
|  | 437 | if (data_port == pmac_ide[ix].regbase) | 
|  | 438 | break; | 
|  | 439 |  | 
| Bartlomiej Zolnierkiewicz | d26805f | 2008-01-25 22:17:07 +0100 | [diff] [blame] | 440 | if (ix >= MAX_HWIFS) | 
|  | 441 | return;		/* not an IDE PMAC interface */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 442 |  | 
|  | 443 | for (i = 0; i < 8; ++i) | 
|  | 444 | hw->io_ports[i] = data_port + i * 0x10; | 
|  | 445 | hw->io_ports[8] = data_port + 0x160; | 
|  | 446 |  | 
|  | 447 | if (irq != NULL) | 
|  | 448 | *irq = pmac_ide[ix].irq; | 
| Benjamin Herrenschmidt | 22192cc | 2006-05-20 14:59:53 -0700 | [diff] [blame] | 449 |  | 
|  | 450 | hw->dev = &pmac_ide[ix].mdev->ofdev.dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 451 | } | 
|  | 452 |  | 
|  | 453 | #define PMAC_IDE_REG(x) ((void __iomem *)(IDE_DATA_REG+(x))) | 
|  | 454 |  | 
|  | 455 | /* | 
|  | 456 | * Apply the timings of the proper unit (master/slave) to the shared | 
|  | 457 | * timing register when selecting that unit. This version is for | 
|  | 458 | * ASICs with a single timing register | 
|  | 459 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 460 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 461 | pmac_ide_selectproc(ide_drive_t *drive) | 
|  | 462 | { | 
|  | 463 | pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; | 
|  | 464 |  | 
|  | 465 | if (pmif == NULL) | 
|  | 466 | return; | 
|  | 467 |  | 
|  | 468 | if (drive->select.b.unit & 0x01) | 
|  | 469 | writel(pmif->timings[1], PMAC_IDE_REG(IDE_TIMING_CONFIG)); | 
|  | 470 | else | 
|  | 471 | writel(pmif->timings[0], PMAC_IDE_REG(IDE_TIMING_CONFIG)); | 
|  | 472 | (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); | 
|  | 473 | } | 
|  | 474 |  | 
|  | 475 | /* | 
|  | 476 | * Apply the timings of the proper unit (master/slave) to the shared | 
|  | 477 | * timing register when selecting that unit. This version is for | 
|  | 478 | * ASICs with a dual timing register (Kauai) | 
|  | 479 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 480 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 481 | pmac_ide_kauai_selectproc(ide_drive_t *drive) | 
|  | 482 | { | 
|  | 483 | pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; | 
|  | 484 |  | 
|  | 485 | if (pmif == NULL) | 
|  | 486 | return; | 
|  | 487 |  | 
|  | 488 | if (drive->select.b.unit & 0x01) { | 
|  | 489 | writel(pmif->timings[1], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); | 
|  | 490 | writel(pmif->timings[3], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG)); | 
|  | 491 | } else { | 
|  | 492 | writel(pmif->timings[0], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); | 
|  | 493 | writel(pmif->timings[2], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG)); | 
|  | 494 | } | 
|  | 495 | (void)readl(PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); | 
|  | 496 | } | 
|  | 497 |  | 
|  | 498 | /* | 
|  | 499 | * Force an update of controller timing values for a given drive | 
|  | 500 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 501 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 502 | pmac_ide_do_update_timings(ide_drive_t *drive) | 
|  | 503 | { | 
|  | 504 | pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; | 
|  | 505 |  | 
|  | 506 | if (pmif == NULL) | 
|  | 507 | return; | 
|  | 508 |  | 
|  | 509 | if (pmif->kind == controller_sh_ata6 || | 
|  | 510 | pmif->kind == controller_un_ata6 || | 
|  | 511 | pmif->kind == controller_k2_ata6) | 
|  | 512 | pmac_ide_kauai_selectproc(drive); | 
|  | 513 | else | 
|  | 514 | pmac_ide_selectproc(drive); | 
|  | 515 | } | 
|  | 516 |  | 
|  | 517 | static void | 
|  | 518 | pmac_outbsync(ide_drive_t *drive, u8 value, unsigned long port) | 
|  | 519 | { | 
|  | 520 | u32 tmp; | 
|  | 521 |  | 
|  | 522 | writeb(value, (void __iomem *) port); | 
|  | 523 | tmp = readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); | 
|  | 524 | } | 
|  | 525 |  | 
|  | 526 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 527 | * Old tuning functions (called on hdparm -p), sets up drive PIO timings | 
|  | 528 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 529 | static void | 
| Bartlomiej Zolnierkiewicz | 26bcb87 | 2007-10-11 23:54:00 +0200 | [diff] [blame] | 530 | pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 531 | { | 
| Benjamin Herrenschmidt | 0b46ff2 | 2007-10-13 17:47:50 +0200 | [diff] [blame] | 532 | u32 *timings, t; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 533 | unsigned accessTicks, recTicks; | 
|  | 534 | unsigned accessTime, recTime; | 
|  | 535 | pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; | 
| Bartlomiej Zolnierkiewicz | 7dd0008 | 2007-07-20 01:11:56 +0200 | [diff] [blame] | 536 | unsigned int cycle_time; | 
|  | 537 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 538 | if (pmif == NULL) | 
|  | 539 | return; | 
|  | 540 |  | 
|  | 541 | /* which drive is it ? */ | 
|  | 542 | timings = &pmif->timings[drive->select.b.unit & 0x01]; | 
| Benjamin Herrenschmidt | 0b46ff2 | 2007-10-13 17:47:50 +0200 | [diff] [blame] | 543 | t = *timings; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 544 |  | 
| Bartlomiej Zolnierkiewicz | 7dd0008 | 2007-07-20 01:11:56 +0200 | [diff] [blame] | 545 | cycle_time = ide_pio_cycle_time(drive, pio); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 546 |  | 
|  | 547 | switch (pmif->kind) { | 
|  | 548 | case controller_sh_ata6: { | 
|  | 549 | /* 133Mhz cell */ | 
| Bartlomiej Zolnierkiewicz | 7dd0008 | 2007-07-20 01:11:56 +0200 | [diff] [blame] | 550 | u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time); | 
| Benjamin Herrenschmidt | 0b46ff2 | 2007-10-13 17:47:50 +0200 | [diff] [blame] | 551 | t = (t & ~TR_133_PIOREG_PIO_MASK) | tr; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 552 | break; | 
|  | 553 | } | 
|  | 554 | case controller_un_ata6: | 
|  | 555 | case controller_k2_ata6: { | 
|  | 556 | /* 100Mhz cell */ | 
| Bartlomiej Zolnierkiewicz | 7dd0008 | 2007-07-20 01:11:56 +0200 | [diff] [blame] | 557 | u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time); | 
| Benjamin Herrenschmidt | 0b46ff2 | 2007-10-13 17:47:50 +0200 | [diff] [blame] | 558 | t = (t & ~TR_100_PIOREG_PIO_MASK) | tr; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 559 | break; | 
|  | 560 | } | 
|  | 561 | case controller_kl_ata4: | 
|  | 562 | /* 66Mhz cell */ | 
| Bartlomiej Zolnierkiewicz | 7dd0008 | 2007-07-20 01:11:56 +0200 | [diff] [blame] | 563 | recTime = cycle_time - ide_pio_timings[pio].active_time | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 564 | - ide_pio_timings[pio].setup_time; | 
|  | 565 | recTime = max(recTime, 150U); | 
|  | 566 | accessTime = ide_pio_timings[pio].active_time; | 
|  | 567 | accessTime = max(accessTime, 150U); | 
|  | 568 | accessTicks = SYSCLK_TICKS_66(accessTime); | 
|  | 569 | accessTicks = min(accessTicks, 0x1fU); | 
|  | 570 | recTicks = SYSCLK_TICKS_66(recTime); | 
|  | 571 | recTicks = min(recTicks, 0x1fU); | 
| Benjamin Herrenschmidt | 0b46ff2 | 2007-10-13 17:47:50 +0200 | [diff] [blame] | 572 | t = (t & ~TR_66_PIO_MASK) | | 
|  | 573 | (accessTicks << TR_66_PIO_ACCESS_SHIFT) | | 
|  | 574 | (recTicks << TR_66_PIO_RECOVERY_SHIFT); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 575 | break; | 
|  | 576 | default: { | 
|  | 577 | /* 33Mhz cell */ | 
|  | 578 | int ebit = 0; | 
| Bartlomiej Zolnierkiewicz | 7dd0008 | 2007-07-20 01:11:56 +0200 | [diff] [blame] | 579 | recTime = cycle_time - ide_pio_timings[pio].active_time | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 580 | - ide_pio_timings[pio].setup_time; | 
|  | 581 | recTime = max(recTime, 150U); | 
|  | 582 | accessTime = ide_pio_timings[pio].active_time; | 
|  | 583 | accessTime = max(accessTime, 150U); | 
|  | 584 | accessTicks = SYSCLK_TICKS(accessTime); | 
|  | 585 | accessTicks = min(accessTicks, 0x1fU); | 
|  | 586 | accessTicks = max(accessTicks, 4U); | 
|  | 587 | recTicks = SYSCLK_TICKS(recTime); | 
|  | 588 | recTicks = min(recTicks, 0x1fU); | 
|  | 589 | recTicks = max(recTicks, 5U) - 4; | 
|  | 590 | if (recTicks > 9) { | 
|  | 591 | recTicks--; /* guess, but it's only for PIO0, so... */ | 
|  | 592 | ebit = 1; | 
|  | 593 | } | 
| Benjamin Herrenschmidt | 0b46ff2 | 2007-10-13 17:47:50 +0200 | [diff] [blame] | 594 | t = (t & ~TR_33_PIO_MASK) | | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 595 | (accessTicks << TR_33_PIO_ACCESS_SHIFT) | | 
|  | 596 | (recTicks << TR_33_PIO_RECOVERY_SHIFT); | 
|  | 597 | if (ebit) | 
| Benjamin Herrenschmidt | 0b46ff2 | 2007-10-13 17:47:50 +0200 | [diff] [blame] | 598 | t |= TR_33_PIO_E; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 599 | break; | 
|  | 600 | } | 
|  | 601 | } | 
|  | 602 |  | 
|  | 603 | #ifdef IDE_PMAC_DEBUG | 
|  | 604 | printk(KERN_ERR "%s: Set PIO timing for mode %d, reg: 0x%08x\n", | 
|  | 605 | drive->name, pio,  *timings); | 
|  | 606 | #endif | 
|  | 607 |  | 
| Benjamin Herrenschmidt | 0b46ff2 | 2007-10-13 17:47:50 +0200 | [diff] [blame] | 608 | *timings = t; | 
| Bartlomiej Zolnierkiewicz | c15d5d4 | 2007-10-11 23:54:01 +0200 | [diff] [blame] | 609 | pmac_ide_do_update_timings(drive); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 610 | } | 
|  | 611 |  | 
|  | 612 | #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC | 
|  | 613 |  | 
|  | 614 | /* | 
|  | 615 | * Calculate KeyLargo ATA/66 UDMA timings | 
|  | 616 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 617 | static int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 618 | set_timings_udma_ata4(u32 *timings, u8 speed) | 
|  | 619 | { | 
|  | 620 | unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks; | 
|  | 621 |  | 
|  | 622 | if (speed > XFER_UDMA_4) | 
|  | 623 | return 1; | 
|  | 624 |  | 
|  | 625 | rdyToPauseTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].rdy2pause); | 
|  | 626 | wrDataSetupTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].wrDataSetup); | 
|  | 627 | addrTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].addrSetup); | 
|  | 628 |  | 
|  | 629 | *timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) | | 
|  | 630 | (wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | | 
|  | 631 | (rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) | | 
|  | 632 | (addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) | | 
|  | 633 | TR_66_UDMA_EN; | 
|  | 634 | #ifdef IDE_PMAC_DEBUG | 
|  | 635 | printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n", | 
|  | 636 | speed & 0xf,  *timings); | 
|  | 637 | #endif | 
|  | 638 |  | 
|  | 639 | return 0; | 
|  | 640 | } | 
|  | 641 |  | 
|  | 642 | /* | 
|  | 643 | * Calculate Kauai ATA/100 UDMA timings | 
|  | 644 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 645 | static int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 646 | set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed) | 
|  | 647 | { | 
|  | 648 | struct ide_timing *t = ide_timing_find_mode(speed); | 
|  | 649 | u32 tr; | 
|  | 650 |  | 
|  | 651 | if (speed > XFER_UDMA_5 || t == NULL) | 
|  | 652 | return 1; | 
|  | 653 | tr = kauai_lookup_timing(kauai_udma_timings, (int)t->udma); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 654 | *ultra_timings = ((*ultra_timings) & ~TR_100_UDMAREG_UDMA_MASK) | tr; | 
|  | 655 | *ultra_timings = (*ultra_timings) | TR_100_UDMAREG_UDMA_EN; | 
|  | 656 |  | 
|  | 657 | return 0; | 
|  | 658 | } | 
|  | 659 |  | 
|  | 660 | /* | 
|  | 661 | * Calculate Shasta ATA/133 UDMA timings | 
|  | 662 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 663 | static int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 664 | set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed) | 
|  | 665 | { | 
|  | 666 | struct ide_timing *t = ide_timing_find_mode(speed); | 
|  | 667 | u32 tr; | 
|  | 668 |  | 
|  | 669 | if (speed > XFER_UDMA_6 || t == NULL) | 
|  | 670 | return 1; | 
|  | 671 | tr = kauai_lookup_timing(shasta_udma133_timings, (int)t->udma); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 672 | *ultra_timings = ((*ultra_timings) & ~TR_133_UDMAREG_UDMA_MASK) | tr; | 
|  | 673 | *ultra_timings = (*ultra_timings) | TR_133_UDMAREG_UDMA_EN; | 
|  | 674 |  | 
|  | 675 | return 0; | 
|  | 676 | } | 
|  | 677 |  | 
|  | 678 | /* | 
|  | 679 | * Calculate MDMA timings for all cells | 
|  | 680 | */ | 
| Bartlomiej Zolnierkiewicz | 90f72ec | 2007-10-13 17:47:48 +0200 | [diff] [blame] | 681 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 682 | set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, | 
| Bartlomiej Zolnierkiewicz | 90f72ec | 2007-10-13 17:47:48 +0200 | [diff] [blame] | 683 | u8 speed) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 684 | { | 
|  | 685 | int cycleTime, accessTime = 0, recTime = 0; | 
|  | 686 | unsigned accessTicks, recTicks; | 
| Bartlomiej Zolnierkiewicz | 90f72ec | 2007-10-13 17:47:48 +0200 | [diff] [blame] | 687 | struct hd_driveid *id = drive->id; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 688 | struct mdma_timings_t* tm = NULL; | 
|  | 689 | int i; | 
|  | 690 |  | 
|  | 691 | /* Get default cycle time for mode */ | 
|  | 692 | switch(speed & 0xf) { | 
|  | 693 | case 0: cycleTime = 480; break; | 
|  | 694 | case 1: cycleTime = 150; break; | 
|  | 695 | case 2: cycleTime = 120; break; | 
|  | 696 | default: | 
| Bartlomiej Zolnierkiewicz | 90f72ec | 2007-10-13 17:47:48 +0200 | [diff] [blame] | 697 | BUG(); | 
|  | 698 | break; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 699 | } | 
| Bartlomiej Zolnierkiewicz | 90f72ec | 2007-10-13 17:47:48 +0200 | [diff] [blame] | 700 |  | 
|  | 701 | /* Check if drive provides explicit DMA cycle time */ | 
|  | 702 | if ((id->field_valid & 2) && id->eide_dma_time) | 
|  | 703 | cycleTime = max_t(int, id->eide_dma_time, cycleTime); | 
|  | 704 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 705 | /* OHare limits according to some old Apple sources */ | 
|  | 706 | if ((intf_type == controller_ohare) && (cycleTime < 150)) | 
|  | 707 | cycleTime = 150; | 
|  | 708 | /* Get the proper timing array for this controller */ | 
|  | 709 | switch(intf_type) { | 
|  | 710 | case controller_sh_ata6: | 
|  | 711 | case controller_un_ata6: | 
|  | 712 | case controller_k2_ata6: | 
|  | 713 | break; | 
|  | 714 | case controller_kl_ata4: | 
|  | 715 | tm = mdma_timings_66; | 
|  | 716 | break; | 
|  | 717 | case controller_kl_ata3: | 
|  | 718 | tm = mdma_timings_33k; | 
|  | 719 | break; | 
|  | 720 | default: | 
|  | 721 | tm = mdma_timings_33; | 
|  | 722 | break; | 
|  | 723 | } | 
|  | 724 | if (tm != NULL) { | 
|  | 725 | /* Lookup matching access & recovery times */ | 
|  | 726 | i = -1; | 
|  | 727 | for (;;) { | 
|  | 728 | if (tm[i+1].cycleTime < cycleTime) | 
|  | 729 | break; | 
|  | 730 | i++; | 
|  | 731 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 732 | cycleTime = tm[i].cycleTime; | 
|  | 733 | accessTime = tm[i].accessTime; | 
|  | 734 | recTime = tm[i].recoveryTime; | 
|  | 735 |  | 
|  | 736 | #ifdef IDE_PMAC_DEBUG | 
|  | 737 | printk(KERN_ERR "%s: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n", | 
|  | 738 | drive->name, cycleTime, accessTime, recTime); | 
|  | 739 | #endif | 
|  | 740 | } | 
|  | 741 | switch(intf_type) { | 
|  | 742 | case controller_sh_ata6: { | 
|  | 743 | /* 133Mhz cell */ | 
|  | 744 | u32 tr = kauai_lookup_timing(shasta_mdma_timings, cycleTime); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 745 | *timings = ((*timings) & ~TR_133_PIOREG_MDMA_MASK) | tr; | 
|  | 746 | *timings2 = (*timings2) & ~TR_133_UDMAREG_UDMA_EN; | 
|  | 747 | } | 
|  | 748 | case controller_un_ata6: | 
|  | 749 | case controller_k2_ata6: { | 
|  | 750 | /* 100Mhz cell */ | 
|  | 751 | u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 752 | *timings = ((*timings) & ~TR_100_PIOREG_MDMA_MASK) | tr; | 
|  | 753 | *timings2 = (*timings2) & ~TR_100_UDMAREG_UDMA_EN; | 
|  | 754 | } | 
|  | 755 | break; | 
|  | 756 | case controller_kl_ata4: | 
|  | 757 | /* 66Mhz cell */ | 
|  | 758 | accessTicks = SYSCLK_TICKS_66(accessTime); | 
|  | 759 | accessTicks = min(accessTicks, 0x1fU); | 
|  | 760 | accessTicks = max(accessTicks, 0x1U); | 
|  | 761 | recTicks = SYSCLK_TICKS_66(recTime); | 
|  | 762 | recTicks = min(recTicks, 0x1fU); | 
|  | 763 | recTicks = max(recTicks, 0x3U); | 
|  | 764 | /* Clear out mdma bits and disable udma */ | 
|  | 765 | *timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) | | 
|  | 766 | (accessTicks << TR_66_MDMA_ACCESS_SHIFT) | | 
|  | 767 | (recTicks << TR_66_MDMA_RECOVERY_SHIFT); | 
|  | 768 | break; | 
|  | 769 | case controller_kl_ata3: | 
|  | 770 | /* 33Mhz cell on KeyLargo */ | 
|  | 771 | accessTicks = SYSCLK_TICKS(accessTime); | 
|  | 772 | accessTicks = max(accessTicks, 1U); | 
|  | 773 | accessTicks = min(accessTicks, 0x1fU); | 
|  | 774 | accessTime = accessTicks * IDE_SYSCLK_NS; | 
|  | 775 | recTicks = SYSCLK_TICKS(recTime); | 
|  | 776 | recTicks = max(recTicks, 1U); | 
|  | 777 | recTicks = min(recTicks, 0x1fU); | 
|  | 778 | *timings = ((*timings) & ~TR_33_MDMA_MASK) | | 
|  | 779 | (accessTicks << TR_33_MDMA_ACCESS_SHIFT) | | 
|  | 780 | (recTicks << TR_33_MDMA_RECOVERY_SHIFT); | 
|  | 781 | break; | 
|  | 782 | default: { | 
|  | 783 | /* 33Mhz cell on others */ | 
|  | 784 | int halfTick = 0; | 
|  | 785 | int origAccessTime = accessTime; | 
|  | 786 | int origRecTime = recTime; | 
|  | 787 |  | 
|  | 788 | accessTicks = SYSCLK_TICKS(accessTime); | 
|  | 789 | accessTicks = max(accessTicks, 1U); | 
|  | 790 | accessTicks = min(accessTicks, 0x1fU); | 
|  | 791 | accessTime = accessTicks * IDE_SYSCLK_NS; | 
|  | 792 | recTicks = SYSCLK_TICKS(recTime); | 
|  | 793 | recTicks = max(recTicks, 2U) - 1; | 
|  | 794 | recTicks = min(recTicks, 0x1fU); | 
|  | 795 | recTime = (recTicks + 1) * IDE_SYSCLK_NS; | 
|  | 796 | if ((accessTicks > 1) && | 
|  | 797 | ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) && | 
|  | 798 | ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) { | 
|  | 799 | halfTick = 1; | 
|  | 800 | accessTicks--; | 
|  | 801 | } | 
|  | 802 | *timings = ((*timings) & ~TR_33_MDMA_MASK) | | 
|  | 803 | (accessTicks << TR_33_MDMA_ACCESS_SHIFT) | | 
|  | 804 | (recTicks << TR_33_MDMA_RECOVERY_SHIFT); | 
|  | 805 | if (halfTick) | 
|  | 806 | *timings |= TR_33_MDMA_HALFTICK; | 
|  | 807 | } | 
|  | 808 | } | 
|  | 809 | #ifdef IDE_PMAC_DEBUG | 
|  | 810 | printk(KERN_ERR "%s: Set MDMA timing for mode %d, reg: 0x%08x\n", | 
|  | 811 | drive->name, speed & 0xf,  *timings); | 
|  | 812 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 813 | } | 
|  | 814 | #endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */ | 
|  | 815 |  | 
| Bartlomiej Zolnierkiewicz | 88b2b32 | 2007-10-13 17:47:51 +0200 | [diff] [blame] | 816 | static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 817 | { | 
|  | 818 | int unit = (drive->select.b.unit & 0x01); | 
|  | 819 | int ret = 0; | 
|  | 820 | pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; | 
| Bartlomiej Zolnierkiewicz | 085798b | 2007-10-13 17:47:48 +0200 | [diff] [blame] | 821 | u32 *timings, *timings2, tl[2]; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 822 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 823 | timings = &pmif->timings[unit]; | 
|  | 824 | timings2 = &pmif->timings[unit+2]; | 
| Bartlomiej Zolnierkiewicz | 085798b | 2007-10-13 17:47:48 +0200 | [diff] [blame] | 825 |  | 
|  | 826 | /* Copy timings to local image */ | 
|  | 827 | tl[0] = *timings; | 
|  | 828 | tl[1] = *timings2; | 
|  | 829 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 830 | #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC | 
| Bartlomiej Zolnierkiewicz | 4db90a1 | 2008-01-25 22:17:18 +0100 | [diff] [blame] | 831 | if (speed >= XFER_UDMA_0) { | 
|  | 832 | if (pmif->kind == controller_kl_ata4) | 
|  | 833 | ret = set_timings_udma_ata4(&tl[0], speed); | 
|  | 834 | else if (pmif->kind == controller_un_ata6 | 
|  | 835 | || pmif->kind == controller_k2_ata6) | 
|  | 836 | ret = set_timings_udma_ata6(&tl[0], &tl[1], speed); | 
|  | 837 | else if (pmif->kind == controller_sh_ata6) | 
|  | 838 | ret = set_timings_udma_shasta(&tl[0], &tl[1], speed); | 
|  | 839 | else | 
|  | 840 | ret = -1; | 
|  | 841 | } else | 
|  | 842 | set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 843 | #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 844 | if (ret) | 
| Bartlomiej Zolnierkiewicz | 88b2b32 | 2007-10-13 17:47:51 +0200 | [diff] [blame] | 845 | return; | 
| Bartlomiej Zolnierkiewicz | 085798b | 2007-10-13 17:47:48 +0200 | [diff] [blame] | 846 |  | 
|  | 847 | /* Apply timings to controller */ | 
|  | 848 | *timings = tl[0]; | 
|  | 849 | *timings2 = tl[1]; | 
|  | 850 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 851 | pmac_ide_do_update_timings(drive); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 852 | } | 
|  | 853 |  | 
|  | 854 | /* | 
|  | 855 | * Blast some well known "safe" values to the timing registers at init or | 
|  | 856 | * wakeup from sleep time, before we do real calculation | 
|  | 857 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 858 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 859 | sanitize_timings(pmac_ide_hwif_t *pmif) | 
|  | 860 | { | 
|  | 861 | unsigned int value, value2 = 0; | 
|  | 862 |  | 
|  | 863 | switch(pmif->kind) { | 
|  | 864 | case controller_sh_ata6: | 
|  | 865 | value = 0x0a820c97; | 
|  | 866 | value2 = 0x00033031; | 
|  | 867 | break; | 
|  | 868 | case controller_un_ata6: | 
|  | 869 | case controller_k2_ata6: | 
|  | 870 | value = 0x08618a92; | 
|  | 871 | value2 = 0x00002921; | 
|  | 872 | break; | 
|  | 873 | case controller_kl_ata4: | 
|  | 874 | value = 0x0008438c; | 
|  | 875 | break; | 
|  | 876 | case controller_kl_ata3: | 
|  | 877 | value = 0x00084526; | 
|  | 878 | break; | 
|  | 879 | case controller_heathrow: | 
|  | 880 | case controller_ohare: | 
|  | 881 | default: | 
|  | 882 | value = 0x00074526; | 
|  | 883 | break; | 
|  | 884 | } | 
|  | 885 | pmif->timings[0] = pmif->timings[1] = value; | 
|  | 886 | pmif->timings[2] = pmif->timings[3] = value2; | 
|  | 887 | } | 
|  | 888 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 889 | unsigned long | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 890 | pmac_ide_get_base(int index) | 
|  | 891 | { | 
|  | 892 | return pmac_ide[index].regbase; | 
|  | 893 | } | 
|  | 894 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 895 | int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 896 | pmac_ide_check_base(unsigned long base) | 
|  | 897 | { | 
|  | 898 | int ix; | 
|  | 899 |  | 
|  | 900 | for (ix = 0; ix < MAX_HWIFS; ++ix) | 
|  | 901 | if (base == pmac_ide[ix].regbase) | 
|  | 902 | return ix; | 
|  | 903 | return -1; | 
|  | 904 | } | 
|  | 905 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 906 | int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 907 | pmac_ide_get_irq(unsigned long base) | 
|  | 908 | { | 
|  | 909 | int ix; | 
|  | 910 |  | 
|  | 911 | for (ix = 0; ix < MAX_HWIFS; ++ix) | 
|  | 912 | if (base == pmac_ide[ix].regbase) | 
|  | 913 | return pmac_ide[ix].irq; | 
|  | 914 | return 0; | 
|  | 915 | } | 
|  | 916 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 917 | static int ide_majors[] = { 3, 22, 33, 34, 56, 57 }; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 918 |  | 
|  | 919 | dev_t __init | 
|  | 920 | pmac_find_ide_boot(char *bootdevice, int n) | 
|  | 921 | { | 
|  | 922 | int i; | 
|  | 923 |  | 
|  | 924 | /* | 
|  | 925 | * Look through the list of IDE interfaces for this one. | 
|  | 926 | */ | 
|  | 927 | for (i = 0; i < pmac_ide_count; ++i) { | 
|  | 928 | char *name; | 
|  | 929 | if (!pmac_ide[i].node || !pmac_ide[i].node->full_name) | 
|  | 930 | continue; | 
|  | 931 | name = pmac_ide[i].node->full_name; | 
|  | 932 | if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) { | 
|  | 933 | /* XXX should cope with the 2nd drive as well... */ | 
|  | 934 | return MKDEV(ide_majors[i], 0); | 
|  | 935 | } | 
|  | 936 | } | 
|  | 937 |  | 
|  | 938 | return 0; | 
|  | 939 | } | 
|  | 940 |  | 
|  | 941 | /* Suspend call back, should be called after the child devices | 
|  | 942 | * have actually been suspended | 
|  | 943 | */ | 
|  | 944 | static int | 
|  | 945 | pmac_ide_do_suspend(ide_hwif_t *hwif) | 
|  | 946 | { | 
|  | 947 | pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data; | 
|  | 948 |  | 
|  | 949 | /* We clear the timings */ | 
|  | 950 | pmif->timings[0] = 0; | 
|  | 951 | pmif->timings[1] = 0; | 
|  | 952 |  | 
| Benjamin Herrenschmidt | 616299a | 2005-05-01 08:58:41 -0700 | [diff] [blame] | 953 | disable_irq(pmif->irq); | 
|  | 954 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 955 | /* The media bay will handle itself just fine */ | 
|  | 956 | if (pmif->mediabay) | 
|  | 957 | return 0; | 
|  | 958 |  | 
|  | 959 | /* Kauai has bus control FCRs directly here */ | 
|  | 960 | if (pmif->kauai_fcr) { | 
|  | 961 | u32 fcr = readl(pmif->kauai_fcr); | 
|  | 962 | fcr &= ~(KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE); | 
|  | 963 | writel(fcr, pmif->kauai_fcr); | 
|  | 964 | } | 
|  | 965 |  | 
|  | 966 | /* Disable the bus on older machines and the cell on kauai */ | 
|  | 967 | ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, | 
|  | 968 | 0); | 
|  | 969 |  | 
|  | 970 | return 0; | 
|  | 971 | } | 
|  | 972 |  | 
|  | 973 | /* Resume call back, should be called before the child devices | 
|  | 974 | * are resumed | 
|  | 975 | */ | 
|  | 976 | static int | 
|  | 977 | pmac_ide_do_resume(ide_hwif_t *hwif) | 
|  | 978 | { | 
|  | 979 | pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data; | 
|  | 980 |  | 
|  | 981 | /* Hard reset & re-enable controller (do we really need to reset ? -BenH) */ | 
|  | 982 | if (!pmif->mediabay) { | 
|  | 983 | ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 1); | 
|  | 984 | ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1); | 
|  | 985 | msleep(10); | 
|  | 986 | ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 987 |  | 
|  | 988 | /* Kauai has it different */ | 
|  | 989 | if (pmif->kauai_fcr) { | 
|  | 990 | u32 fcr = readl(pmif->kauai_fcr); | 
|  | 991 | fcr |= KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE; | 
|  | 992 | writel(fcr, pmif->kauai_fcr); | 
|  | 993 | } | 
| Benjamin Herrenschmidt | 616299a | 2005-05-01 08:58:41 -0700 | [diff] [blame] | 994 |  | 
|  | 995 | msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 996 | } | 
|  | 997 |  | 
|  | 998 | /* Sanitize drive timings */ | 
|  | 999 | sanitize_timings(pmif); | 
|  | 1000 |  | 
| Benjamin Herrenschmidt | 616299a | 2005-05-01 08:58:41 -0700 | [diff] [blame] | 1001 | enable_irq(pmif->irq); | 
|  | 1002 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1003 | return 0; | 
|  | 1004 | } | 
|  | 1005 |  | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1006 | static const struct ide_port_info pmac_port_info = { | 
|  | 1007 | .chipset		= ide_pmac, | 
|  | 1008 | .host_flags		= IDE_HFLAG_SET_PIO_MODE_KEEP_DMA | | 
|  | 1009 | IDE_HFLAG_PIO_NO_DOWNGRADE | | 
|  | 1010 | IDE_HFLAG_POST_SET_MODE | | 
|  | 1011 | IDE_HFLAG_NO_DMA | /* no SFF-style DMA */ | 
|  | 1012 | IDE_HFLAG_UNMASK_IRQS, | 
|  | 1013 | .pio_mask		= ATA_PIO4, | 
|  | 1014 | .mwdma_mask		= ATA_MWDMA2, | 
|  | 1015 | }; | 
|  | 1016 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1017 | /* | 
|  | 1018 | * Setup, register & probe an IDE channel driven by this driver, this is | 
|  | 1019 | * called by one of the 2 probe functions (macio or PCI). Note that a channel | 
|  | 1020 | * that ends up beeing free of any device is not kept around by this driver | 
|  | 1021 | * (it is kept in 2.4). This introduce an interface numbering change on some | 
|  | 1022 | * rare machines unfortunately, but it's better this way. | 
|  | 1023 | */ | 
| Adrian Bunk | 468e468 | 2008-02-01 23:09:16 +0100 | [diff] [blame] | 1024 | static int __devinit | 
| Bartlomiej Zolnierkiewicz | 57c802e | 2008-01-26 20:13:05 +0100 | [diff] [blame] | 1025 | pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1026 | { | 
|  | 1027 | struct device_node *np = pmif->node; | 
| Jeremy Kerr | 018a3d1 | 2006-07-12 15:40:29 +1000 | [diff] [blame] | 1028 | const int *bidp; | 
| Bartlomiej Zolnierkiewicz | 8447d9d | 2007-10-20 00:32:31 +0200 | [diff] [blame] | 1029 | u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1030 | struct ide_port_info d = pmac_port_info; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1031 |  | 
|  | 1032 | pmif->cable_80 = 0; | 
|  | 1033 | pmif->broken_dma = pmif->broken_dma_warn = 0; | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1034 | if (of_device_is_compatible(np, "shasta-ata")) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1035 | pmif->kind = controller_sh_ata6; | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1036 | d.udma_mask = ATA_UDMA6; | 
|  | 1037 | } else if (of_device_is_compatible(np, "kauai-ata")) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1038 | pmif->kind = controller_un_ata6; | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1039 | d.udma_mask = ATA_UDMA5; | 
|  | 1040 | } else if (of_device_is_compatible(np, "K2-UATA")) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1041 | pmif->kind = controller_k2_ata6; | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1042 | d.udma_mask = ATA_UDMA5; | 
|  | 1043 | } else if (of_device_is_compatible(np, "keylargo-ata")) { | 
|  | 1044 | if (strcmp(np->name, "ata-4") == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1045 | pmif->kind = controller_kl_ata4; | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1046 | d.udma_mask = ATA_UDMA4; | 
|  | 1047 | } else | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1048 | pmif->kind = controller_kl_ata3; | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1049 | } else if (of_device_is_compatible(np, "heathrow-ata")) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1050 | pmif->kind = controller_heathrow; | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1051 | } else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1052 | pmif->kind = controller_ohare; | 
|  | 1053 | pmif->broken_dma = 1; | 
|  | 1054 | } | 
|  | 1055 |  | 
| Stephen Rothwell | 40cd3a4 | 2007-05-01 13:54:02 +1000 | [diff] [blame] | 1056 | bidp = of_get_property(np, "AAPL,bus-id", NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1057 | pmif->aapl_bus_id =  bidp ? *bidp : 0; | 
|  | 1058 |  | 
|  | 1059 | /* Get cable type from device-tree */ | 
|  | 1060 | if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6 | 
|  | 1061 | || pmif->kind == controller_k2_ata6 | 
|  | 1062 | || pmif->kind == controller_sh_ata6) { | 
| Stephen Rothwell | 40cd3a4 | 2007-05-01 13:54:02 +1000 | [diff] [blame] | 1063 | const char* cable = of_get_property(np, "cable-type", NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1064 | if (cable && !strncmp(cable, "80-", 3)) | 
|  | 1065 | pmif->cable_80 = 1; | 
|  | 1066 | } | 
|  | 1067 | /* G5's seem to have incorrect cable type in device-tree. Let's assume | 
|  | 1068 | * they have a 80 conductor cable, this seem to be always the case unless | 
|  | 1069 | * the user mucked around | 
|  | 1070 | */ | 
| Stephen Rothwell | 55b61fe | 2007-05-03 17:26:52 +1000 | [diff] [blame] | 1071 | if (of_device_is_compatible(np, "K2-UATA") || | 
|  | 1072 | of_device_is_compatible(np, "shasta-ata")) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1073 | pmif->cable_80 = 1; | 
|  | 1074 |  | 
|  | 1075 | /* On Kauai-type controllers, we make sure the FCR is correct */ | 
|  | 1076 | if (pmif->kauai_fcr) | 
|  | 1077 | writel(KAUAI_FCR_UATA_MAGIC | | 
|  | 1078 | KAUAI_FCR_UATA_RESET_N | | 
|  | 1079 | KAUAI_FCR_UATA_ENABLE, pmif->kauai_fcr); | 
|  | 1080 |  | 
|  | 1081 | pmif->mediabay = 0; | 
|  | 1082 |  | 
|  | 1083 | /* Make sure we have sane timings */ | 
|  | 1084 | sanitize_timings(pmif); | 
|  | 1085 |  | 
|  | 1086 | #ifndef CONFIG_PPC64 | 
|  | 1087 | /* XXX FIXME: Media bay stuff need re-organizing */ | 
|  | 1088 | if (np->parent && np->parent->name | 
|  | 1089 | && strcasecmp(np->parent->name, "media-bay") == 0) { | 
| Benjamin Herrenschmidt | 8c87093 | 2005-06-27 14:36:34 -0700 | [diff] [blame] | 1090 | #ifdef CONFIG_PMAC_MEDIABAY | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1091 | media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq, hwif->index); | 
| Benjamin Herrenschmidt | 8c87093 | 2005-06-27 14:36:34 -0700 | [diff] [blame] | 1092 | #endif /* CONFIG_PMAC_MEDIABAY */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1093 | pmif->mediabay = 1; | 
|  | 1094 | if (!bidp) | 
|  | 1095 | pmif->aapl_bus_id = 1; | 
|  | 1096 | } else if (pmif->kind == controller_ohare) { | 
|  | 1097 | /* The code below is having trouble on some ohare machines | 
|  | 1098 | * (timing related ?). Until I can put my hand on one of these | 
|  | 1099 | * units, I keep the old way | 
|  | 1100 | */ | 
|  | 1101 | ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1); | 
|  | 1102 | } else | 
|  | 1103 | #endif | 
|  | 1104 | { | 
|  | 1105 | /* This is necessary to enable IDE when net-booting */ | 
|  | 1106 | ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1); | 
|  | 1107 | ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1); | 
|  | 1108 | msleep(10); | 
|  | 1109 | ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0); | 
|  | 1110 | msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY)); | 
|  | 1111 | } | 
|  | 1112 |  | 
|  | 1113 | /* Setup MMIO ops */ | 
|  | 1114 | default_hwif_mmiops(hwif); | 
|  | 1115 | hwif->OUTBSYNC = pmac_outbsync; | 
|  | 1116 |  | 
|  | 1117 | /* Tell common code _not_ to mess with resources */ | 
| Bartlomiej Zolnierkiewicz | 2ad1e55 | 2007-02-17 02:40:25 +0100 | [diff] [blame] | 1118 | hwif->mmio = 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1119 | hwif->hwif_data = pmif; | 
| Bartlomiej Zolnierkiewicz | 57c802e | 2008-01-26 20:13:05 +0100 | [diff] [blame] | 1120 | ide_init_port_hw(hwif, hw); | 
|  | 1121 | hwif->noprobe = pmif->mediabay; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1122 | hwif->hold = pmif->mediabay; | 
| Bartlomiej Zolnierkiewicz | 49521f9 | 2007-07-09 23:17:58 +0200 | [diff] [blame] | 1123 | hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40; | 
| Bartlomiej Zolnierkiewicz | 26bcb87 | 2007-10-11 23:54:00 +0200 | [diff] [blame] | 1124 | hwif->set_pio_mode = pmac_ide_set_pio_mode; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1125 | if (pmif->kind == controller_un_ata6 | 
|  | 1126 | || pmif->kind == controller_k2_ata6 | 
|  | 1127 | || pmif->kind == controller_sh_ata6) | 
|  | 1128 | hwif->selectproc = pmac_ide_kauai_selectproc; | 
|  | 1129 | else | 
|  | 1130 | hwif->selectproc = pmac_ide_selectproc; | 
| Bartlomiej Zolnierkiewicz | 88b2b32 | 2007-10-13 17:47:51 +0200 | [diff] [blame] | 1131 | hwif->set_dma_mode = pmac_ide_set_dma_mode; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1132 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1133 | printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n", | 
|  | 1134 | hwif->index, model_name[pmif->kind], pmif->aapl_bus_id, | 
|  | 1135 | pmif->mediabay ? " (mediabay)" : "", hwif->irq); | 
|  | 1136 |  | 
| Benjamin Herrenschmidt | 8c87093 | 2005-06-27 14:36:34 -0700 | [diff] [blame] | 1137 | #ifdef CONFIG_PMAC_MEDIABAY | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1138 | if (pmif->mediabay && check_media_bay_by_base(pmif->regbase, MB_CD) == 0) | 
|  | 1139 | hwif->noprobe = 0; | 
| Benjamin Herrenschmidt | 8c87093 | 2005-06-27 14:36:34 -0700 | [diff] [blame] | 1140 | #endif /* CONFIG_PMAC_MEDIABAY */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1141 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1142 | #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1143 | if (pmif->cable_80 == 0) | 
|  | 1144 | d.udma_mask &= ATA_UDMA2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1145 | /* has a DBDMA controller channel */ | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1146 | if (pmif->dma_regs == 0 || pmac_ide_setup_dma(pmif, hwif) < 0) | 
|  | 1147 | #endif | 
|  | 1148 | d.udma_mask = d.mwdma_mask = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1149 |  | 
| Bartlomiej Zolnierkiewicz | 8447d9d | 2007-10-20 00:32:31 +0200 | [diff] [blame] | 1150 | idx[0] = hwif->index; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1151 |  | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1152 | ide_device_add(idx, &d); | 
| Bartlomiej Zolnierkiewicz | 5cbf79c | 2007-05-10 00:01:11 +0200 | [diff] [blame] | 1153 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1154 | return 0; | 
|  | 1155 | } | 
|  | 1156 |  | 
|  | 1157 | /* | 
|  | 1158 | * Attach to a macio probed interface | 
|  | 1159 | */ | 
|  | 1160 | static int __devinit | 
| Jeff Mahoney | 5e65577 | 2005-07-06 15:44:41 -0400 | [diff] [blame] | 1161 | pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1162 | { | 
|  | 1163 | void __iomem *base; | 
|  | 1164 | unsigned long regbase; | 
|  | 1165 | int irq; | 
|  | 1166 | ide_hwif_t *hwif; | 
|  | 1167 | pmac_ide_hwif_t *pmif; | 
|  | 1168 | int i, rc; | 
| Bartlomiej Zolnierkiewicz | 57c802e | 2008-01-26 20:13:05 +0100 | [diff] [blame] | 1169 | hw_regs_t hw; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1170 |  | 
|  | 1171 | i = 0; | 
|  | 1172 | while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0 | 
|  | 1173 | || pmac_ide[i].node != NULL)) | 
|  | 1174 | ++i; | 
|  | 1175 | if (i >= MAX_HWIFS) { | 
|  | 1176 | printk(KERN_ERR "ide-pmac: MacIO interface attach with no slot\n"); | 
|  | 1177 | printk(KERN_ERR "          %s\n", mdev->ofdev.node->full_name); | 
|  | 1178 | return -ENODEV; | 
|  | 1179 | } | 
|  | 1180 |  | 
|  | 1181 | pmif = &pmac_ide[i]; | 
|  | 1182 | hwif = &ide_hwifs[i]; | 
|  | 1183 |  | 
| Benjamin Herrenschmidt | cc5d018 | 2005-12-13 18:01:21 +1100 | [diff] [blame] | 1184 | if (macio_resource_count(mdev) == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1185 | printk(KERN_WARNING "ide%d: no address for %s\n", | 
|  | 1186 | i, mdev->ofdev.node->full_name); | 
|  | 1187 | return -ENXIO; | 
|  | 1188 | } | 
|  | 1189 |  | 
|  | 1190 | /* Request memory resource for IO ports */ | 
|  | 1191 | if (macio_request_resource(mdev, 0, "ide-pmac (ports)")) { | 
|  | 1192 | printk(KERN_ERR "ide%d: can't request mmio resource !\n", i); | 
|  | 1193 | return -EBUSY; | 
|  | 1194 | } | 
|  | 1195 |  | 
|  | 1196 | /* XXX This is bogus. Should be fixed in the registry by checking | 
|  | 1197 | * the kind of host interrupt controller, a bit like gatwick | 
|  | 1198 | * fixes in irq.c. That works well enough for the single case | 
|  | 1199 | * where that happens though... | 
|  | 1200 | */ | 
|  | 1201 | if (macio_irq_count(mdev) == 0) { | 
|  | 1202 | printk(KERN_WARNING "ide%d: no intrs for device %s, using 13\n", | 
|  | 1203 | i, mdev->ofdev.node->full_name); | 
| Benjamin Herrenschmidt | 69917c2 | 2006-09-22 12:56:30 +1000 | [diff] [blame] | 1204 | irq = irq_create_mapping(NULL, 13); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1205 | } else | 
|  | 1206 | irq = macio_irq(mdev, 0); | 
|  | 1207 |  | 
|  | 1208 | base = ioremap(macio_resource_start(mdev, 0), 0x400); | 
|  | 1209 | regbase = (unsigned long) base; | 
|  | 1210 |  | 
| Bartlomiej Zolnierkiewicz | 3650165 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 1211 | hwif->dev = &mdev->bus->pdev->dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1212 |  | 
|  | 1213 | pmif->mdev = mdev; | 
|  | 1214 | pmif->node = mdev->ofdev.node; | 
|  | 1215 | pmif->regbase = regbase; | 
|  | 1216 | pmif->irq = irq; | 
|  | 1217 | pmif->kauai_fcr = NULL; | 
|  | 1218 | #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC | 
|  | 1219 | if (macio_resource_count(mdev) >= 2) { | 
|  | 1220 | if (macio_request_resource(mdev, 1, "ide-pmac (dma)")) | 
|  | 1221 | printk(KERN_WARNING "ide%d: can't request DMA resource !\n", i); | 
|  | 1222 | else | 
|  | 1223 | pmif->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x1000); | 
|  | 1224 | } else | 
|  | 1225 | pmif->dma_regs = NULL; | 
|  | 1226 | #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ | 
|  | 1227 | dev_set_drvdata(&mdev->ofdev.dev, hwif); | 
|  | 1228 |  | 
| Bartlomiej Zolnierkiewicz | 57c802e | 2008-01-26 20:13:05 +0100 | [diff] [blame] | 1229 | memset(&hw, 0, sizeof(hw)); | 
|  | 1230 | pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL); | 
|  | 1231 | hw.irq = irq; | 
|  | 1232 | hw.dev = &mdev->ofdev.dev; | 
|  | 1233 |  | 
|  | 1234 | rc = pmac_ide_setup_device(pmif, hwif, &hw); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1235 | if (rc != 0) { | 
|  | 1236 | /* The inteface is released to the common IDE layer */ | 
|  | 1237 | dev_set_drvdata(&mdev->ofdev.dev, NULL); | 
|  | 1238 | iounmap(base); | 
| Bartlomiej Zolnierkiewicz | ed908fa | 2008-02-01 23:09:32 +0100 | [diff] [blame] | 1239 | if (pmif->dma_regs) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1240 | iounmap(pmif->dma_regs); | 
| Bartlomiej Zolnierkiewicz | ed908fa | 2008-02-01 23:09:32 +0100 | [diff] [blame] | 1241 | macio_release_resource(mdev, 1); | 
|  | 1242 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1243 | memset(pmif, 0, sizeof(*pmif)); | 
|  | 1244 | macio_release_resource(mdev, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1245 | } | 
|  | 1246 |  | 
|  | 1247 | return rc; | 
|  | 1248 | } | 
|  | 1249 |  | 
|  | 1250 | static int | 
| David Brownell | 8b4b8a2 | 2006-08-14 23:11:03 -0700 | [diff] [blame] | 1251 | pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t mesg) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1252 | { | 
|  | 1253 | ide_hwif_t	*hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev); | 
|  | 1254 | int		rc = 0; | 
|  | 1255 |  | 
| David Brownell | 8b4b8a2 | 2006-08-14 23:11:03 -0700 | [diff] [blame] | 1256 | if (mesg.event != mdev->ofdev.dev.power.power_state.event | 
|  | 1257 | && mesg.event == PM_EVENT_SUSPEND) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1258 | rc = pmac_ide_do_suspend(hwif); | 
|  | 1259 | if (rc == 0) | 
| David Brownell | 8b4b8a2 | 2006-08-14 23:11:03 -0700 | [diff] [blame] | 1260 | mdev->ofdev.dev.power.power_state = mesg; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1261 | } | 
|  | 1262 |  | 
|  | 1263 | return rc; | 
|  | 1264 | } | 
|  | 1265 |  | 
|  | 1266 | static int | 
|  | 1267 | pmac_ide_macio_resume(struct macio_dev *mdev) | 
|  | 1268 | { | 
|  | 1269 | ide_hwif_t	*hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev); | 
|  | 1270 | int		rc = 0; | 
|  | 1271 |  | 
| Pavel Machek | ca078ba | 2005-09-03 15:56:57 -0700 | [diff] [blame] | 1272 | if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1273 | rc = pmac_ide_do_resume(hwif); | 
|  | 1274 | if (rc == 0) | 
| Pavel Machek | 829ca9a | 2005-09-03 15:56:56 -0700 | [diff] [blame] | 1275 | mdev->ofdev.dev.power.power_state = PMSG_ON; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1276 | } | 
|  | 1277 |  | 
|  | 1278 | return rc; | 
|  | 1279 | } | 
|  | 1280 |  | 
|  | 1281 | /* | 
|  | 1282 | * Attach to a PCI probed interface | 
|  | 1283 | */ | 
|  | 1284 | static int __devinit | 
|  | 1285 | pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id) | 
|  | 1286 | { | 
|  | 1287 | ide_hwif_t *hwif; | 
|  | 1288 | struct device_node *np; | 
|  | 1289 | pmac_ide_hwif_t *pmif; | 
|  | 1290 | void __iomem *base; | 
|  | 1291 | unsigned long rbase, rlen; | 
|  | 1292 | int i, rc; | 
| Bartlomiej Zolnierkiewicz | 57c802e | 2008-01-26 20:13:05 +0100 | [diff] [blame] | 1293 | hw_regs_t hw; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1294 |  | 
|  | 1295 | np = pci_device_to_OF_node(pdev); | 
|  | 1296 | if (np == NULL) { | 
|  | 1297 | printk(KERN_ERR "ide-pmac: cannot find MacIO node for Kauai ATA interface\n"); | 
|  | 1298 | return -ENODEV; | 
|  | 1299 | } | 
|  | 1300 | i = 0; | 
|  | 1301 | while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0 | 
|  | 1302 | || pmac_ide[i].node != NULL)) | 
|  | 1303 | ++i; | 
|  | 1304 | if (i >= MAX_HWIFS) { | 
|  | 1305 | printk(KERN_ERR "ide-pmac: PCI interface attach with no slot\n"); | 
|  | 1306 | printk(KERN_ERR "          %s\n", np->full_name); | 
|  | 1307 | return -ENODEV; | 
|  | 1308 | } | 
|  | 1309 |  | 
|  | 1310 | pmif = &pmac_ide[i]; | 
|  | 1311 | hwif = &ide_hwifs[i]; | 
|  | 1312 |  | 
|  | 1313 | if (pci_enable_device(pdev)) { | 
|  | 1314 | printk(KERN_WARNING "ide%i: Can't enable PCI device for %s\n", | 
|  | 1315 | i, np->full_name); | 
|  | 1316 | return -ENXIO; | 
|  | 1317 | } | 
|  | 1318 | pci_set_master(pdev); | 
|  | 1319 |  | 
|  | 1320 | if (pci_request_regions(pdev, "Kauai ATA")) { | 
|  | 1321 | printk(KERN_ERR "ide%d: Cannot obtain PCI resources for %s\n", | 
|  | 1322 | i, np->full_name); | 
|  | 1323 | return -ENXIO; | 
|  | 1324 | } | 
|  | 1325 |  | 
| Bartlomiej Zolnierkiewicz | 3650165 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 1326 | hwif->dev = &pdev->dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1327 | pmif->mdev = NULL; | 
|  | 1328 | pmif->node = np; | 
|  | 1329 |  | 
|  | 1330 | rbase = pci_resource_start(pdev, 0); | 
|  | 1331 | rlen = pci_resource_len(pdev, 0); | 
|  | 1332 |  | 
|  | 1333 | base = ioremap(rbase, rlen); | 
|  | 1334 | pmif->regbase = (unsigned long) base + 0x2000; | 
|  | 1335 | #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC | 
|  | 1336 | pmif->dma_regs = base + 0x1000; | 
|  | 1337 | #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ | 
|  | 1338 | pmif->kauai_fcr = base; | 
|  | 1339 | pmif->irq = pdev->irq; | 
|  | 1340 |  | 
|  | 1341 | pci_set_drvdata(pdev, hwif); | 
|  | 1342 |  | 
| Bartlomiej Zolnierkiewicz | 57c802e | 2008-01-26 20:13:05 +0100 | [diff] [blame] | 1343 | memset(&hw, 0, sizeof(hw)); | 
|  | 1344 | pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL); | 
|  | 1345 | hw.irq = pdev->irq; | 
|  | 1346 | hw.dev = &pdev->dev; | 
|  | 1347 |  | 
|  | 1348 | rc = pmac_ide_setup_device(pmif, hwif, &hw); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1349 | if (rc != 0) { | 
|  | 1350 | /* The inteface is released to the common IDE layer */ | 
|  | 1351 | pci_set_drvdata(pdev, NULL); | 
|  | 1352 | iounmap(base); | 
|  | 1353 | memset(pmif, 0, sizeof(*pmif)); | 
|  | 1354 | pci_release_regions(pdev); | 
|  | 1355 | } | 
|  | 1356 |  | 
|  | 1357 | return rc; | 
|  | 1358 | } | 
|  | 1359 |  | 
|  | 1360 | static int | 
| David Brownell | 8b4b8a2 | 2006-08-14 23:11:03 -0700 | [diff] [blame] | 1361 | pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1362 | { | 
|  | 1363 | ide_hwif_t	*hwif = (ide_hwif_t *)pci_get_drvdata(pdev); | 
|  | 1364 | int		rc = 0; | 
|  | 1365 |  | 
| David Brownell | 8b4b8a2 | 2006-08-14 23:11:03 -0700 | [diff] [blame] | 1366 | if (mesg.event != pdev->dev.power.power_state.event | 
|  | 1367 | && mesg.event == PM_EVENT_SUSPEND) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1368 | rc = pmac_ide_do_suspend(hwif); | 
|  | 1369 | if (rc == 0) | 
| David Brownell | 8b4b8a2 | 2006-08-14 23:11:03 -0700 | [diff] [blame] | 1370 | pdev->dev.power.power_state = mesg; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1371 | } | 
|  | 1372 |  | 
|  | 1373 | return rc; | 
|  | 1374 | } | 
|  | 1375 |  | 
|  | 1376 | static int | 
|  | 1377 | pmac_ide_pci_resume(struct pci_dev *pdev) | 
|  | 1378 | { | 
|  | 1379 | ide_hwif_t	*hwif = (ide_hwif_t *)pci_get_drvdata(pdev); | 
|  | 1380 | int		rc = 0; | 
|  | 1381 |  | 
| Pavel Machek | ca078ba | 2005-09-03 15:56:57 -0700 | [diff] [blame] | 1382 | if (pdev->dev.power.power_state.event != PM_EVENT_ON) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1383 | rc = pmac_ide_do_resume(hwif); | 
|  | 1384 | if (rc == 0) | 
| Pavel Machek | 829ca9a | 2005-09-03 15:56:56 -0700 | [diff] [blame] | 1385 | pdev->dev.power.power_state = PMSG_ON; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1386 | } | 
|  | 1387 |  | 
|  | 1388 | return rc; | 
|  | 1389 | } | 
|  | 1390 |  | 
| Jeff Mahoney | 5e65577 | 2005-07-06 15:44:41 -0400 | [diff] [blame] | 1391 | static struct of_device_id pmac_ide_macio_match[] = | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1392 | { | 
|  | 1393 | { | 
|  | 1394 | .name 		= "IDE", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1395 | }, | 
|  | 1396 | { | 
|  | 1397 | .name 		= "ATA", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1398 | }, | 
|  | 1399 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1400 | .type		= "ide", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1401 | }, | 
|  | 1402 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1403 | .type		= "ata", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1404 | }, | 
|  | 1405 | {}, | 
|  | 1406 | }; | 
|  | 1407 |  | 
|  | 1408 | static struct macio_driver pmac_ide_macio_driver = | 
|  | 1409 | { | 
|  | 1410 | .name 		= "ide-pmac", | 
|  | 1411 | .match_table	= pmac_ide_macio_match, | 
|  | 1412 | .probe		= pmac_ide_macio_attach, | 
|  | 1413 | .suspend	= pmac_ide_macio_suspend, | 
|  | 1414 | .resume		= pmac_ide_macio_resume, | 
|  | 1415 | }; | 
|  | 1416 |  | 
| Bartlomiej Zolnierkiewicz | 9cbcc5e | 2007-10-16 22:29:56 +0200 | [diff] [blame] | 1417 | static const struct pci_device_id pmac_ide_pci_match[] = { | 
|  | 1418 | { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA),	0 }, | 
|  | 1419 | { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100),	0 }, | 
|  | 1420 | { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100),	0 }, | 
|  | 1421 | { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_SH_ATA),	0 }, | 
|  | 1422 | { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA),	0 }, | 
| Benjamin Herrenschmidt | 71e4eda | 2007-10-06 18:52:27 +1000 | [diff] [blame] | 1423 | {}, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1424 | }; | 
|  | 1425 |  | 
|  | 1426 | static struct pci_driver pmac_ide_pci_driver = { | 
|  | 1427 | .name		= "ide-pmac", | 
|  | 1428 | .id_table	= pmac_ide_pci_match, | 
|  | 1429 | .probe		= pmac_ide_pci_attach, | 
|  | 1430 | .suspend	= pmac_ide_pci_suspend, | 
|  | 1431 | .resume		= pmac_ide_pci_resume, | 
|  | 1432 | }; | 
|  | 1433 | MODULE_DEVICE_TABLE(pci, pmac_ide_pci_match); | 
|  | 1434 |  | 
| Andrew Morton | 9e5755b | 2007-03-03 17:48:54 +0100 | [diff] [blame] | 1435 | int __init pmac_ide_probe(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1436 | { | 
| Andrew Morton | 9e5755b | 2007-03-03 17:48:54 +0100 | [diff] [blame] | 1437 | int error; | 
|  | 1438 |  | 
| Benjamin Herrenschmidt | e822250 | 2006-03-28 23:15:54 +1100 | [diff] [blame] | 1439 | if (!machine_is(powermac)) | 
| Andrew Morton | 9e5755b | 2007-03-03 17:48:54 +0100 | [diff] [blame] | 1440 | return -ENODEV; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1441 |  | 
|  | 1442 | #ifdef CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST | 
| Andrew Morton | 9e5755b | 2007-03-03 17:48:54 +0100 | [diff] [blame] | 1443 | error = pci_register_driver(&pmac_ide_pci_driver); | 
|  | 1444 | if (error) | 
|  | 1445 | goto out; | 
|  | 1446 | error = macio_register_driver(&pmac_ide_macio_driver); | 
|  | 1447 | if (error) { | 
|  | 1448 | pci_unregister_driver(&pmac_ide_pci_driver); | 
|  | 1449 | goto out; | 
|  | 1450 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1451 | #else | 
| Andrew Morton | 9e5755b | 2007-03-03 17:48:54 +0100 | [diff] [blame] | 1452 | error = macio_register_driver(&pmac_ide_macio_driver); | 
|  | 1453 | if (error) | 
|  | 1454 | goto out; | 
|  | 1455 | error = pci_register_driver(&pmac_ide_pci_driver); | 
|  | 1456 | if (error) { | 
|  | 1457 | macio_unregister_driver(&pmac_ide_macio_driver); | 
|  | 1458 | goto out; | 
|  | 1459 | } | 
| Benjamin Herrenschmidt | 1beb6a7 | 2005-12-14 13:10:10 +1100 | [diff] [blame] | 1460 | #endif | 
| Andrew Morton | 9e5755b | 2007-03-03 17:48:54 +0100 | [diff] [blame] | 1461 | out: | 
|  | 1462 | return error; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1463 | } | 
|  | 1464 |  | 
|  | 1465 | #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC | 
|  | 1466 |  | 
|  | 1467 | /* | 
|  | 1468 | * pmac_ide_build_dmatable builds the DBDMA command list | 
|  | 1469 | * for a transfer and sets the DBDMA channel to point to it. | 
|  | 1470 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 1471 | static int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1472 | pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq) | 
|  | 1473 | { | 
|  | 1474 | struct dbdma_cmd *table; | 
|  | 1475 | int i, count = 0; | 
|  | 1476 | ide_hwif_t *hwif = HWIF(drive); | 
|  | 1477 | pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; | 
|  | 1478 | volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; | 
|  | 1479 | struct scatterlist *sg; | 
|  | 1480 | int wr = (rq_data_dir(rq) == WRITE); | 
|  | 1481 |  | 
|  | 1482 | /* DMA table is already aligned */ | 
|  | 1483 | table = (struct dbdma_cmd *) pmif->dma_table_cpu; | 
|  | 1484 |  | 
|  | 1485 | /* Make sure DMA controller is stopped (necessary ?) */ | 
|  | 1486 | writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma->control); | 
|  | 1487 | while (readl(&dma->status) & RUN) | 
|  | 1488 | udelay(1); | 
|  | 1489 |  | 
|  | 1490 | hwif->sg_nents = i = ide_build_sglist(drive, rq); | 
|  | 1491 |  | 
|  | 1492 | if (!i) | 
|  | 1493 | return 0; | 
|  | 1494 |  | 
|  | 1495 | /* Build DBDMA commands list */ | 
|  | 1496 | sg = hwif->sg_table; | 
|  | 1497 | while (i && sg_dma_len(sg)) { | 
|  | 1498 | u32 cur_addr; | 
|  | 1499 | u32 cur_len; | 
|  | 1500 |  | 
|  | 1501 | cur_addr = sg_dma_address(sg); | 
|  | 1502 | cur_len = sg_dma_len(sg); | 
|  | 1503 |  | 
|  | 1504 | if (pmif->broken_dma && cur_addr & (L1_CACHE_BYTES - 1)) { | 
|  | 1505 | if (pmif->broken_dma_warn == 0) { | 
| Joe Perches | aca38a5 | 2007-11-27 21:35:55 +0100 | [diff] [blame] | 1506 | printk(KERN_WARNING "%s: DMA on non aligned address, " | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1507 | "switching to PIO on Ohare chipset\n", drive->name); | 
|  | 1508 | pmif->broken_dma_warn = 1; | 
|  | 1509 | } | 
|  | 1510 | goto use_pio_instead; | 
|  | 1511 | } | 
|  | 1512 | while (cur_len) { | 
|  | 1513 | unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00; | 
|  | 1514 |  | 
|  | 1515 | if (count++ >= MAX_DCMDS) { | 
|  | 1516 | printk(KERN_WARNING "%s: DMA table too small\n", | 
|  | 1517 | drive->name); | 
|  | 1518 | goto use_pio_instead; | 
|  | 1519 | } | 
|  | 1520 | st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE); | 
|  | 1521 | st_le16(&table->req_count, tc); | 
|  | 1522 | st_le32(&table->phy_addr, cur_addr); | 
|  | 1523 | table->cmd_dep = 0; | 
|  | 1524 | table->xfer_status = 0; | 
|  | 1525 | table->res_count = 0; | 
|  | 1526 | cur_addr += tc; | 
|  | 1527 | cur_len -= tc; | 
|  | 1528 | ++table; | 
|  | 1529 | } | 
| Jens Axboe | 55c16a7 | 2007-07-25 08:13:56 +0200 | [diff] [blame] | 1530 | sg = sg_next(sg); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1531 | i--; | 
|  | 1532 | } | 
|  | 1533 |  | 
|  | 1534 | /* convert the last command to an input/output last command */ | 
|  | 1535 | if (count) { | 
|  | 1536 | st_le16(&table[-1].command, wr? OUTPUT_LAST: INPUT_LAST); | 
|  | 1537 | /* add the stop command to the end of the list */ | 
|  | 1538 | memset(table, 0, sizeof(struct dbdma_cmd)); | 
|  | 1539 | st_le16(&table->command, DBDMA_STOP); | 
|  | 1540 | mb(); | 
|  | 1541 | writel(hwif->dmatable_dma, &dma->cmdptr); | 
|  | 1542 | return 1; | 
|  | 1543 | } | 
|  | 1544 |  | 
|  | 1545 | printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name); | 
| Bartlomiej Zolnierkiewicz | f6fb786 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 1546 |  | 
|  | 1547 | use_pio_instead: | 
|  | 1548 | ide_destroy_dmatable(drive); | 
|  | 1549 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1550 | return 0; /* revert to PIO for this request */ | 
|  | 1551 | } | 
|  | 1552 |  | 
|  | 1553 | /* Teardown mappings after DMA has completed.  */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 1554 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1555 | pmac_ide_destroy_dmatable (ide_drive_t *drive) | 
|  | 1556 | { | 
|  | 1557 | ide_hwif_t *hwif = drive->hwif; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1558 |  | 
| Bartlomiej Zolnierkiewicz | f6fb786 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 1559 | if (hwif->sg_nents) { | 
|  | 1560 | ide_destroy_dmatable(drive); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1561 | hwif->sg_nents = 0; | 
|  | 1562 | } | 
|  | 1563 | } | 
|  | 1564 |  | 
|  | 1565 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1566 | * Prepare a DMA transfer. We build the DMA table, adjust the timings for | 
|  | 1567 | * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion | 
|  | 1568 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 1569 | static int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1570 | pmac_ide_dma_setup(ide_drive_t *drive) | 
|  | 1571 | { | 
|  | 1572 | ide_hwif_t *hwif = HWIF(drive); | 
|  | 1573 | pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; | 
|  | 1574 | struct request *rq = HWGROUP(drive)->rq; | 
|  | 1575 | u8 unit = (drive->select.b.unit & 0x01); | 
|  | 1576 | u8 ata4; | 
|  | 1577 |  | 
|  | 1578 | if (pmif == NULL) | 
|  | 1579 | return 1; | 
|  | 1580 | ata4 = (pmif->kind == controller_kl_ata4); | 
|  | 1581 |  | 
|  | 1582 | if (!pmac_ide_build_dmatable(drive, rq)) { | 
|  | 1583 | ide_map_sg(drive, rq); | 
|  | 1584 | return 1; | 
|  | 1585 | } | 
|  | 1586 |  | 
|  | 1587 | /* Apple adds 60ns to wrDataSetup on reads */ | 
|  | 1588 | if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) { | 
|  | 1589 | writel(pmif->timings[unit] + (!rq_data_dir(rq) ? 0x00800000UL : 0), | 
|  | 1590 | PMAC_IDE_REG(IDE_TIMING_CONFIG)); | 
|  | 1591 | (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); | 
|  | 1592 | } | 
|  | 1593 |  | 
|  | 1594 | drive->waiting_for_dma = 1; | 
|  | 1595 |  | 
|  | 1596 | return 0; | 
|  | 1597 | } | 
|  | 1598 |  | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 1599 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1600 | pmac_ide_dma_exec_cmd(ide_drive_t *drive, u8 command) | 
|  | 1601 | { | 
|  | 1602 | /* issue cmd to drive */ | 
|  | 1603 | ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, NULL); | 
|  | 1604 | } | 
|  | 1605 |  | 
|  | 1606 | /* | 
|  | 1607 | * Kick the DMA controller into life after the DMA command has been issued | 
|  | 1608 | * to the drive. | 
|  | 1609 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 1610 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1611 | pmac_ide_dma_start(ide_drive_t *drive) | 
|  | 1612 | { | 
|  | 1613 | pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; | 
|  | 1614 | volatile struct dbdma_regs __iomem *dma; | 
|  | 1615 |  | 
|  | 1616 | dma = pmif->dma_regs; | 
|  | 1617 |  | 
|  | 1618 | writel((RUN << 16) | RUN, &dma->control); | 
|  | 1619 | /* Make sure it gets to the controller right now */ | 
|  | 1620 | (void)readl(&dma->control); | 
|  | 1621 | } | 
|  | 1622 |  | 
|  | 1623 | /* | 
|  | 1624 | * After a DMA transfer, make sure the controller is stopped | 
|  | 1625 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 1626 | static int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1627 | pmac_ide_dma_end (ide_drive_t *drive) | 
|  | 1628 | { | 
|  | 1629 | pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; | 
|  | 1630 | volatile struct dbdma_regs __iomem *dma; | 
|  | 1631 | u32 dstat; | 
|  | 1632 |  | 
|  | 1633 | if (pmif == NULL) | 
|  | 1634 | return 0; | 
|  | 1635 | dma = pmif->dma_regs; | 
|  | 1636 |  | 
|  | 1637 | drive->waiting_for_dma = 0; | 
|  | 1638 | dstat = readl(&dma->status); | 
|  | 1639 | writel(((RUN|WAKE|DEAD) << 16), &dma->control); | 
|  | 1640 | pmac_ide_destroy_dmatable(drive); | 
|  | 1641 | /* verify good dma status. we don't check for ACTIVE beeing 0. We should... | 
|  | 1642 | * in theory, but with ATAPI decices doing buffer underruns, that would | 
|  | 1643 | * cause us to disable DMA, which isn't what we want | 
|  | 1644 | */ | 
|  | 1645 | return (dstat & (RUN|DEAD)) != RUN; | 
|  | 1646 | } | 
|  | 1647 |  | 
|  | 1648 | /* | 
|  | 1649 | * Check out that the interrupt we got was for us. We can't always know this | 
|  | 1650 | * for sure with those Apple interfaces (well, we could on the recent ones but | 
|  | 1651 | * that's not implemented yet), on the other hand, we don't have shared interrupts | 
|  | 1652 | * so it's not really a problem | 
|  | 1653 | */ | 
| Jon Loeliger | aacaf9b | 2005-09-17 10:36:54 -0500 | [diff] [blame] | 1654 | static int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1655 | pmac_ide_dma_test_irq (ide_drive_t *drive) | 
|  | 1656 | { | 
|  | 1657 | pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; | 
|  | 1658 | volatile struct dbdma_regs __iomem *dma; | 
|  | 1659 | unsigned long status, timeout; | 
|  | 1660 |  | 
|  | 1661 | if (pmif == NULL) | 
|  | 1662 | return 0; | 
|  | 1663 | dma = pmif->dma_regs; | 
|  | 1664 |  | 
|  | 1665 | /* We have to things to deal with here: | 
|  | 1666 | * | 
|  | 1667 | * - The dbdma won't stop if the command was started | 
|  | 1668 | * but completed with an error without transferring all | 
|  | 1669 | * datas. This happens when bad blocks are met during | 
|  | 1670 | * a multi-block transfer. | 
|  | 1671 | * | 
|  | 1672 | * - The dbdma fifo hasn't yet finished flushing to | 
|  | 1673 | * to system memory when the disk interrupt occurs. | 
|  | 1674 | * | 
|  | 1675 | */ | 
|  | 1676 |  | 
|  | 1677 | /* If ACTIVE is cleared, the STOP command have passed and | 
|  | 1678 | * transfer is complete. | 
|  | 1679 | */ | 
|  | 1680 | status = readl(&dma->status); | 
|  | 1681 | if (!(status & ACTIVE)) | 
|  | 1682 | return 1; | 
|  | 1683 | if (!drive->waiting_for_dma) | 
|  | 1684 | printk(KERN_WARNING "ide%d, ide_dma_test_irq \ | 
|  | 1685 | called while not waiting\n", HWIF(drive)->index); | 
|  | 1686 |  | 
|  | 1687 | /* If dbdma didn't execute the STOP command yet, the | 
|  | 1688 | * active bit is still set. We consider that we aren't | 
|  | 1689 | * sharing interrupts (which is hopefully the case with | 
|  | 1690 | * those controllers) and so we just try to flush the | 
|  | 1691 | * channel for pending data in the fifo | 
|  | 1692 | */ | 
|  | 1693 | udelay(1); | 
|  | 1694 | writel((FLUSH << 16) | FLUSH, &dma->control); | 
|  | 1695 | timeout = 0; | 
|  | 1696 | for (;;) { | 
|  | 1697 | udelay(1); | 
|  | 1698 | status = readl(&dma->status); | 
|  | 1699 | if ((status & FLUSH) == 0) | 
|  | 1700 | break; | 
|  | 1701 | if (++timeout > 100) { | 
|  | 1702 | printk(KERN_WARNING "ide%d, ide_dma_test_irq \ | 
|  | 1703 | timeout flushing channel\n", HWIF(drive)->index); | 
|  | 1704 | break; | 
|  | 1705 | } | 
|  | 1706 | } | 
|  | 1707 | return 1; | 
|  | 1708 | } | 
|  | 1709 |  | 
| Bartlomiej Zolnierkiewicz | 15ce926 | 2008-01-26 20:13:03 +0100 | [diff] [blame] | 1710 | static void pmac_ide_dma_host_set(ide_drive_t *drive, int on) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1711 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1712 | } | 
|  | 1713 |  | 
| Sergei Shtylyov | 841d2a9 | 2007-07-09 23:17:54 +0200 | [diff] [blame] | 1714 | static void | 
|  | 1715 | pmac_ide_dma_lost_irq (ide_drive_t *drive) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1716 | { | 
|  | 1717 | pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; | 
|  | 1718 | volatile struct dbdma_regs __iomem *dma; | 
|  | 1719 | unsigned long status; | 
|  | 1720 |  | 
|  | 1721 | if (pmif == NULL) | 
| Sergei Shtylyov | 841d2a9 | 2007-07-09 23:17:54 +0200 | [diff] [blame] | 1722 | return; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1723 | dma = pmif->dma_regs; | 
|  | 1724 |  | 
|  | 1725 | status = readl(&dma->status); | 
|  | 1726 | printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1727 | } | 
|  | 1728 |  | 
|  | 1729 | /* | 
|  | 1730 | * Allocate the data structures needed for using DMA with an interface | 
|  | 1731 | * and fill the proper list of functions pointers | 
|  | 1732 | */ | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1733 | static int __devinit pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1734 | { | 
| Bartlomiej Zolnierkiewicz | 3650165 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 1735 | struct pci_dev *dev = to_pci_dev(hwif->dev); | 
|  | 1736 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1737 | /* We won't need pci_dev if we switch to generic consistent | 
|  | 1738 | * DMA routines ... | 
|  | 1739 | */ | 
| Bartlomiej Zolnierkiewicz | 3650165 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 1740 | if (dev == NULL) | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1741 | return -ENODEV; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1742 | /* | 
|  | 1743 | * Allocate space for the DBDMA commands. | 
|  | 1744 | * The +2 is +1 for the stop command and +1 to allow for | 
|  | 1745 | * aligning the start address to a multiple of 16 bytes. | 
|  | 1746 | */ | 
|  | 1747 | pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent( | 
| Bartlomiej Zolnierkiewicz | 3650165 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 1748 | dev, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1749 | (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), | 
|  | 1750 | &hwif->dmatable_dma); | 
|  | 1751 | if (pmif->dma_table_cpu == NULL) { | 
|  | 1752 | printk(KERN_ERR "%s: unable to allocate DMA command list\n", | 
|  | 1753 | hwif->name); | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1754 | return -ENOMEM; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1755 | } | 
|  | 1756 |  | 
| Bartlomiej Zolnierkiewicz | 4f52a32 | 2008-01-26 20:13:08 +0100 | [diff] [blame] | 1757 | hwif->sg_max_nents = MAX_DCMDS; | 
|  | 1758 |  | 
| Bartlomiej Zolnierkiewicz | 15ce926 | 2008-01-26 20:13:03 +0100 | [diff] [blame] | 1759 | hwif->dma_host_set = &pmac_ide_dma_host_set; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1760 | hwif->dma_setup = &pmac_ide_dma_setup; | 
|  | 1761 | hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd; | 
|  | 1762 | hwif->dma_start = &pmac_ide_dma_start; | 
|  | 1763 | hwif->ide_dma_end = &pmac_ide_dma_end; | 
|  | 1764 | hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq; | 
| Sergei Shtylyov | c283f5d | 2007-07-09 23:17:54 +0200 | [diff] [blame] | 1765 | hwif->dma_timeout = &ide_dma_timeout; | 
| Sergei Shtylyov | 841d2a9 | 2007-07-09 23:17:54 +0200 | [diff] [blame] | 1766 | hwif->dma_lost_irq = &pmac_ide_dma_lost_irq; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1767 |  | 
| Bartlomiej Zolnierkiewicz | c413b9b | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 1768 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1769 | } | 
|  | 1770 |  | 
|  | 1771 | #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ | 
| Bartlomiej Zolnierkiewicz | ade2daf | 2008-01-26 20:13:07 +0100 | [diff] [blame] | 1772 |  | 
|  | 1773 | module_init(pmac_ide_probe); |