18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> 48c2ecf20Sopenharmony_ci * Portions Copyright (C) 2001 Sun Microsystems, Inc. 58c2ecf20Sopenharmony_ci * Portions Copyright (C) 2003 Red Hat Inc 68c2ecf20Sopenharmony_ci * Portions Copyright (C) 2007 Bartlomiej Zolnierkiewicz 78c2ecf20Sopenharmony_ci * Portions Copyright (C) 2005-2009 MontaVista Software, Inc. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Thanks to HighPoint Technologies for their assistance, and hardware. 108c2ecf20Sopenharmony_ci * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his 118c2ecf20Sopenharmony_ci * donation of an ABit BP6 mainboard, processor, and memory acellerated 128c2ecf20Sopenharmony_ci * development and support. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * HighPoint has its own drivers (open source except for the RAID part) 168c2ecf20Sopenharmony_ci * available from http://www.highpoint-tech.com/USA_new/service_support.htm 178c2ecf20Sopenharmony_ci * This may be useful to anyone wanting to work on this driver, however do not 188c2ecf20Sopenharmony_ci * trust them too much since the code tends to become less and less meaningful 198c2ecf20Sopenharmony_ci * as the time passes... :-/ 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Note that final HPT370 support was done by force extraction of GPL. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * - add function for getting/setting power status of drive 248c2ecf20Sopenharmony_ci * - the HPT370's state machine can get confused. reset it before each dma 258c2ecf20Sopenharmony_ci * xfer to prevent that from happening. 268c2ecf20Sopenharmony_ci * - reset state engine whenever we get an error. 278c2ecf20Sopenharmony_ci * - check for busmaster state at end of dma. 288c2ecf20Sopenharmony_ci * - use new highpoint timings. 298c2ecf20Sopenharmony_ci * - detect bus speed using highpoint register. 308c2ecf20Sopenharmony_ci * - use pll if we don't have a clock table. added a 66MHz table that's 318c2ecf20Sopenharmony_ci * just 2x the 33MHz table. 328c2ecf20Sopenharmony_ci * - removed turnaround. NOTE: we never want to switch between pll and 338c2ecf20Sopenharmony_ci * pci clocks as the chip can glitch in those cases. the highpoint 348c2ecf20Sopenharmony_ci * approved workaround slows everything down too much to be useful. in 358c2ecf20Sopenharmony_ci * addition, we would have to serialize access to each chip. 368c2ecf20Sopenharmony_ci * Adrian Sun <a.sun@sun.com> 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * add drive timings for 66MHz PCI bus, 398c2ecf20Sopenharmony_ci * fix ATA Cable signal detection, fix incorrect /proc info 408c2ecf20Sopenharmony_ci * add /proc display for per-drive PIO/DMA/UDMA mode and 418c2ecf20Sopenharmony_ci * per-channel ATA-33/66 Cable detect. 428c2ecf20Sopenharmony_ci * Duncan Laurie <void@sun.com> 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * fixup /proc output for multiple controllers 458c2ecf20Sopenharmony_ci * Tim Hockin <thockin@sun.com> 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * On hpt366: 488c2ecf20Sopenharmony_ci * Reset the hpt366 on error, reset on dma 498c2ecf20Sopenharmony_ci * Fix disabling Fast Interrupt hpt366. 508c2ecf20Sopenharmony_ci * Mike Waychison <crlf@sun.com> 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * Added support for 372N clocking and clock switching. The 372N needs 538c2ecf20Sopenharmony_ci * different clocks on read/write. This requires overloading rw_disk and 548c2ecf20Sopenharmony_ci * other deeply crazy things. Thanks to <http://www.hoerstreich.de> for 558c2ecf20Sopenharmony_ci * keeping me sane. 568c2ecf20Sopenharmony_ci * Alan Cox <alan@lxorguk.ukuu.org.uk> 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * - fix the clock turnaround code: it was writing to the wrong ports when 598c2ecf20Sopenharmony_ci * called for the secondary channel, caching the current clock mode per- 608c2ecf20Sopenharmony_ci * channel caused the cached register value to get out of sync with the 618c2ecf20Sopenharmony_ci * actual one, the channels weren't serialized, the turnaround shouldn't 628c2ecf20Sopenharmony_ci * be done on 66 MHz PCI bus 638c2ecf20Sopenharmony_ci * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used 648c2ecf20Sopenharmony_ci * does not allow for this speed anyway 658c2ecf20Sopenharmony_ci * - avoid touching disabled channels (e.g. HPT371/N are single channel chips, 668c2ecf20Sopenharmony_ci * their primary channel is kind of virtual, it isn't tied to any pins) 678c2ecf20Sopenharmony_ci * - fix/remove bad/unused timing tables and use one set of tables for the whole 688c2ecf20Sopenharmony_ci * HPT37x chip family; save space by introducing the separate transfer mode 698c2ecf20Sopenharmony_ci * table in which the mode lookup is done 708c2ecf20Sopenharmony_ci * - use f_CNT value saved by the HighPoint BIOS as reading it directly gives 718c2ecf20Sopenharmony_ci * the wrong PCI frequency since DPLL has already been calibrated by BIOS; 728c2ecf20Sopenharmony_ci * read it only from the function 0 of HPT374 chips 738c2ecf20Sopenharmony_ci * - fix the hotswap code: it caused RESET- to glitch when tristating the bus, 748c2ecf20Sopenharmony_ci * and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead 758c2ecf20Sopenharmony_ci * - pass to init_chipset() handlers a copy of the IDE PCI device structure as 768c2ecf20Sopenharmony_ci * they tamper with its fields 778c2ecf20Sopenharmony_ci * - pass to the init_setup handlers a copy of the ide_pci_device_t structure 788c2ecf20Sopenharmony_ci * since they may tamper with its fields 798c2ecf20Sopenharmony_ci * - prefix the driver startup messages with the real chip name 808c2ecf20Sopenharmony_ci * - claim the extra 240 bytes of I/O space for all chips 818c2ecf20Sopenharmony_ci * - optimize the UltraDMA filtering and the drive list lookup code 828c2ecf20Sopenharmony_ci * - use pci_get_slot() to get to the function 1 of HPT36x/374 838c2ecf20Sopenharmony_ci * - cache offset of the channel's misc. control registers (MCRs) being used 848c2ecf20Sopenharmony_ci * throughout the driver 858c2ecf20Sopenharmony_ci * - only touch the relevant MCR when detecting the cable type on HPT374's 868c2ecf20Sopenharmony_ci * function 1 878c2ecf20Sopenharmony_ci * - rename all the register related variables consistently 888c2ecf20Sopenharmony_ci * - move all the interrupt twiddling code from the speedproc handlers into 898c2ecf20Sopenharmony_ci * init_hwif_hpt366(), also grouping all the DMA related code together there 908c2ecf20Sopenharmony_ci * - merge HPT36x/HPT37x speedproc handlers, fix PIO timing register mask and 918c2ecf20Sopenharmony_ci * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings 928c2ecf20Sopenharmony_ci * when setting an UltraDMA mode 938c2ecf20Sopenharmony_ci * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select 948c2ecf20Sopenharmony_ci * the best possible one 958c2ecf20Sopenharmony_ci * - clean up DMA timeout handling for HPT370 968c2ecf20Sopenharmony_ci * - switch to using the enumeration type to differ between the numerous chip 978c2ecf20Sopenharmony_ci * variants, matching PCI device/revision ID with the chip type early, at the 988c2ecf20Sopenharmony_ci * init_setup stage 998c2ecf20Sopenharmony_ci * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies, 1008c2ecf20Sopenharmony_ci * stop duplicating it for each channel by storing the pointer in the pci_dev 1018c2ecf20Sopenharmony_ci * structure: first, at the init_setup stage, point it to a static "template" 1028c2ecf20Sopenharmony_ci * with only the chip type and its specific base DPLL frequency, the highest 1038c2ecf20Sopenharmony_ci * UltraDMA mode, and the chip settings table pointer filled, then, at the 1048c2ecf20Sopenharmony_ci * init_chipset stage, allocate per-chip instance and fill it with the rest 1058c2ecf20Sopenharmony_ci * of the necessary information 1068c2ecf20Sopenharmony_ci * - get rid of the constant thresholds in the HPT37x PCI clock detection code, 1078c2ecf20Sopenharmony_ci * switch to calculating PCI clock frequency based on the chip's base DPLL 1088c2ecf20Sopenharmony_ci * frequency 1098c2ecf20Sopenharmony_ci * - switch to using the DPLL clock and enable UltraATA/133 mode by default on 1108c2ecf20Sopenharmony_ci * anything newer than HPT370/A (except HPT374 that is not capable of this 1118c2ecf20Sopenharmony_ci * mode according to the manual) 1128c2ecf20Sopenharmony_ci * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(), 1138c2ecf20Sopenharmony_ci * also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips; 1148c2ecf20Sopenharmony_ci * unify HPT36x/37x timing setup code and the speedproc handlers by joining 1158c2ecf20Sopenharmony_ci * the register setting lists into the table indexed by the clock selected 1168c2ecf20Sopenharmony_ci * - set the correct hwif->ultra_mask for each individual chip 1178c2ecf20Sopenharmony_ci * - add Ultra and MW DMA mode filtering for the HPT37[24] based SATA cards 1188c2ecf20Sopenharmony_ci * - stop resetting HPT370's state machine before each DMA transfer as that has 1198c2ecf20Sopenharmony_ci * caused more harm than good 1208c2ecf20Sopenharmony_ci * Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com> 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci#include <linux/types.h> 1248c2ecf20Sopenharmony_ci#include <linux/module.h> 1258c2ecf20Sopenharmony_ci#include <linux/kernel.h> 1268c2ecf20Sopenharmony_ci#include <linux/delay.h> 1278c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 1288c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 1298c2ecf20Sopenharmony_ci#include <linux/pci.h> 1308c2ecf20Sopenharmony_ci#include <linux/init.h> 1318c2ecf20Sopenharmony_ci#include <linux/ide.h> 1328c2ecf20Sopenharmony_ci#include <linux/slab.h> 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 1358c2ecf20Sopenharmony_ci#include <asm/io.h> 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci#define DRV_NAME "hpt366" 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* various tuning parameters */ 1408c2ecf20Sopenharmony_ci#undef HPT_RESET_STATE_ENGINE 1418c2ecf20Sopenharmony_ci#undef HPT_DELAY_INTERRUPT 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic const char *bad_ata100_5[] = { 1448c2ecf20Sopenharmony_ci "IBM-DTLA-307075", 1458c2ecf20Sopenharmony_ci "IBM-DTLA-307060", 1468c2ecf20Sopenharmony_ci "IBM-DTLA-307045", 1478c2ecf20Sopenharmony_ci "IBM-DTLA-307030", 1488c2ecf20Sopenharmony_ci "IBM-DTLA-307020", 1498c2ecf20Sopenharmony_ci "IBM-DTLA-307015", 1508c2ecf20Sopenharmony_ci "IBM-DTLA-305040", 1518c2ecf20Sopenharmony_ci "IBM-DTLA-305030", 1528c2ecf20Sopenharmony_ci "IBM-DTLA-305020", 1538c2ecf20Sopenharmony_ci "IC35L010AVER07-0", 1548c2ecf20Sopenharmony_ci "IC35L020AVER07-0", 1558c2ecf20Sopenharmony_ci "IC35L030AVER07-0", 1568c2ecf20Sopenharmony_ci "IC35L040AVER07-0", 1578c2ecf20Sopenharmony_ci "IC35L060AVER07-0", 1588c2ecf20Sopenharmony_ci "WDC AC310200R", 1598c2ecf20Sopenharmony_ci NULL 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic const char *bad_ata66_4[] = { 1638c2ecf20Sopenharmony_ci "IBM-DTLA-307075", 1648c2ecf20Sopenharmony_ci "IBM-DTLA-307060", 1658c2ecf20Sopenharmony_ci "IBM-DTLA-307045", 1668c2ecf20Sopenharmony_ci "IBM-DTLA-307030", 1678c2ecf20Sopenharmony_ci "IBM-DTLA-307020", 1688c2ecf20Sopenharmony_ci "IBM-DTLA-307015", 1698c2ecf20Sopenharmony_ci "IBM-DTLA-305040", 1708c2ecf20Sopenharmony_ci "IBM-DTLA-305030", 1718c2ecf20Sopenharmony_ci "IBM-DTLA-305020", 1728c2ecf20Sopenharmony_ci "IC35L010AVER07-0", 1738c2ecf20Sopenharmony_ci "IC35L020AVER07-0", 1748c2ecf20Sopenharmony_ci "IC35L030AVER07-0", 1758c2ecf20Sopenharmony_ci "IC35L040AVER07-0", 1768c2ecf20Sopenharmony_ci "IC35L060AVER07-0", 1778c2ecf20Sopenharmony_ci "WDC AC310200R", 1788c2ecf20Sopenharmony_ci "MAXTOR STM3320620A", 1798c2ecf20Sopenharmony_ci NULL 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic const char *bad_ata66_3[] = { 1838c2ecf20Sopenharmony_ci "WDC AC310200R", 1848c2ecf20Sopenharmony_ci NULL 1858c2ecf20Sopenharmony_ci}; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic const char *bad_ata33[] = { 1888c2ecf20Sopenharmony_ci "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2", 1898c2ecf20Sopenharmony_ci "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2", 1908c2ecf20Sopenharmony_ci "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4", 1918c2ecf20Sopenharmony_ci "Maxtor 90510D4", 1928c2ecf20Sopenharmony_ci "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2", 1938c2ecf20Sopenharmony_ci "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4", 1948c2ecf20Sopenharmony_ci "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2", 1958c2ecf20Sopenharmony_ci NULL 1968c2ecf20Sopenharmony_ci}; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic u8 xfer_speeds[] = { 1998c2ecf20Sopenharmony_ci XFER_UDMA_6, 2008c2ecf20Sopenharmony_ci XFER_UDMA_5, 2018c2ecf20Sopenharmony_ci XFER_UDMA_4, 2028c2ecf20Sopenharmony_ci XFER_UDMA_3, 2038c2ecf20Sopenharmony_ci XFER_UDMA_2, 2048c2ecf20Sopenharmony_ci XFER_UDMA_1, 2058c2ecf20Sopenharmony_ci XFER_UDMA_0, 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci XFER_MW_DMA_2, 2088c2ecf20Sopenharmony_ci XFER_MW_DMA_1, 2098c2ecf20Sopenharmony_ci XFER_MW_DMA_0, 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci XFER_PIO_4, 2128c2ecf20Sopenharmony_ci XFER_PIO_3, 2138c2ecf20Sopenharmony_ci XFER_PIO_2, 2148c2ecf20Sopenharmony_ci XFER_PIO_1, 2158c2ecf20Sopenharmony_ci XFER_PIO_0 2168c2ecf20Sopenharmony_ci}; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* Key for bus clock timings 2198c2ecf20Sopenharmony_ci * 36x 37x 2208c2ecf20Sopenharmony_ci * bits bits 2218c2ecf20Sopenharmony_ci * 0:3 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA. 2228c2ecf20Sopenharmony_ci * cycles = value + 1 2238c2ecf20Sopenharmony_ci * 4:7 4:8 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA. 2248c2ecf20Sopenharmony_ci * cycles = value + 1 2258c2ecf20Sopenharmony_ci * 8:11 9:12 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file 2268c2ecf20Sopenharmony_ci * register access. 2278c2ecf20Sopenharmony_ci * 12:15 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file 2288c2ecf20Sopenharmony_ci * register access. 2298c2ecf20Sopenharmony_ci * 16:18 18:20 udma_cycle_time. Clock cycles for UDMA xfer. 2308c2ecf20Sopenharmony_ci * - 21 CLK frequency: 0=ATA clock, 1=dual ATA clock. 2318c2ecf20Sopenharmony_ci * 19:21 22:24 pre_high_time. Time to initialize the 1st cycle for PIO and 2328c2ecf20Sopenharmony_ci * MW DMA xfer. 2338c2ecf20Sopenharmony_ci * 22:24 25:27 cmd_pre_high_time. Time to initialize the 1st PIO cycle for 2348c2ecf20Sopenharmony_ci * task file register access. 2358c2ecf20Sopenharmony_ci * 28 28 UDMA enable. 2368c2ecf20Sopenharmony_ci * 29 29 DMA enable. 2378c2ecf20Sopenharmony_ci * 30 30 PIO MST enable. If set, the chip is in bus master mode during 2388c2ecf20Sopenharmony_ci * PIO xfer. 2398c2ecf20Sopenharmony_ci * 31 31 FIFO enable. 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic u32 forty_base_hpt36x[] = { 2438c2ecf20Sopenharmony_ci /* XFER_UDMA_6 */ 0x900fd943, 2448c2ecf20Sopenharmony_ci /* XFER_UDMA_5 */ 0x900fd943, 2458c2ecf20Sopenharmony_ci /* XFER_UDMA_4 */ 0x900fd943, 2468c2ecf20Sopenharmony_ci /* XFER_UDMA_3 */ 0x900ad943, 2478c2ecf20Sopenharmony_ci /* XFER_UDMA_2 */ 0x900bd943, 2488c2ecf20Sopenharmony_ci /* XFER_UDMA_1 */ 0x9008d943, 2498c2ecf20Sopenharmony_ci /* XFER_UDMA_0 */ 0x9008d943, 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* XFER_MW_DMA_2 */ 0xa008d943, 2528c2ecf20Sopenharmony_ci /* XFER_MW_DMA_1 */ 0xa010d955, 2538c2ecf20Sopenharmony_ci /* XFER_MW_DMA_0 */ 0xa010d9fc, 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* XFER_PIO_4 */ 0xc008d963, 2568c2ecf20Sopenharmony_ci /* XFER_PIO_3 */ 0xc010d974, 2578c2ecf20Sopenharmony_ci /* XFER_PIO_2 */ 0xc010d997, 2588c2ecf20Sopenharmony_ci /* XFER_PIO_1 */ 0xc010d9c7, 2598c2ecf20Sopenharmony_ci /* XFER_PIO_0 */ 0xc018d9d9 2608c2ecf20Sopenharmony_ci}; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic u32 thirty_three_base_hpt36x[] = { 2638c2ecf20Sopenharmony_ci /* XFER_UDMA_6 */ 0x90c9a731, 2648c2ecf20Sopenharmony_ci /* XFER_UDMA_5 */ 0x90c9a731, 2658c2ecf20Sopenharmony_ci /* XFER_UDMA_4 */ 0x90c9a731, 2668c2ecf20Sopenharmony_ci /* XFER_UDMA_3 */ 0x90cfa731, 2678c2ecf20Sopenharmony_ci /* XFER_UDMA_2 */ 0x90caa731, 2688c2ecf20Sopenharmony_ci /* XFER_UDMA_1 */ 0x90cba731, 2698c2ecf20Sopenharmony_ci /* XFER_UDMA_0 */ 0x90c8a731, 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* XFER_MW_DMA_2 */ 0xa0c8a731, 2728c2ecf20Sopenharmony_ci /* XFER_MW_DMA_1 */ 0xa0c8a732, /* 0xa0c8a733 */ 2738c2ecf20Sopenharmony_ci /* XFER_MW_DMA_0 */ 0xa0c8a797, 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* XFER_PIO_4 */ 0xc0c8a731, 2768c2ecf20Sopenharmony_ci /* XFER_PIO_3 */ 0xc0c8a742, 2778c2ecf20Sopenharmony_ci /* XFER_PIO_2 */ 0xc0d0a753, 2788c2ecf20Sopenharmony_ci /* XFER_PIO_1 */ 0xc0d0a7a3, /* 0xc0d0a793 */ 2798c2ecf20Sopenharmony_ci /* XFER_PIO_0 */ 0xc0d0a7aa /* 0xc0d0a7a7 */ 2808c2ecf20Sopenharmony_ci}; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic u32 twenty_five_base_hpt36x[] = { 2838c2ecf20Sopenharmony_ci /* XFER_UDMA_6 */ 0x90c98521, 2848c2ecf20Sopenharmony_ci /* XFER_UDMA_5 */ 0x90c98521, 2858c2ecf20Sopenharmony_ci /* XFER_UDMA_4 */ 0x90c98521, 2868c2ecf20Sopenharmony_ci /* XFER_UDMA_3 */ 0x90cf8521, 2878c2ecf20Sopenharmony_ci /* XFER_UDMA_2 */ 0x90cf8521, 2888c2ecf20Sopenharmony_ci /* XFER_UDMA_1 */ 0x90cb8521, 2898c2ecf20Sopenharmony_ci /* XFER_UDMA_0 */ 0x90cb8521, 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* XFER_MW_DMA_2 */ 0xa0ca8521, 2928c2ecf20Sopenharmony_ci /* XFER_MW_DMA_1 */ 0xa0ca8532, 2938c2ecf20Sopenharmony_ci /* XFER_MW_DMA_0 */ 0xa0ca8575, 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* XFER_PIO_4 */ 0xc0ca8521, 2968c2ecf20Sopenharmony_ci /* XFER_PIO_3 */ 0xc0ca8532, 2978c2ecf20Sopenharmony_ci /* XFER_PIO_2 */ 0xc0ca8542, 2988c2ecf20Sopenharmony_ci /* XFER_PIO_1 */ 0xc0d08572, 2998c2ecf20Sopenharmony_ci /* XFER_PIO_0 */ 0xc0d08585 3008c2ecf20Sopenharmony_ci}; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci/* 3038c2ecf20Sopenharmony_ci * The following are the new timing tables with PIO mode data/taskfile transfer 3048c2ecf20Sopenharmony_ci * overclocking fixed... 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci/* This table is taken from the HPT370 data manual rev. 1.02 */ 3088c2ecf20Sopenharmony_cistatic u32 thirty_three_base_hpt37x[] = { 3098c2ecf20Sopenharmony_ci /* XFER_UDMA_6 */ 0x16455031, /* 0x16655031 ?? */ 3108c2ecf20Sopenharmony_ci /* XFER_UDMA_5 */ 0x16455031, 3118c2ecf20Sopenharmony_ci /* XFER_UDMA_4 */ 0x16455031, 3128c2ecf20Sopenharmony_ci /* XFER_UDMA_3 */ 0x166d5031, 3138c2ecf20Sopenharmony_ci /* XFER_UDMA_2 */ 0x16495031, 3148c2ecf20Sopenharmony_ci /* XFER_UDMA_1 */ 0x164d5033, 3158c2ecf20Sopenharmony_ci /* XFER_UDMA_0 */ 0x16515097, 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* XFER_MW_DMA_2 */ 0x26515031, 3188c2ecf20Sopenharmony_ci /* XFER_MW_DMA_1 */ 0x26515033, 3198c2ecf20Sopenharmony_ci /* XFER_MW_DMA_0 */ 0x26515097, 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* XFER_PIO_4 */ 0x06515021, 3228c2ecf20Sopenharmony_ci /* XFER_PIO_3 */ 0x06515022, 3238c2ecf20Sopenharmony_ci /* XFER_PIO_2 */ 0x06515033, 3248c2ecf20Sopenharmony_ci /* XFER_PIO_1 */ 0x06915065, 3258c2ecf20Sopenharmony_ci /* XFER_PIO_0 */ 0x06d1508a 3268c2ecf20Sopenharmony_ci}; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic u32 fifty_base_hpt37x[] = { 3298c2ecf20Sopenharmony_ci /* XFER_UDMA_6 */ 0x1a861842, 3308c2ecf20Sopenharmony_ci /* XFER_UDMA_5 */ 0x1a861842, 3318c2ecf20Sopenharmony_ci /* XFER_UDMA_4 */ 0x1aae1842, 3328c2ecf20Sopenharmony_ci /* XFER_UDMA_3 */ 0x1a8e1842, 3338c2ecf20Sopenharmony_ci /* XFER_UDMA_2 */ 0x1a0e1842, 3348c2ecf20Sopenharmony_ci /* XFER_UDMA_1 */ 0x1a161854, 3358c2ecf20Sopenharmony_ci /* XFER_UDMA_0 */ 0x1a1a18ea, 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* XFER_MW_DMA_2 */ 0x2a821842, 3388c2ecf20Sopenharmony_ci /* XFER_MW_DMA_1 */ 0x2a821854, 3398c2ecf20Sopenharmony_ci /* XFER_MW_DMA_0 */ 0x2a8218ea, 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* XFER_PIO_4 */ 0x0a821842, 3428c2ecf20Sopenharmony_ci /* XFER_PIO_3 */ 0x0a821843, 3438c2ecf20Sopenharmony_ci /* XFER_PIO_2 */ 0x0a821855, 3448c2ecf20Sopenharmony_ci /* XFER_PIO_1 */ 0x0ac218a8, 3458c2ecf20Sopenharmony_ci /* XFER_PIO_0 */ 0x0b02190c 3468c2ecf20Sopenharmony_ci}; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic u32 sixty_six_base_hpt37x[] = { 3498c2ecf20Sopenharmony_ci /* XFER_UDMA_6 */ 0x1c86fe62, 3508c2ecf20Sopenharmony_ci /* XFER_UDMA_5 */ 0x1caefe62, /* 0x1c8afe62 */ 3518c2ecf20Sopenharmony_ci /* XFER_UDMA_4 */ 0x1c8afe62, 3528c2ecf20Sopenharmony_ci /* XFER_UDMA_3 */ 0x1c8efe62, 3538c2ecf20Sopenharmony_ci /* XFER_UDMA_2 */ 0x1c92fe62, 3548c2ecf20Sopenharmony_ci /* XFER_UDMA_1 */ 0x1c9afe62, 3558c2ecf20Sopenharmony_ci /* XFER_UDMA_0 */ 0x1c82fe62, 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* XFER_MW_DMA_2 */ 0x2c82fe62, 3588c2ecf20Sopenharmony_ci /* XFER_MW_DMA_1 */ 0x2c82fe66, 3598c2ecf20Sopenharmony_ci /* XFER_MW_DMA_0 */ 0x2c82ff2e, 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* XFER_PIO_4 */ 0x0c82fe62, 3628c2ecf20Sopenharmony_ci /* XFER_PIO_3 */ 0x0c82fe84, 3638c2ecf20Sopenharmony_ci /* XFER_PIO_2 */ 0x0c82fea6, 3648c2ecf20Sopenharmony_ci /* XFER_PIO_1 */ 0x0d02ff26, 3658c2ecf20Sopenharmony_ci /* XFER_PIO_0 */ 0x0d42ff7f 3668c2ecf20Sopenharmony_ci}; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci#define HPT371_ALLOW_ATA133_6 1 3698c2ecf20Sopenharmony_ci#define HPT302_ALLOW_ATA133_6 1 3708c2ecf20Sopenharmony_ci#define HPT372_ALLOW_ATA133_6 1 3718c2ecf20Sopenharmony_ci#define HPT370_ALLOW_ATA100_5 0 3728c2ecf20Sopenharmony_ci#define HPT366_ALLOW_ATA66_4 1 3738c2ecf20Sopenharmony_ci#define HPT366_ALLOW_ATA66_3 1 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci/* Supported ATA clock frequencies */ 3768c2ecf20Sopenharmony_cienum ata_clock { 3778c2ecf20Sopenharmony_ci ATA_CLOCK_25MHZ, 3788c2ecf20Sopenharmony_ci ATA_CLOCK_33MHZ, 3798c2ecf20Sopenharmony_ci ATA_CLOCK_40MHZ, 3808c2ecf20Sopenharmony_ci ATA_CLOCK_50MHZ, 3818c2ecf20Sopenharmony_ci ATA_CLOCK_66MHZ, 3828c2ecf20Sopenharmony_ci NUM_ATA_CLOCKS 3838c2ecf20Sopenharmony_ci}; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistruct hpt_timings { 3868c2ecf20Sopenharmony_ci u32 pio_mask; 3878c2ecf20Sopenharmony_ci u32 dma_mask; 3888c2ecf20Sopenharmony_ci u32 ultra_mask; 3898c2ecf20Sopenharmony_ci u32 *clock_table[NUM_ATA_CLOCKS]; 3908c2ecf20Sopenharmony_ci}; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci/* 3938c2ecf20Sopenharmony_ci * Hold all the HighPoint chip information in one place. 3948c2ecf20Sopenharmony_ci */ 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistruct hpt_info { 3978c2ecf20Sopenharmony_ci char *chip_name; /* Chip name */ 3988c2ecf20Sopenharmony_ci u8 chip_type; /* Chip type */ 3998c2ecf20Sopenharmony_ci u8 udma_mask; /* Allowed UltraDMA modes mask. */ 4008c2ecf20Sopenharmony_ci u8 dpll_clk; /* DPLL clock in MHz */ 4018c2ecf20Sopenharmony_ci u8 pci_clk; /* PCI clock in MHz */ 4028c2ecf20Sopenharmony_ci struct hpt_timings *timings; /* Chipset timing data */ 4038c2ecf20Sopenharmony_ci u8 clock; /* ATA clock selected */ 4048c2ecf20Sopenharmony_ci}; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci/* Supported HighPoint chips */ 4078c2ecf20Sopenharmony_cienum { 4088c2ecf20Sopenharmony_ci HPT36x, 4098c2ecf20Sopenharmony_ci HPT370, 4108c2ecf20Sopenharmony_ci HPT370A, 4118c2ecf20Sopenharmony_ci HPT374, 4128c2ecf20Sopenharmony_ci HPT372, 4138c2ecf20Sopenharmony_ci HPT372A, 4148c2ecf20Sopenharmony_ci HPT302, 4158c2ecf20Sopenharmony_ci HPT371, 4168c2ecf20Sopenharmony_ci HPT372N, 4178c2ecf20Sopenharmony_ci HPT302N, 4188c2ecf20Sopenharmony_ci HPT371N 4198c2ecf20Sopenharmony_ci}; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic struct hpt_timings hpt36x_timings = { 4228c2ecf20Sopenharmony_ci .pio_mask = 0xc1f8ffff, 4238c2ecf20Sopenharmony_ci .dma_mask = 0x303800ff, 4248c2ecf20Sopenharmony_ci .ultra_mask = 0x30070000, 4258c2ecf20Sopenharmony_ci .clock_table = { 4268c2ecf20Sopenharmony_ci [ATA_CLOCK_25MHZ] = twenty_five_base_hpt36x, 4278c2ecf20Sopenharmony_ci [ATA_CLOCK_33MHZ] = thirty_three_base_hpt36x, 4288c2ecf20Sopenharmony_ci [ATA_CLOCK_40MHZ] = forty_base_hpt36x, 4298c2ecf20Sopenharmony_ci [ATA_CLOCK_50MHZ] = NULL, 4308c2ecf20Sopenharmony_ci [ATA_CLOCK_66MHZ] = NULL 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci}; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic struct hpt_timings hpt37x_timings = { 4358c2ecf20Sopenharmony_ci .pio_mask = 0xcfc3ffff, 4368c2ecf20Sopenharmony_ci .dma_mask = 0x31c001ff, 4378c2ecf20Sopenharmony_ci .ultra_mask = 0x303c0000, 4388c2ecf20Sopenharmony_ci .clock_table = { 4398c2ecf20Sopenharmony_ci [ATA_CLOCK_25MHZ] = NULL, 4408c2ecf20Sopenharmony_ci [ATA_CLOCK_33MHZ] = thirty_three_base_hpt37x, 4418c2ecf20Sopenharmony_ci [ATA_CLOCK_40MHZ] = NULL, 4428c2ecf20Sopenharmony_ci [ATA_CLOCK_50MHZ] = fifty_base_hpt37x, 4438c2ecf20Sopenharmony_ci [ATA_CLOCK_66MHZ] = sixty_six_base_hpt37x 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci}; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic const struct hpt_info hpt36x = { 4488c2ecf20Sopenharmony_ci .chip_name = "HPT36x", 4498c2ecf20Sopenharmony_ci .chip_type = HPT36x, 4508c2ecf20Sopenharmony_ci .udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2, 4518c2ecf20Sopenharmony_ci .dpll_clk = 0, /* no DPLL */ 4528c2ecf20Sopenharmony_ci .timings = &hpt36x_timings 4538c2ecf20Sopenharmony_ci}; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic const struct hpt_info hpt370 = { 4568c2ecf20Sopenharmony_ci .chip_name = "HPT370", 4578c2ecf20Sopenharmony_ci .chip_type = HPT370, 4588c2ecf20Sopenharmony_ci .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4, 4598c2ecf20Sopenharmony_ci .dpll_clk = 48, 4608c2ecf20Sopenharmony_ci .timings = &hpt37x_timings 4618c2ecf20Sopenharmony_ci}; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic const struct hpt_info hpt370a = { 4648c2ecf20Sopenharmony_ci .chip_name = "HPT370A", 4658c2ecf20Sopenharmony_ci .chip_type = HPT370A, 4668c2ecf20Sopenharmony_ci .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4, 4678c2ecf20Sopenharmony_ci .dpll_clk = 48, 4688c2ecf20Sopenharmony_ci .timings = &hpt37x_timings 4698c2ecf20Sopenharmony_ci}; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic const struct hpt_info hpt374 = { 4728c2ecf20Sopenharmony_ci .chip_name = "HPT374", 4738c2ecf20Sopenharmony_ci .chip_type = HPT374, 4748c2ecf20Sopenharmony_ci .udma_mask = ATA_UDMA5, 4758c2ecf20Sopenharmony_ci .dpll_clk = 48, 4768c2ecf20Sopenharmony_ci .timings = &hpt37x_timings 4778c2ecf20Sopenharmony_ci}; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic const struct hpt_info hpt372 = { 4808c2ecf20Sopenharmony_ci .chip_name = "HPT372", 4818c2ecf20Sopenharmony_ci .chip_type = HPT372, 4828c2ecf20Sopenharmony_ci .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, 4838c2ecf20Sopenharmony_ci .dpll_clk = 55, 4848c2ecf20Sopenharmony_ci .timings = &hpt37x_timings 4858c2ecf20Sopenharmony_ci}; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic const struct hpt_info hpt372a = { 4888c2ecf20Sopenharmony_ci .chip_name = "HPT372A", 4898c2ecf20Sopenharmony_ci .chip_type = HPT372A, 4908c2ecf20Sopenharmony_ci .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, 4918c2ecf20Sopenharmony_ci .dpll_clk = 66, 4928c2ecf20Sopenharmony_ci .timings = &hpt37x_timings 4938c2ecf20Sopenharmony_ci}; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic const struct hpt_info hpt302 = { 4968c2ecf20Sopenharmony_ci .chip_name = "HPT302", 4978c2ecf20Sopenharmony_ci .chip_type = HPT302, 4988c2ecf20Sopenharmony_ci .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, 4998c2ecf20Sopenharmony_ci .dpll_clk = 66, 5008c2ecf20Sopenharmony_ci .timings = &hpt37x_timings 5018c2ecf20Sopenharmony_ci}; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic const struct hpt_info hpt371 = { 5048c2ecf20Sopenharmony_ci .chip_name = "HPT371", 5058c2ecf20Sopenharmony_ci .chip_type = HPT371, 5068c2ecf20Sopenharmony_ci .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, 5078c2ecf20Sopenharmony_ci .dpll_clk = 66, 5088c2ecf20Sopenharmony_ci .timings = &hpt37x_timings 5098c2ecf20Sopenharmony_ci}; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic const struct hpt_info hpt372n = { 5128c2ecf20Sopenharmony_ci .chip_name = "HPT372N", 5138c2ecf20Sopenharmony_ci .chip_type = HPT372N, 5148c2ecf20Sopenharmony_ci .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, 5158c2ecf20Sopenharmony_ci .dpll_clk = 77, 5168c2ecf20Sopenharmony_ci .timings = &hpt37x_timings 5178c2ecf20Sopenharmony_ci}; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic const struct hpt_info hpt302n = { 5208c2ecf20Sopenharmony_ci .chip_name = "HPT302N", 5218c2ecf20Sopenharmony_ci .chip_type = HPT302N, 5228c2ecf20Sopenharmony_ci .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, 5238c2ecf20Sopenharmony_ci .dpll_clk = 77, 5248c2ecf20Sopenharmony_ci .timings = &hpt37x_timings 5258c2ecf20Sopenharmony_ci}; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic const struct hpt_info hpt371n = { 5288c2ecf20Sopenharmony_ci .chip_name = "HPT371N", 5298c2ecf20Sopenharmony_ci .chip_type = HPT371N, 5308c2ecf20Sopenharmony_ci .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, 5318c2ecf20Sopenharmony_ci .dpll_clk = 77, 5328c2ecf20Sopenharmony_ci .timings = &hpt37x_timings 5338c2ecf20Sopenharmony_ci}; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic bool check_in_drive_list(ide_drive_t *drive, const char **list) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci return match_string(list, -1, (char *)&drive->id[ATA_ID_PROD]) >= 0; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic struct hpt_info *hpt3xx_get_info(struct device *dev) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct ide_host *host = dev_get_drvdata(dev); 5438c2ecf20Sopenharmony_ci struct hpt_info *info = (struct hpt_info *)host->host_priv; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci return dev == host->dev[1] ? info + 1 : info; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci/* 5498c2ecf20Sopenharmony_ci * The Marvell bridge chips used on the HighPoint SATA cards do not seem 5508c2ecf20Sopenharmony_ci * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes... 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic u8 hpt3xx_udma_filter(ide_drive_t *drive) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 5568c2ecf20Sopenharmony_ci struct hpt_info *info = hpt3xx_get_info(hwif->dev); 5578c2ecf20Sopenharmony_ci u8 mask = hwif->ultra_mask; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci switch (info->chip_type) { 5608c2ecf20Sopenharmony_ci case HPT36x: 5618c2ecf20Sopenharmony_ci if (!HPT366_ALLOW_ATA66_4 || 5628c2ecf20Sopenharmony_ci check_in_drive_list(drive, bad_ata66_4)) 5638c2ecf20Sopenharmony_ci mask = ATA_UDMA3; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (!HPT366_ALLOW_ATA66_3 || 5668c2ecf20Sopenharmony_ci check_in_drive_list(drive, bad_ata66_3)) 5678c2ecf20Sopenharmony_ci mask = ATA_UDMA2; 5688c2ecf20Sopenharmony_ci break; 5698c2ecf20Sopenharmony_ci case HPT370: 5708c2ecf20Sopenharmony_ci if (!HPT370_ALLOW_ATA100_5 || 5718c2ecf20Sopenharmony_ci check_in_drive_list(drive, bad_ata100_5)) 5728c2ecf20Sopenharmony_ci mask = ATA_UDMA4; 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci case HPT370A: 5758c2ecf20Sopenharmony_ci if (!HPT370_ALLOW_ATA100_5 || 5768c2ecf20Sopenharmony_ci check_in_drive_list(drive, bad_ata100_5)) 5778c2ecf20Sopenharmony_ci return ATA_UDMA4; 5788c2ecf20Sopenharmony_ci fallthrough; 5798c2ecf20Sopenharmony_ci case HPT372 : 5808c2ecf20Sopenharmony_ci case HPT372A: 5818c2ecf20Sopenharmony_ci case HPT372N: 5828c2ecf20Sopenharmony_ci case HPT374 : 5838c2ecf20Sopenharmony_ci if (ata_id_is_sata(drive->id)) 5848c2ecf20Sopenharmony_ci mask &= ~0x0e; 5858c2ecf20Sopenharmony_ci fallthrough; 5868c2ecf20Sopenharmony_ci default: 5878c2ecf20Sopenharmony_ci return mask; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic u8 hpt3xx_mdma_filter(ide_drive_t *drive) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 5968c2ecf20Sopenharmony_ci struct hpt_info *info = hpt3xx_get_info(hwif->dev); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci switch (info->chip_type) { 5998c2ecf20Sopenharmony_ci case HPT372 : 6008c2ecf20Sopenharmony_ci case HPT372A: 6018c2ecf20Sopenharmony_ci case HPT372N: 6028c2ecf20Sopenharmony_ci case HPT374 : 6038c2ecf20Sopenharmony_ci if (ata_id_is_sata(drive->id)) 6048c2ecf20Sopenharmony_ci return 0x00; 6058c2ecf20Sopenharmony_ci fallthrough; 6068c2ecf20Sopenharmony_ci default: 6078c2ecf20Sopenharmony_ci return 0x07; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic u32 get_speed_setting(u8 speed, struct hpt_info *info) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci int i; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* 6168c2ecf20Sopenharmony_ci * Lookup the transfer mode table to get the index into 6178c2ecf20Sopenharmony_ci * the timing table. 6188c2ecf20Sopenharmony_ci * 6198c2ecf20Sopenharmony_ci * NOTE: For XFER_PIO_SLOW, PIO mode 0 timings will be used. 6208c2ecf20Sopenharmony_ci */ 6218c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++) 6228c2ecf20Sopenharmony_ci if (xfer_speeds[i] == speed) 6238c2ecf20Sopenharmony_ci break; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci return info->timings->clock_table[info->clock][i]; 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_cistatic void hpt3xx_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 6318c2ecf20Sopenharmony_ci struct hpt_info *info = hpt3xx_get_info(hwif->dev); 6328c2ecf20Sopenharmony_ci struct hpt_timings *t = info->timings; 6338c2ecf20Sopenharmony_ci u8 itr_addr = 0x40 + (drive->dn * 4); 6348c2ecf20Sopenharmony_ci u32 old_itr = 0; 6358c2ecf20Sopenharmony_ci const u8 speed = drive->dma_mode; 6368c2ecf20Sopenharmony_ci u32 new_itr = get_speed_setting(speed, info); 6378c2ecf20Sopenharmony_ci u32 itr_mask = speed < XFER_MW_DMA_0 ? t->pio_mask : 6388c2ecf20Sopenharmony_ci (speed < XFER_UDMA_0 ? t->dma_mask : 6398c2ecf20Sopenharmony_ci t->ultra_mask); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci pci_read_config_dword(dev, itr_addr, &old_itr); 6428c2ecf20Sopenharmony_ci new_itr = (old_itr & ~itr_mask) | (new_itr & itr_mask); 6438c2ecf20Sopenharmony_ci /* 6448c2ecf20Sopenharmony_ci * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well) 6458c2ecf20Sopenharmony_ci * to avoid problems handling I/O errors later 6468c2ecf20Sopenharmony_ci */ 6478c2ecf20Sopenharmony_ci new_itr &= ~0xc0000000; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci pci_write_config_dword(dev, itr_addr, new_itr); 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic void hpt3xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci drive->dma_mode = drive->pio_mode; 6558c2ecf20Sopenharmony_ci hpt3xx_set_mode(hwif, drive); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic void hpt3xx_maskproc(ide_drive_t *drive, int mask) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 6618c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 6628c2ecf20Sopenharmony_ci struct hpt_info *info = hpt3xx_get_info(hwif->dev); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0) 6658c2ecf20Sopenharmony_ci return; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (info->chip_type >= HPT370) { 6688c2ecf20Sopenharmony_ci u8 scr1 = 0; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x5a, &scr1); 6718c2ecf20Sopenharmony_ci if (((scr1 & 0x10) >> 4) != mask) { 6728c2ecf20Sopenharmony_ci if (mask) 6738c2ecf20Sopenharmony_ci scr1 |= 0x10; 6748c2ecf20Sopenharmony_ci else 6758c2ecf20Sopenharmony_ci scr1 &= ~0x10; 6768c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x5a, scr1); 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci } else if (mask) 6798c2ecf20Sopenharmony_ci disable_irq(hwif->irq); 6808c2ecf20Sopenharmony_ci else 6818c2ecf20Sopenharmony_ci enable_irq(hwif->irq); 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci/* 6858c2ecf20Sopenharmony_ci * This is specific to the HPT366 UDMA chipset 6868c2ecf20Sopenharmony_ci * by HighPoint|Triones Technologies, Inc. 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_cistatic void hpt366_dma_lost_irq(ide_drive_t *drive) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(drive->hwif->dev); 6918c2ecf20Sopenharmony_ci u8 mcr1 = 0, mcr3 = 0, scr1 = 0; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x50, &mcr1); 6948c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x52, &mcr3); 6958c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x5a, &scr1); 6968c2ecf20Sopenharmony_ci printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n", 6978c2ecf20Sopenharmony_ci drive->name, __func__, mcr1, mcr3, scr1); 6988c2ecf20Sopenharmony_ci if (scr1 & 0x10) 6998c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x5a, scr1 & ~0x10); 7008c2ecf20Sopenharmony_ci ide_dma_lost_irq(drive); 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic void hpt370_clear_engine(ide_drive_t *drive) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 7068c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci pci_write_config_byte(dev, hwif->select_data, 0x37); 7098c2ecf20Sopenharmony_ci udelay(10); 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic void hpt370_irq_timeout(ide_drive_t *drive) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 7158c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 7168c2ecf20Sopenharmony_ci u16 bfifo = 0; 7178c2ecf20Sopenharmony_ci u8 dma_cmd; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci pci_read_config_word(dev, hwif->select_data + 2, &bfifo); 7208c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* get DMA command mode */ 7238c2ecf20Sopenharmony_ci dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); 7248c2ecf20Sopenharmony_ci /* stop DMA */ 7258c2ecf20Sopenharmony_ci outb(dma_cmd & ~ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD); 7268c2ecf20Sopenharmony_ci hpt370_clear_engine(drive); 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic void hpt370_dma_start(ide_drive_t *drive) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci#ifdef HPT_RESET_STATE_ENGINE 7328c2ecf20Sopenharmony_ci hpt370_clear_engine(drive); 7338c2ecf20Sopenharmony_ci#endif 7348c2ecf20Sopenharmony_ci ide_dma_start(drive); 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic int hpt370_dma_end(ide_drive_t *drive) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 7408c2ecf20Sopenharmony_ci u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (dma_stat & ATA_DMA_ACTIVE) { 7438c2ecf20Sopenharmony_ci /* wait a little */ 7448c2ecf20Sopenharmony_ci udelay(20); 7458c2ecf20Sopenharmony_ci dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); 7468c2ecf20Sopenharmony_ci if (dma_stat & ATA_DMA_ACTIVE) 7478c2ecf20Sopenharmony_ci hpt370_irq_timeout(drive); 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci return ide_dma_end(drive); 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci/* returns 1 if DMA IRQ issued, 0 otherwise */ 7538c2ecf20Sopenharmony_cistatic int hpt374_dma_test_irq(ide_drive_t *drive) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 7568c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 7578c2ecf20Sopenharmony_ci u16 bfifo = 0; 7588c2ecf20Sopenharmony_ci u8 dma_stat; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci pci_read_config_word(dev, hwif->select_data + 2, &bfifo); 7618c2ecf20Sopenharmony_ci if (bfifo & 0x1FF) { 7628c2ecf20Sopenharmony_ci// printk("%s: %d bytes in FIFO\n", drive->name, bfifo); 7638c2ecf20Sopenharmony_ci return 0; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); 7678c2ecf20Sopenharmony_ci /* return 1 if INTR asserted */ 7688c2ecf20Sopenharmony_ci if (dma_stat & ATA_DMA_INTR) 7698c2ecf20Sopenharmony_ci return 1; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return 0; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int hpt374_dma_end(ide_drive_t *drive) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 7778c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 7788c2ecf20Sopenharmony_ci u8 mcr = 0, mcr_addr = hwif->select_data; 7798c2ecf20Sopenharmony_ci u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x6a, &bwsr); 7828c2ecf20Sopenharmony_ci pci_read_config_byte(dev, mcr_addr, &mcr); 7838c2ecf20Sopenharmony_ci if (bwsr & mask) 7848c2ecf20Sopenharmony_ci pci_write_config_byte(dev, mcr_addr, mcr | 0x30); 7858c2ecf20Sopenharmony_ci return ide_dma_end(drive); 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci/** 7898c2ecf20Sopenharmony_ci * hpt3xxn_set_clock - perform clock switching dance 7908c2ecf20Sopenharmony_ci * @hwif: hwif to switch 7918c2ecf20Sopenharmony_ci * @mode: clocking mode (0x21 for write, 0x23 otherwise) 7928c2ecf20Sopenharmony_ci * 7938c2ecf20Sopenharmony_ci * Switch the DPLL clock on the HPT3xxN devices. This is a right mess. 7948c2ecf20Sopenharmony_ci */ 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci unsigned long base = hwif->extra_base; 7998c2ecf20Sopenharmony_ci u8 scr2 = inb(base + 0x6b); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if ((scr2 & 0x7f) == mode) 8028c2ecf20Sopenharmony_ci return; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* Tristate the bus */ 8058c2ecf20Sopenharmony_ci outb(0x80, base + 0x63); 8068c2ecf20Sopenharmony_ci outb(0x80, base + 0x67); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* Switch clock and reset channels */ 8098c2ecf20Sopenharmony_ci outb(mode, base + 0x6b); 8108c2ecf20Sopenharmony_ci outb(0xc0, base + 0x69); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci /* 8138c2ecf20Sopenharmony_ci * Reset the state machines. 8148c2ecf20Sopenharmony_ci * NOTE: avoid accidentally enabling the disabled channels. 8158c2ecf20Sopenharmony_ci */ 8168c2ecf20Sopenharmony_ci outb(inb(base + 0x60) | 0x32, base + 0x60); 8178c2ecf20Sopenharmony_ci outb(inb(base + 0x64) | 0x32, base + 0x64); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* Complete reset */ 8208c2ecf20Sopenharmony_ci outb(0x00, base + 0x69); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* Reconnect channels to bus */ 8238c2ecf20Sopenharmony_ci outb(0x00, base + 0x63); 8248c2ecf20Sopenharmony_ci outb(0x00, base + 0x67); 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci/** 8288c2ecf20Sopenharmony_ci * hpt3xxn_rw_disk - prepare for I/O 8298c2ecf20Sopenharmony_ci * @drive: drive for command 8308c2ecf20Sopenharmony_ci * @rq: block request structure 8318c2ecf20Sopenharmony_ci * 8328c2ecf20Sopenharmony_ci * This is called when a disk I/O is issued to HPT3xxN. 8338c2ecf20Sopenharmony_ci * We need it because of the clock switching. 8348c2ecf20Sopenharmony_ci */ 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci hpt3xxn_set_clock(drive->hwif, rq_data_dir(rq) ? 0x21 : 0x23); 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci/** 8428c2ecf20Sopenharmony_ci * hpt37x_calibrate_dpll - calibrate the DPLL 8438c2ecf20Sopenharmony_ci * @dev: PCI device 8448c2ecf20Sopenharmony_ci * 8458c2ecf20Sopenharmony_ci * Perform a calibration cycle on the DPLL. 8468c2ecf20Sopenharmony_ci * Returns 1 if this succeeds 8478c2ecf20Sopenharmony_ci */ 8488c2ecf20Sopenharmony_cistatic int hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci u32 dpll = (f_high << 16) | f_low | 0x100; 8518c2ecf20Sopenharmony_ci u8 scr2; 8528c2ecf20Sopenharmony_ci int i; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci pci_write_config_dword(dev, 0x5c, dpll); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci /* Wait for oscillator ready */ 8578c2ecf20Sopenharmony_ci for(i = 0; i < 0x5000; ++i) { 8588c2ecf20Sopenharmony_ci udelay(50); 8598c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x5b, &scr2); 8608c2ecf20Sopenharmony_ci if (scr2 & 0x80) 8618c2ecf20Sopenharmony_ci break; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci /* See if it stays ready (we'll just bail out if it's not yet) */ 8648c2ecf20Sopenharmony_ci for(i = 0; i < 0x1000; ++i) { 8658c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x5b, &scr2); 8668c2ecf20Sopenharmony_ci /* DPLL destabilized? */ 8678c2ecf20Sopenharmony_ci if(!(scr2 & 0x80)) 8688c2ecf20Sopenharmony_ci return 0; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci /* Turn off tuning, we have the DPLL set */ 8718c2ecf20Sopenharmony_ci pci_read_config_dword (dev, 0x5c, &dpll); 8728c2ecf20Sopenharmony_ci pci_write_config_dword(dev, 0x5c, (dpll & ~0x100)); 8738c2ecf20Sopenharmony_ci return 1; 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic void hpt3xx_disable_fast_irq(struct pci_dev *dev, u8 mcr_addr) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci struct ide_host *host = pci_get_drvdata(dev); 8798c2ecf20Sopenharmony_ci struct hpt_info *info = host->host_priv + (&dev->dev == host->dev[1]); 8808c2ecf20Sopenharmony_ci u8 chip_type = info->chip_type; 8818c2ecf20Sopenharmony_ci u8 new_mcr, old_mcr = 0; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* 8848c2ecf20Sopenharmony_ci * Disable the "fast interrupt" prediction. Don't hold off 8858c2ecf20Sopenharmony_ci * on interrupts. (== 0x01 despite what the docs say) 8868c2ecf20Sopenharmony_ci */ 8878c2ecf20Sopenharmony_ci pci_read_config_byte(dev, mcr_addr + 1, &old_mcr); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (chip_type >= HPT374) 8908c2ecf20Sopenharmony_ci new_mcr = old_mcr & ~0x07; 8918c2ecf20Sopenharmony_ci else if (chip_type >= HPT370) { 8928c2ecf20Sopenharmony_ci new_mcr = old_mcr; 8938c2ecf20Sopenharmony_ci new_mcr &= ~0x02; 8948c2ecf20Sopenharmony_ci#ifdef HPT_DELAY_INTERRUPT 8958c2ecf20Sopenharmony_ci new_mcr &= ~0x01; 8968c2ecf20Sopenharmony_ci#else 8978c2ecf20Sopenharmony_ci new_mcr |= 0x01; 8988c2ecf20Sopenharmony_ci#endif 8998c2ecf20Sopenharmony_ci } else /* HPT366 and HPT368 */ 9008c2ecf20Sopenharmony_ci new_mcr = old_mcr & ~0x80; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (new_mcr != old_mcr) 9038c2ecf20Sopenharmony_ci pci_write_config_byte(dev, mcr_addr + 1, new_mcr); 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic int init_chipset_hpt366(struct pci_dev *dev) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci unsigned long io_base = pci_resource_start(dev, 4); 9098c2ecf20Sopenharmony_ci struct hpt_info *info = hpt3xx_get_info(&dev->dev); 9108c2ecf20Sopenharmony_ci const char *name = DRV_NAME; 9118c2ecf20Sopenharmony_ci u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */ 9128c2ecf20Sopenharmony_ci u8 chip_type; 9138c2ecf20Sopenharmony_ci enum ata_clock clock; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci chip_type = info->chip_type; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); 9188c2ecf20Sopenharmony_ci pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); 9198c2ecf20Sopenharmony_ci pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); 9208c2ecf20Sopenharmony_ci pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci /* 9238c2ecf20Sopenharmony_ci * First, try to estimate the PCI clock frequency... 9248c2ecf20Sopenharmony_ci */ 9258c2ecf20Sopenharmony_ci if (chip_type >= HPT370) { 9268c2ecf20Sopenharmony_ci u8 scr1 = 0; 9278c2ecf20Sopenharmony_ci u16 f_cnt = 0; 9288c2ecf20Sopenharmony_ci u32 temp = 0; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* Interrupt force enable. */ 9318c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x5a, &scr1); 9328c2ecf20Sopenharmony_ci if (scr1 & 0x10) 9338c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x5a, scr1 & ~0x10); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* 9368c2ecf20Sopenharmony_ci * HighPoint does this for HPT372A. 9378c2ecf20Sopenharmony_ci * NOTE: This register is only writeable via I/O space. 9388c2ecf20Sopenharmony_ci */ 9398c2ecf20Sopenharmony_ci if (chip_type == HPT372A) 9408c2ecf20Sopenharmony_ci outb(0x0e, io_base + 0x9c); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* 9438c2ecf20Sopenharmony_ci * Default to PCI clock. Make sure MA15/16 are set to output 9448c2ecf20Sopenharmony_ci * to prevent drives having problems with 40-pin cables. 9458c2ecf20Sopenharmony_ci */ 9468c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x5b, 0x23); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci /* 9498c2ecf20Sopenharmony_ci * We'll have to read f_CNT value in order to determine 9508c2ecf20Sopenharmony_ci * the PCI clock frequency according to the following ratio: 9518c2ecf20Sopenharmony_ci * 9528c2ecf20Sopenharmony_ci * f_CNT = Fpci * 192 / Fdpll 9538c2ecf20Sopenharmony_ci * 9548c2ecf20Sopenharmony_ci * First try reading the register in which the HighPoint BIOS 9558c2ecf20Sopenharmony_ci * saves f_CNT value before reprogramming the DPLL from its 9568c2ecf20Sopenharmony_ci * default setting (which differs for the various chips). 9578c2ecf20Sopenharmony_ci * 9588c2ecf20Sopenharmony_ci * NOTE: This register is only accessible via I/O space; 9598c2ecf20Sopenharmony_ci * HPT374 BIOS only saves it for the function 0, so we have to 9608c2ecf20Sopenharmony_ci * always read it from there -- no need to check the result of 9618c2ecf20Sopenharmony_ci * pci_get_slot() for the function 0 as the whole device has 9628c2ecf20Sopenharmony_ci * been already "pinned" (via function 1) in init_setup_hpt374() 9638c2ecf20Sopenharmony_ci */ 9648c2ecf20Sopenharmony_ci if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) { 9658c2ecf20Sopenharmony_ci struct pci_dev *dev1 = pci_get_slot(dev->bus, 9668c2ecf20Sopenharmony_ci dev->devfn - 1); 9678c2ecf20Sopenharmony_ci unsigned long io_base = pci_resource_start(dev1, 4); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci temp = inl(io_base + 0x90); 9708c2ecf20Sopenharmony_ci pci_dev_put(dev1); 9718c2ecf20Sopenharmony_ci } else 9728c2ecf20Sopenharmony_ci temp = inl(io_base + 0x90); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* 9758c2ecf20Sopenharmony_ci * In case the signature check fails, we'll have to 9768c2ecf20Sopenharmony_ci * resort to reading the f_CNT register itself in hopes 9778c2ecf20Sopenharmony_ci * that nobody has touched the DPLL yet... 9788c2ecf20Sopenharmony_ci */ 9798c2ecf20Sopenharmony_ci if ((temp & 0xFFFFF000) != 0xABCDE000) { 9808c2ecf20Sopenharmony_ci int i; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s %s: no clock data saved by " 9838c2ecf20Sopenharmony_ci "BIOS\n", name, pci_name(dev)); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci /* Calculate the average value of f_CNT. */ 9868c2ecf20Sopenharmony_ci for (temp = i = 0; i < 128; i++) { 9878c2ecf20Sopenharmony_ci pci_read_config_word(dev, 0x78, &f_cnt); 9888c2ecf20Sopenharmony_ci temp += f_cnt & 0x1ff; 9898c2ecf20Sopenharmony_ci mdelay(1); 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci f_cnt = temp / 128; 9928c2ecf20Sopenharmony_ci } else 9938c2ecf20Sopenharmony_ci f_cnt = temp & 0x1ff; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci dpll_clk = info->dpll_clk; 9968c2ecf20Sopenharmony_ci pci_clk = (f_cnt * dpll_clk) / 192; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci /* Clamp PCI clock to bands. */ 9998c2ecf20Sopenharmony_ci if (pci_clk < 40) 10008c2ecf20Sopenharmony_ci pci_clk = 33; 10018c2ecf20Sopenharmony_ci else if(pci_clk < 45) 10028c2ecf20Sopenharmony_ci pci_clk = 40; 10038c2ecf20Sopenharmony_ci else if(pci_clk < 55) 10048c2ecf20Sopenharmony_ci pci_clk = 50; 10058c2ecf20Sopenharmony_ci else 10068c2ecf20Sopenharmony_ci pci_clk = 66; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci printk(KERN_INFO "%s %s: DPLL base: %d MHz, f_CNT: %d, " 10098c2ecf20Sopenharmony_ci "assuming %d MHz PCI\n", name, pci_name(dev), 10108c2ecf20Sopenharmony_ci dpll_clk, f_cnt, pci_clk); 10118c2ecf20Sopenharmony_ci } else { 10128c2ecf20Sopenharmony_ci u32 itr1 = 0; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci pci_read_config_dword(dev, 0x40, &itr1); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci /* Detect PCI clock by looking at cmd_high_time. */ 10178c2ecf20Sopenharmony_ci switch ((itr1 >> 8) & 0x0f) { 10188c2ecf20Sopenharmony_ci case 0x09: 10198c2ecf20Sopenharmony_ci pci_clk = 40; 10208c2ecf20Sopenharmony_ci break; 10218c2ecf20Sopenharmony_ci case 0x05: 10228c2ecf20Sopenharmony_ci pci_clk = 25; 10238c2ecf20Sopenharmony_ci break; 10248c2ecf20Sopenharmony_ci case 0x07: 10258c2ecf20Sopenharmony_ci default: 10268c2ecf20Sopenharmony_ci pci_clk = 33; 10278c2ecf20Sopenharmony_ci break; 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /* Let's assume we'll use PCI clock for the ATA clock... */ 10328c2ecf20Sopenharmony_ci switch (pci_clk) { 10338c2ecf20Sopenharmony_ci case 25: 10348c2ecf20Sopenharmony_ci clock = ATA_CLOCK_25MHZ; 10358c2ecf20Sopenharmony_ci break; 10368c2ecf20Sopenharmony_ci case 33: 10378c2ecf20Sopenharmony_ci default: 10388c2ecf20Sopenharmony_ci clock = ATA_CLOCK_33MHZ; 10398c2ecf20Sopenharmony_ci break; 10408c2ecf20Sopenharmony_ci case 40: 10418c2ecf20Sopenharmony_ci clock = ATA_CLOCK_40MHZ; 10428c2ecf20Sopenharmony_ci break; 10438c2ecf20Sopenharmony_ci case 50: 10448c2ecf20Sopenharmony_ci clock = ATA_CLOCK_50MHZ; 10458c2ecf20Sopenharmony_ci break; 10468c2ecf20Sopenharmony_ci case 66: 10478c2ecf20Sopenharmony_ci clock = ATA_CLOCK_66MHZ; 10488c2ecf20Sopenharmony_ci break; 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* 10528c2ecf20Sopenharmony_ci * Only try the DPLL if we don't have a table for the PCI clock that 10538c2ecf20Sopenharmony_ci * we are running at for HPT370/A, always use it for anything newer... 10548c2ecf20Sopenharmony_ci * 10558c2ecf20Sopenharmony_ci * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI. 10568c2ecf20Sopenharmony_ci * We also don't like using the DPLL because this causes glitches 10578c2ecf20Sopenharmony_ci * on PRST-/SRST- when the state engine gets reset... 10588c2ecf20Sopenharmony_ci */ 10598c2ecf20Sopenharmony_ci if (chip_type >= HPT374 || info->timings->clock_table[clock] == NULL) { 10608c2ecf20Sopenharmony_ci u16 f_low, delta = pci_clk < 50 ? 2 : 4; 10618c2ecf20Sopenharmony_ci int adjust; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci /* 10648c2ecf20Sopenharmony_ci * Select 66 MHz DPLL clock only if UltraATA/133 mode is 10658c2ecf20Sopenharmony_ci * supported/enabled, use 50 MHz DPLL clock otherwise... 10668c2ecf20Sopenharmony_ci */ 10678c2ecf20Sopenharmony_ci if (info->udma_mask == ATA_UDMA6) { 10688c2ecf20Sopenharmony_ci dpll_clk = 66; 10698c2ecf20Sopenharmony_ci clock = ATA_CLOCK_66MHZ; 10708c2ecf20Sopenharmony_ci } else if (dpll_clk) { /* HPT36x chips don't have DPLL */ 10718c2ecf20Sopenharmony_ci dpll_clk = 50; 10728c2ecf20Sopenharmony_ci clock = ATA_CLOCK_50MHZ; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci if (info->timings->clock_table[clock] == NULL) { 10768c2ecf20Sopenharmony_ci printk(KERN_ERR "%s %s: unknown bus timing!\n", 10778c2ecf20Sopenharmony_ci name, pci_name(dev)); 10788c2ecf20Sopenharmony_ci return -EIO; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* Select the DPLL clock. */ 10828c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x5b, 0x21); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci /* 10858c2ecf20Sopenharmony_ci * Adjust the DPLL based upon PCI clock, enable it, 10868c2ecf20Sopenharmony_ci * and wait for stabilization... 10878c2ecf20Sopenharmony_ci */ 10888c2ecf20Sopenharmony_ci f_low = (pci_clk * 48) / dpll_clk; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci for (adjust = 0; adjust < 8; adjust++) { 10918c2ecf20Sopenharmony_ci if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta)) 10928c2ecf20Sopenharmony_ci break; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci /* 10958c2ecf20Sopenharmony_ci * See if it'll settle at a fractionally different clock 10968c2ecf20Sopenharmony_ci */ 10978c2ecf20Sopenharmony_ci if (adjust & 1) 10988c2ecf20Sopenharmony_ci f_low -= adjust >> 1; 10998c2ecf20Sopenharmony_ci else 11008c2ecf20Sopenharmony_ci f_low += adjust >> 1; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci if (adjust == 8) { 11038c2ecf20Sopenharmony_ci printk(KERN_ERR "%s %s: DPLL did not stabilize!\n", 11048c2ecf20Sopenharmony_ci name, pci_name(dev)); 11058c2ecf20Sopenharmony_ci return -EIO; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci printk(KERN_INFO "%s %s: using %d MHz DPLL clock\n", 11098c2ecf20Sopenharmony_ci name, pci_name(dev), dpll_clk); 11108c2ecf20Sopenharmony_ci } else { 11118c2ecf20Sopenharmony_ci /* Mark the fact that we're not using the DPLL. */ 11128c2ecf20Sopenharmony_ci dpll_clk = 0; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci printk(KERN_INFO "%s %s: using %d MHz PCI clock\n", 11158c2ecf20Sopenharmony_ci name, pci_name(dev), pci_clk); 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci /* Store the clock frequencies. */ 11198c2ecf20Sopenharmony_ci info->dpll_clk = dpll_clk; 11208c2ecf20Sopenharmony_ci info->pci_clk = pci_clk; 11218c2ecf20Sopenharmony_ci info->clock = clock; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci if (chip_type >= HPT370) { 11248c2ecf20Sopenharmony_ci u8 mcr1, mcr4; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci /* 11278c2ecf20Sopenharmony_ci * Reset the state engines. 11288c2ecf20Sopenharmony_ci * NOTE: Avoid accidentally enabling the disabled channels. 11298c2ecf20Sopenharmony_ci */ 11308c2ecf20Sopenharmony_ci pci_read_config_byte (dev, 0x50, &mcr1); 11318c2ecf20Sopenharmony_ci pci_read_config_byte (dev, 0x54, &mcr4); 11328c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x50, (mcr1 | 0x32)); 11338c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x54, (mcr4 | 0x32)); 11348c2ecf20Sopenharmony_ci udelay(100); 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci /* 11388c2ecf20Sopenharmony_ci * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in 11398c2ecf20Sopenharmony_ci * the MISC. register to stretch the UltraDMA Tss timing. 11408c2ecf20Sopenharmony_ci * NOTE: This register is only writeable via I/O space. 11418c2ecf20Sopenharmony_ci */ 11428c2ecf20Sopenharmony_ci if (chip_type == HPT371N && clock == ATA_CLOCK_66MHZ) 11438c2ecf20Sopenharmony_ci outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci hpt3xx_disable_fast_irq(dev, 0x50); 11468c2ecf20Sopenharmony_ci hpt3xx_disable_fast_irq(dev, 0x54); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci return 0; 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic u8 hpt3xx_cable_detect(ide_hwif_t *hwif) 11528c2ecf20Sopenharmony_ci{ 11538c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 11548c2ecf20Sopenharmony_ci struct hpt_info *info = hpt3xx_get_info(hwif->dev); 11558c2ecf20Sopenharmony_ci u8 chip_type = info->chip_type; 11568c2ecf20Sopenharmony_ci u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci /* 11598c2ecf20Sopenharmony_ci * The HPT37x uses the CBLID pins as outputs for MA15/MA16 11608c2ecf20Sopenharmony_ci * address lines to access an external EEPROM. To read valid 11618c2ecf20Sopenharmony_ci * cable detect state the pins must be enabled as inputs. 11628c2ecf20Sopenharmony_ci */ 11638c2ecf20Sopenharmony_ci if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) { 11648c2ecf20Sopenharmony_ci /* 11658c2ecf20Sopenharmony_ci * HPT374 PCI function 1 11668c2ecf20Sopenharmony_ci * - set bit 15 of reg 0x52 to enable TCBLID as input 11678c2ecf20Sopenharmony_ci * - set bit 15 of reg 0x56 to enable FCBLID as input 11688c2ecf20Sopenharmony_ci */ 11698c2ecf20Sopenharmony_ci u8 mcr_addr = hwif->select_data + 2; 11708c2ecf20Sopenharmony_ci u16 mcr; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci pci_read_config_word(dev, mcr_addr, &mcr); 11738c2ecf20Sopenharmony_ci pci_write_config_word(dev, mcr_addr, mcr | 0x8000); 11748c2ecf20Sopenharmony_ci /* Debounce, then read cable ID register */ 11758c2ecf20Sopenharmony_ci udelay(10); 11768c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x5a, &scr1); 11778c2ecf20Sopenharmony_ci pci_write_config_word(dev, mcr_addr, mcr); 11788c2ecf20Sopenharmony_ci } else if (chip_type >= HPT370) { 11798c2ecf20Sopenharmony_ci /* 11808c2ecf20Sopenharmony_ci * HPT370/372 and 374 pcifn 0 11818c2ecf20Sopenharmony_ci * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs 11828c2ecf20Sopenharmony_ci */ 11838c2ecf20Sopenharmony_ci u8 scr2 = 0; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x5b, &scr2); 11868c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x5b, scr2 & ~1); 11878c2ecf20Sopenharmony_ci /* Debounce, then read cable ID register */ 11888c2ecf20Sopenharmony_ci udelay(10); 11898c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x5a, &scr1); 11908c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x5b, scr2); 11918c2ecf20Sopenharmony_ci } else 11928c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x5a, &scr1); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci return (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; 11958c2ecf20Sopenharmony_ci} 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_cistatic void init_hwif_hpt366(ide_hwif_t *hwif) 11988c2ecf20Sopenharmony_ci{ 11998c2ecf20Sopenharmony_ci struct hpt_info *info = hpt3xx_get_info(hwif->dev); 12008c2ecf20Sopenharmony_ci u8 chip_type = info->chip_type; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci /* Cache the channel's MISC. control registers' offset */ 12038c2ecf20Sopenharmony_ci hwif->select_data = hwif->channel ? 0x54 : 0x50; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci /* 12068c2ecf20Sopenharmony_ci * HPT3xxN chips have some complications: 12078c2ecf20Sopenharmony_ci * 12088c2ecf20Sopenharmony_ci * - on 33 MHz PCI we must clock switch 12098c2ecf20Sopenharmony_ci * - on 66 MHz PCI we must NOT use the PCI clock 12108c2ecf20Sopenharmony_ci */ 12118c2ecf20Sopenharmony_ci if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) { 12128c2ecf20Sopenharmony_ci /* 12138c2ecf20Sopenharmony_ci * Clock is shared between the channels, 12148c2ecf20Sopenharmony_ci * so we'll have to serialize them... :-( 12158c2ecf20Sopenharmony_ci */ 12168c2ecf20Sopenharmony_ci hwif->host->host_flags |= IDE_HFLAG_SERIALIZE; 12178c2ecf20Sopenharmony_ci hwif->rw_disk = &hpt3xxn_rw_disk; 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_cistatic int init_dma_hpt366(ide_hwif_t *hwif, 12228c2ecf20Sopenharmony_ci const struct ide_port_info *d) 12238c2ecf20Sopenharmony_ci{ 12248c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 12258c2ecf20Sopenharmony_ci unsigned long flags, base = ide_pci_dma_base(hwif, d); 12268c2ecf20Sopenharmony_ci u8 dma_old, dma_new, masterdma = 0, slavedma = 0; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci if (base == 0) 12298c2ecf20Sopenharmony_ci return -1; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci hwif->dma_base = base; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci if (ide_pci_check_simplex(hwif, d) < 0) 12348c2ecf20Sopenharmony_ci return -1; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci if (ide_pci_set_master(dev, d->name) < 0) 12378c2ecf20Sopenharmony_ci return -1; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci dma_old = inb(base + 2); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci local_irq_save(flags); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci dma_new = dma_old; 12448c2ecf20Sopenharmony_ci pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma); 12458c2ecf20Sopenharmony_ci pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47, &slavedma); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci if (masterdma & 0x30) dma_new |= 0x20; 12488c2ecf20Sopenharmony_ci if ( slavedma & 0x30) dma_new |= 0x40; 12498c2ecf20Sopenharmony_ci if (dma_new != dma_old) 12508c2ecf20Sopenharmony_ci outb(dma_new, base + 2); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci local_irq_restore(flags); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n", 12558c2ecf20Sopenharmony_ci hwif->name, base, base + 7); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci hwif->extra_base = base + (hwif->channel ? 8 : 16); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if (ide_allocate_dma_engine(hwif)) 12608c2ecf20Sopenharmony_ci return -1; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci return 0; 12638c2ecf20Sopenharmony_ci} 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_cistatic void hpt374_init(struct pci_dev *dev, struct pci_dev *dev2) 12668c2ecf20Sopenharmony_ci{ 12678c2ecf20Sopenharmony_ci if (dev2->irq != dev->irq) { 12688c2ecf20Sopenharmony_ci /* FIXME: we need a core pci_set_interrupt() */ 12698c2ecf20Sopenharmony_ci dev2->irq = dev->irq; 12708c2ecf20Sopenharmony_ci printk(KERN_INFO DRV_NAME " %s: PCI config space interrupt " 12718c2ecf20Sopenharmony_ci "fixed\n", pci_name(dev2)); 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci} 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_cistatic void hpt371_init(struct pci_dev *dev) 12768c2ecf20Sopenharmony_ci{ 12778c2ecf20Sopenharmony_ci u8 mcr1 = 0; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci /* 12808c2ecf20Sopenharmony_ci * HPT371 chips physically have only one channel, the secondary one, 12818c2ecf20Sopenharmony_ci * but the primary channel registers do exist! Go figure... 12828c2ecf20Sopenharmony_ci * So, we manually disable the non-existing channel here 12838c2ecf20Sopenharmony_ci * (if the BIOS hasn't done this already). 12848c2ecf20Sopenharmony_ci */ 12858c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x50, &mcr1); 12868c2ecf20Sopenharmony_ci if (mcr1 & 0x04) 12878c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x50, mcr1 & ~0x04); 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_cistatic int hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2) 12918c2ecf20Sopenharmony_ci{ 12928c2ecf20Sopenharmony_ci u8 mcr1 = 0, pin1 = 0, pin2 = 0; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci /* 12958c2ecf20Sopenharmony_ci * Now we'll have to force both channels enabled if 12968c2ecf20Sopenharmony_ci * at least one of them has been enabled by BIOS... 12978c2ecf20Sopenharmony_ci */ 12988c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x50, &mcr1); 12998c2ecf20Sopenharmony_ci if (mcr1 & 0x30) 13008c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x50, mcr1 | 0x30); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); 13038c2ecf20Sopenharmony_ci pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci if (pin1 != pin2 && dev->irq == dev2->irq) { 13068c2ecf20Sopenharmony_ci printk(KERN_INFO DRV_NAME " %s: onboard version of chipset, " 13078c2ecf20Sopenharmony_ci "pin1=%d pin2=%d\n", pci_name(dev), pin1, pin2); 13088c2ecf20Sopenharmony_ci return 1; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci return 0; 13128c2ecf20Sopenharmony_ci} 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci#define IDE_HFLAGS_HPT3XX \ 13158c2ecf20Sopenharmony_ci (IDE_HFLAG_NO_ATAPI_DMA | \ 13168c2ecf20Sopenharmony_ci IDE_HFLAG_OFF_BOARD) 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_cistatic const struct ide_port_ops hpt3xx_port_ops = { 13198c2ecf20Sopenharmony_ci .set_pio_mode = hpt3xx_set_pio_mode, 13208c2ecf20Sopenharmony_ci .set_dma_mode = hpt3xx_set_mode, 13218c2ecf20Sopenharmony_ci .maskproc = hpt3xx_maskproc, 13228c2ecf20Sopenharmony_ci .mdma_filter = hpt3xx_mdma_filter, 13238c2ecf20Sopenharmony_ci .udma_filter = hpt3xx_udma_filter, 13248c2ecf20Sopenharmony_ci .cable_detect = hpt3xx_cable_detect, 13258c2ecf20Sopenharmony_ci}; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_cistatic const struct ide_dma_ops hpt37x_dma_ops = { 13288c2ecf20Sopenharmony_ci .dma_host_set = ide_dma_host_set, 13298c2ecf20Sopenharmony_ci .dma_setup = ide_dma_setup, 13308c2ecf20Sopenharmony_ci .dma_start = ide_dma_start, 13318c2ecf20Sopenharmony_ci .dma_end = hpt374_dma_end, 13328c2ecf20Sopenharmony_ci .dma_test_irq = hpt374_dma_test_irq, 13338c2ecf20Sopenharmony_ci .dma_lost_irq = ide_dma_lost_irq, 13348c2ecf20Sopenharmony_ci .dma_timer_expiry = ide_dma_sff_timer_expiry, 13358c2ecf20Sopenharmony_ci .dma_sff_read_status = ide_dma_sff_read_status, 13368c2ecf20Sopenharmony_ci}; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_cistatic const struct ide_dma_ops hpt370_dma_ops = { 13398c2ecf20Sopenharmony_ci .dma_host_set = ide_dma_host_set, 13408c2ecf20Sopenharmony_ci .dma_setup = ide_dma_setup, 13418c2ecf20Sopenharmony_ci .dma_start = hpt370_dma_start, 13428c2ecf20Sopenharmony_ci .dma_end = hpt370_dma_end, 13438c2ecf20Sopenharmony_ci .dma_test_irq = ide_dma_test_irq, 13448c2ecf20Sopenharmony_ci .dma_lost_irq = ide_dma_lost_irq, 13458c2ecf20Sopenharmony_ci .dma_timer_expiry = ide_dma_sff_timer_expiry, 13468c2ecf20Sopenharmony_ci .dma_clear = hpt370_irq_timeout, 13478c2ecf20Sopenharmony_ci .dma_sff_read_status = ide_dma_sff_read_status, 13488c2ecf20Sopenharmony_ci}; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_cistatic const struct ide_dma_ops hpt36x_dma_ops = { 13518c2ecf20Sopenharmony_ci .dma_host_set = ide_dma_host_set, 13528c2ecf20Sopenharmony_ci .dma_setup = ide_dma_setup, 13538c2ecf20Sopenharmony_ci .dma_start = ide_dma_start, 13548c2ecf20Sopenharmony_ci .dma_end = ide_dma_end, 13558c2ecf20Sopenharmony_ci .dma_test_irq = ide_dma_test_irq, 13568c2ecf20Sopenharmony_ci .dma_lost_irq = hpt366_dma_lost_irq, 13578c2ecf20Sopenharmony_ci .dma_timer_expiry = ide_dma_sff_timer_expiry, 13588c2ecf20Sopenharmony_ci .dma_sff_read_status = ide_dma_sff_read_status, 13598c2ecf20Sopenharmony_ci}; 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_cistatic const struct ide_port_info hpt366_chipsets[] = { 13628c2ecf20Sopenharmony_ci { /* 0: HPT36x */ 13638c2ecf20Sopenharmony_ci .name = DRV_NAME, 13648c2ecf20Sopenharmony_ci .init_chipset = init_chipset_hpt366, 13658c2ecf20Sopenharmony_ci .init_hwif = init_hwif_hpt366, 13668c2ecf20Sopenharmony_ci .init_dma = init_dma_hpt366, 13678c2ecf20Sopenharmony_ci /* 13688c2ecf20Sopenharmony_ci * HPT36x chips have one channel per function and have 13698c2ecf20Sopenharmony_ci * both channel enable bits located differently and visible 13708c2ecf20Sopenharmony_ci * to both functions -- really stupid design decision... :-( 13718c2ecf20Sopenharmony_ci * Bit 4 is for the primary channel, bit 5 for the secondary. 13728c2ecf20Sopenharmony_ci */ 13738c2ecf20Sopenharmony_ci .enablebits = {{0x50,0x10,0x10}, {0x54,0x04,0x04}}, 13748c2ecf20Sopenharmony_ci .port_ops = &hpt3xx_port_ops, 13758c2ecf20Sopenharmony_ci .dma_ops = &hpt36x_dma_ops, 13768c2ecf20Sopenharmony_ci .host_flags = IDE_HFLAGS_HPT3XX | IDE_HFLAG_SINGLE, 13778c2ecf20Sopenharmony_ci .pio_mask = ATA_PIO4, 13788c2ecf20Sopenharmony_ci .mwdma_mask = ATA_MWDMA2, 13798c2ecf20Sopenharmony_ci }, 13808c2ecf20Sopenharmony_ci { /* 1: HPT3xx */ 13818c2ecf20Sopenharmony_ci .name = DRV_NAME, 13828c2ecf20Sopenharmony_ci .init_chipset = init_chipset_hpt366, 13838c2ecf20Sopenharmony_ci .init_hwif = init_hwif_hpt366, 13848c2ecf20Sopenharmony_ci .init_dma = init_dma_hpt366, 13858c2ecf20Sopenharmony_ci .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, 13868c2ecf20Sopenharmony_ci .port_ops = &hpt3xx_port_ops, 13878c2ecf20Sopenharmony_ci .dma_ops = &hpt37x_dma_ops, 13888c2ecf20Sopenharmony_ci .host_flags = IDE_HFLAGS_HPT3XX, 13898c2ecf20Sopenharmony_ci .pio_mask = ATA_PIO4, 13908c2ecf20Sopenharmony_ci .mwdma_mask = ATA_MWDMA2, 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci}; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci/** 13958c2ecf20Sopenharmony_ci * hpt366_init_one - called when an HPT366 is found 13968c2ecf20Sopenharmony_ci * @dev: the hpt366 device 13978c2ecf20Sopenharmony_ci * @id: the matching pci id 13988c2ecf20Sopenharmony_ci * 13998c2ecf20Sopenharmony_ci * Called when the PCI registration layer (or the IDE initialization) 14008c2ecf20Sopenharmony_ci * finds a device matching our IDE device tables. 14018c2ecf20Sopenharmony_ci */ 14028c2ecf20Sopenharmony_cistatic int hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id) 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci const struct hpt_info *info = NULL; 14058c2ecf20Sopenharmony_ci struct hpt_info *dyn_info; 14068c2ecf20Sopenharmony_ci struct pci_dev *dev2 = NULL; 14078c2ecf20Sopenharmony_ci struct ide_port_info d; 14088c2ecf20Sopenharmony_ci u8 idx = id->driver_data; 14098c2ecf20Sopenharmony_ci u8 rev = dev->revision; 14108c2ecf20Sopenharmony_ci int ret; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci if ((idx == 0 || idx == 4) && (PCI_FUNC(dev->devfn) & 1)) 14138c2ecf20Sopenharmony_ci return -ENODEV; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci switch (idx) { 14168c2ecf20Sopenharmony_ci case 0: 14178c2ecf20Sopenharmony_ci if (rev < 3) 14188c2ecf20Sopenharmony_ci info = &hpt36x; 14198c2ecf20Sopenharmony_ci else { 14208c2ecf20Sopenharmony_ci switch (min_t(u8, rev, 6)) { 14218c2ecf20Sopenharmony_ci case 3: info = &hpt370; break; 14228c2ecf20Sopenharmony_ci case 4: info = &hpt370a; break; 14238c2ecf20Sopenharmony_ci case 5: info = &hpt372; break; 14248c2ecf20Sopenharmony_ci case 6: info = &hpt372n; break; 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci idx++; 14278c2ecf20Sopenharmony_ci } 14288c2ecf20Sopenharmony_ci break; 14298c2ecf20Sopenharmony_ci case 1: 14308c2ecf20Sopenharmony_ci info = (rev > 1) ? &hpt372n : &hpt372a; 14318c2ecf20Sopenharmony_ci break; 14328c2ecf20Sopenharmony_ci case 2: 14338c2ecf20Sopenharmony_ci info = (rev > 1) ? &hpt302n : &hpt302; 14348c2ecf20Sopenharmony_ci break; 14358c2ecf20Sopenharmony_ci case 3: 14368c2ecf20Sopenharmony_ci hpt371_init(dev); 14378c2ecf20Sopenharmony_ci info = (rev > 1) ? &hpt371n : &hpt371; 14388c2ecf20Sopenharmony_ci break; 14398c2ecf20Sopenharmony_ci case 4: 14408c2ecf20Sopenharmony_ci info = &hpt374; 14418c2ecf20Sopenharmony_ci break; 14428c2ecf20Sopenharmony_ci case 5: 14438c2ecf20Sopenharmony_ci info = &hpt372n; 14448c2ecf20Sopenharmony_ci break; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci printk(KERN_INFO DRV_NAME ": %s chipset detected\n", info->chip_name); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci d = hpt366_chipsets[min_t(u8, idx, 1)]; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci d.udma_mask = info->udma_mask; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci /* fixup ->dma_ops for HPT370/HPT370A */ 14548c2ecf20Sopenharmony_ci if (info == &hpt370 || info == &hpt370a) 14558c2ecf20Sopenharmony_ci d.dma_ops = &hpt370_dma_ops; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci if (info == &hpt36x || info == &hpt374) 14588c2ecf20Sopenharmony_ci dev2 = pci_get_slot(dev->bus, dev->devfn + 1); 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci dyn_info = kcalloc(dev2 ? 2 : 1, sizeof(*dyn_info), GFP_KERNEL); 14618c2ecf20Sopenharmony_ci if (dyn_info == NULL) { 14628c2ecf20Sopenharmony_ci printk(KERN_ERR "%s %s: out of memory!\n", 14638c2ecf20Sopenharmony_ci d.name, pci_name(dev)); 14648c2ecf20Sopenharmony_ci pci_dev_put(dev2); 14658c2ecf20Sopenharmony_ci return -ENOMEM; 14668c2ecf20Sopenharmony_ci } 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci /* 14698c2ecf20Sopenharmony_ci * Copy everything from a static "template" structure 14708c2ecf20Sopenharmony_ci * to just allocated per-chip hpt_info structure. 14718c2ecf20Sopenharmony_ci */ 14728c2ecf20Sopenharmony_ci memcpy(dyn_info, info, sizeof(*dyn_info)); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci if (dev2) { 14758c2ecf20Sopenharmony_ci memcpy(dyn_info + 1, info, sizeof(*dyn_info)); 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci if (info == &hpt374) 14788c2ecf20Sopenharmony_ci hpt374_init(dev, dev2); 14798c2ecf20Sopenharmony_ci else { 14808c2ecf20Sopenharmony_ci if (hpt36x_init(dev, dev2)) 14818c2ecf20Sopenharmony_ci d.host_flags &= ~IDE_HFLAG_NON_BOOTABLE; 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci ret = ide_pci_init_two(dev, dev2, &d, dyn_info); 14858c2ecf20Sopenharmony_ci if (ret < 0) { 14868c2ecf20Sopenharmony_ci pci_dev_put(dev2); 14878c2ecf20Sopenharmony_ci kfree(dyn_info); 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci return ret; 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci ret = ide_pci_init_one(dev, &d, dyn_info); 14938c2ecf20Sopenharmony_ci if (ret < 0) 14948c2ecf20Sopenharmony_ci kfree(dyn_info); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci return ret; 14978c2ecf20Sopenharmony_ci} 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_cistatic void hpt366_remove(struct pci_dev *dev) 15008c2ecf20Sopenharmony_ci{ 15018c2ecf20Sopenharmony_ci struct ide_host *host = pci_get_drvdata(dev); 15028c2ecf20Sopenharmony_ci struct ide_info *info = host->host_priv; 15038c2ecf20Sopenharmony_ci struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci ide_pci_remove(dev); 15068c2ecf20Sopenharmony_ci pci_dev_put(dev2); 15078c2ecf20Sopenharmony_ci kfree(info); 15088c2ecf20Sopenharmony_ci} 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_cistatic const struct pci_device_id hpt366_pci_tbl[] = { 15118c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), 0 }, 15128c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), 1 }, 15138c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), 2 }, 15148c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), 3 }, 15158c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT374), 4 }, 15168c2ecf20Sopenharmony_ci { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), 5 }, 15178c2ecf20Sopenharmony_ci { 0, }, 15188c2ecf20Sopenharmony_ci}; 15198c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hpt366_pci_tbl); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_cistatic struct pci_driver hpt366_pci_driver = { 15228c2ecf20Sopenharmony_ci .name = "HPT366_IDE", 15238c2ecf20Sopenharmony_ci .id_table = hpt366_pci_tbl, 15248c2ecf20Sopenharmony_ci .probe = hpt366_init_one, 15258c2ecf20Sopenharmony_ci .remove = hpt366_remove, 15268c2ecf20Sopenharmony_ci .suspend = ide_pci_suspend, 15278c2ecf20Sopenharmony_ci .resume = ide_pci_resume, 15288c2ecf20Sopenharmony_ci}; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_cistatic int __init hpt366_ide_init(void) 15318c2ecf20Sopenharmony_ci{ 15328c2ecf20Sopenharmony_ci return ide_pci_register_driver(&hpt366_pci_driver); 15338c2ecf20Sopenharmony_ci} 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_cistatic void __exit hpt366_ide_exit(void) 15368c2ecf20Sopenharmony_ci{ 15378c2ecf20Sopenharmony_ci pci_unregister_driver(&hpt366_pci_driver); 15388c2ecf20Sopenharmony_ci} 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_cimodule_init(hpt366_ide_init); 15418c2ecf20Sopenharmony_cimodule_exit(hpt366_ide_exit); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andre Hedrick"); 15448c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE"); 15458c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1546