18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Support for IDE interfaces on PowerMacs. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * These IDE interfaces are memory-mapped and have a DBDMA channel 68c2ecf20Sopenharmony_ci * for doing DMA. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 1998-2003 Paul Mackerras & Ben. Herrenschmidt 98c2ecf20Sopenharmony_ci * Copyright (C) 2007-2008 Bartlomiej Zolnierkiewicz 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Some code taken from drivers/ide/ide-dma.c: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Copyright (c) 1995-1998 Mark Lord 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * TODO: - Use pre-calculated (kauai) timing tables all the time and 168c2ecf20Sopenharmony_ci * get rid of the "rounded" tables used previously, so we have the 178c2ecf20Sopenharmony_ci * same table format for all controllers and can then just have one 188c2ecf20Sopenharmony_ci * big table 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci#include <linux/types.h> 218c2ecf20Sopenharmony_ci#include <linux/kernel.h> 228c2ecf20Sopenharmony_ci#include <linux/init.h> 238c2ecf20Sopenharmony_ci#include <linux/delay.h> 248c2ecf20Sopenharmony_ci#include <linux/ide.h> 258c2ecf20Sopenharmony_ci#include <linux/notifier.h> 268c2ecf20Sopenharmony_ci#include <linux/module.h> 278c2ecf20Sopenharmony_ci#include <linux/reboot.h> 288c2ecf20Sopenharmony_ci#include <linux/pci.h> 298c2ecf20Sopenharmony_ci#include <linux/adb.h> 308c2ecf20Sopenharmony_ci#include <linux/pmu.h> 318c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 328c2ecf20Sopenharmony_ci#include <linux/slab.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <asm/prom.h> 358c2ecf20Sopenharmony_ci#include <asm/io.h> 368c2ecf20Sopenharmony_ci#include <asm/dbdma.h> 378c2ecf20Sopenharmony_ci#include <asm/ide.h> 388c2ecf20Sopenharmony_ci#include <asm/machdep.h> 398c2ecf20Sopenharmony_ci#include <asm/pmac_feature.h> 408c2ecf20Sopenharmony_ci#include <asm/sections.h> 418c2ecf20Sopenharmony_ci#include <asm/irq.h> 428c2ecf20Sopenharmony_ci#include <asm/mediabay.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define DRV_NAME "ide-pmac" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#undef IDE_PMAC_DEBUG 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define DMA_WAIT_TIMEOUT 50 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_citypedef struct pmac_ide_hwif { 518c2ecf20Sopenharmony_ci unsigned long regbase; 528c2ecf20Sopenharmony_ci int irq; 538c2ecf20Sopenharmony_ci int kind; 548c2ecf20Sopenharmony_ci int aapl_bus_id; 558c2ecf20Sopenharmony_ci unsigned broken_dma : 1; 568c2ecf20Sopenharmony_ci unsigned broken_dma_warn : 1; 578c2ecf20Sopenharmony_ci struct device_node* node; 588c2ecf20Sopenharmony_ci struct macio_dev *mdev; 598c2ecf20Sopenharmony_ci u32 timings[4]; 608c2ecf20Sopenharmony_ci volatile u32 __iomem * *kauai_fcr; 618c2ecf20Sopenharmony_ci ide_hwif_t *hwif; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* Those fields are duplicating what is in hwif. We currently 648c2ecf20Sopenharmony_ci * can't use the hwif ones because of some assumptions that are 658c2ecf20Sopenharmony_ci * beeing done by the generic code about the kind of dma controller 668c2ecf20Sopenharmony_ci * and format of the dma table. This will have to be fixed though. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem * dma_regs; 698c2ecf20Sopenharmony_ci struct dbdma_cmd* dma_table_cpu; 708c2ecf20Sopenharmony_ci} pmac_ide_hwif_t; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cienum { 738c2ecf20Sopenharmony_ci controller_ohare, /* OHare based */ 748c2ecf20Sopenharmony_ci controller_heathrow, /* Heathrow/Paddington */ 758c2ecf20Sopenharmony_ci controller_kl_ata3, /* KeyLargo ATA-3 */ 768c2ecf20Sopenharmony_ci controller_kl_ata4, /* KeyLargo ATA-4 */ 778c2ecf20Sopenharmony_ci controller_un_ata6, /* UniNorth2 ATA-6 */ 788c2ecf20Sopenharmony_ci controller_k2_ata6, /* K2 ATA-6 */ 798c2ecf20Sopenharmony_ci controller_sh_ata6, /* Shasta ATA-6 */ 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic const char* model_name[] = { 838c2ecf20Sopenharmony_ci "OHare ATA", /* OHare based */ 848c2ecf20Sopenharmony_ci "Heathrow ATA", /* Heathrow/Paddington */ 858c2ecf20Sopenharmony_ci "KeyLargo ATA-3", /* KeyLargo ATA-3 (MDMA only) */ 868c2ecf20Sopenharmony_ci "KeyLargo ATA-4", /* KeyLargo ATA-4 (UDMA/66) */ 878c2ecf20Sopenharmony_ci "UniNorth ATA-6", /* UniNorth2 ATA-6 (UDMA/100) */ 888c2ecf20Sopenharmony_ci "K2 ATA-6", /* K2 ATA-6 (UDMA/100) */ 898c2ecf20Sopenharmony_ci "Shasta ATA-6", /* Shasta ATA-6 (UDMA/133) */ 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* 938c2ecf20Sopenharmony_ci * Extra registers, both 32-bit little-endian 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci#define IDE_TIMING_CONFIG 0x200 968c2ecf20Sopenharmony_ci#define IDE_INTERRUPT 0x300 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* Kauai (U2) ATA has different register setup */ 998c2ecf20Sopenharmony_ci#define IDE_KAUAI_PIO_CONFIG 0x200 1008c2ecf20Sopenharmony_ci#define IDE_KAUAI_ULTRA_CONFIG 0x210 1018c2ecf20Sopenharmony_ci#define IDE_KAUAI_POLL_CONFIG 0x220 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* 1048c2ecf20Sopenharmony_ci * Timing configuration register definitions 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */ 1088c2ecf20Sopenharmony_ci#define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS) 1098c2ecf20Sopenharmony_ci#define SYSCLK_TICKS_66(t) (((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS) 1108c2ecf20Sopenharmony_ci#define IDE_SYSCLK_NS 30 /* 33Mhz cell */ 1118c2ecf20Sopenharmony_ci#define IDE_SYSCLK_66_NS 15 /* 66Mhz cell */ 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* 133Mhz cell, found in shasta. 1148c2ecf20Sopenharmony_ci * See comments about 100 Mhz Uninorth 2... 1158c2ecf20Sopenharmony_ci * Note that PIO_MASK and MDMA_MASK seem to overlap 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci#define TR_133_PIOREG_PIO_MASK 0xff000fff 1188c2ecf20Sopenharmony_ci#define TR_133_PIOREG_MDMA_MASK 0x00fff800 1198c2ecf20Sopenharmony_ci#define TR_133_UDMAREG_UDMA_MASK 0x0003ffff 1208c2ecf20Sopenharmony_ci#define TR_133_UDMAREG_UDMA_EN 0x00000001 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* 100Mhz cell, found in Uninorth 2. I don't have much infos about 1238c2ecf20Sopenharmony_ci * this one yet, it appears as a pci device (106b/0033) on uninorth 1248c2ecf20Sopenharmony_ci * internal PCI bus and it's clock is controlled like gem or fw. It 1258c2ecf20Sopenharmony_ci * appears to be an evolution of keylargo ATA4 with a timing register 1268c2ecf20Sopenharmony_ci * extended to 2 32bits registers and a similar DBDMA channel. Other 1278c2ecf20Sopenharmony_ci * registers seem to exist but I can't tell much about them. 1288c2ecf20Sopenharmony_ci * 1298c2ecf20Sopenharmony_ci * So far, I'm using pre-calculated tables for this extracted from 1308c2ecf20Sopenharmony_ci * the values used by the MacOS X driver. 1318c2ecf20Sopenharmony_ci * 1328c2ecf20Sopenharmony_ci * The "PIO" register controls PIO and MDMA timings, the "ULTRA" 1338c2ecf20Sopenharmony_ci * register controls the UDMA timings. At least, it seems bit 0 1348c2ecf20Sopenharmony_ci * of this one enables UDMA vs. MDMA, and bits 4..7 are the 1358c2ecf20Sopenharmony_ci * cycle time in units of 10ns. Bits 8..15 are used by I don't 1368c2ecf20Sopenharmony_ci * know their meaning yet 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_ci#define TR_100_PIOREG_PIO_MASK 0xff000fff 1398c2ecf20Sopenharmony_ci#define TR_100_PIOREG_MDMA_MASK 0x00fff000 1408c2ecf20Sopenharmony_ci#define TR_100_UDMAREG_UDMA_MASK 0x0000ffff 1418c2ecf20Sopenharmony_ci#define TR_100_UDMAREG_UDMA_EN 0x00000001 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on 1458c2ecf20Sopenharmony_ci * 40 connector cable and to 4 on 80 connector one. 1468c2ecf20Sopenharmony_ci * Clock unit is 15ns (66Mhz) 1478c2ecf20Sopenharmony_ci * 1488c2ecf20Sopenharmony_ci * 3 Values can be programmed: 1498c2ecf20Sopenharmony_ci * - Write data setup, which appears to match the cycle time. They 1508c2ecf20Sopenharmony_ci * also call it DIOW setup. 1518c2ecf20Sopenharmony_ci * - Ready to pause time (from spec) 1528c2ecf20Sopenharmony_ci * - Address setup. That one is weird. I don't see where exactly 1538c2ecf20Sopenharmony_ci * it fits in UDMA cycles, I got it's name from an obscure piece 1548c2ecf20Sopenharmony_ci * of commented out code in Darwin. They leave it to 0, we do as 1558c2ecf20Sopenharmony_ci * well, despite a comment that would lead to think it has a 1568c2ecf20Sopenharmony_ci * min value of 45ns. 1578c2ecf20Sopenharmony_ci * Apple also add 60ns to the write data setup (or cycle time ?) on 1588c2ecf20Sopenharmony_ci * reads. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ci#define TR_66_UDMA_MASK 0xfff00000 1618c2ecf20Sopenharmony_ci#define TR_66_UDMA_EN 0x00100000 /* Enable Ultra mode for DMA */ 1628c2ecf20Sopenharmony_ci#define TR_66_UDMA_ADDRSETUP_MASK 0xe0000000 /* Address setup */ 1638c2ecf20Sopenharmony_ci#define TR_66_UDMA_ADDRSETUP_SHIFT 29 1648c2ecf20Sopenharmony_ci#define TR_66_UDMA_RDY2PAUS_MASK 0x1e000000 /* Ready 2 pause time */ 1658c2ecf20Sopenharmony_ci#define TR_66_UDMA_RDY2PAUS_SHIFT 25 1668c2ecf20Sopenharmony_ci#define TR_66_UDMA_WRDATASETUP_MASK 0x01e00000 /* Write data setup time */ 1678c2ecf20Sopenharmony_ci#define TR_66_UDMA_WRDATASETUP_SHIFT 21 1688c2ecf20Sopenharmony_ci#define TR_66_MDMA_MASK 0x000ffc00 1698c2ecf20Sopenharmony_ci#define TR_66_MDMA_RECOVERY_MASK 0x000f8000 1708c2ecf20Sopenharmony_ci#define TR_66_MDMA_RECOVERY_SHIFT 15 1718c2ecf20Sopenharmony_ci#define TR_66_MDMA_ACCESS_MASK 0x00007c00 1728c2ecf20Sopenharmony_ci#define TR_66_MDMA_ACCESS_SHIFT 10 1738c2ecf20Sopenharmony_ci#define TR_66_PIO_MASK 0x000003ff 1748c2ecf20Sopenharmony_ci#define TR_66_PIO_RECOVERY_MASK 0x000003e0 1758c2ecf20Sopenharmony_ci#define TR_66_PIO_RECOVERY_SHIFT 5 1768c2ecf20Sopenharmony_ci#define TR_66_PIO_ACCESS_MASK 0x0000001f 1778c2ecf20Sopenharmony_ci#define TR_66_PIO_ACCESS_SHIFT 0 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo 1808c2ecf20Sopenharmony_ci * Can do pio & mdma modes, clock unit is 30ns (33Mhz) 1818c2ecf20Sopenharmony_ci * 1828c2ecf20Sopenharmony_ci * The access time and recovery time can be programmed. Some older 1838c2ecf20Sopenharmony_ci * Darwin code base limit OHare to 150ns cycle time. I decided to do 1848c2ecf20Sopenharmony_ci * the same here fore safety against broken old hardware ;) 1858c2ecf20Sopenharmony_ci * The HalfTick bit, when set, adds half a clock (15ns) to the access 1868c2ecf20Sopenharmony_ci * time and removes one from recovery. It's not supported on KeyLargo 1878c2ecf20Sopenharmony_ci * implementation afaik. The E bit appears to be set for PIO mode 0 and 1888c2ecf20Sopenharmony_ci * is used to reach long timings used in this mode. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ci#define TR_33_MDMA_MASK 0x003ff800 1918c2ecf20Sopenharmony_ci#define TR_33_MDMA_RECOVERY_MASK 0x001f0000 1928c2ecf20Sopenharmony_ci#define TR_33_MDMA_RECOVERY_SHIFT 16 1938c2ecf20Sopenharmony_ci#define TR_33_MDMA_ACCESS_MASK 0x0000f800 1948c2ecf20Sopenharmony_ci#define TR_33_MDMA_ACCESS_SHIFT 11 1958c2ecf20Sopenharmony_ci#define TR_33_MDMA_HALFTICK 0x00200000 1968c2ecf20Sopenharmony_ci#define TR_33_PIO_MASK 0x000007ff 1978c2ecf20Sopenharmony_ci#define TR_33_PIO_E 0x00000400 1988c2ecf20Sopenharmony_ci#define TR_33_PIO_RECOVERY_MASK 0x000003e0 1998c2ecf20Sopenharmony_ci#define TR_33_PIO_RECOVERY_SHIFT 5 2008c2ecf20Sopenharmony_ci#define TR_33_PIO_ACCESS_MASK 0x0000001f 2018c2ecf20Sopenharmony_ci#define TR_33_PIO_ACCESS_SHIFT 0 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/* 2048c2ecf20Sopenharmony_ci * Interrupt register definitions 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci#define IDE_INTR_DMA 0x80000000 2078c2ecf20Sopenharmony_ci#define IDE_INTR_DEVICE 0x40000000 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/* 2108c2ecf20Sopenharmony_ci * FCR Register on Kauai. Not sure what bit 0x4 is ... 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_ci#define KAUAI_FCR_UATA_MAGIC 0x00000004 2138c2ecf20Sopenharmony_ci#define KAUAI_FCR_UATA_RESET_N 0x00000002 2148c2ecf20Sopenharmony_ci#define KAUAI_FCR_UATA_ENABLE 0x00000001 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* Rounded Multiword DMA timings 2178c2ecf20Sopenharmony_ci * 2188c2ecf20Sopenharmony_ci * I gave up finding a generic formula for all controller 2198c2ecf20Sopenharmony_ci * types and instead, built tables based on timing values 2208c2ecf20Sopenharmony_ci * used by Apple in Darwin's implementation. 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_cistruct mdma_timings_t { 2238c2ecf20Sopenharmony_ci int accessTime; 2248c2ecf20Sopenharmony_ci int recoveryTime; 2258c2ecf20Sopenharmony_ci int cycleTime; 2268c2ecf20Sopenharmony_ci}; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistruct mdma_timings_t mdma_timings_33[] = 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci { 240, 240, 480 }, 2318c2ecf20Sopenharmony_ci { 180, 180, 360 }, 2328c2ecf20Sopenharmony_ci { 135, 135, 270 }, 2338c2ecf20Sopenharmony_ci { 120, 120, 240 }, 2348c2ecf20Sopenharmony_ci { 105, 105, 210 }, 2358c2ecf20Sopenharmony_ci { 90, 90, 180 }, 2368c2ecf20Sopenharmony_ci { 75, 75, 150 }, 2378c2ecf20Sopenharmony_ci { 75, 45, 120 }, 2388c2ecf20Sopenharmony_ci { 0, 0, 0 } 2398c2ecf20Sopenharmony_ci}; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistruct mdma_timings_t mdma_timings_33k[] = 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci { 240, 240, 480 }, 2448c2ecf20Sopenharmony_ci { 180, 180, 360 }, 2458c2ecf20Sopenharmony_ci { 150, 150, 300 }, 2468c2ecf20Sopenharmony_ci { 120, 120, 240 }, 2478c2ecf20Sopenharmony_ci { 90, 120, 210 }, 2488c2ecf20Sopenharmony_ci { 90, 90, 180 }, 2498c2ecf20Sopenharmony_ci { 90, 60, 150 }, 2508c2ecf20Sopenharmony_ci { 90, 30, 120 }, 2518c2ecf20Sopenharmony_ci { 0, 0, 0 } 2528c2ecf20Sopenharmony_ci}; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistruct mdma_timings_t mdma_timings_66[] = 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci { 240, 240, 480 }, 2578c2ecf20Sopenharmony_ci { 180, 180, 360 }, 2588c2ecf20Sopenharmony_ci { 135, 135, 270 }, 2598c2ecf20Sopenharmony_ci { 120, 120, 240 }, 2608c2ecf20Sopenharmony_ci { 105, 105, 210 }, 2618c2ecf20Sopenharmony_ci { 90, 90, 180 }, 2628c2ecf20Sopenharmony_ci { 90, 75, 165 }, 2638c2ecf20Sopenharmony_ci { 75, 45, 120 }, 2648c2ecf20Sopenharmony_ci { 0, 0, 0 } 2658c2ecf20Sopenharmony_ci}; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* KeyLargo ATA-4 Ultra DMA timings (rounded) */ 2688c2ecf20Sopenharmony_cistruct { 2698c2ecf20Sopenharmony_ci int addrSetup; /* ??? */ 2708c2ecf20Sopenharmony_ci int rdy2pause; 2718c2ecf20Sopenharmony_ci int wrDataSetup; 2728c2ecf20Sopenharmony_ci} kl66_udma_timings[] = 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci { 0, 180, 120 }, /* Mode 0 */ 2758c2ecf20Sopenharmony_ci { 0, 150, 90 }, /* 1 */ 2768c2ecf20Sopenharmony_ci { 0, 120, 60 }, /* 2 */ 2778c2ecf20Sopenharmony_ci { 0, 90, 45 }, /* 3 */ 2788c2ecf20Sopenharmony_ci { 0, 90, 30 } /* 4 */ 2798c2ecf20Sopenharmony_ci}; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci/* UniNorth 2 ATA/100 timings */ 2828c2ecf20Sopenharmony_cistruct kauai_timing { 2838c2ecf20Sopenharmony_ci int cycle_time; 2848c2ecf20Sopenharmony_ci u32 timing_reg; 2858c2ecf20Sopenharmony_ci}; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic struct kauai_timing kauai_pio_timings[] = 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci { 930 , 0x08000fff }, 2908c2ecf20Sopenharmony_ci { 600 , 0x08000a92 }, 2918c2ecf20Sopenharmony_ci { 383 , 0x0800060f }, 2928c2ecf20Sopenharmony_ci { 360 , 0x08000492 }, 2938c2ecf20Sopenharmony_ci { 330 , 0x0800048f }, 2948c2ecf20Sopenharmony_ci { 300 , 0x080003cf }, 2958c2ecf20Sopenharmony_ci { 270 , 0x080003cc }, 2968c2ecf20Sopenharmony_ci { 240 , 0x0800038b }, 2978c2ecf20Sopenharmony_ci { 239 , 0x0800030c }, 2988c2ecf20Sopenharmony_ci { 180 , 0x05000249 }, 2998c2ecf20Sopenharmony_ci { 120 , 0x04000148 }, 3008c2ecf20Sopenharmony_ci { 0 , 0 }, 3018c2ecf20Sopenharmony_ci}; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic struct kauai_timing kauai_mdma_timings[] = 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci { 1260 , 0x00fff000 }, 3068c2ecf20Sopenharmony_ci { 480 , 0x00618000 }, 3078c2ecf20Sopenharmony_ci { 360 , 0x00492000 }, 3088c2ecf20Sopenharmony_ci { 270 , 0x0038e000 }, 3098c2ecf20Sopenharmony_ci { 240 , 0x0030c000 }, 3108c2ecf20Sopenharmony_ci { 210 , 0x002cb000 }, 3118c2ecf20Sopenharmony_ci { 180 , 0x00249000 }, 3128c2ecf20Sopenharmony_ci { 150 , 0x00209000 }, 3138c2ecf20Sopenharmony_ci { 120 , 0x00148000 }, 3148c2ecf20Sopenharmony_ci { 0 , 0 }, 3158c2ecf20Sopenharmony_ci}; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic struct kauai_timing kauai_udma_timings[] = 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci { 120 , 0x000070c0 }, 3208c2ecf20Sopenharmony_ci { 90 , 0x00005d80 }, 3218c2ecf20Sopenharmony_ci { 60 , 0x00004a60 }, 3228c2ecf20Sopenharmony_ci { 45 , 0x00003a50 }, 3238c2ecf20Sopenharmony_ci { 30 , 0x00002a30 }, 3248c2ecf20Sopenharmony_ci { 20 , 0x00002921 }, 3258c2ecf20Sopenharmony_ci { 0 , 0 }, 3268c2ecf20Sopenharmony_ci}; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic struct kauai_timing shasta_pio_timings[] = 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci { 930 , 0x08000fff }, 3318c2ecf20Sopenharmony_ci { 600 , 0x0A000c97 }, 3328c2ecf20Sopenharmony_ci { 383 , 0x07000712 }, 3338c2ecf20Sopenharmony_ci { 360 , 0x040003cd }, 3348c2ecf20Sopenharmony_ci { 330 , 0x040003cd }, 3358c2ecf20Sopenharmony_ci { 300 , 0x040003cd }, 3368c2ecf20Sopenharmony_ci { 270 , 0x040003cd }, 3378c2ecf20Sopenharmony_ci { 240 , 0x040003cd }, 3388c2ecf20Sopenharmony_ci { 239 , 0x040003cd }, 3398c2ecf20Sopenharmony_ci { 180 , 0x0400028b }, 3408c2ecf20Sopenharmony_ci { 120 , 0x0400010a }, 3418c2ecf20Sopenharmony_ci { 0 , 0 }, 3428c2ecf20Sopenharmony_ci}; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic struct kauai_timing shasta_mdma_timings[] = 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci { 1260 , 0x00fff000 }, 3478c2ecf20Sopenharmony_ci { 480 , 0x00820800 }, 3488c2ecf20Sopenharmony_ci { 360 , 0x00820800 }, 3498c2ecf20Sopenharmony_ci { 270 , 0x00820800 }, 3508c2ecf20Sopenharmony_ci { 240 , 0x00820800 }, 3518c2ecf20Sopenharmony_ci { 210 , 0x00820800 }, 3528c2ecf20Sopenharmony_ci { 180 , 0x00820800 }, 3538c2ecf20Sopenharmony_ci { 150 , 0x0028b000 }, 3548c2ecf20Sopenharmony_ci { 120 , 0x001ca000 }, 3558c2ecf20Sopenharmony_ci { 0 , 0 }, 3568c2ecf20Sopenharmony_ci}; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic struct kauai_timing shasta_udma133_timings[] = 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci { 120 , 0x00035901, }, 3618c2ecf20Sopenharmony_ci { 90 , 0x000348b1, }, 3628c2ecf20Sopenharmony_ci { 60 , 0x00033881, }, 3638c2ecf20Sopenharmony_ci { 45 , 0x00033861, }, 3648c2ecf20Sopenharmony_ci { 30 , 0x00033841, }, 3658c2ecf20Sopenharmony_ci { 20 , 0x00033031, }, 3668c2ecf20Sopenharmony_ci { 15 , 0x00033021, }, 3678c2ecf20Sopenharmony_ci { 0 , 0 }, 3688c2ecf20Sopenharmony_ci}; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic inline u32 3728c2ecf20Sopenharmony_cikauai_lookup_timing(struct kauai_timing* table, int cycle_time) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci int i; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci for (i=0; table[i].cycle_time; i++) 3778c2ecf20Sopenharmony_ci if (cycle_time > table[i+1].cycle_time) 3788c2ecf20Sopenharmony_ci return table[i].timing_reg; 3798c2ecf20Sopenharmony_ci BUG(); 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci/* allow up to 256 DBDMA commands per xfer */ 3848c2ecf20Sopenharmony_ci#define MAX_DCMDS 256 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci/* 3878c2ecf20Sopenharmony_ci * Wait 1s for disk to answer on IDE bus after a hard reset 3888c2ecf20Sopenharmony_ci * of the device (via GPIO/FCR). 3898c2ecf20Sopenharmony_ci * 3908c2ecf20Sopenharmony_ci * Some devices seem to "pollute" the bus even after dropping 3918c2ecf20Sopenharmony_ci * the BSY bit (typically some combo drives slave on the UDMA 3928c2ecf20Sopenharmony_ci * bus) after a hard reset. Since we hard reset all drives on 3938c2ecf20Sopenharmony_ci * KeyLargo ATA66, we have to keep that delay around. I may end 3948c2ecf20Sopenharmony_ci * up not hard resetting anymore on these and keep the delay only 3958c2ecf20Sopenharmony_ci * for older interfaces instead (we have to reset when coming 3968c2ecf20Sopenharmony_ci * from MacOS...) --BenH. 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_ci#define IDE_WAKEUP_DELAY (1*HZ) 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic int pmac_ide_init_dma(ide_hwif_t *, const struct ide_port_info *); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci#define PMAC_IDE_REG(x) \ 4038c2ecf20Sopenharmony_ci ((void __iomem *)((drive)->hwif->io_ports.data_addr + (x))) 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* 4068c2ecf20Sopenharmony_ci * Apply the timings of the proper unit (master/slave) to the shared 4078c2ecf20Sopenharmony_ci * timing register when selecting that unit. This version is for 4088c2ecf20Sopenharmony_ci * ASICs with a single timing register 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_cistatic void pmac_ide_apply_timings(ide_drive_t *drive) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 4138c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (drive->dn & 1) 4168c2ecf20Sopenharmony_ci writel(pmif->timings[1], PMAC_IDE_REG(IDE_TIMING_CONFIG)); 4178c2ecf20Sopenharmony_ci else 4188c2ecf20Sopenharmony_ci writel(pmif->timings[0], PMAC_IDE_REG(IDE_TIMING_CONFIG)); 4198c2ecf20Sopenharmony_ci (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci/* 4238c2ecf20Sopenharmony_ci * Apply the timings of the proper unit (master/slave) to the shared 4248c2ecf20Sopenharmony_ci * timing register when selecting that unit. This version is for 4258c2ecf20Sopenharmony_ci * ASICs with a dual timing register (Kauai) 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_cistatic void pmac_ide_kauai_apply_timings(ide_drive_t *drive) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 4308c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (drive->dn & 1) { 4338c2ecf20Sopenharmony_ci writel(pmif->timings[1], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); 4348c2ecf20Sopenharmony_ci writel(pmif->timings[3], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG)); 4358c2ecf20Sopenharmony_ci } else { 4368c2ecf20Sopenharmony_ci writel(pmif->timings[0], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); 4378c2ecf20Sopenharmony_ci writel(pmif->timings[2], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG)); 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci (void)readl(PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci/* 4438c2ecf20Sopenharmony_ci * Force an update of controller timing values for a given drive 4448c2ecf20Sopenharmony_ci */ 4458c2ecf20Sopenharmony_cistatic void 4468c2ecf20Sopenharmony_cipmac_ide_do_update_timings(ide_drive_t *drive) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 4498c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (pmif->kind == controller_sh_ata6 || 4528c2ecf20Sopenharmony_ci pmif->kind == controller_un_ata6 || 4538c2ecf20Sopenharmony_ci pmif->kind == controller_k2_ata6) 4548c2ecf20Sopenharmony_ci pmac_ide_kauai_apply_timings(drive); 4558c2ecf20Sopenharmony_ci else 4568c2ecf20Sopenharmony_ci pmac_ide_apply_timings(drive); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic void pmac_dev_select(ide_drive_t *drive) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci pmac_ide_apply_timings(drive); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci writeb(drive->select | ATA_DEVICE_OBS, 4648c2ecf20Sopenharmony_ci (void __iomem *)drive->hwif->io_ports.device_addr); 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic void pmac_kauai_dev_select(ide_drive_t *drive) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci pmac_ide_kauai_apply_timings(drive); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci writeb(drive->select | ATA_DEVICE_OBS, 4728c2ecf20Sopenharmony_ci (void __iomem *)drive->hwif->io_ports.device_addr); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic void pmac_exec_command(ide_hwif_t *hwif, u8 cmd) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci writeb(cmd, (void __iomem *)hwif->io_ports.command_addr); 4788c2ecf20Sopenharmony_ci (void)readl((void __iomem *)(hwif->io_ports.data_addr 4798c2ecf20Sopenharmony_ci + IDE_TIMING_CONFIG)); 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic void pmac_write_devctl(ide_hwif_t *hwif, u8 ctl) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr); 4858c2ecf20Sopenharmony_ci (void)readl((void __iomem *)(hwif->io_ports.data_addr 4868c2ecf20Sopenharmony_ci + IDE_TIMING_CONFIG)); 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci/* 4908c2ecf20Sopenharmony_ci * Old tuning functions (called on hdparm -p), sets up drive PIO timings 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_cistatic void pmac_ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 4958c2ecf20Sopenharmony_ci const u8 pio = drive->pio_mode - XFER_PIO_0; 4968c2ecf20Sopenharmony_ci struct ide_timing *tim = ide_timing_find_mode(XFER_PIO_0 + pio); 4978c2ecf20Sopenharmony_ci u32 *timings, t; 4988c2ecf20Sopenharmony_ci unsigned accessTicks, recTicks; 4998c2ecf20Sopenharmony_ci unsigned accessTime, recTime; 5008c2ecf20Sopenharmony_ci unsigned int cycle_time; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* which drive is it ? */ 5038c2ecf20Sopenharmony_ci timings = &pmif->timings[drive->dn & 1]; 5048c2ecf20Sopenharmony_ci t = *timings; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci cycle_time = ide_pio_cycle_time(drive, pio); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci switch (pmif->kind) { 5098c2ecf20Sopenharmony_ci case controller_sh_ata6: { 5108c2ecf20Sopenharmony_ci /* 133Mhz cell */ 5118c2ecf20Sopenharmony_ci u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time); 5128c2ecf20Sopenharmony_ci t = (t & ~TR_133_PIOREG_PIO_MASK) | tr; 5138c2ecf20Sopenharmony_ci break; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci case controller_un_ata6: 5168c2ecf20Sopenharmony_ci case controller_k2_ata6: { 5178c2ecf20Sopenharmony_ci /* 100Mhz cell */ 5188c2ecf20Sopenharmony_ci u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time); 5198c2ecf20Sopenharmony_ci t = (t & ~TR_100_PIOREG_PIO_MASK) | tr; 5208c2ecf20Sopenharmony_ci break; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci case controller_kl_ata4: 5238c2ecf20Sopenharmony_ci /* 66Mhz cell */ 5248c2ecf20Sopenharmony_ci recTime = cycle_time - tim->active - tim->setup; 5258c2ecf20Sopenharmony_ci recTime = max(recTime, 150U); 5268c2ecf20Sopenharmony_ci accessTime = tim->active; 5278c2ecf20Sopenharmony_ci accessTime = max(accessTime, 150U); 5288c2ecf20Sopenharmony_ci accessTicks = SYSCLK_TICKS_66(accessTime); 5298c2ecf20Sopenharmony_ci accessTicks = min(accessTicks, 0x1fU); 5308c2ecf20Sopenharmony_ci recTicks = SYSCLK_TICKS_66(recTime); 5318c2ecf20Sopenharmony_ci recTicks = min(recTicks, 0x1fU); 5328c2ecf20Sopenharmony_ci t = (t & ~TR_66_PIO_MASK) | 5338c2ecf20Sopenharmony_ci (accessTicks << TR_66_PIO_ACCESS_SHIFT) | 5348c2ecf20Sopenharmony_ci (recTicks << TR_66_PIO_RECOVERY_SHIFT); 5358c2ecf20Sopenharmony_ci break; 5368c2ecf20Sopenharmony_ci default: { 5378c2ecf20Sopenharmony_ci /* 33Mhz cell */ 5388c2ecf20Sopenharmony_ci int ebit = 0; 5398c2ecf20Sopenharmony_ci recTime = cycle_time - tim->active - tim->setup; 5408c2ecf20Sopenharmony_ci recTime = max(recTime, 150U); 5418c2ecf20Sopenharmony_ci accessTime = tim->active; 5428c2ecf20Sopenharmony_ci accessTime = max(accessTime, 150U); 5438c2ecf20Sopenharmony_ci accessTicks = SYSCLK_TICKS(accessTime); 5448c2ecf20Sopenharmony_ci accessTicks = min(accessTicks, 0x1fU); 5458c2ecf20Sopenharmony_ci accessTicks = max(accessTicks, 4U); 5468c2ecf20Sopenharmony_ci recTicks = SYSCLK_TICKS(recTime); 5478c2ecf20Sopenharmony_ci recTicks = min(recTicks, 0x1fU); 5488c2ecf20Sopenharmony_ci recTicks = max(recTicks, 5U) - 4; 5498c2ecf20Sopenharmony_ci if (recTicks > 9) { 5508c2ecf20Sopenharmony_ci recTicks--; /* guess, but it's only for PIO0, so... */ 5518c2ecf20Sopenharmony_ci ebit = 1; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci t = (t & ~TR_33_PIO_MASK) | 5548c2ecf20Sopenharmony_ci (accessTicks << TR_33_PIO_ACCESS_SHIFT) | 5558c2ecf20Sopenharmony_ci (recTicks << TR_33_PIO_RECOVERY_SHIFT); 5568c2ecf20Sopenharmony_ci if (ebit) 5578c2ecf20Sopenharmony_ci t |= TR_33_PIO_E; 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci#ifdef IDE_PMAC_DEBUG 5638c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Set PIO timing for mode %d, reg: 0x%08x\n", 5648c2ecf20Sopenharmony_ci drive->name, pio, *timings); 5658c2ecf20Sopenharmony_ci#endif 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci *timings = t; 5688c2ecf20Sopenharmony_ci pmac_ide_do_update_timings(drive); 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci/* 5728c2ecf20Sopenharmony_ci * Calculate KeyLargo ATA/66 UDMA timings 5738c2ecf20Sopenharmony_ci */ 5748c2ecf20Sopenharmony_cistatic int 5758c2ecf20Sopenharmony_ciset_timings_udma_ata4(u32 *timings, u8 speed) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (speed > XFER_UDMA_4) 5808c2ecf20Sopenharmony_ci return 1; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci rdyToPauseTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].rdy2pause); 5838c2ecf20Sopenharmony_ci wrDataSetupTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].wrDataSetup); 5848c2ecf20Sopenharmony_ci addrTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].addrSetup); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci *timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) | 5878c2ecf20Sopenharmony_ci (wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | 5888c2ecf20Sopenharmony_ci (rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) | 5898c2ecf20Sopenharmony_ci (addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) | 5908c2ecf20Sopenharmony_ci TR_66_UDMA_EN; 5918c2ecf20Sopenharmony_ci#ifdef IDE_PMAC_DEBUG 5928c2ecf20Sopenharmony_ci printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n", 5938c2ecf20Sopenharmony_ci speed & 0xf, *timings); 5948c2ecf20Sopenharmony_ci#endif 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci/* 6008c2ecf20Sopenharmony_ci * Calculate Kauai ATA/100 UDMA timings 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_cistatic int 6038c2ecf20Sopenharmony_ciset_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci struct ide_timing *t = ide_timing_find_mode(speed); 6068c2ecf20Sopenharmony_ci u32 tr; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (speed > XFER_UDMA_5 || t == NULL) 6098c2ecf20Sopenharmony_ci return 1; 6108c2ecf20Sopenharmony_ci tr = kauai_lookup_timing(kauai_udma_timings, (int)t->udma); 6118c2ecf20Sopenharmony_ci *ultra_timings = ((*ultra_timings) & ~TR_100_UDMAREG_UDMA_MASK) | tr; 6128c2ecf20Sopenharmony_ci *ultra_timings = (*ultra_timings) | TR_100_UDMAREG_UDMA_EN; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci return 0; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci/* 6188c2ecf20Sopenharmony_ci * Calculate Shasta ATA/133 UDMA timings 6198c2ecf20Sopenharmony_ci */ 6208c2ecf20Sopenharmony_cistatic int 6218c2ecf20Sopenharmony_ciset_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct ide_timing *t = ide_timing_find_mode(speed); 6248c2ecf20Sopenharmony_ci u32 tr; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (speed > XFER_UDMA_6 || t == NULL) 6278c2ecf20Sopenharmony_ci return 1; 6288c2ecf20Sopenharmony_ci tr = kauai_lookup_timing(shasta_udma133_timings, (int)t->udma); 6298c2ecf20Sopenharmony_ci *ultra_timings = ((*ultra_timings) & ~TR_133_UDMAREG_UDMA_MASK) | tr; 6308c2ecf20Sopenharmony_ci *ultra_timings = (*ultra_timings) | TR_133_UDMAREG_UDMA_EN; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return 0; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci/* 6368c2ecf20Sopenharmony_ci * Calculate MDMA timings for all cells 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_cistatic void 6398c2ecf20Sopenharmony_ciset_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, 6408c2ecf20Sopenharmony_ci u8 speed) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci u16 *id = drive->id; 6438c2ecf20Sopenharmony_ci int cycleTime, accessTime = 0, recTime = 0; 6448c2ecf20Sopenharmony_ci unsigned accessTicks, recTicks; 6458c2ecf20Sopenharmony_ci struct mdma_timings_t* tm = NULL; 6468c2ecf20Sopenharmony_ci int i; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci /* Get default cycle time for mode */ 6498c2ecf20Sopenharmony_ci switch(speed & 0xf) { 6508c2ecf20Sopenharmony_ci case 0: cycleTime = 480; break; 6518c2ecf20Sopenharmony_ci case 1: cycleTime = 150; break; 6528c2ecf20Sopenharmony_ci case 2: cycleTime = 120; break; 6538c2ecf20Sopenharmony_ci default: 6548c2ecf20Sopenharmony_ci BUG(); 6558c2ecf20Sopenharmony_ci break; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci /* Check if drive provides explicit DMA cycle time */ 6598c2ecf20Sopenharmony_ci if ((id[ATA_ID_FIELD_VALID] & 2) && id[ATA_ID_EIDE_DMA_TIME]) 6608c2ecf20Sopenharmony_ci cycleTime = max_t(int, id[ATA_ID_EIDE_DMA_TIME], cycleTime); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* OHare limits according to some old Apple sources */ 6638c2ecf20Sopenharmony_ci if ((intf_type == controller_ohare) && (cycleTime < 150)) 6648c2ecf20Sopenharmony_ci cycleTime = 150; 6658c2ecf20Sopenharmony_ci /* Get the proper timing array for this controller */ 6668c2ecf20Sopenharmony_ci switch(intf_type) { 6678c2ecf20Sopenharmony_ci case controller_sh_ata6: 6688c2ecf20Sopenharmony_ci case controller_un_ata6: 6698c2ecf20Sopenharmony_ci case controller_k2_ata6: 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci case controller_kl_ata4: 6728c2ecf20Sopenharmony_ci tm = mdma_timings_66; 6738c2ecf20Sopenharmony_ci break; 6748c2ecf20Sopenharmony_ci case controller_kl_ata3: 6758c2ecf20Sopenharmony_ci tm = mdma_timings_33k; 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci default: 6788c2ecf20Sopenharmony_ci tm = mdma_timings_33; 6798c2ecf20Sopenharmony_ci break; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci if (tm != NULL) { 6828c2ecf20Sopenharmony_ci /* Lookup matching access & recovery times */ 6838c2ecf20Sopenharmony_ci i = -1; 6848c2ecf20Sopenharmony_ci for (;;) { 6858c2ecf20Sopenharmony_ci if (tm[i+1].cycleTime < cycleTime) 6868c2ecf20Sopenharmony_ci break; 6878c2ecf20Sopenharmony_ci i++; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci cycleTime = tm[i].cycleTime; 6908c2ecf20Sopenharmony_ci accessTime = tm[i].accessTime; 6918c2ecf20Sopenharmony_ci recTime = tm[i].recoveryTime; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci#ifdef IDE_PMAC_DEBUG 6948c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n", 6958c2ecf20Sopenharmony_ci drive->name, cycleTime, accessTime, recTime); 6968c2ecf20Sopenharmony_ci#endif 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci switch(intf_type) { 6998c2ecf20Sopenharmony_ci case controller_sh_ata6: { 7008c2ecf20Sopenharmony_ci /* 133Mhz cell */ 7018c2ecf20Sopenharmony_ci u32 tr = kauai_lookup_timing(shasta_mdma_timings, cycleTime); 7028c2ecf20Sopenharmony_ci *timings = ((*timings) & ~TR_133_PIOREG_MDMA_MASK) | tr; 7038c2ecf20Sopenharmony_ci *timings2 = (*timings2) & ~TR_133_UDMAREG_UDMA_EN; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci break; 7068c2ecf20Sopenharmony_ci case controller_un_ata6: 7078c2ecf20Sopenharmony_ci case controller_k2_ata6: { 7088c2ecf20Sopenharmony_ci /* 100Mhz cell */ 7098c2ecf20Sopenharmony_ci u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime); 7108c2ecf20Sopenharmony_ci *timings = ((*timings) & ~TR_100_PIOREG_MDMA_MASK) | tr; 7118c2ecf20Sopenharmony_ci *timings2 = (*timings2) & ~TR_100_UDMAREG_UDMA_EN; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci break; 7148c2ecf20Sopenharmony_ci case controller_kl_ata4: 7158c2ecf20Sopenharmony_ci /* 66Mhz cell */ 7168c2ecf20Sopenharmony_ci accessTicks = SYSCLK_TICKS_66(accessTime); 7178c2ecf20Sopenharmony_ci accessTicks = min(accessTicks, 0x1fU); 7188c2ecf20Sopenharmony_ci accessTicks = max(accessTicks, 0x1U); 7198c2ecf20Sopenharmony_ci recTicks = SYSCLK_TICKS_66(recTime); 7208c2ecf20Sopenharmony_ci recTicks = min(recTicks, 0x1fU); 7218c2ecf20Sopenharmony_ci recTicks = max(recTicks, 0x3U); 7228c2ecf20Sopenharmony_ci /* Clear out mdma bits and disable udma */ 7238c2ecf20Sopenharmony_ci *timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) | 7248c2ecf20Sopenharmony_ci (accessTicks << TR_66_MDMA_ACCESS_SHIFT) | 7258c2ecf20Sopenharmony_ci (recTicks << TR_66_MDMA_RECOVERY_SHIFT); 7268c2ecf20Sopenharmony_ci break; 7278c2ecf20Sopenharmony_ci case controller_kl_ata3: 7288c2ecf20Sopenharmony_ci /* 33Mhz cell on KeyLargo */ 7298c2ecf20Sopenharmony_ci accessTicks = SYSCLK_TICKS(accessTime); 7308c2ecf20Sopenharmony_ci accessTicks = max(accessTicks, 1U); 7318c2ecf20Sopenharmony_ci accessTicks = min(accessTicks, 0x1fU); 7328c2ecf20Sopenharmony_ci accessTime = accessTicks * IDE_SYSCLK_NS; 7338c2ecf20Sopenharmony_ci recTicks = SYSCLK_TICKS(recTime); 7348c2ecf20Sopenharmony_ci recTicks = max(recTicks, 1U); 7358c2ecf20Sopenharmony_ci recTicks = min(recTicks, 0x1fU); 7368c2ecf20Sopenharmony_ci *timings = ((*timings) & ~TR_33_MDMA_MASK) | 7378c2ecf20Sopenharmony_ci (accessTicks << TR_33_MDMA_ACCESS_SHIFT) | 7388c2ecf20Sopenharmony_ci (recTicks << TR_33_MDMA_RECOVERY_SHIFT); 7398c2ecf20Sopenharmony_ci break; 7408c2ecf20Sopenharmony_ci default: { 7418c2ecf20Sopenharmony_ci /* 33Mhz cell on others */ 7428c2ecf20Sopenharmony_ci int halfTick = 0; 7438c2ecf20Sopenharmony_ci int origAccessTime = accessTime; 7448c2ecf20Sopenharmony_ci int origRecTime = recTime; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci accessTicks = SYSCLK_TICKS(accessTime); 7478c2ecf20Sopenharmony_ci accessTicks = max(accessTicks, 1U); 7488c2ecf20Sopenharmony_ci accessTicks = min(accessTicks, 0x1fU); 7498c2ecf20Sopenharmony_ci accessTime = accessTicks * IDE_SYSCLK_NS; 7508c2ecf20Sopenharmony_ci recTicks = SYSCLK_TICKS(recTime); 7518c2ecf20Sopenharmony_ci recTicks = max(recTicks, 2U) - 1; 7528c2ecf20Sopenharmony_ci recTicks = min(recTicks, 0x1fU); 7538c2ecf20Sopenharmony_ci recTime = (recTicks + 1) * IDE_SYSCLK_NS; 7548c2ecf20Sopenharmony_ci if ((accessTicks > 1) && 7558c2ecf20Sopenharmony_ci ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) && 7568c2ecf20Sopenharmony_ci ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) { 7578c2ecf20Sopenharmony_ci halfTick = 1; 7588c2ecf20Sopenharmony_ci accessTicks--; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci *timings = ((*timings) & ~TR_33_MDMA_MASK) | 7618c2ecf20Sopenharmony_ci (accessTicks << TR_33_MDMA_ACCESS_SHIFT) | 7628c2ecf20Sopenharmony_ci (recTicks << TR_33_MDMA_RECOVERY_SHIFT); 7638c2ecf20Sopenharmony_ci if (halfTick) 7648c2ecf20Sopenharmony_ci *timings |= TR_33_MDMA_HALFTICK; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci#ifdef IDE_PMAC_DEBUG 7688c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Set MDMA timing for mode %d, reg: 0x%08x\n", 7698c2ecf20Sopenharmony_ci drive->name, speed & 0xf, *timings); 7708c2ecf20Sopenharmony_ci#endif 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_cistatic void pmac_ide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 7768c2ecf20Sopenharmony_ci int ret = 0; 7778c2ecf20Sopenharmony_ci u32 *timings, *timings2, tl[2]; 7788c2ecf20Sopenharmony_ci u8 unit = drive->dn & 1; 7798c2ecf20Sopenharmony_ci const u8 speed = drive->dma_mode; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci timings = &pmif->timings[unit]; 7828c2ecf20Sopenharmony_ci timings2 = &pmif->timings[unit+2]; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* Copy timings to local image */ 7858c2ecf20Sopenharmony_ci tl[0] = *timings; 7868c2ecf20Sopenharmony_ci tl[1] = *timings2; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (speed >= XFER_UDMA_0) { 7898c2ecf20Sopenharmony_ci if (pmif->kind == controller_kl_ata4) 7908c2ecf20Sopenharmony_ci ret = set_timings_udma_ata4(&tl[0], speed); 7918c2ecf20Sopenharmony_ci else if (pmif->kind == controller_un_ata6 7928c2ecf20Sopenharmony_ci || pmif->kind == controller_k2_ata6) 7938c2ecf20Sopenharmony_ci ret = set_timings_udma_ata6(&tl[0], &tl[1], speed); 7948c2ecf20Sopenharmony_ci else if (pmif->kind == controller_sh_ata6) 7958c2ecf20Sopenharmony_ci ret = set_timings_udma_shasta(&tl[0], &tl[1], speed); 7968c2ecf20Sopenharmony_ci else 7978c2ecf20Sopenharmony_ci ret = -1; 7988c2ecf20Sopenharmony_ci } else 7998c2ecf20Sopenharmony_ci set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (ret) 8028c2ecf20Sopenharmony_ci return; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* Apply timings to controller */ 8058c2ecf20Sopenharmony_ci *timings = tl[0]; 8068c2ecf20Sopenharmony_ci *timings2 = tl[1]; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci pmac_ide_do_update_timings(drive); 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci/* 8128c2ecf20Sopenharmony_ci * Blast some well known "safe" values to the timing registers at init or 8138c2ecf20Sopenharmony_ci * wakeup from sleep time, before we do real calculation 8148c2ecf20Sopenharmony_ci */ 8158c2ecf20Sopenharmony_cistatic void 8168c2ecf20Sopenharmony_cisanitize_timings(pmac_ide_hwif_t *pmif) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci unsigned int value, value2 = 0; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci switch(pmif->kind) { 8218c2ecf20Sopenharmony_ci case controller_sh_ata6: 8228c2ecf20Sopenharmony_ci value = 0x0a820c97; 8238c2ecf20Sopenharmony_ci value2 = 0x00033031; 8248c2ecf20Sopenharmony_ci break; 8258c2ecf20Sopenharmony_ci case controller_un_ata6: 8268c2ecf20Sopenharmony_ci case controller_k2_ata6: 8278c2ecf20Sopenharmony_ci value = 0x08618a92; 8288c2ecf20Sopenharmony_ci value2 = 0x00002921; 8298c2ecf20Sopenharmony_ci break; 8308c2ecf20Sopenharmony_ci case controller_kl_ata4: 8318c2ecf20Sopenharmony_ci value = 0x0008438c; 8328c2ecf20Sopenharmony_ci break; 8338c2ecf20Sopenharmony_ci case controller_kl_ata3: 8348c2ecf20Sopenharmony_ci value = 0x00084526; 8358c2ecf20Sopenharmony_ci break; 8368c2ecf20Sopenharmony_ci case controller_heathrow: 8378c2ecf20Sopenharmony_ci case controller_ohare: 8388c2ecf20Sopenharmony_ci default: 8398c2ecf20Sopenharmony_ci value = 0x00074526; 8408c2ecf20Sopenharmony_ci break; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci pmif->timings[0] = pmif->timings[1] = value; 8438c2ecf20Sopenharmony_ci pmif->timings[2] = pmif->timings[3] = value2; 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic int on_media_bay(pmac_ide_hwif_t *pmif) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci return pmif->mdev && pmif->mdev->media_bay != NULL; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci/* Suspend call back, should be called after the child devices 8528c2ecf20Sopenharmony_ci * have actually been suspended 8538c2ecf20Sopenharmony_ci */ 8548c2ecf20Sopenharmony_cistatic int pmac_ide_do_suspend(pmac_ide_hwif_t *pmif) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci /* We clear the timings */ 8578c2ecf20Sopenharmony_ci pmif->timings[0] = 0; 8588c2ecf20Sopenharmony_ci pmif->timings[1] = 0; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci disable_irq(pmif->irq); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci /* The media bay will handle itself just fine */ 8638c2ecf20Sopenharmony_ci if (on_media_bay(pmif)) 8648c2ecf20Sopenharmony_ci return 0; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* Kauai has bus control FCRs directly here */ 8678c2ecf20Sopenharmony_ci if (pmif->kauai_fcr) { 8688c2ecf20Sopenharmony_ci u32 fcr = readl(pmif->kauai_fcr); 8698c2ecf20Sopenharmony_ci fcr &= ~(KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE); 8708c2ecf20Sopenharmony_ci writel(fcr, pmif->kauai_fcr); 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* Disable the bus on older machines and the cell on kauai */ 8748c2ecf20Sopenharmony_ci ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 8758c2ecf20Sopenharmony_ci 0); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci return 0; 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci/* Resume call back, should be called before the child devices 8818c2ecf20Sopenharmony_ci * are resumed 8828c2ecf20Sopenharmony_ci */ 8838c2ecf20Sopenharmony_cistatic int pmac_ide_do_resume(pmac_ide_hwif_t *pmif) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci /* Hard reset & re-enable controller (do we really need to reset ? -BenH) */ 8868c2ecf20Sopenharmony_ci if (!on_media_bay(pmif)) { 8878c2ecf20Sopenharmony_ci ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 1); 8888c2ecf20Sopenharmony_ci ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1); 8898c2ecf20Sopenharmony_ci msleep(10); 8908c2ecf20Sopenharmony_ci ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 0); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci /* Kauai has it different */ 8938c2ecf20Sopenharmony_ci if (pmif->kauai_fcr) { 8948c2ecf20Sopenharmony_ci u32 fcr = readl(pmif->kauai_fcr); 8958c2ecf20Sopenharmony_ci fcr |= KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE; 8968c2ecf20Sopenharmony_ci writel(fcr, pmif->kauai_fcr); 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY)); 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci /* Sanitize drive timings */ 9038c2ecf20Sopenharmony_ci sanitize_timings(pmif); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci enable_irq(pmif->irq); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci return 0; 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cistatic u8 pmac_ide_cable_detect(ide_hwif_t *hwif) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 9138c2ecf20Sopenharmony_ci struct device_node *np = pmif->node; 9148c2ecf20Sopenharmony_ci const char *cable = of_get_property(np, "cable-type", NULL); 9158c2ecf20Sopenharmony_ci struct device_node *root = of_find_node_by_path("/"); 9168c2ecf20Sopenharmony_ci const char *model = of_get_property(root, "model", NULL); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci of_node_put(root); 9198c2ecf20Sopenharmony_ci /* Get cable type from device-tree. */ 9208c2ecf20Sopenharmony_ci if (cable && !strncmp(cable, "80-", 3)) { 9218c2ecf20Sopenharmony_ci /* Some drives fail to detect 80c cable in PowerBook */ 9228c2ecf20Sopenharmony_ci /* These machine use proprietary short IDE cable anyway */ 9238c2ecf20Sopenharmony_ci if (!strncmp(model, "PowerBook", 9)) 9248c2ecf20Sopenharmony_ci return ATA_CBL_PATA40_SHORT; 9258c2ecf20Sopenharmony_ci else 9268c2ecf20Sopenharmony_ci return ATA_CBL_PATA80; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* 9308c2ecf20Sopenharmony_ci * G5's seem to have incorrect cable type in device-tree. 9318c2ecf20Sopenharmony_ci * Let's assume they have a 80 conductor cable, this seem 9328c2ecf20Sopenharmony_ci * to be always the case unless the user mucked around. 9338c2ecf20Sopenharmony_ci */ 9348c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "K2-UATA") || 9358c2ecf20Sopenharmony_ci of_device_is_compatible(np, "shasta-ata")) 9368c2ecf20Sopenharmony_ci return ATA_CBL_PATA80; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci return ATA_CBL_PATA40; 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic void pmac_ide_init_dev(ide_drive_t *drive) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 9448c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci if (on_media_bay(pmif)) { 9478c2ecf20Sopenharmony_ci if (check_media_bay(pmif->mdev->media_bay) == MB_CD) { 9488c2ecf20Sopenharmony_ci drive->dev_flags &= ~IDE_DFLAG_NOPROBE; 9498c2ecf20Sopenharmony_ci return; 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_NOPROBE; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_cistatic const struct ide_tp_ops pmac_tp_ops = { 9568c2ecf20Sopenharmony_ci .exec_command = pmac_exec_command, 9578c2ecf20Sopenharmony_ci .read_status = ide_read_status, 9588c2ecf20Sopenharmony_ci .read_altstatus = ide_read_altstatus, 9598c2ecf20Sopenharmony_ci .write_devctl = pmac_write_devctl, 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci .dev_select = pmac_dev_select, 9628c2ecf20Sopenharmony_ci .tf_load = ide_tf_load, 9638c2ecf20Sopenharmony_ci .tf_read = ide_tf_read, 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci .input_data = ide_input_data, 9668c2ecf20Sopenharmony_ci .output_data = ide_output_data, 9678c2ecf20Sopenharmony_ci}; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_cistatic const struct ide_tp_ops pmac_ata6_tp_ops = { 9708c2ecf20Sopenharmony_ci .exec_command = pmac_exec_command, 9718c2ecf20Sopenharmony_ci .read_status = ide_read_status, 9728c2ecf20Sopenharmony_ci .read_altstatus = ide_read_altstatus, 9738c2ecf20Sopenharmony_ci .write_devctl = pmac_write_devctl, 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci .dev_select = pmac_kauai_dev_select, 9768c2ecf20Sopenharmony_ci .tf_load = ide_tf_load, 9778c2ecf20Sopenharmony_ci .tf_read = ide_tf_read, 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci .input_data = ide_input_data, 9808c2ecf20Sopenharmony_ci .output_data = ide_output_data, 9818c2ecf20Sopenharmony_ci}; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_cistatic const struct ide_port_ops pmac_ide_ata4_port_ops = { 9848c2ecf20Sopenharmony_ci .init_dev = pmac_ide_init_dev, 9858c2ecf20Sopenharmony_ci .set_pio_mode = pmac_ide_set_pio_mode, 9868c2ecf20Sopenharmony_ci .set_dma_mode = pmac_ide_set_dma_mode, 9878c2ecf20Sopenharmony_ci .cable_detect = pmac_ide_cable_detect, 9888c2ecf20Sopenharmony_ci}; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_cistatic const struct ide_port_ops pmac_ide_port_ops = { 9918c2ecf20Sopenharmony_ci .init_dev = pmac_ide_init_dev, 9928c2ecf20Sopenharmony_ci .set_pio_mode = pmac_ide_set_pio_mode, 9938c2ecf20Sopenharmony_ci .set_dma_mode = pmac_ide_set_dma_mode, 9948c2ecf20Sopenharmony_ci}; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cistatic const struct ide_dma_ops pmac_dma_ops; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic const struct ide_port_info pmac_port_info = { 9998c2ecf20Sopenharmony_ci .name = DRV_NAME, 10008c2ecf20Sopenharmony_ci .init_dma = pmac_ide_init_dma, 10018c2ecf20Sopenharmony_ci .chipset = ide_pmac, 10028c2ecf20Sopenharmony_ci .tp_ops = &pmac_tp_ops, 10038c2ecf20Sopenharmony_ci .port_ops = &pmac_ide_port_ops, 10048c2ecf20Sopenharmony_ci .dma_ops = &pmac_dma_ops, 10058c2ecf20Sopenharmony_ci .host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA | 10068c2ecf20Sopenharmony_ci IDE_HFLAG_POST_SET_MODE | 10078c2ecf20Sopenharmony_ci IDE_HFLAG_MMIO | 10088c2ecf20Sopenharmony_ci IDE_HFLAG_UNMASK_IRQS, 10098c2ecf20Sopenharmony_ci .pio_mask = ATA_PIO4, 10108c2ecf20Sopenharmony_ci .mwdma_mask = ATA_MWDMA2, 10118c2ecf20Sopenharmony_ci}; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci/* 10148c2ecf20Sopenharmony_ci * Setup, register & probe an IDE channel driven by this driver, this is 10158c2ecf20Sopenharmony_ci * called by one of the 2 probe functions (macio or PCI). 10168c2ecf20Sopenharmony_ci */ 10178c2ecf20Sopenharmony_cistatic int pmac_ide_setup_device(pmac_ide_hwif_t *pmif, struct ide_hw *hw) 10188c2ecf20Sopenharmony_ci{ 10198c2ecf20Sopenharmony_ci struct device_node *np = pmif->node; 10208c2ecf20Sopenharmony_ci const int *bidp; 10218c2ecf20Sopenharmony_ci struct ide_host *host; 10228c2ecf20Sopenharmony_ci struct ide_hw *hws[] = { hw }; 10238c2ecf20Sopenharmony_ci struct ide_port_info d = pmac_port_info; 10248c2ecf20Sopenharmony_ci int rc; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci pmif->broken_dma = pmif->broken_dma_warn = 0; 10278c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "shasta-ata")) { 10288c2ecf20Sopenharmony_ci pmif->kind = controller_sh_ata6; 10298c2ecf20Sopenharmony_ci d.tp_ops = &pmac_ata6_tp_ops; 10308c2ecf20Sopenharmony_ci d.port_ops = &pmac_ide_ata4_port_ops; 10318c2ecf20Sopenharmony_ci d.udma_mask = ATA_UDMA6; 10328c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(np, "kauai-ata")) { 10338c2ecf20Sopenharmony_ci pmif->kind = controller_un_ata6; 10348c2ecf20Sopenharmony_ci d.tp_ops = &pmac_ata6_tp_ops; 10358c2ecf20Sopenharmony_ci d.port_ops = &pmac_ide_ata4_port_ops; 10368c2ecf20Sopenharmony_ci d.udma_mask = ATA_UDMA5; 10378c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(np, "K2-UATA")) { 10388c2ecf20Sopenharmony_ci pmif->kind = controller_k2_ata6; 10398c2ecf20Sopenharmony_ci d.tp_ops = &pmac_ata6_tp_ops; 10408c2ecf20Sopenharmony_ci d.port_ops = &pmac_ide_ata4_port_ops; 10418c2ecf20Sopenharmony_ci d.udma_mask = ATA_UDMA5; 10428c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(np, "keylargo-ata")) { 10438c2ecf20Sopenharmony_ci if (of_node_name_eq(np, "ata-4")) { 10448c2ecf20Sopenharmony_ci pmif->kind = controller_kl_ata4; 10458c2ecf20Sopenharmony_ci d.port_ops = &pmac_ide_ata4_port_ops; 10468c2ecf20Sopenharmony_ci d.udma_mask = ATA_UDMA4; 10478c2ecf20Sopenharmony_ci } else 10488c2ecf20Sopenharmony_ci pmif->kind = controller_kl_ata3; 10498c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(np, "heathrow-ata")) { 10508c2ecf20Sopenharmony_ci pmif->kind = controller_heathrow; 10518c2ecf20Sopenharmony_ci } else { 10528c2ecf20Sopenharmony_ci pmif->kind = controller_ohare; 10538c2ecf20Sopenharmony_ci pmif->broken_dma = 1; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci bidp = of_get_property(np, "AAPL,bus-id", NULL); 10578c2ecf20Sopenharmony_ci pmif->aapl_bus_id = bidp ? *bidp : 0; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci /* On Kauai-type controllers, we make sure the FCR is correct */ 10608c2ecf20Sopenharmony_ci if (pmif->kauai_fcr) 10618c2ecf20Sopenharmony_ci writel(KAUAI_FCR_UATA_MAGIC | 10628c2ecf20Sopenharmony_ci KAUAI_FCR_UATA_RESET_N | 10638c2ecf20Sopenharmony_ci KAUAI_FCR_UATA_ENABLE, pmif->kauai_fcr); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci /* Make sure we have sane timings */ 10668c2ecf20Sopenharmony_ci sanitize_timings(pmif); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci /* If we are on a media bay, wait for it to settle and lock it */ 10698c2ecf20Sopenharmony_ci if (pmif->mdev) 10708c2ecf20Sopenharmony_ci lock_media_bay(pmif->mdev->media_bay); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci host = ide_host_alloc(&d, hws, 1); 10738c2ecf20Sopenharmony_ci if (host == NULL) { 10748c2ecf20Sopenharmony_ci rc = -ENOMEM; 10758c2ecf20Sopenharmony_ci goto bail; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci pmif->hwif = host->ports[0]; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (on_media_bay(pmif)) { 10808c2ecf20Sopenharmony_ci /* Fixup bus ID for media bay */ 10818c2ecf20Sopenharmony_ci if (!bidp) 10828c2ecf20Sopenharmony_ci pmif->aapl_bus_id = 1; 10838c2ecf20Sopenharmony_ci } else if (pmif->kind == controller_ohare) { 10848c2ecf20Sopenharmony_ci /* The code below is having trouble on some ohare machines 10858c2ecf20Sopenharmony_ci * (timing related ?). Until I can put my hand on one of these 10868c2ecf20Sopenharmony_ci * units, I keep the old way 10878c2ecf20Sopenharmony_ci */ 10888c2ecf20Sopenharmony_ci ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1); 10898c2ecf20Sopenharmony_ci } else { 10908c2ecf20Sopenharmony_ci /* This is necessary to enable IDE when net-booting */ 10918c2ecf20Sopenharmony_ci ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1); 10928c2ecf20Sopenharmony_ci ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1); 10938c2ecf20Sopenharmony_ci msleep(10); 10948c2ecf20Sopenharmony_ci ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0); 10958c2ecf20Sopenharmony_ci msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY)); 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci printk(KERN_INFO DRV_NAME ": Found Apple %s controller (%s), " 10998c2ecf20Sopenharmony_ci "bus ID %d%s, irq %d\n", model_name[pmif->kind], 11008c2ecf20Sopenharmony_ci pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id, 11018c2ecf20Sopenharmony_ci on_media_bay(pmif) ? " (mediabay)" : "", hw->irq); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci rc = ide_host_register(host, &d, hws); 11048c2ecf20Sopenharmony_ci if (rc) 11058c2ecf20Sopenharmony_ci pmif->hwif = NULL; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci if (pmif->mdev) 11088c2ecf20Sopenharmony_ci unlock_media_bay(pmif->mdev->media_bay); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci bail: 11118c2ecf20Sopenharmony_ci if (rc && host) 11128c2ecf20Sopenharmony_ci ide_host_free(host); 11138c2ecf20Sopenharmony_ci return rc; 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cistatic void pmac_ide_init_ports(struct ide_hw *hw, unsigned long base) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci int i; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) 11218c2ecf20Sopenharmony_ci hw->io_ports_array[i] = base + i * 0x10; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci hw->io_ports.ctl_addr = base + 0x160; 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci/* 11278c2ecf20Sopenharmony_ci * Attach to a macio probed interface 11288c2ecf20Sopenharmony_ci */ 11298c2ecf20Sopenharmony_cistatic int pmac_ide_macio_attach(struct macio_dev *mdev, 11308c2ecf20Sopenharmony_ci const struct of_device_id *match) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci void __iomem *base; 11338c2ecf20Sopenharmony_ci unsigned long regbase; 11348c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif; 11358c2ecf20Sopenharmony_ci int irq, rc; 11368c2ecf20Sopenharmony_ci struct ide_hw hw; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci pmif = kzalloc(sizeof(*pmif), GFP_KERNEL); 11398c2ecf20Sopenharmony_ci if (pmif == NULL) 11408c2ecf20Sopenharmony_ci return -ENOMEM; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (macio_resource_count(mdev) == 0) { 11438c2ecf20Sopenharmony_ci printk(KERN_WARNING "ide-pmac: no address for %pOF\n", 11448c2ecf20Sopenharmony_ci mdev->ofdev.dev.of_node); 11458c2ecf20Sopenharmony_ci rc = -ENXIO; 11468c2ecf20Sopenharmony_ci goto out_free_pmif; 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci /* Request memory resource for IO ports */ 11508c2ecf20Sopenharmony_ci if (macio_request_resource(mdev, 0, "ide-pmac (ports)")) { 11518c2ecf20Sopenharmony_ci printk(KERN_ERR "ide-pmac: can't request MMIO resource for " 11528c2ecf20Sopenharmony_ci "%pOF!\n", mdev->ofdev.dev.of_node); 11538c2ecf20Sopenharmony_ci rc = -EBUSY; 11548c2ecf20Sopenharmony_ci goto out_free_pmif; 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci /* XXX This is bogus. Should be fixed in the registry by checking 11588c2ecf20Sopenharmony_ci * the kind of host interrupt controller, a bit like gatwick 11598c2ecf20Sopenharmony_ci * fixes in irq.c. That works well enough for the single case 11608c2ecf20Sopenharmony_ci * where that happens though... 11618c2ecf20Sopenharmony_ci */ 11628c2ecf20Sopenharmony_ci if (macio_irq_count(mdev) == 0) { 11638c2ecf20Sopenharmony_ci printk(KERN_WARNING "ide-pmac: no intrs for device %pOF, using " 11648c2ecf20Sopenharmony_ci "13\n", mdev->ofdev.dev.of_node); 11658c2ecf20Sopenharmony_ci irq = irq_create_mapping(NULL, 13); 11668c2ecf20Sopenharmony_ci } else 11678c2ecf20Sopenharmony_ci irq = macio_irq(mdev, 0); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci base = ioremap(macio_resource_start(mdev, 0), 0x400); 11708c2ecf20Sopenharmony_ci regbase = (unsigned long) base; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci pmif->mdev = mdev; 11738c2ecf20Sopenharmony_ci pmif->node = mdev->ofdev.dev.of_node; 11748c2ecf20Sopenharmony_ci pmif->regbase = regbase; 11758c2ecf20Sopenharmony_ci pmif->irq = irq; 11768c2ecf20Sopenharmony_ci pmif->kauai_fcr = NULL; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (macio_resource_count(mdev) >= 2) { 11798c2ecf20Sopenharmony_ci if (macio_request_resource(mdev, 1, "ide-pmac (dma)")) 11808c2ecf20Sopenharmony_ci printk(KERN_WARNING "ide-pmac: can't request DMA " 11818c2ecf20Sopenharmony_ci "resource for %pOF!\n", 11828c2ecf20Sopenharmony_ci mdev->ofdev.dev.of_node); 11838c2ecf20Sopenharmony_ci else 11848c2ecf20Sopenharmony_ci pmif->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x1000); 11858c2ecf20Sopenharmony_ci } else 11868c2ecf20Sopenharmony_ci pmif->dma_regs = NULL; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci dev_set_drvdata(&mdev->ofdev.dev, pmif); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci memset(&hw, 0, sizeof(hw)); 11918c2ecf20Sopenharmony_ci pmac_ide_init_ports(&hw, pmif->regbase); 11928c2ecf20Sopenharmony_ci hw.irq = irq; 11938c2ecf20Sopenharmony_ci hw.dev = &mdev->bus->pdev->dev; 11948c2ecf20Sopenharmony_ci hw.parent = &mdev->ofdev.dev; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci rc = pmac_ide_setup_device(pmif, &hw); 11978c2ecf20Sopenharmony_ci if (rc != 0) { 11988c2ecf20Sopenharmony_ci /* The inteface is released to the common IDE layer */ 11998c2ecf20Sopenharmony_ci dev_set_drvdata(&mdev->ofdev.dev, NULL); 12008c2ecf20Sopenharmony_ci iounmap(base); 12018c2ecf20Sopenharmony_ci if (pmif->dma_regs) { 12028c2ecf20Sopenharmony_ci iounmap(pmif->dma_regs); 12038c2ecf20Sopenharmony_ci macio_release_resource(mdev, 1); 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci macio_release_resource(mdev, 0); 12068c2ecf20Sopenharmony_ci kfree(pmif); 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci return rc; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ciout_free_pmif: 12128c2ecf20Sopenharmony_ci kfree(pmif); 12138c2ecf20Sopenharmony_ci return rc; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic int 12178c2ecf20Sopenharmony_cipmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t mesg) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev); 12208c2ecf20Sopenharmony_ci int rc = 0; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (mesg.event != mdev->ofdev.dev.power.power_state.event 12238c2ecf20Sopenharmony_ci && (mesg.event & PM_EVENT_SLEEP)) { 12248c2ecf20Sopenharmony_ci rc = pmac_ide_do_suspend(pmif); 12258c2ecf20Sopenharmony_ci if (rc == 0) 12268c2ecf20Sopenharmony_ci mdev->ofdev.dev.power.power_state = mesg; 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci return rc; 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_cistatic int 12338c2ecf20Sopenharmony_cipmac_ide_macio_resume(struct macio_dev *mdev) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev); 12368c2ecf20Sopenharmony_ci int rc = 0; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) { 12398c2ecf20Sopenharmony_ci rc = pmac_ide_do_resume(pmif); 12408c2ecf20Sopenharmony_ci if (rc == 0) 12418c2ecf20Sopenharmony_ci mdev->ofdev.dev.power.power_state = PMSG_ON; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci return rc; 12458c2ecf20Sopenharmony_ci} 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci/* 12488c2ecf20Sopenharmony_ci * Attach to a PCI probed interface 12498c2ecf20Sopenharmony_ci */ 12508c2ecf20Sopenharmony_cistatic int pmac_ide_pci_attach(struct pci_dev *pdev, 12518c2ecf20Sopenharmony_ci const struct pci_device_id *id) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci struct device_node *np; 12548c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif; 12558c2ecf20Sopenharmony_ci void __iomem *base; 12568c2ecf20Sopenharmony_ci unsigned long rbase, rlen; 12578c2ecf20Sopenharmony_ci int rc; 12588c2ecf20Sopenharmony_ci struct ide_hw hw; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci np = pci_device_to_OF_node(pdev); 12618c2ecf20Sopenharmony_ci if (np == NULL) { 12628c2ecf20Sopenharmony_ci printk(KERN_ERR "ide-pmac: cannot find MacIO node for Kauai ATA interface\n"); 12638c2ecf20Sopenharmony_ci return -ENODEV; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci pmif = kzalloc(sizeof(*pmif), GFP_KERNEL); 12678c2ecf20Sopenharmony_ci if (pmif == NULL) 12688c2ecf20Sopenharmony_ci return -ENOMEM; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) { 12718c2ecf20Sopenharmony_ci printk(KERN_WARNING "ide-pmac: Can't enable PCI device for " 12728c2ecf20Sopenharmony_ci "%pOF\n", np); 12738c2ecf20Sopenharmony_ci rc = -ENXIO; 12748c2ecf20Sopenharmony_ci goto out_free_pmif; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci pci_set_master(pdev); 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci if (pci_request_regions(pdev, "Kauai ATA")) { 12798c2ecf20Sopenharmony_ci printk(KERN_ERR "ide-pmac: Cannot obtain PCI resources for " 12808c2ecf20Sopenharmony_ci "%pOF\n", np); 12818c2ecf20Sopenharmony_ci rc = -ENXIO; 12828c2ecf20Sopenharmony_ci goto out_free_pmif; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci pmif->mdev = NULL; 12868c2ecf20Sopenharmony_ci pmif->node = np; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci rbase = pci_resource_start(pdev, 0); 12898c2ecf20Sopenharmony_ci rlen = pci_resource_len(pdev, 0); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci base = ioremap(rbase, rlen); 12928c2ecf20Sopenharmony_ci pmif->regbase = (unsigned long) base + 0x2000; 12938c2ecf20Sopenharmony_ci pmif->dma_regs = base + 0x1000; 12948c2ecf20Sopenharmony_ci pmif->kauai_fcr = base; 12958c2ecf20Sopenharmony_ci pmif->irq = pdev->irq; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, pmif); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci memset(&hw, 0, sizeof(hw)); 13008c2ecf20Sopenharmony_ci pmac_ide_init_ports(&hw, pmif->regbase); 13018c2ecf20Sopenharmony_ci hw.irq = pdev->irq; 13028c2ecf20Sopenharmony_ci hw.dev = &pdev->dev; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci rc = pmac_ide_setup_device(pmif, &hw); 13058c2ecf20Sopenharmony_ci if (rc != 0) { 13068c2ecf20Sopenharmony_ci /* The inteface is released to the common IDE layer */ 13078c2ecf20Sopenharmony_ci iounmap(base); 13088c2ecf20Sopenharmony_ci pci_release_regions(pdev); 13098c2ecf20Sopenharmony_ci kfree(pmif); 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci return rc; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ciout_free_pmif: 13158c2ecf20Sopenharmony_ci kfree(pmif); 13168c2ecf20Sopenharmony_ci return rc; 13178c2ecf20Sopenharmony_ci} 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cistatic int 13208c2ecf20Sopenharmony_cipmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) 13218c2ecf20Sopenharmony_ci{ 13228c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = pci_get_drvdata(pdev); 13238c2ecf20Sopenharmony_ci int rc = 0; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci if (mesg.event != pdev->dev.power.power_state.event 13268c2ecf20Sopenharmony_ci && (mesg.event & PM_EVENT_SLEEP)) { 13278c2ecf20Sopenharmony_ci rc = pmac_ide_do_suspend(pmif); 13288c2ecf20Sopenharmony_ci if (rc == 0) 13298c2ecf20Sopenharmony_ci pdev->dev.power.power_state = mesg; 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci return rc; 13338c2ecf20Sopenharmony_ci} 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_cistatic int 13368c2ecf20Sopenharmony_cipmac_ide_pci_resume(struct pci_dev *pdev) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = pci_get_drvdata(pdev); 13398c2ecf20Sopenharmony_ci int rc = 0; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci if (pdev->dev.power.power_state.event != PM_EVENT_ON) { 13428c2ecf20Sopenharmony_ci rc = pmac_ide_do_resume(pmif); 13438c2ecf20Sopenharmony_ci if (rc == 0) 13448c2ecf20Sopenharmony_ci pdev->dev.power.power_state = PMSG_ON; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci return rc; 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci#ifdef CONFIG_PMAC_MEDIABAY 13518c2ecf20Sopenharmony_cistatic void pmac_ide_macio_mb_event(struct macio_dev* mdev, int mb_state) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci switch(mb_state) { 13568c2ecf20Sopenharmony_ci case MB_CD: 13578c2ecf20Sopenharmony_ci if (!pmif->hwif->present) 13588c2ecf20Sopenharmony_ci ide_port_scan(pmif->hwif); 13598c2ecf20Sopenharmony_ci break; 13608c2ecf20Sopenharmony_ci default: 13618c2ecf20Sopenharmony_ci if (pmif->hwif->present) 13628c2ecf20Sopenharmony_ci ide_port_unregister_devices(pmif->hwif); 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci} 13658c2ecf20Sopenharmony_ci#endif /* CONFIG_PMAC_MEDIABAY */ 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_cistatic struct of_device_id pmac_ide_macio_match[] = 13698c2ecf20Sopenharmony_ci{ 13708c2ecf20Sopenharmony_ci { 13718c2ecf20Sopenharmony_ci .name = "IDE", 13728c2ecf20Sopenharmony_ci }, 13738c2ecf20Sopenharmony_ci { 13748c2ecf20Sopenharmony_ci .name = "ATA", 13758c2ecf20Sopenharmony_ci }, 13768c2ecf20Sopenharmony_ci { 13778c2ecf20Sopenharmony_ci .type = "ide", 13788c2ecf20Sopenharmony_ci }, 13798c2ecf20Sopenharmony_ci { 13808c2ecf20Sopenharmony_ci .type = "ata", 13818c2ecf20Sopenharmony_ci }, 13828c2ecf20Sopenharmony_ci {}, 13838c2ecf20Sopenharmony_ci}; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_cistatic struct macio_driver pmac_ide_macio_driver = 13868c2ecf20Sopenharmony_ci{ 13878c2ecf20Sopenharmony_ci .driver = { 13888c2ecf20Sopenharmony_ci .name = "ide-pmac", 13898c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 13908c2ecf20Sopenharmony_ci .of_match_table = pmac_ide_macio_match, 13918c2ecf20Sopenharmony_ci }, 13928c2ecf20Sopenharmony_ci .probe = pmac_ide_macio_attach, 13938c2ecf20Sopenharmony_ci .suspend = pmac_ide_macio_suspend, 13948c2ecf20Sopenharmony_ci .resume = pmac_ide_macio_resume, 13958c2ecf20Sopenharmony_ci#ifdef CONFIG_PMAC_MEDIABAY 13968c2ecf20Sopenharmony_ci .mediabay_event = pmac_ide_macio_mb_event, 13978c2ecf20Sopenharmony_ci#endif 13988c2ecf20Sopenharmony_ci}; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_cistatic const struct pci_device_id pmac_ide_pci_match[] = { 14018c2ecf20Sopenharmony_ci { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA), 0 }, 14028c2ecf20Sopenharmony_ci { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100), 0 }, 14038c2ecf20Sopenharmony_ci { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100), 0 }, 14048c2ecf20Sopenharmony_ci { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_SH_ATA), 0 }, 14058c2ecf20Sopenharmony_ci { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA), 0 }, 14068c2ecf20Sopenharmony_ci {}, 14078c2ecf20Sopenharmony_ci}; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_cistatic struct pci_driver pmac_ide_pci_driver = { 14108c2ecf20Sopenharmony_ci .name = "ide-pmac", 14118c2ecf20Sopenharmony_ci .id_table = pmac_ide_pci_match, 14128c2ecf20Sopenharmony_ci .probe = pmac_ide_pci_attach, 14138c2ecf20Sopenharmony_ci .suspend = pmac_ide_pci_suspend, 14148c2ecf20Sopenharmony_ci .resume = pmac_ide_pci_resume, 14158c2ecf20Sopenharmony_ci}; 14168c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pmac_ide_pci_match); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ciint __init pmac_ide_probe(void) 14198c2ecf20Sopenharmony_ci{ 14208c2ecf20Sopenharmony_ci int error; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (!machine_is(powermac)) 14238c2ecf20Sopenharmony_ci return -ENODEV; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci#ifdef CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST 14268c2ecf20Sopenharmony_ci error = pci_register_driver(&pmac_ide_pci_driver); 14278c2ecf20Sopenharmony_ci if (error) 14288c2ecf20Sopenharmony_ci goto out; 14298c2ecf20Sopenharmony_ci error = macio_register_driver(&pmac_ide_macio_driver); 14308c2ecf20Sopenharmony_ci if (error) { 14318c2ecf20Sopenharmony_ci pci_unregister_driver(&pmac_ide_pci_driver); 14328c2ecf20Sopenharmony_ci goto out; 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci#else 14358c2ecf20Sopenharmony_ci error = macio_register_driver(&pmac_ide_macio_driver); 14368c2ecf20Sopenharmony_ci if (error) 14378c2ecf20Sopenharmony_ci goto out; 14388c2ecf20Sopenharmony_ci error = pci_register_driver(&pmac_ide_pci_driver); 14398c2ecf20Sopenharmony_ci if (error) { 14408c2ecf20Sopenharmony_ci macio_unregister_driver(&pmac_ide_macio_driver); 14418c2ecf20Sopenharmony_ci goto out; 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci#endif 14448c2ecf20Sopenharmony_ciout: 14458c2ecf20Sopenharmony_ci return error; 14468c2ecf20Sopenharmony_ci} 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci/* 14498c2ecf20Sopenharmony_ci * pmac_ide_build_dmatable builds the DBDMA command list 14508c2ecf20Sopenharmony_ci * for a transfer and sets the DBDMA channel to point to it. 14518c2ecf20Sopenharmony_ci */ 14528c2ecf20Sopenharmony_cistatic int pmac_ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) 14538c2ecf20Sopenharmony_ci{ 14548c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 14558c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 14568c2ecf20Sopenharmony_ci struct dbdma_cmd *table; 14578c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; 14588c2ecf20Sopenharmony_ci struct scatterlist *sg; 14598c2ecf20Sopenharmony_ci int wr = !!(cmd->tf_flags & IDE_TFLAG_WRITE); 14608c2ecf20Sopenharmony_ci int i = cmd->sg_nents, count = 0; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci /* DMA table is already aligned */ 14638c2ecf20Sopenharmony_ci table = (struct dbdma_cmd *) pmif->dma_table_cpu; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci /* Make sure DMA controller is stopped (necessary ?) */ 14668c2ecf20Sopenharmony_ci writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma->control); 14678c2ecf20Sopenharmony_ci while (readl(&dma->status) & RUN) 14688c2ecf20Sopenharmony_ci udelay(1); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci /* Build DBDMA commands list */ 14718c2ecf20Sopenharmony_ci sg = hwif->sg_table; 14728c2ecf20Sopenharmony_ci while (i && sg_dma_len(sg)) { 14738c2ecf20Sopenharmony_ci u32 cur_addr; 14748c2ecf20Sopenharmony_ci u32 cur_len; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci cur_addr = sg_dma_address(sg); 14778c2ecf20Sopenharmony_ci cur_len = sg_dma_len(sg); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci if (pmif->broken_dma && cur_addr & (L1_CACHE_BYTES - 1)) { 14808c2ecf20Sopenharmony_ci if (pmif->broken_dma_warn == 0) { 14818c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: DMA on non aligned address, " 14828c2ecf20Sopenharmony_ci "switching to PIO on Ohare chipset\n", drive->name); 14838c2ecf20Sopenharmony_ci pmif->broken_dma_warn = 1; 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci return 0; 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci while (cur_len) { 14888c2ecf20Sopenharmony_ci unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci if (count++ >= MAX_DCMDS) { 14918c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: DMA table too small\n", 14928c2ecf20Sopenharmony_ci drive->name); 14938c2ecf20Sopenharmony_ci return 0; 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci table->command = cpu_to_le16(wr? OUTPUT_MORE: INPUT_MORE); 14968c2ecf20Sopenharmony_ci table->req_count = cpu_to_le16(tc); 14978c2ecf20Sopenharmony_ci table->phy_addr = cpu_to_le32(cur_addr); 14988c2ecf20Sopenharmony_ci table->cmd_dep = 0; 14998c2ecf20Sopenharmony_ci table->xfer_status = 0; 15008c2ecf20Sopenharmony_ci table->res_count = 0; 15018c2ecf20Sopenharmony_ci cur_addr += tc; 15028c2ecf20Sopenharmony_ci cur_len -= tc; 15038c2ecf20Sopenharmony_ci ++table; 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci sg = sg_next(sg); 15068c2ecf20Sopenharmony_ci i--; 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci /* convert the last command to an input/output last command */ 15108c2ecf20Sopenharmony_ci if (count) { 15118c2ecf20Sopenharmony_ci table[-1].command = cpu_to_le16(wr? OUTPUT_LAST: INPUT_LAST); 15128c2ecf20Sopenharmony_ci /* add the stop command to the end of the list */ 15138c2ecf20Sopenharmony_ci memset(table, 0, sizeof(struct dbdma_cmd)); 15148c2ecf20Sopenharmony_ci table->command = cpu_to_le16(DBDMA_STOP); 15158c2ecf20Sopenharmony_ci mb(); 15168c2ecf20Sopenharmony_ci writel(hwif->dmatable_dma, &dma->cmdptr); 15178c2ecf20Sopenharmony_ci return 1; 15188c2ecf20Sopenharmony_ci } 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci return 0; /* revert to PIO for this request */ 15238c2ecf20Sopenharmony_ci} 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci/* 15268c2ecf20Sopenharmony_ci * Prepare a DMA transfer. We build the DMA table, adjust the timings for 15278c2ecf20Sopenharmony_ci * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion 15288c2ecf20Sopenharmony_ci */ 15298c2ecf20Sopenharmony_cistatic int pmac_ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) 15308c2ecf20Sopenharmony_ci{ 15318c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 15328c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 15338c2ecf20Sopenharmony_ci u8 unit = drive->dn & 1, ata4 = (pmif->kind == controller_kl_ata4); 15348c2ecf20Sopenharmony_ci u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci if (pmac_ide_build_dmatable(drive, cmd) == 0) 15378c2ecf20Sopenharmony_ci return 1; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci /* Apple adds 60ns to wrDataSetup on reads */ 15408c2ecf20Sopenharmony_ci if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) { 15418c2ecf20Sopenharmony_ci writel(pmif->timings[unit] + (write ? 0 : 0x00800000UL), 15428c2ecf20Sopenharmony_ci PMAC_IDE_REG(IDE_TIMING_CONFIG)); 15438c2ecf20Sopenharmony_ci (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci return 0; 15478c2ecf20Sopenharmony_ci} 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci/* 15508c2ecf20Sopenharmony_ci * Kick the DMA controller into life after the DMA command has been issued 15518c2ecf20Sopenharmony_ci * to the drive. 15528c2ecf20Sopenharmony_ci */ 15538c2ecf20Sopenharmony_cistatic void 15548c2ecf20Sopenharmony_cipmac_ide_dma_start(ide_drive_t *drive) 15558c2ecf20Sopenharmony_ci{ 15568c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 15578c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 15588c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *dma; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci dma = pmif->dma_regs; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci writel((RUN << 16) | RUN, &dma->control); 15638c2ecf20Sopenharmony_ci /* Make sure it gets to the controller right now */ 15648c2ecf20Sopenharmony_ci (void)readl(&dma->control); 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci/* 15688c2ecf20Sopenharmony_ci * After a DMA transfer, make sure the controller is stopped 15698c2ecf20Sopenharmony_ci */ 15708c2ecf20Sopenharmony_cistatic int 15718c2ecf20Sopenharmony_cipmac_ide_dma_end (ide_drive_t *drive) 15728c2ecf20Sopenharmony_ci{ 15738c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 15748c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 15758c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; 15768c2ecf20Sopenharmony_ci u32 dstat; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci dstat = readl(&dma->status); 15798c2ecf20Sopenharmony_ci writel(((RUN|WAKE|DEAD) << 16), &dma->control); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci /* verify good dma status. we don't check for ACTIVE beeing 0. We should... 15828c2ecf20Sopenharmony_ci * in theory, but with ATAPI decices doing buffer underruns, that would 15838c2ecf20Sopenharmony_ci * cause us to disable DMA, which isn't what we want 15848c2ecf20Sopenharmony_ci */ 15858c2ecf20Sopenharmony_ci return (dstat & (RUN|DEAD)) != RUN; 15868c2ecf20Sopenharmony_ci} 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci/* 15898c2ecf20Sopenharmony_ci * Check out that the interrupt we got was for us. We can't always know this 15908c2ecf20Sopenharmony_ci * for sure with those Apple interfaces (well, we could on the recent ones but 15918c2ecf20Sopenharmony_ci * that's not implemented yet), on the other hand, we don't have shared interrupts 15928c2ecf20Sopenharmony_ci * so it's not really a problem 15938c2ecf20Sopenharmony_ci */ 15948c2ecf20Sopenharmony_cistatic int 15958c2ecf20Sopenharmony_cipmac_ide_dma_test_irq (ide_drive_t *drive) 15968c2ecf20Sopenharmony_ci{ 15978c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 15988c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 15998c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; 16008c2ecf20Sopenharmony_ci unsigned long status, timeout; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci /* We have to things to deal with here: 16038c2ecf20Sopenharmony_ci * 16048c2ecf20Sopenharmony_ci * - The dbdma won't stop if the command was started 16058c2ecf20Sopenharmony_ci * but completed with an error without transferring all 16068c2ecf20Sopenharmony_ci * datas. This happens when bad blocks are met during 16078c2ecf20Sopenharmony_ci * a multi-block transfer. 16088c2ecf20Sopenharmony_ci * 16098c2ecf20Sopenharmony_ci * - The dbdma fifo hasn't yet finished flushing to 16108c2ecf20Sopenharmony_ci * to system memory when the disk interrupt occurs. 16118c2ecf20Sopenharmony_ci * 16128c2ecf20Sopenharmony_ci */ 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci /* If ACTIVE is cleared, the STOP command have passed and 16158c2ecf20Sopenharmony_ci * transfer is complete. 16168c2ecf20Sopenharmony_ci */ 16178c2ecf20Sopenharmony_ci status = readl(&dma->status); 16188c2ecf20Sopenharmony_ci if (!(status & ACTIVE)) 16198c2ecf20Sopenharmony_ci return 1; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci /* If dbdma didn't execute the STOP command yet, the 16228c2ecf20Sopenharmony_ci * active bit is still set. We consider that we aren't 16238c2ecf20Sopenharmony_ci * sharing interrupts (which is hopefully the case with 16248c2ecf20Sopenharmony_ci * those controllers) and so we just try to flush the 16258c2ecf20Sopenharmony_ci * channel for pending data in the fifo 16268c2ecf20Sopenharmony_ci */ 16278c2ecf20Sopenharmony_ci udelay(1); 16288c2ecf20Sopenharmony_ci writel((FLUSH << 16) | FLUSH, &dma->control); 16298c2ecf20Sopenharmony_ci timeout = 0; 16308c2ecf20Sopenharmony_ci for (;;) { 16318c2ecf20Sopenharmony_ci udelay(1); 16328c2ecf20Sopenharmony_ci status = readl(&dma->status); 16338c2ecf20Sopenharmony_ci if ((status & FLUSH) == 0) 16348c2ecf20Sopenharmony_ci break; 16358c2ecf20Sopenharmony_ci if (++timeout > 100) { 16368c2ecf20Sopenharmony_ci printk(KERN_WARNING "ide%d, ide_dma_test_irq timeout flushing channel\n", 16378c2ecf20Sopenharmony_ci hwif->index); 16388c2ecf20Sopenharmony_ci break; 16398c2ecf20Sopenharmony_ci } 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci return 1; 16428c2ecf20Sopenharmony_ci} 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_cistatic void pmac_ide_dma_host_set(ide_drive_t *drive, int on) 16458c2ecf20Sopenharmony_ci{ 16468c2ecf20Sopenharmony_ci} 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_cistatic void 16498c2ecf20Sopenharmony_cipmac_ide_dma_lost_irq (ide_drive_t *drive) 16508c2ecf20Sopenharmony_ci{ 16518c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 16528c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 16538c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; 16548c2ecf20Sopenharmony_ci unsigned long status = readl(&dma->status); 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status); 16578c2ecf20Sopenharmony_ci} 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_cistatic const struct ide_dma_ops pmac_dma_ops = { 16608c2ecf20Sopenharmony_ci .dma_host_set = pmac_ide_dma_host_set, 16618c2ecf20Sopenharmony_ci .dma_setup = pmac_ide_dma_setup, 16628c2ecf20Sopenharmony_ci .dma_start = pmac_ide_dma_start, 16638c2ecf20Sopenharmony_ci .dma_end = pmac_ide_dma_end, 16648c2ecf20Sopenharmony_ci .dma_test_irq = pmac_ide_dma_test_irq, 16658c2ecf20Sopenharmony_ci .dma_lost_irq = pmac_ide_dma_lost_irq, 16668c2ecf20Sopenharmony_ci}; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci/* 16698c2ecf20Sopenharmony_ci * Allocate the data structures needed for using DMA with an interface 16708c2ecf20Sopenharmony_ci * and fill the proper list of functions pointers 16718c2ecf20Sopenharmony_ci */ 16728c2ecf20Sopenharmony_cistatic int pmac_ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d) 16738c2ecf20Sopenharmony_ci{ 16748c2ecf20Sopenharmony_ci pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); 16758c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci /* We won't need pci_dev if we switch to generic consistent 16788c2ecf20Sopenharmony_ci * DMA routines ... 16798c2ecf20Sopenharmony_ci */ 16808c2ecf20Sopenharmony_ci if (dev == NULL || pmif->dma_regs == 0) 16818c2ecf20Sopenharmony_ci return -ENODEV; 16828c2ecf20Sopenharmony_ci /* 16838c2ecf20Sopenharmony_ci * Allocate space for the DBDMA commands. 16848c2ecf20Sopenharmony_ci * The +2 is +1 for the stop command and +1 to allow for 16858c2ecf20Sopenharmony_ci * aligning the start address to a multiple of 16 bytes. 16868c2ecf20Sopenharmony_ci */ 16878c2ecf20Sopenharmony_ci pmif->dma_table_cpu = dma_alloc_coherent(&dev->dev, 16888c2ecf20Sopenharmony_ci (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), 16898c2ecf20Sopenharmony_ci &hwif->dmatable_dma, GFP_KERNEL); 16908c2ecf20Sopenharmony_ci if (pmif->dma_table_cpu == NULL) { 16918c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: unable to allocate DMA command list\n", 16928c2ecf20Sopenharmony_ci hwif->name); 16938c2ecf20Sopenharmony_ci return -ENOMEM; 16948c2ecf20Sopenharmony_ci } 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci hwif->sg_max_nents = MAX_DCMDS; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci return 0; 16998c2ecf20Sopenharmony_ci} 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_cimodule_init(pmac_ide_probe); 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1704