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