diff options
Diffstat (limited to 'drivers/ata/pata_hpt3x2n.c')
-rw-r--r-- | drivers/ata/pata_hpt3x2n.c | 154 |
1 files changed, 103 insertions, 51 deletions
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 32f3463216b8..eca68caf5f46 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -1,5 +1,5 @@ /* - * Libata driver for the highpoint 372N and 302N UDMA66 ATA controllers. + * Libata driver for the HighPoint 371N, 372N, and 302N UDMA66 ATA controllers. * * This driver is heavily based upon: * @@ -8,7 +8,7 @@ * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> * Portions Copyright (C) 2001 Sun Microsystems, Inc. * Portions Copyright (C) 2003 Red Hat Inc - * Portions Copyright (C) 2005-2009 MontaVista Software, Inc. + * Portions Copyright (C) 2005-2010 MontaVista Software, Inc. * * * TODO @@ -25,7 +25,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt3x2n" -#define DRV_VERSION "0.3.10" +#define DRV_VERSION "0.3.14" enum { HPT_PCI_FAST = (1 << 31), @@ -103,7 +103,7 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed) { struct hpt_clock *clocks = hpt3x2n_clocks; - while(clocks->xfer_speed) { + while (clocks->xfer_speed) { if (clocks->xfer_speed == speed) return clocks->timing; clocks++; @@ -113,6 +113,22 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed) } /** + * hpt372n_filter - mode selection filter + * @adev: ATA device + * @mask: mode mask + * + * The Marvell bridge chips used on the HighPoint SATA cards do not seem + * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes... + */ +static unsigned long hpt372n_filter(struct ata_device *adev, unsigned long mask) +{ + if (ata_id_is_sata(adev->id)) + mask &= ~((0xE << ATA_SHIFT_UDMA) | ATA_MASK_MWDMA); + + return mask; +} + +/** * hpt3x2n_cable_detect - Detect the cable type * @ap: ATA port to detect on * @@ -153,6 +169,7 @@ static int hpt3x2n_pre_reset(struct ata_link *link, unsigned long deadline) { struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); + /* Reset the state machine */ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); @@ -328,10 +345,10 @@ static struct scsi_host_template hpt3x2n_sht = { }; /* - * Configuration for HPT3x2n. + * Configuration for HPT302N/371N. */ -static struct ata_port_operations hpt3x2n_port_ops = { +static struct ata_port_operations hpt3xxn_port_ops = { .inherits = &ata_bmdma_port_ops, .bmdma_stop = hpt3x2n_bmdma_stop, @@ -345,6 +362,15 @@ static struct ata_port_operations hpt3x2n_port_ops = { .prereset = hpt3x2n_pre_reset, }; +/* + * Configuration for HPT372N. Same as 302N/371N but we have a mode filter. + */ + +static struct ata_port_operations hpt372n_port_ops = { + .inherits = &hpt3xxn_port_ops, + .mode_filter = &hpt372n_filter, +}; + /** * hpt3xn_calibrate_dpll - Calibrate the DPLL loop * @dev: PCI device @@ -359,12 +385,12 @@ static int hpt3xn_calibrate_dpll(struct pci_dev *dev) u32 reg5c; int tries; - for(tries = 0; tries < 0x5000; tries++) { + for (tries = 0; tries < 0x5000; tries++) { udelay(50); pci_read_config_byte(dev, 0x5b, ®5b); if (reg5b & 0x80) { /* See if it stays set */ - for(tries = 0; tries < 0x1000; tries ++) { + for (tries = 0; tries < 0x1000; tries++) { pci_read_config_byte(dev, 0x5b, ®5b); /* Failed ? */ if ((reg5b & 0x80) == 0) @@ -372,7 +398,7 @@ static int hpt3xn_calibrate_dpll(struct pci_dev *dev) } /* Turn off tuning, we have the DPLL set */ pci_read_config_dword(dev, 0x5c, ®5c); - pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100); + pci_write_config_dword(dev, 0x5c, reg5c & ~0x100); return 1; } } @@ -388,8 +414,19 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev) fcnt = inl(iobase + 0x90); /* Not PCI readable for some chips */ if ((fcnt >> 12) != 0xABCDE) { - printk(KERN_WARNING "hpt3xn: BIOS clock data not set.\n"); - return 33; /* Not BIOS set */ + int i; + u16 sr; + u32 total = 0; + + pr_warning(DRV_NAME ": BIOS clock data not set.\n"); + + /* This is the process the HPT371 BIOS is reported to use */ + for (i = 0; i < 128; i++) { + pci_read_config_word(pdev, 0x78, &sr); + total += sr & 0x1FF; + udelay(15); + } + fcnt = total / 128; } fcnt &= 0x1FF; @@ -431,21 +468,27 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev) * HPT372N 9 (HPT372N) * UDMA133 * * (1) UDMA133 support depends on the bus clock - * - * To pin down HPT371N */ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - /* HPT372N and friends - UDMA133 */ - static const struct ata_port_info info = { + /* HPT372N - UDMA133 */ + static const struct ata_port_info info_hpt372n = { + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA6, + .port_ops = &hpt372n_port_ops + }; + /* HPT302N and HPT371N - UDMA133 */ + static const struct ata_port_info info_hpt3xxn = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA6, - .port_ops = &hpt3x2n_port_ops + .port_ops = &hpt3xxn_port_ops }; - const struct ata_port_info *ppi[] = { &info, NULL }; + const struct ata_port_info *ppi[] = { &info_hpt3xxn, NULL }; u8 rev = dev->revision; u8 irqmask; unsigned int pci_mhz; @@ -459,30 +502,35 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (rc) return rc; - switch(dev->device) { - case PCI_DEVICE_ID_TTI_HPT366: - if (rev < 6) - return -ENODEV; - break; - case PCI_DEVICE_ID_TTI_HPT371: - if (rev < 2) - return -ENODEV; - /* 371N if rev > 1 */ - break; - case PCI_DEVICE_ID_TTI_HPT372: - /* 372N if rev >= 2*/ - if (rev < 2) - return -ENODEV; - break; - case PCI_DEVICE_ID_TTI_HPT302: - if (rev < 2) - return -ENODEV; - break; - case PCI_DEVICE_ID_TTI_HPT372N: - break; - default: - printk(KERN_ERR "pata_hpt3x2n: PCI table is bogus please report (%d).\n", dev->device); + switch (dev->device) { + case PCI_DEVICE_ID_TTI_HPT366: + /* 372N if rev >= 6 */ + if (rev < 6) return -ENODEV; + goto hpt372n; + case PCI_DEVICE_ID_TTI_HPT371: + /* 371N if rev >= 2 */ + if (rev < 2) + return -ENODEV; + break; + case PCI_DEVICE_ID_TTI_HPT372: + /* 372N if rev >= 2 */ + if (rev < 2) + return -ENODEV; + goto hpt372n; + case PCI_DEVICE_ID_TTI_HPT302: + /* 302N if rev >= 2 */ + if (rev < 2) + return -ENODEV; + break; + case PCI_DEVICE_ID_TTI_HPT372N: +hpt372n: + ppi[0] = &info_hpt372n; + break; + default: + pr_err(DRV_NAME ": PCI table is bogus, please report (%d).\n", + dev->device); + return -ENODEV; } /* Ok so this is a chip we support */ @@ -509,8 +557,10 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) pci_write_config_byte(dev, 0x50, mcr1); } - /* Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or - 50 for UDMA100. Right now we always use 66 */ + /* + * Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or + * 50 for UDMA100. Right now we always use 66 + */ pci_mhz = hpt3x2n_pci_clock(dev); @@ -522,20 +572,22 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) pci_write_config_byte(dev, 0x5B, 0x21); /* Unlike the 37x we don't try jiggling the frequency */ - for(adjust = 0; adjust < 8; adjust++) { + for (adjust = 0; adjust < 8; adjust++) { if (hpt3xn_calibrate_dpll(dev)) break; pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low); } if (adjust == 8) { - printk(KERN_ERR "pata_hpt3x2n: DPLL did not stabilize!\n"); + pr_err(DRV_NAME ": DPLL did not stabilize!\n"); return -ENODEV; } - printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using 66MHz DPLL.\n", - pci_mhz); - /* Set our private data up. We only need a few flags so we use - it directly */ + pr_info(DRV_NAME ": bus clock %dMHz, using 66MHz DPLL.\n", pci_mhz); + + /* + * Set our private data up. We only need a few flags + * so we use it directly. + */ if (pci_mhz > 60) hpriv = (void *)(PCI66 | USE_DPLL); @@ -562,9 +614,9 @@ static const struct pci_device_id hpt3x2n[] = { }; static struct pci_driver hpt3x2n_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = hpt3x2n, - .probe = hpt3x2n_init_one, + .probe = hpt3x2n_init_one, .remove = ata_pci_remove_one }; @@ -579,7 +631,7 @@ static void __exit hpt3x2n_exit(void) } MODULE_AUTHOR("Alan Cox"); -MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3x2n/30x"); +MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3xxN"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, hpt3x2n); MODULE_VERSION(DRV_VERSION); |