18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Libata driver for the highpoint 366 and 368 UDMA66 ATA controllers. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This driver is heavily based upon: 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> 108c2ecf20Sopenharmony_ci * Portions Copyright (C) 2001 Sun Microsystems, Inc. 118c2ecf20Sopenharmony_ci * Portions Copyright (C) 2003 Red Hat Inc 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * TODO 158c2ecf20Sopenharmony_ci * Look into engine reset on timeout errors. Should not be required. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/pci.h> 238c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 248c2ecf20Sopenharmony_ci#include <linux/delay.h> 258c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 268c2ecf20Sopenharmony_ci#include <linux/libata.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define DRV_NAME "pata_hpt366" 298c2ecf20Sopenharmony_ci#define DRV_VERSION "0.6.11" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct hpt_clock { 328c2ecf20Sopenharmony_ci u8 xfer_mode; 338c2ecf20Sopenharmony_ci u32 timing; 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* key for bus clock timings 378c2ecf20Sopenharmony_ci * bit 388c2ecf20Sopenharmony_ci * 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA. 398c2ecf20Sopenharmony_ci * cycles = value + 1 408c2ecf20Sopenharmony_ci * 4:7 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA. 418c2ecf20Sopenharmony_ci * cycles = value + 1 428c2ecf20Sopenharmony_ci * 8:11 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file 438c2ecf20Sopenharmony_ci * register access. 448c2ecf20Sopenharmony_ci * 12:15 cmd_low_time. Active time of DIOW_/DIOR_ during task file 458c2ecf20Sopenharmony_ci * register access. 468c2ecf20Sopenharmony_ci * 16:18 udma_cycle_time. Clock cycles for UDMA xfer? 478c2ecf20Sopenharmony_ci * 19:21 pre_high_time. Time to initialize 1st cycle for PIO and MW DMA xfer. 488c2ecf20Sopenharmony_ci * 22:24 cmd_pre_high_time. Time to initialize 1st PIO cycle for task file 498c2ecf20Sopenharmony_ci * register access. 508c2ecf20Sopenharmony_ci * 28 UDMA enable. 518c2ecf20Sopenharmony_ci * 29 DMA enable. 528c2ecf20Sopenharmony_ci * 30 PIO_MST enable. If set, the chip is in bus master mode during 538c2ecf20Sopenharmony_ci * PIO xfer. 548c2ecf20Sopenharmony_ci * 31 FIFO enable. 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic const struct hpt_clock hpt366_40[] = { 588c2ecf20Sopenharmony_ci { XFER_UDMA_4, 0x900fd943 }, 598c2ecf20Sopenharmony_ci { XFER_UDMA_3, 0x900ad943 }, 608c2ecf20Sopenharmony_ci { XFER_UDMA_2, 0x900bd943 }, 618c2ecf20Sopenharmony_ci { XFER_UDMA_1, 0x9008d943 }, 628c2ecf20Sopenharmony_ci { XFER_UDMA_0, 0x9008d943 }, 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci { XFER_MW_DMA_2, 0xa008d943 }, 658c2ecf20Sopenharmony_ci { XFER_MW_DMA_1, 0xa010d955 }, 668c2ecf20Sopenharmony_ci { XFER_MW_DMA_0, 0xa010d9fc }, 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci { XFER_PIO_4, 0xc008d963 }, 698c2ecf20Sopenharmony_ci { XFER_PIO_3, 0xc010d974 }, 708c2ecf20Sopenharmony_ci { XFER_PIO_2, 0xc010d997 }, 718c2ecf20Sopenharmony_ci { XFER_PIO_1, 0xc010d9c7 }, 728c2ecf20Sopenharmony_ci { XFER_PIO_0, 0xc018d9d9 }, 738c2ecf20Sopenharmony_ci { 0, 0x0120d9d9 } 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic const struct hpt_clock hpt366_33[] = { 778c2ecf20Sopenharmony_ci { XFER_UDMA_4, 0x90c9a731 }, 788c2ecf20Sopenharmony_ci { XFER_UDMA_3, 0x90cfa731 }, 798c2ecf20Sopenharmony_ci { XFER_UDMA_2, 0x90caa731 }, 808c2ecf20Sopenharmony_ci { XFER_UDMA_1, 0x90cba731 }, 818c2ecf20Sopenharmony_ci { XFER_UDMA_0, 0x90c8a731 }, 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci { XFER_MW_DMA_2, 0xa0c8a731 }, 848c2ecf20Sopenharmony_ci { XFER_MW_DMA_1, 0xa0c8a732 }, /* 0xa0c8a733 */ 858c2ecf20Sopenharmony_ci { XFER_MW_DMA_0, 0xa0c8a797 }, 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci { XFER_PIO_4, 0xc0c8a731 }, 888c2ecf20Sopenharmony_ci { XFER_PIO_3, 0xc0c8a742 }, 898c2ecf20Sopenharmony_ci { XFER_PIO_2, 0xc0d0a753 }, 908c2ecf20Sopenharmony_ci { XFER_PIO_1, 0xc0d0a7a3 }, /* 0xc0d0a793 */ 918c2ecf20Sopenharmony_ci { XFER_PIO_0, 0xc0d0a7aa }, /* 0xc0d0a7a7 */ 928c2ecf20Sopenharmony_ci { 0, 0x0120a7a7 } 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic const struct hpt_clock hpt366_25[] = { 968c2ecf20Sopenharmony_ci { XFER_UDMA_4, 0x90c98521 }, 978c2ecf20Sopenharmony_ci { XFER_UDMA_3, 0x90cf8521 }, 988c2ecf20Sopenharmony_ci { XFER_UDMA_2, 0x90cf8521 }, 998c2ecf20Sopenharmony_ci { XFER_UDMA_1, 0x90cb8521 }, 1008c2ecf20Sopenharmony_ci { XFER_UDMA_0, 0x90cb8521 }, 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci { XFER_MW_DMA_2, 0xa0ca8521 }, 1038c2ecf20Sopenharmony_ci { XFER_MW_DMA_1, 0xa0ca8532 }, 1048c2ecf20Sopenharmony_ci { XFER_MW_DMA_0, 0xa0ca8575 }, 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci { XFER_PIO_4, 0xc0ca8521 }, 1078c2ecf20Sopenharmony_ci { XFER_PIO_3, 0xc0ca8532 }, 1088c2ecf20Sopenharmony_ci { XFER_PIO_2, 0xc0ca8542 }, 1098c2ecf20Sopenharmony_ci { XFER_PIO_1, 0xc0d08572 }, 1108c2ecf20Sopenharmony_ci { XFER_PIO_0, 0xc0d08585 }, 1118c2ecf20Sopenharmony_ci { 0, 0x01208585 } 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/** 1158c2ecf20Sopenharmony_ci * hpt36x_find_mode - find the hpt36x timing 1168c2ecf20Sopenharmony_ci * @ap: ATA port 1178c2ecf20Sopenharmony_ci * @speed: transfer mode 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * Return the 32bit register programming information for this channel 1208c2ecf20Sopenharmony_ci * that matches the speed provided. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic u32 hpt36x_find_mode(struct ata_port *ap, int speed) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct hpt_clock *clocks = ap->host->private_data; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci while (clocks->xfer_mode) { 1288c2ecf20Sopenharmony_ci if (clocks->xfer_mode == speed) 1298c2ecf20Sopenharmony_ci return clocks->timing; 1308c2ecf20Sopenharmony_ci clocks++; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci BUG(); 1338c2ecf20Sopenharmony_ci return 0xffffffffU; /* silence compiler warning */ 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic const char * const bad_ata33[] = { 1378c2ecf20Sopenharmony_ci "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", 1388c2ecf20Sopenharmony_ci "Maxtor 90845U3", "Maxtor 90650U2", 1398c2ecf20Sopenharmony_ci "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", 1408c2ecf20Sopenharmony_ci "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2", 1418c2ecf20Sopenharmony_ci "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", 1428c2ecf20Sopenharmony_ci "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4", 1438c2ecf20Sopenharmony_ci "Maxtor 90510D4", 1448c2ecf20Sopenharmony_ci "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2", 1458c2ecf20Sopenharmony_ci "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", 1468c2ecf20Sopenharmony_ci "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4", 1478c2ecf20Sopenharmony_ci "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", 1488c2ecf20Sopenharmony_ci "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2", 1498c2ecf20Sopenharmony_ci NULL 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic const char * const bad_ata66_4[] = { 1538c2ecf20Sopenharmony_ci "IBM-DTLA-307075", 1548c2ecf20Sopenharmony_ci "IBM-DTLA-307060", 1558c2ecf20Sopenharmony_ci "IBM-DTLA-307045", 1568c2ecf20Sopenharmony_ci "IBM-DTLA-307030", 1578c2ecf20Sopenharmony_ci "IBM-DTLA-307020", 1588c2ecf20Sopenharmony_ci "IBM-DTLA-307015", 1598c2ecf20Sopenharmony_ci "IBM-DTLA-305040", 1608c2ecf20Sopenharmony_ci "IBM-DTLA-305030", 1618c2ecf20Sopenharmony_ci "IBM-DTLA-305020", 1628c2ecf20Sopenharmony_ci "IC35L010AVER07-0", 1638c2ecf20Sopenharmony_ci "IC35L020AVER07-0", 1648c2ecf20Sopenharmony_ci "IC35L030AVER07-0", 1658c2ecf20Sopenharmony_ci "IC35L040AVER07-0", 1668c2ecf20Sopenharmony_ci "IC35L060AVER07-0", 1678c2ecf20Sopenharmony_ci "WDC AC310200R", 1688c2ecf20Sopenharmony_ci NULL 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic const char * const bad_ata66_3[] = { 1728c2ecf20Sopenharmony_ci "WDC AC310200R", 1738c2ecf20Sopenharmony_ci NULL 1748c2ecf20Sopenharmony_ci}; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, 1778c2ecf20Sopenharmony_ci const char * const list[]) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci unsigned char model_num[ATA_ID_PROD_LEN + 1]; 1808c2ecf20Sopenharmony_ci int i; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci i = match_string(list, -1, model_num); 1858c2ecf20Sopenharmony_ci if (i >= 0) { 1868c2ecf20Sopenharmony_ci pr_warn("%s is not supported for %s\n", modestr, list[i]); 1878c2ecf20Sopenharmony_ci return 1; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/** 1938c2ecf20Sopenharmony_ci * hpt366_filter - mode selection filter 1948c2ecf20Sopenharmony_ci * @adev: ATA device 1958c2ecf20Sopenharmony_ci * 1968c2ecf20Sopenharmony_ci * Block UDMA on devices that cause trouble with this controller. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci if (adev->class == ATA_DEV_ATA) { 2028c2ecf20Sopenharmony_ci if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33)) 2038c2ecf20Sopenharmony_ci mask &= ~ATA_MASK_UDMA; 2048c2ecf20Sopenharmony_ci if (hpt_dma_blacklisted(adev, "UDMA3", bad_ata66_3)) 2058c2ecf20Sopenharmony_ci mask &= ~(0xF8 << ATA_SHIFT_UDMA); 2068c2ecf20Sopenharmony_ci if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4)) 2078c2ecf20Sopenharmony_ci mask &= ~(0xF0 << ATA_SHIFT_UDMA); 2088c2ecf20Sopenharmony_ci } else if (adev->class == ATA_DEV_ATAPI) 2098c2ecf20Sopenharmony_ci mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return mask; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int hpt36x_cable_detect(struct ata_port *ap) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(ap->host->dev); 2178c2ecf20Sopenharmony_ci u8 ata66; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* 2208c2ecf20Sopenharmony_ci * Each channel of pata_hpt366 occupies separate PCI function 2218c2ecf20Sopenharmony_ci * as the primary channel and bit1 indicates the cable type. 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, 0x5A, &ata66); 2248c2ecf20Sopenharmony_ci if (ata66 & 2) 2258c2ecf20Sopenharmony_ci return ATA_CBL_PATA40; 2268c2ecf20Sopenharmony_ci return ATA_CBL_PATA80; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic void hpt366_set_mode(struct ata_port *ap, struct ata_device *adev, 2308c2ecf20Sopenharmony_ci u8 mode) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(ap->host->dev); 2338c2ecf20Sopenharmony_ci u32 addr = 0x40 + 4 * adev->devno; 2348c2ecf20Sopenharmony_ci u32 mask, reg, t; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* determine timing mask and find matching clock entry */ 2378c2ecf20Sopenharmony_ci if (mode < XFER_MW_DMA_0) 2388c2ecf20Sopenharmony_ci mask = 0xc1f8ffff; 2398c2ecf20Sopenharmony_ci else if (mode < XFER_UDMA_0) 2408c2ecf20Sopenharmony_ci mask = 0x303800ff; 2418c2ecf20Sopenharmony_ci else 2428c2ecf20Sopenharmony_ci mask = 0x30070000; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci t = hpt36x_find_mode(ap, mode); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* 2478c2ecf20Sopenharmony_ci * Combine new mode bits with old config bits and disable 2488c2ecf20Sopenharmony_ci * on-chip PIO FIFO/buffer (and PIO MST mode as well) to avoid 2498c2ecf20Sopenharmony_ci * problems handling I/O errors later. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, addr, ®); 2528c2ecf20Sopenharmony_ci reg = ((reg & ~mask) | (t & mask)) & ~0xc0000000; 2538c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, addr, reg); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/** 2578c2ecf20Sopenharmony_ci * hpt366_set_piomode - PIO setup 2588c2ecf20Sopenharmony_ci * @ap: ATA interface 2598c2ecf20Sopenharmony_ci * @adev: device on the interface 2608c2ecf20Sopenharmony_ci * 2618c2ecf20Sopenharmony_ci * Perform PIO mode setup. 2628c2ecf20Sopenharmony_ci */ 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci hpt366_set_mode(ap, adev, adev->pio_mode); 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/** 2708c2ecf20Sopenharmony_ci * hpt366_set_dmamode - DMA timing setup 2718c2ecf20Sopenharmony_ci * @ap: ATA interface 2728c2ecf20Sopenharmony_ci * @adev: Device being configured 2738c2ecf20Sopenharmony_ci * 2748c2ecf20Sopenharmony_ci * Set up the channel for MWDMA or UDMA modes. Much the same as with 2758c2ecf20Sopenharmony_ci * PIO, load the mode number and then set MWDMA or UDMA flag. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic void hpt366_set_dmamode(struct ata_port *ap, struct ata_device *adev) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci hpt366_set_mode(ap, adev, adev->dma_mode); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic struct scsi_host_template hpt36x_sht = { 2848c2ecf20Sopenharmony_ci ATA_BMDMA_SHT(DRV_NAME), 2858c2ecf20Sopenharmony_ci}; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/* 2888c2ecf20Sopenharmony_ci * Configuration for HPT366/68 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic struct ata_port_operations hpt366_port_ops = { 2928c2ecf20Sopenharmony_ci .inherits = &ata_bmdma_port_ops, 2938c2ecf20Sopenharmony_ci .cable_detect = hpt36x_cable_detect, 2948c2ecf20Sopenharmony_ci .mode_filter = hpt366_filter, 2958c2ecf20Sopenharmony_ci .set_piomode = hpt366_set_piomode, 2968c2ecf20Sopenharmony_ci .set_dmamode = hpt366_set_dmamode, 2978c2ecf20Sopenharmony_ci}; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/** 3008c2ecf20Sopenharmony_ci * hpt36x_init_chipset - common chip setup 3018c2ecf20Sopenharmony_ci * @dev: PCI device 3028c2ecf20Sopenharmony_ci * 3038c2ecf20Sopenharmony_ci * Perform the chip setup work that must be done at both init and 3048c2ecf20Sopenharmony_ci * resume time 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void hpt36x_init_chipset(struct pci_dev *dev) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci u8 drive_fast; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); 3128c2ecf20Sopenharmony_ci pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); 3138c2ecf20Sopenharmony_ci pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); 3148c2ecf20Sopenharmony_ci pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x51, &drive_fast); 3178c2ecf20Sopenharmony_ci if (drive_fast & 0x80) 3188c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x51, drive_fast & ~0x80); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/** 3228c2ecf20Sopenharmony_ci * hpt36x_init_one - Initialise an HPT366/368 3238c2ecf20Sopenharmony_ci * @dev: PCI device 3248c2ecf20Sopenharmony_ci * @id: Entry in match table 3258c2ecf20Sopenharmony_ci * 3268c2ecf20Sopenharmony_ci * Initialise an HPT36x device. There are some interesting complications 3278c2ecf20Sopenharmony_ci * here. Firstly the chip may report 366 and be one of several variants. 3288c2ecf20Sopenharmony_ci * Secondly all the timings depend on the clock for the chip which we must 3298c2ecf20Sopenharmony_ci * detect and look up 3308c2ecf20Sopenharmony_ci * 3318c2ecf20Sopenharmony_ci * This is the known chip mappings. It may be missing a couple of later 3328c2ecf20Sopenharmony_ci * releases. 3338c2ecf20Sopenharmony_ci * 3348c2ecf20Sopenharmony_ci * Chip version PCI Rev Notes 3358c2ecf20Sopenharmony_ci * HPT366 4 (HPT366) 0 UDMA66 3368c2ecf20Sopenharmony_ci * HPT366 4 (HPT366) 1 UDMA66 3378c2ecf20Sopenharmony_ci * HPT368 4 (HPT366) 2 UDMA66 3388c2ecf20Sopenharmony_ci * HPT37x/30x 4 (HPT366) 3+ Other driver 3398c2ecf20Sopenharmony_ci * 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci static const struct ata_port_info info_hpt366 = { 3458c2ecf20Sopenharmony_ci .flags = ATA_FLAG_SLAVE_POSS, 3468c2ecf20Sopenharmony_ci .pio_mask = ATA_PIO4, 3478c2ecf20Sopenharmony_ci .mwdma_mask = ATA_MWDMA2, 3488c2ecf20Sopenharmony_ci .udma_mask = ATA_UDMA4, 3498c2ecf20Sopenharmony_ci .port_ops = &hpt366_port_ops 3508c2ecf20Sopenharmony_ci }; 3518c2ecf20Sopenharmony_ci const struct ata_port_info *ppi[] = { &info_hpt366, NULL }; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci const void *hpriv = NULL; 3548c2ecf20Sopenharmony_ci u32 reg1; 3558c2ecf20Sopenharmony_ci int rc; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci rc = pcim_enable_device(dev); 3588c2ecf20Sopenharmony_ci if (rc) 3598c2ecf20Sopenharmony_ci return rc; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* May be a later chip in disguise. Check */ 3628c2ecf20Sopenharmony_ci /* Newer chips are not in the HPT36x driver. Ignore them */ 3638c2ecf20Sopenharmony_ci if (dev->revision > 2) 3648c2ecf20Sopenharmony_ci return -ENODEV; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci hpt36x_init_chipset(dev); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci pci_read_config_dword(dev, 0x40, ®1); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* PCI clocking determines the ATA timing values to use */ 3718c2ecf20Sopenharmony_ci /* info_hpt366 is safe against re-entry so we can scribble on it */ 3728c2ecf20Sopenharmony_ci switch ((reg1 & 0xf00) >> 8) { 3738c2ecf20Sopenharmony_ci case 9: 3748c2ecf20Sopenharmony_ci hpriv = &hpt366_40; 3758c2ecf20Sopenharmony_ci break; 3768c2ecf20Sopenharmony_ci case 5: 3778c2ecf20Sopenharmony_ci hpriv = &hpt366_25; 3788c2ecf20Sopenharmony_ci break; 3798c2ecf20Sopenharmony_ci default: 3808c2ecf20Sopenharmony_ci hpriv = &hpt366_33; 3818c2ecf20Sopenharmony_ci break; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci /* Now kick off ATA set up */ 3848c2ecf20Sopenharmony_ci return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, (void *)hpriv, 0); 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 3888c2ecf20Sopenharmony_cistatic int hpt36x_reinit_one(struct pci_dev *dev) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct ata_host *host = pci_get_drvdata(dev); 3918c2ecf20Sopenharmony_ci int rc; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci rc = ata_pci_device_do_resume(dev); 3948c2ecf20Sopenharmony_ci if (rc) 3958c2ecf20Sopenharmony_ci return rc; 3968c2ecf20Sopenharmony_ci hpt36x_init_chipset(dev); 3978c2ecf20Sopenharmony_ci ata_host_resume(host); 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci#endif 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic const struct pci_device_id hpt36x[] = { 4038c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), }, 4048c2ecf20Sopenharmony_ci { }, 4058c2ecf20Sopenharmony_ci}; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic struct pci_driver hpt36x_pci_driver = { 4088c2ecf20Sopenharmony_ci .name = DRV_NAME, 4098c2ecf20Sopenharmony_ci .id_table = hpt36x, 4108c2ecf20Sopenharmony_ci .probe = hpt36x_init_one, 4118c2ecf20Sopenharmony_ci .remove = ata_pci_remove_one, 4128c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 4138c2ecf20Sopenharmony_ci .suspend = ata_pci_device_suspend, 4148c2ecf20Sopenharmony_ci .resume = hpt36x_reinit_one, 4158c2ecf20Sopenharmony_ci#endif 4168c2ecf20Sopenharmony_ci}; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cimodule_pci_driver(hpt36x_pci_driver); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alan Cox"); 4218c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("low-level driver for the Highpoint HPT366/368"); 4228c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4238c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hpt36x); 4248c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 425