| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 1 | /* | 
|  | 2 | *  Promise PATA TX2/TX4/TX2000/133 IDE driver for pdc20268 to pdc20277. | 
|  | 3 | * | 
|  | 4 | *  This program is free software; you can redistribute it and/or | 
|  | 5 | *  modify it under the terms of the GNU General Public License | 
|  | 6 | *  as published by the Free Software Foundation; either version | 
|  | 7 | *  2 of the License, or (at your option) any later version. | 
|  | 8 | * | 
|  | 9 | *  Ported to libata by: | 
|  | 10 | *  Albert Lee <albertcc@tw.ibm.com> IBM Corporation | 
|  | 11 | * | 
|  | 12 | *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org> | 
|  | 13 | *  Portions Copyright (C) 1999 Promise Technology, Inc. | 
|  | 14 | * | 
|  | 15 | *  Author: Frank Tiernan (frankt@promise.com) | 
|  | 16 | *  Released under terms of General Public License | 
|  | 17 | * | 
|  | 18 | * | 
|  | 19 | *  libata documentation is available via 'make {ps|pdf}docs', | 
|  | 20 | *  as Documentation/DocBook/libata.* | 
|  | 21 | * | 
|  | 22 | *  Hardware information only available under NDA. | 
|  | 23 | * | 
|  | 24 | */ | 
|  | 25 | #include <linux/kernel.h> | 
|  | 26 | #include <linux/module.h> | 
|  | 27 | #include <linux/pci.h> | 
|  | 28 | #include <linux/init.h> | 
|  | 29 | #include <linux/blkdev.h> | 
|  | 30 | #include <linux/delay.h> | 
|  | 31 | #include <linux/device.h> | 
|  | 32 | #include <scsi/scsi.h> | 
|  | 33 | #include <scsi/scsi_host.h> | 
|  | 34 | #include <scsi/scsi_cmnd.h> | 
|  | 35 | #include <linux/libata.h> | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 36 |  | 
|  | 37 | #define DRV_NAME	"pata_pdc2027x" | 
| Jeff Garzik | 2a3103c | 2007-08-31 04:54:06 -0400 | [diff] [blame] | 38 | #define DRV_VERSION	"1.0" | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 39 | #undef PDC_DEBUG | 
|  | 40 |  | 
|  | 41 | #ifdef PDC_DEBUG | 
| Harvey Harrison | 7f5e4e8 | 2008-03-05 18:24:52 -0800 | [diff] [blame] | 42 | #define PDPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args) | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 43 | #else | 
|  | 44 | #define PDPRINTK(fmt, args...) | 
|  | 45 | #endif | 
|  | 46 |  | 
|  | 47 | enum { | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 48 | PDC_MMIO_BAR		= 5, | 
|  | 49 |  | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 50 | PDC_UDMA_100		= 0, | 
|  | 51 | PDC_UDMA_133		= 1, | 
|  | 52 |  | 
|  | 53 | PDC_100_MHZ		= 100000000, | 
|  | 54 | PDC_133_MHZ		= 133333333, | 
|  | 55 |  | 
|  | 56 | PDC_SYS_CTL		= 0x1100, | 
|  | 57 | PDC_ATA_CTL		= 0x1104, | 
|  | 58 | PDC_GLOBAL_CTL		= 0x1108, | 
|  | 59 | PDC_CTCR0		= 0x110C, | 
|  | 60 | PDC_CTCR1		= 0x1110, | 
|  | 61 | PDC_BYTE_COUNT		= 0x1120, | 
|  | 62 | PDC_PLL_CTL		= 0x1202, | 
|  | 63 | }; | 
|  | 64 |  | 
|  | 65 | static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); | 
| Tejun Heo | a1efdab | 2008-03-25 12:22:50 +0900 | [diff] [blame] | 66 | static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 67 | static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev); | 
|  | 68 | static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 69 | static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc); | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 70 | static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask); | 
|  | 71 | static int pdc2027x_cable_detect(struct ata_port *ap); | 
| Tejun Heo | 0260731 | 2007-08-06 18:36:23 +0900 | [diff] [blame] | 72 | static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 73 |  | 
|  | 74 | /* | 
|  | 75 | * ATA Timing Tables based on 133MHz controller clock. | 
|  | 76 | * These tables are only used when the controller is in 133MHz clock. | 
|  | 77 | * If the controller is in 100MHz clock, the ASIC hardware will | 
|  | 78 | * set the timing registers automatically when "set feature" command | 
|  | 79 | * is issued to the device. However, if the controller clock is 133MHz, | 
|  | 80 | * the following tables must be used. | 
|  | 81 | */ | 
|  | 82 | static struct pdc2027x_pio_timing { | 
|  | 83 | u8 value0, value1, value2; | 
|  | 84 | } pdc2027x_pio_timing_tbl [] = { | 
|  | 85 | { 0xfb, 0x2b, 0xac }, /* PIO mode 0 */ | 
|  | 86 | { 0x46, 0x29, 0xa4 }, /* PIO mode 1 */ | 
|  | 87 | { 0x23, 0x26, 0x64 }, /* PIO mode 2 */ | 
|  | 88 | { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */ | 
|  | 89 | { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */ | 
|  | 90 | }; | 
|  | 91 |  | 
|  | 92 | static struct pdc2027x_mdma_timing { | 
|  | 93 | u8 value0, value1; | 
|  | 94 | } pdc2027x_mdma_timing_tbl [] = { | 
|  | 95 | { 0xdf, 0x5f }, /* MDMA mode 0 */ | 
|  | 96 | { 0x6b, 0x27 }, /* MDMA mode 1 */ | 
|  | 97 | { 0x69, 0x25 }, /* MDMA mode 2 */ | 
|  | 98 | }; | 
|  | 99 |  | 
|  | 100 | static struct pdc2027x_udma_timing { | 
|  | 101 | u8 value0, value1, value2; | 
|  | 102 | } pdc2027x_udma_timing_tbl [] = { | 
|  | 103 | { 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */ | 
|  | 104 | { 0x3a, 0x0a, 0xd0 }, /* UDMA mode 1 */ | 
|  | 105 | { 0x2a, 0x07, 0xcd }, /* UDMA mode 2 */ | 
|  | 106 | { 0x1a, 0x05, 0xcd }, /* UDMA mode 3 */ | 
|  | 107 | { 0x1a, 0x03, 0xcd }, /* UDMA mode 4 */ | 
|  | 108 | { 0x1a, 0x02, 0xcb }, /* UDMA mode 5 */ | 
|  | 109 | { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */ | 
|  | 110 | }; | 
|  | 111 |  | 
|  | 112 | static const struct pci_device_id pdc2027x_pci_tbl[] = { | 
| Jeff Garzik | 2d2744f | 2006-09-28 20:21:59 -0400 | [diff] [blame] | 113 | { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), PDC_UDMA_100 }, | 
|  | 114 | { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), PDC_UDMA_133 }, | 
|  | 115 | { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), PDC_UDMA_100 }, | 
|  | 116 | { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), PDC_UDMA_133 }, | 
|  | 117 | { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), PDC_UDMA_133 }, | 
|  | 118 | { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), PDC_UDMA_133 }, | 
|  | 119 | { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), PDC_UDMA_133 }, | 
|  | 120 |  | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 121 | { }	/* terminate list */ | 
|  | 122 | }; | 
|  | 123 |  | 
|  | 124 | static struct pci_driver pdc2027x_pci_driver = { | 
|  | 125 | .name			= DRV_NAME, | 
|  | 126 | .id_table		= pdc2027x_pci_tbl, | 
|  | 127 | .probe			= pdc2027x_init_one, | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 128 | .remove			= ata_pci_remove_one, | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 129 | }; | 
|  | 130 |  | 
|  | 131 | static struct scsi_host_template pdc2027x_sht = { | 
| Tejun Heo | 68d1d07 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 132 | ATA_BMDMA_SHT(DRV_NAME), | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 133 | }; | 
|  | 134 |  | 
|  | 135 | static struct ata_port_operations pdc2027x_pata100_ops = { | 
| Tejun Heo | 029cfd6 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 136 | .inherits		= &ata_bmdma_port_ops, | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 137 | .check_atapi_dma	= pdc2027x_check_atapi_dma, | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 138 | .cable_detect		= pdc2027x_cable_detect, | 
| Tejun Heo | a1efdab | 2008-03-25 12:22:50 +0900 | [diff] [blame] | 139 | .prereset		= pdc2027x_prereset, | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 140 | }; | 
|  | 141 |  | 
|  | 142 | static struct ata_port_operations pdc2027x_pata133_ops = { | 
| Tejun Heo | 029cfd6 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 143 | .inherits		= &pdc2027x_pata100_ops, | 
|  | 144 | .mode_filter		= pdc2027x_mode_filter, | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 145 | .set_piomode		= pdc2027x_set_piomode, | 
|  | 146 | .set_dmamode		= pdc2027x_set_dmamode, | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 147 | .set_mode		= pdc2027x_set_mode, | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 148 | }; | 
|  | 149 |  | 
|  | 150 | static struct ata_port_info pdc2027x_port_info[] = { | 
|  | 151 | /* PDC_UDMA_100 */ | 
|  | 152 | { | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 153 | .flags		= ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS | | 
|  | 154 | ATA_FLAG_MMIO, | 
| Erik Inge Bolsø | 14bdef9 | 2009-03-14 21:38:24 +0100 | [diff] [blame] | 155 | .pio_mask	= ATA_PIO4, | 
|  | 156 | .mwdma_mask	= ATA_MWDMA2, | 
|  | 157 | .udma_mask	= ATA_UDMA5, | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 158 | .port_ops	= &pdc2027x_pata100_ops, | 
|  | 159 | }, | 
|  | 160 | /* PDC_UDMA_133 */ | 
|  | 161 | { | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 162 | .flags		= ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS | | 
|  | 163 | ATA_FLAG_MMIO, | 
| Erik Inge Bolsø | 14bdef9 | 2009-03-14 21:38:24 +0100 | [diff] [blame] | 164 | .pio_mask	= ATA_PIO4, | 
|  | 165 | .mwdma_mask	= ATA_MWDMA2, | 
|  | 166 | .udma_mask	= ATA_UDMA6, | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 167 | .port_ops	= &pdc2027x_pata133_ops, | 
|  | 168 | }, | 
|  | 169 | }; | 
|  | 170 |  | 
|  | 171 | MODULE_AUTHOR("Andre Hedrick, Frank Tiernan, Albert Lee"); | 
|  | 172 | MODULE_DESCRIPTION("libata driver module for Promise PDC20268 to PDC20277"); | 
|  | 173 | MODULE_LICENSE("GPL"); | 
|  | 174 | MODULE_VERSION(DRV_VERSION); | 
|  | 175 | MODULE_DEVICE_TABLE(pci, pdc2027x_pci_tbl); | 
|  | 176 |  | 
|  | 177 | /** | 
|  | 178 | *	port_mmio - Get the MMIO address of PDC2027x extended registers | 
|  | 179 | *	@ap: Port | 
|  | 180 | *	@offset: offset from mmio base | 
|  | 181 | */ | 
| Al Viro | 7c25041 | 2006-09-25 02:57:57 +0100 | [diff] [blame] | 182 | static inline void __iomem *port_mmio(struct ata_port *ap, unsigned int offset) | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 183 | { | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 184 | return ap->host->iomap[PDC_MMIO_BAR] + ap->port_no * 0x100 + offset; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 185 | } | 
|  | 186 |  | 
|  | 187 | /** | 
|  | 188 | *	dev_mmio - Get the MMIO address of PDC2027x extended registers | 
|  | 189 | *	@ap: Port | 
|  | 190 | *	@adev: device | 
|  | 191 | *	@offset: offset from mmio base | 
|  | 192 | */ | 
| Al Viro | 7c25041 | 2006-09-25 02:57:57 +0100 | [diff] [blame] | 193 | static inline void __iomem *dev_mmio(struct ata_port *ap, struct ata_device *adev, unsigned int offset) | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 194 | { | 
|  | 195 | u8 adj = (adev->devno) ? 0x08 : 0x00; | 
|  | 196 | return port_mmio(ap, offset) + adj; | 
|  | 197 | } | 
|  | 198 |  | 
|  | 199 | /** | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 200 | *	pdc2027x_pata_cable_detect - Probe host controller cable detect info | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 201 | *	@ap: Port for which cable detect info is desired | 
|  | 202 | * | 
|  | 203 | *	Read 80c cable indicator from Promise extended register. | 
|  | 204 | *      This register is latched when the system is reset. | 
|  | 205 | * | 
|  | 206 | *	LOCKING: | 
|  | 207 | *	None (inherited from caller). | 
|  | 208 | */ | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 209 | static int pdc2027x_cable_detect(struct ata_port *ap) | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 210 | { | 
|  | 211 | u32 cgcr; | 
|  | 212 |  | 
|  | 213 | /* check cable detect results */ | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 214 | cgcr = ioread32(port_mmio(ap, PDC_GLOBAL_CTL)); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 215 | if (cgcr & (1 << 26)) | 
|  | 216 | goto cbl40; | 
|  | 217 |  | 
|  | 218 | PDPRINTK("No cable or 80-conductor cable on port %d\n", ap->port_no); | 
|  | 219 |  | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 220 | return ATA_CBL_PATA80; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 221 | cbl40: | 
|  | 222 | printk(KERN_INFO DRV_NAME ": 40-conductor cable detected on port %d\n", ap->port_no); | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 223 | return ATA_CBL_PATA40; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 224 | } | 
|  | 225 |  | 
|  | 226 | /** | 
|  | 227 | * pdc2027x_port_enabled - Check PDC ATA control register to see whether the port is enabled. | 
|  | 228 | * @ap: Port to check | 
|  | 229 | */ | 
|  | 230 | static inline int pdc2027x_port_enabled(struct ata_port *ap) | 
|  | 231 | { | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 232 | return ioread8(port_mmio(ap, PDC_ATA_CTL)) & 0x02; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 233 | } | 
|  | 234 |  | 
|  | 235 | /** | 
|  | 236 | *	pdc2027x_prereset - prereset for PATA host controller | 
| Tejun Heo | cc0680a | 2007-08-06 18:36:23 +0900 | [diff] [blame] | 237 | *	@link: Target link | 
| Tejun Heo | d4b2bab | 2007-02-02 16:50:52 +0900 | [diff] [blame] | 238 | *	@deadline: deadline jiffies for the operation | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 239 | * | 
|  | 240 | *	Probeinit including cable detection. | 
|  | 241 | * | 
|  | 242 | *	LOCKING: | 
|  | 243 | *	None (inherited from caller). | 
|  | 244 | */ | 
|  | 245 |  | 
| Tejun Heo | cc0680a | 2007-08-06 18:36:23 +0900 | [diff] [blame] | 246 | static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline) | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 247 | { | 
|  | 248 | /* Check whether port enabled */ | 
| Tejun Heo | cc0680a | 2007-08-06 18:36:23 +0900 | [diff] [blame] | 249 | if (!pdc2027x_port_enabled(link->ap)) | 
| Alan Cox | c961922 | 2006-09-26 17:53:38 +0100 | [diff] [blame] | 250 | return -ENOENT; | 
| Tejun Heo | 9363c38 | 2008-04-07 22:47:16 +0900 | [diff] [blame] | 251 | return ata_sff_prereset(link, deadline); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 252 | } | 
|  | 253 |  | 
|  | 254 | /** | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 255 | *	pdc2720x_mode_filter	-	mode selection filter | 
|  | 256 | *	@adev: ATA device | 
|  | 257 | *	@mask: list of modes proposed | 
|  | 258 | * | 
|  | 259 | *	Block UDMA on devices that cause trouble with this controller. | 
|  | 260 | */ | 
|  | 261 |  | 
|  | 262 | static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask) | 
|  | 263 | { | 
|  | 264 | unsigned char model_num[ATA_ID_PROD_LEN + 1]; | 
|  | 265 | struct ata_device *pair = ata_dev_pair(adev); | 
|  | 266 |  | 
|  | 267 | if (adev->class != ATA_DEV_ATA || adev->devno == 0 || pair == NULL) | 
| Tejun Heo | 9363c38 | 2008-04-07 22:47:16 +0900 | [diff] [blame] | 268 | return ata_bmdma_mode_filter(adev, mask); | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 269 |  | 
|  | 270 | /* Check for slave of a Maxtor at UDMA6 */ | 
|  | 271 | ata_id_c_string(pair->id, model_num, ATA_ID_PROD, | 
|  | 272 | ATA_ID_PROD_LEN + 1); | 
|  | 273 | /* If the master is a maxtor in UDMA6 then the slave should not use UDMA 6 */ | 
| Al Viro | 4ca4e43 | 2007-12-30 09:32:22 +0000 | [diff] [blame] | 274 | if (strstr(model_num, "Maxtor") == NULL && pair->dma_mode == XFER_UDMA_6) | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 275 | mask &= ~ (1 << (6 + ATA_SHIFT_UDMA)); | 
|  | 276 |  | 
| Tejun Heo | 9363c38 | 2008-04-07 22:47:16 +0900 | [diff] [blame] | 277 | return ata_bmdma_mode_filter(adev, mask); | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 278 | } | 
|  | 279 |  | 
|  | 280 | /** | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 281 | *	pdc2027x_set_piomode - Initialize host controller PATA PIO timings | 
|  | 282 | *	@ap: Port to configure | 
|  | 283 | *	@adev: um | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 284 | * | 
|  | 285 | *	Set PIO mode for device. | 
|  | 286 | * | 
|  | 287 | *	LOCKING: | 
|  | 288 | *	None (inherited from caller). | 
|  | 289 | */ | 
|  | 290 |  | 
|  | 291 | static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev) | 
|  | 292 | { | 
|  | 293 | unsigned int pio = adev->pio_mode - XFER_PIO_0; | 
|  | 294 | u32 ctcr0, ctcr1; | 
|  | 295 |  | 
|  | 296 | PDPRINTK("adev->pio_mode[%X]\n", adev->pio_mode); | 
|  | 297 |  | 
|  | 298 | /* Sanity check */ | 
|  | 299 | if (pio > 4) { | 
|  | 300 | printk(KERN_ERR DRV_NAME ": Unknown pio mode [%d] ignored\n", pio); | 
|  | 301 | return; | 
|  | 302 |  | 
|  | 303 | } | 
|  | 304 |  | 
|  | 305 | /* Set the PIO timing registers using value table for 133MHz */ | 
|  | 306 | PDPRINTK("Set pio regs... \n"); | 
|  | 307 |  | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 308 | ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0)); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 309 | ctcr0 &= 0xffff0000; | 
|  | 310 | ctcr0 |= pdc2027x_pio_timing_tbl[pio].value0 | | 
|  | 311 | (pdc2027x_pio_timing_tbl[pio].value1 << 8); | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 312 | iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 313 |  | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 314 | ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1)); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 315 | ctcr1 &= 0x00ffffff; | 
|  | 316 | ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24); | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 317 | iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 318 |  | 
|  | 319 | PDPRINTK("Set pio regs done\n"); | 
|  | 320 |  | 
|  | 321 | PDPRINTK("Set to pio mode[%u] \n", pio); | 
|  | 322 | } | 
|  | 323 |  | 
|  | 324 | /** | 
|  | 325 | *	pdc2027x_set_dmamode - Initialize host controller PATA UDMA timings | 
|  | 326 | *	@ap: Port to configure | 
|  | 327 | *	@adev: um | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 328 | * | 
|  | 329 | *	Set UDMA mode for device. | 
|  | 330 | * | 
|  | 331 | *	LOCKING: | 
|  | 332 | *	None (inherited from caller). | 
|  | 333 | */ | 
|  | 334 | static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) | 
|  | 335 | { | 
|  | 336 | unsigned int dma_mode = adev->dma_mode; | 
|  | 337 | u32 ctcr0, ctcr1; | 
|  | 338 |  | 
|  | 339 | if ((dma_mode >= XFER_UDMA_0) && | 
|  | 340 | (dma_mode <= XFER_UDMA_6)) { | 
|  | 341 | /* Set the UDMA timing registers with value table for 133MHz */ | 
|  | 342 | unsigned int udma_mode = dma_mode & 0x07; | 
|  | 343 |  | 
|  | 344 | if (dma_mode == XFER_UDMA_2) { | 
|  | 345 | /* | 
|  | 346 | * Turn off tHOLD. | 
|  | 347 | * If tHOLD is '1', the hardware will add half clock for data hold time. | 
|  | 348 | * This code segment seems to be no effect. tHOLD will be overwritten below. | 
|  | 349 | */ | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 350 | ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1)); | 
|  | 351 | iowrite32(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1)); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 352 | } | 
|  | 353 |  | 
|  | 354 | PDPRINTK("Set udma regs... \n"); | 
|  | 355 |  | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 356 | ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1)); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 357 | ctcr1 &= 0xff000000; | 
|  | 358 | ctcr1 |= pdc2027x_udma_timing_tbl[udma_mode].value0 | | 
|  | 359 | (pdc2027x_udma_timing_tbl[udma_mode].value1 << 8) | | 
|  | 360 | (pdc2027x_udma_timing_tbl[udma_mode].value2 << 16); | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 361 | iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 362 |  | 
|  | 363 | PDPRINTK("Set udma regs done\n"); | 
|  | 364 |  | 
|  | 365 | PDPRINTK("Set to udma mode[%u] \n", udma_mode); | 
|  | 366 |  | 
|  | 367 | } else  if ((dma_mode >= XFER_MW_DMA_0) && | 
|  | 368 | (dma_mode <= XFER_MW_DMA_2)) { | 
|  | 369 | /* Set the MDMA timing registers with value table for 133MHz */ | 
|  | 370 | unsigned int mdma_mode = dma_mode & 0x07; | 
|  | 371 |  | 
|  | 372 | PDPRINTK("Set mdma regs... \n"); | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 373 | ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0)); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 374 |  | 
|  | 375 | ctcr0 &= 0x0000ffff; | 
|  | 376 | ctcr0 |= (pdc2027x_mdma_timing_tbl[mdma_mode].value0 << 16) | | 
|  | 377 | (pdc2027x_mdma_timing_tbl[mdma_mode].value1 << 24); | 
|  | 378 |  | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 379 | iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 380 | PDPRINTK("Set mdma regs done\n"); | 
|  | 381 |  | 
|  | 382 | PDPRINTK("Set to mdma mode[%u] \n", mdma_mode); | 
|  | 383 | } else { | 
|  | 384 | printk(KERN_ERR DRV_NAME ": Unknown dma mode [%u] ignored\n", dma_mode); | 
|  | 385 | } | 
|  | 386 | } | 
|  | 387 |  | 
|  | 388 | /** | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 389 | *	pdc2027x_set_mode - Set the timing registers back to correct values. | 
| Tejun Heo | 0260731 | 2007-08-06 18:36:23 +0900 | [diff] [blame] | 390 | *	@link: link to configure | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 391 | *	@r_failed: Returned device for failure | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 392 | * | 
|  | 393 | *	The pdc2027x hardware will look at "SET FEATURES" and change the timing registers | 
|  | 394 | *	automatically. The values set by the hardware might be incorrect, under 133Mhz PLL. | 
|  | 395 | *	This function overwrites the possibly incorrect values set by the hardware to be correct. | 
|  | 396 | */ | 
| Tejun Heo | 0260731 | 2007-08-06 18:36:23 +0900 | [diff] [blame] | 397 | static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed) | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 398 | { | 
| Tejun Heo | 0260731 | 2007-08-06 18:36:23 +0900 | [diff] [blame] | 399 | struct ata_port *ap = link->ap; | 
| Tejun Heo | f58229f | 2007-08-06 18:36:23 +0900 | [diff] [blame] | 400 | struct ata_device *dev; | 
|  | 401 | int rc; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 402 |  | 
| Tejun Heo | 0260731 | 2007-08-06 18:36:23 +0900 | [diff] [blame] | 403 | rc = ata_do_set_mode(link, r_failed); | 
| Tejun Heo | f58229f | 2007-08-06 18:36:23 +0900 | [diff] [blame] | 404 | if (rc < 0) | 
|  | 405 | return rc; | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 406 |  | 
| Tejun Heo | 1eca436 | 2008-11-03 20:03:17 +0900 | [diff] [blame] | 407 | ata_for_each_dev(dev, link, ENABLED) { | 
|  | 408 | pdc2027x_set_piomode(ap, dev); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 409 |  | 
| Tejun Heo | 1eca436 | 2008-11-03 20:03:17 +0900 | [diff] [blame] | 410 | /* | 
|  | 411 | * Enable prefetch if the device support PIO only. | 
|  | 412 | */ | 
|  | 413 | if (dev->xfer_shift == ATA_SHIFT_PIO) { | 
|  | 414 | u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1)); | 
|  | 415 | ctcr1 |= (1 << 25); | 
|  | 416 | iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1)); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 417 |  | 
| Tejun Heo | 1eca436 | 2008-11-03 20:03:17 +0900 | [diff] [blame] | 418 | PDPRINTK("Turn on prefetch\n"); | 
|  | 419 | } else { | 
|  | 420 | pdc2027x_set_dmamode(ap, dev); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 421 | } | 
|  | 422 | } | 
| Alan Cox | 9bedb79 | 2007-04-11 00:19:00 +0100 | [diff] [blame] | 423 | return 0; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 424 | } | 
|  | 425 |  | 
|  | 426 | /** | 
|  | 427 | *	pdc2027x_check_atapi_dma - Check whether ATAPI DMA can be supported for this command | 
|  | 428 | *	@qc: Metadata associated with taskfile to check | 
|  | 429 | * | 
|  | 430 | *	LOCKING: | 
|  | 431 | *	None (inherited from caller). | 
|  | 432 | * | 
|  | 433 | *	RETURNS: 0 when ATAPI DMA can be used | 
|  | 434 | *		 1 otherwise | 
|  | 435 | */ | 
|  | 436 | static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc) | 
|  | 437 | { | 
|  | 438 | struct scsi_cmnd *cmd = qc->scsicmd; | 
|  | 439 | u8 *scsicmd = cmd->cmnd; | 
|  | 440 | int rc = 1; /* atapi dma off by default */ | 
|  | 441 |  | 
|  | 442 | /* | 
|  | 443 | * This workaround is from Promise's GPL driver. | 
|  | 444 | * If ATAPI DMA is used for commands not in the | 
|  | 445 | * following white list, say MODE_SENSE and REQUEST_SENSE, | 
|  | 446 | * pdc2027x might hit the irq lost problem. | 
|  | 447 | */ | 
|  | 448 | switch (scsicmd[0]) { | 
|  | 449 | case READ_10: | 
|  | 450 | case WRITE_10: | 
|  | 451 | case READ_12: | 
|  | 452 | case WRITE_12: | 
|  | 453 | case READ_6: | 
|  | 454 | case WRITE_6: | 
|  | 455 | case 0xad: /* READ_DVD_STRUCTURE */ | 
|  | 456 | case 0xbe: /* READ_CD */ | 
|  | 457 | /* ATAPI DMA is ok */ | 
|  | 458 | rc = 0; | 
|  | 459 | break; | 
|  | 460 | default: | 
|  | 461 | ; | 
|  | 462 | } | 
|  | 463 |  | 
|  | 464 | return rc; | 
|  | 465 | } | 
|  | 466 |  | 
|  | 467 | /** | 
|  | 468 | * pdc_read_counter - Read the ctr counter | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 469 | * @host: target ATA host | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 470 | */ | 
|  | 471 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 472 | static long pdc_read_counter(struct ata_host *host) | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 473 | { | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 474 | void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR]; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 475 | long counter; | 
|  | 476 | int retry = 1; | 
|  | 477 | u32 bccrl, bccrh, bccrlv, bccrhv; | 
|  | 478 |  | 
|  | 479 | retry: | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 480 | bccrl = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff; | 
|  | 481 | bccrh = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 482 |  | 
|  | 483 | /* Read the counter values again for verification */ | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 484 | bccrlv = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff; | 
|  | 485 | bccrhv = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 486 |  | 
|  | 487 | counter = (bccrh << 15) | bccrl; | 
|  | 488 |  | 
|  | 489 | PDPRINTK("bccrh [%X] bccrl [%X]\n", bccrh,  bccrl); | 
|  | 490 | PDPRINTK("bccrhv[%X] bccrlv[%X]\n", bccrhv, bccrlv); | 
|  | 491 |  | 
|  | 492 | /* | 
|  | 493 | * The 30-bit decreasing counter are read by 2 pieces. | 
|  | 494 | * Incorrect value may be read when both bccrh and bccrl are changing. | 
|  | 495 | * Ex. When 7900 decrease to 78FF, wrong value 7800 might be read. | 
|  | 496 | */ | 
|  | 497 | if (retry && !(bccrh == bccrhv && bccrl >= bccrlv)) { | 
|  | 498 | retry--; | 
|  | 499 | PDPRINTK("rereading counter\n"); | 
|  | 500 | goto retry; | 
|  | 501 | } | 
|  | 502 |  | 
|  | 503 | return counter; | 
|  | 504 | } | 
|  | 505 |  | 
|  | 506 | /** | 
|  | 507 | * adjust_pll - Adjust the PLL input clock in Hz. | 
|  | 508 | * | 
|  | 509 | * @pdc_controller: controller specific information | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 510 | * @host: target ATA host | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 511 | * @pll_clock: The input of PLL in HZ | 
|  | 512 | */ | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 513 | static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int board_idx) | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 514 | { | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 515 | void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR]; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 516 | u16 pll_ctl; | 
|  | 517 | long pll_clock_khz = pll_clock / 1000; | 
|  | 518 | long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ; | 
|  | 519 | long ratio = pout_required / pll_clock_khz; | 
|  | 520 | int F, R; | 
|  | 521 |  | 
|  | 522 | /* Sanity check */ | 
|  | 523 | if (unlikely(pll_clock_khz < 5000L || pll_clock_khz > 70000L)) { | 
|  | 524 | printk(KERN_ERR DRV_NAME ": Invalid PLL input clock %ldkHz, give up!\n", pll_clock_khz); | 
|  | 525 | return; | 
|  | 526 | } | 
|  | 527 |  | 
|  | 528 | #ifdef PDC_DEBUG | 
|  | 529 | PDPRINTK("pout_required is %ld\n", pout_required); | 
|  | 530 |  | 
|  | 531 | /* Show the current clock value of PLL control register | 
|  | 532 | * (maybe already configured by the firmware) | 
|  | 533 | */ | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 534 | pll_ctl = ioread16(mmio_base + PDC_PLL_CTL); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 535 |  | 
|  | 536 | PDPRINTK("pll_ctl[%X]\n", pll_ctl); | 
|  | 537 | #endif | 
|  | 538 |  | 
|  | 539 | /* | 
|  | 540 | * Calculate the ratio of F, R and OD | 
|  | 541 | * POUT = (F + 2) / (( R + 2) * NO) | 
|  | 542 | */ | 
|  | 543 | if (ratio < 8600L) { /* 8.6x */ | 
|  | 544 | /* Using NO = 0x01, R = 0x0D */ | 
|  | 545 | R = 0x0d; | 
|  | 546 | } else if (ratio < 12900L) { /* 12.9x */ | 
|  | 547 | /* Using NO = 0x01, R = 0x08 */ | 
|  | 548 | R = 0x08; | 
|  | 549 | } else if (ratio < 16100L) { /* 16.1x */ | 
|  | 550 | /* Using NO = 0x01, R = 0x06 */ | 
|  | 551 | R = 0x06; | 
|  | 552 | } else if (ratio < 64000L) { /* 64x */ | 
|  | 553 | R = 0x00; | 
|  | 554 | } else { | 
|  | 555 | /* Invalid ratio */ | 
|  | 556 | printk(KERN_ERR DRV_NAME ": Invalid ratio %ld, give up!\n", ratio); | 
|  | 557 | return; | 
|  | 558 | } | 
|  | 559 |  | 
|  | 560 | F = (ratio * (R+2)) / 1000 - 2; | 
|  | 561 |  | 
|  | 562 | if (unlikely(F < 0 || F > 127)) { | 
|  | 563 | /* Invalid F */ | 
|  | 564 | printk(KERN_ERR DRV_NAME ": F[%d] invalid!\n", F); | 
|  | 565 | return; | 
|  | 566 | } | 
|  | 567 |  | 
|  | 568 | PDPRINTK("F[%d] R[%d] ratio*1000[%ld]\n", F, R, ratio); | 
|  | 569 |  | 
|  | 570 | pll_ctl = (R << 8) | F; | 
|  | 571 |  | 
|  | 572 | PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl); | 
|  | 573 |  | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 574 | iowrite16(pll_ctl, mmio_base + PDC_PLL_CTL); | 
|  | 575 | ioread16(mmio_base + PDC_PLL_CTL); /* flush */ | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 576 |  | 
|  | 577 | /* Wait the PLL circuit to be stable */ | 
|  | 578 | mdelay(30); | 
|  | 579 |  | 
|  | 580 | #ifdef PDC_DEBUG | 
|  | 581 | /* | 
|  | 582 | *  Show the current clock value of PLL control register | 
|  | 583 | * (maybe configured by the firmware) | 
|  | 584 | */ | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 585 | pll_ctl = ioread16(mmio_base + PDC_PLL_CTL); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 586 |  | 
|  | 587 | PDPRINTK("pll_ctl[%X]\n", pll_ctl); | 
|  | 588 | #endif | 
|  | 589 |  | 
|  | 590 | return; | 
|  | 591 | } | 
|  | 592 |  | 
|  | 593 | /** | 
|  | 594 | * detect_pll_input_clock - Detect the PLL input clock in Hz. | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 595 | * @host: target ATA host | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 596 | * Ex. 16949000 on 33MHz PCI bus for pdc20275. | 
|  | 597 | *     Half of the PCI clock. | 
|  | 598 | */ | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 599 | static long pdc_detect_pll_input_clock(struct ata_host *host) | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 600 | { | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 601 | void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR]; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 602 | u32 scr; | 
|  | 603 | long start_count, end_count; | 
| Albert Lee | 8c781bf | 2007-06-26 13:43:15 +0800 | [diff] [blame] | 604 | struct timeval start_time, end_time; | 
|  | 605 | long pll_clock, usec_elapsed; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 606 |  | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 607 | /* Start the test mode */ | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 608 | scr = ioread32(mmio_base + PDC_SYS_CTL); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 609 | PDPRINTK("scr[%X]\n", scr); | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 610 | iowrite32(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL); | 
|  | 611 | ioread32(mmio_base + PDC_SYS_CTL); /* flush */ | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 612 |  | 
| Mikael Pettersson | 78c4af0 | 2007-08-18 22:58:53 +0200 | [diff] [blame] | 613 | /* Read current counter value */ | 
|  | 614 | start_count = pdc_read_counter(host); | 
|  | 615 | do_gettimeofday(&start_time); | 
|  | 616 |  | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 617 | /* Let the counter run for 100 ms. */ | 
|  | 618 | mdelay(100); | 
|  | 619 |  | 
|  | 620 | /* Read the counter values again */ | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 621 | end_count = pdc_read_counter(host); | 
| Albert Lee | 8c781bf | 2007-06-26 13:43:15 +0800 | [diff] [blame] | 622 | do_gettimeofday(&end_time); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 623 |  | 
|  | 624 | /* Stop the test mode */ | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 625 | scr = ioread32(mmio_base + PDC_SYS_CTL); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 626 | PDPRINTK("scr[%X]\n", scr); | 
| Alan Cox | d2a84f4 | 2007-09-20 15:07:12 +0100 | [diff] [blame] | 627 | iowrite32(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL); | 
|  | 628 | ioread32(mmio_base + PDC_SYS_CTL); /* flush */ | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 629 |  | 
|  | 630 | /* calculate the input clock in Hz */ | 
| Albert Lee | 8c781bf | 2007-06-26 13:43:15 +0800 | [diff] [blame] | 631 | usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 + | 
|  | 632 | (end_time.tv_usec - start_time.tv_usec); | 
|  | 633 |  | 
| Mikael Pettersson | 78c4af0 | 2007-08-18 22:58:53 +0200 | [diff] [blame] | 634 | pll_clock = ((start_count - end_count) & 0x3fffffff) / 100 * | 
| Albert Lee | 8c781bf | 2007-06-26 13:43:15 +0800 | [diff] [blame] | 635 | (100000000 / usec_elapsed); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 636 |  | 
|  | 637 | PDPRINTK("start[%ld] end[%ld] \n", start_count, end_count); | 
|  | 638 | PDPRINTK("PLL input clock[%ld]Hz\n", pll_clock); | 
|  | 639 |  | 
|  | 640 | return pll_clock; | 
|  | 641 | } | 
|  | 642 |  | 
|  | 643 | /** | 
|  | 644 | * pdc_hardware_init - Initialize the hardware. | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 645 | * @host: target ATA host | 
|  | 646 | * @board_idx: board identifier | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 647 | */ | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 648 | static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx) | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 649 | { | 
|  | 650 | long pll_clock; | 
|  | 651 |  | 
|  | 652 | /* | 
|  | 653 | * Detect PLL input clock rate. | 
|  | 654 | * On some system, where PCI bus is running at non-standard clock rate. | 
|  | 655 | * Ex. 25MHz or 40MHz, we have to adjust the cycle_time. | 
|  | 656 | * The pdc20275 controller employs PLL circuit to help correct timing registers setting. | 
|  | 657 | */ | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 658 | pll_clock = pdc_detect_pll_input_clock(host); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 659 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 660 | dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 661 |  | 
|  | 662 | /* Adjust PLL control register */ | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 663 | pdc_adjust_pll(host, pll_clock, board_idx); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 664 |  | 
|  | 665 | return 0; | 
|  | 666 | } | 
|  | 667 |  | 
|  | 668 | /** | 
|  | 669 | * pdc_ata_setup_port - setup the mmio address | 
|  | 670 | * @port: ata ioports to setup | 
|  | 671 | * @base: base address | 
|  | 672 | */ | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 673 | static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base) | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 674 | { | 
|  | 675 | port->cmd_addr		= | 
|  | 676 | port->data_addr		= base; | 
|  | 677 | port->feature_addr	= | 
|  | 678 | port->error_addr	= base + 0x05; | 
|  | 679 | port->nsect_addr	= base + 0x0a; | 
|  | 680 | port->lbal_addr		= base + 0x0f; | 
|  | 681 | port->lbam_addr		= base + 0x10; | 
|  | 682 | port->lbah_addr		= base + 0x15; | 
|  | 683 | port->device_addr	= base + 0x1a; | 
|  | 684 | port->command_addr	= | 
|  | 685 | port->status_addr	= base + 0x1f; | 
|  | 686 | port->altstatus_addr	= | 
|  | 687 | port->ctl_addr		= base + 0x81a; | 
|  | 688 | } | 
|  | 689 |  | 
|  | 690 | /** | 
|  | 691 | * pdc2027x_init_one - PCI probe function | 
|  | 692 | * Called when an instance of PCI adapter is inserted. | 
|  | 693 | * This function checks whether the hardware is supported, | 
|  | 694 | * initialize hardware and register an instance of ata_host to | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 695 | * libata.  (implements struct pci_driver.probe() ) | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 696 | * | 
|  | 697 | * @pdev: instance of pci_dev found | 
|  | 698 | * @ent:  matching entry in the id_tbl[] | 
|  | 699 | */ | 
|  | 700 | static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | 
|  | 701 | { | 
|  | 702 | static int printed_version; | 
| Tejun Heo | cbcdd87 | 2007-08-18 13:14:55 +0900 | [diff] [blame] | 703 | static const unsigned long cmd_offset[] = { 0x17c0, 0x15c0 }; | 
|  | 704 | static const unsigned long bmdma_offset[] = { 0x1000, 0x1008 }; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 705 | unsigned int board_idx = (unsigned int) ent->driver_data; | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 706 | const struct ata_port_info *ppi[] = | 
|  | 707 | { &pdc2027x_port_info[board_idx], NULL }; | 
|  | 708 | struct ata_host *host; | 
| Al Viro | 7c25041 | 2006-09-25 02:57:57 +0100 | [diff] [blame] | 709 | void __iomem *mmio_base; | 
| Tejun Heo | cbcdd87 | 2007-08-18 13:14:55 +0900 | [diff] [blame] | 710 | int i, rc; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 711 |  | 
|  | 712 | if (!printed_version++) | 
|  | 713 | dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); | 
|  | 714 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 715 | /* alloc host */ | 
|  | 716 | host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2); | 
|  | 717 | if (!host) | 
|  | 718 | return -ENOMEM; | 
|  | 719 |  | 
|  | 720 | /* acquire resources and fill host */ | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 721 | rc = pcim_enable_device(pdev); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 722 | if (rc) | 
|  | 723 | return rc; | 
|  | 724 |  | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 725 | rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 726 | if (rc) | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 727 | return rc; | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 728 | host->iomap = pcim_iomap_table(pdev); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 729 |  | 
|  | 730 | rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); | 
|  | 731 | if (rc) | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 732 | return rc; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 733 |  | 
|  | 734 | rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); | 
|  | 735 | if (rc) | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 736 | return rc; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 737 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 738 | mmio_base = host->iomap[PDC_MMIO_BAR]; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 739 |  | 
| Tejun Heo | cbcdd87 | 2007-08-18 13:14:55 +0900 | [diff] [blame] | 740 | for (i = 0; i < 2; i++) { | 
|  | 741 | struct ata_port *ap = host->ports[i]; | 
|  | 742 |  | 
|  | 743 | pdc_ata_setup_port(&ap->ioaddr, mmio_base + cmd_offset[i]); | 
|  | 744 | ap->ioaddr.bmdma_addr = mmio_base + bmdma_offset[i]; | 
|  | 745 |  | 
|  | 746 | ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio"); | 
|  | 747 | ata_port_pbar_desc(ap, PDC_MMIO_BAR, cmd_offset[i], "cmd"); | 
|  | 748 | } | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 749 |  | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 750 | //pci_enable_intx(pdev); | 
|  | 751 |  | 
|  | 752 | /* initialize adapter */ | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 753 | if (pdc_hardware_init(host, board_idx) != 0) | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 754 | return -EIO; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 755 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 756 | pci_set_master(pdev); | 
| Tejun Heo | 9363c38 | 2008-04-07 22:47:16 +0900 | [diff] [blame] | 757 | return ata_host_activate(host, pdev->irq, ata_sff_interrupt, | 
|  | 758 | IRQF_SHARED, &pdc2027x_sht); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 759 | } | 
|  | 760 |  | 
|  | 761 | /** | 
|  | 762 | * pdc2027x_init - Called after this module is loaded into the kernel. | 
|  | 763 | */ | 
|  | 764 | static int __init pdc2027x_init(void) | 
|  | 765 | { | 
| Henrik Kretzschmar | 72dc679 | 2006-10-10 14:29:24 -0700 | [diff] [blame] | 766 | return pci_register_driver(&pdc2027x_pci_driver); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 767 | } | 
|  | 768 |  | 
|  | 769 | /** | 
|  | 770 | * pdc2027x_exit - Called before this module unloaded from the kernel | 
|  | 771 | */ | 
|  | 772 | static void __exit pdc2027x_exit(void) | 
|  | 773 | { | 
|  | 774 | pci_unregister_driver(&pdc2027x_pci_driver); | 
|  | 775 | } | 
|  | 776 |  | 
|  | 777 | module_init(pdc2027x_init); | 
|  | 778 | module_exit(pdc2027x_exit); |