18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Promise TX2/TX4/TX2000/133 IDE driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Split from: 68c2ecf20Sopenharmony_ci * linux/drivers/ide/pdc202xx.c Version 0.35 Mar. 30, 2002 78c2ecf20Sopenharmony_ci * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org> 88c2ecf20Sopenharmony_ci * Copyright (C) 2005-2007 MontaVista Software, Inc. 98c2ecf20Sopenharmony_ci * Portions Copyright (C) 1999 Promise Technology, Inc. 108c2ecf20Sopenharmony_ci * Author: Frank Tiernan (frankt@promise.com) 118c2ecf20Sopenharmony_ci * Released under terms of General Public License 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/types.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/pci.h> 198c2ecf20Sopenharmony_ci#include <linux/init.h> 208c2ecf20Sopenharmony_ci#include <linux/ide.h> 218c2ecf20Sopenharmony_ci#include <linux/ktime.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <asm/io.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 268c2ecf20Sopenharmony_ci#include <asm/prom.h> 278c2ecf20Sopenharmony_ci#endif 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define DRV_NAME "pdc202xx_new" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#undef DEBUG 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#ifdef DEBUG 348c2ecf20Sopenharmony_ci#define DBG(fmt, args...) printk("%s: " fmt, __func__, ## args) 358c2ecf20Sopenharmony_ci#else 368c2ecf20Sopenharmony_ci#define DBG(fmt, args...) 378c2ecf20Sopenharmony_ci#endif 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic u8 max_dma_rate(struct pci_dev *pdev) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci u8 mode; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci switch(pdev->device) { 448c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_PROMISE_20277: 458c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_PROMISE_20276: 468c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_PROMISE_20275: 478c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_PROMISE_20271: 488c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_PROMISE_20269: 498c2ecf20Sopenharmony_ci mode = 4; 508c2ecf20Sopenharmony_ci break; 518c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_PROMISE_20270: 528c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_PROMISE_20268: 538c2ecf20Sopenharmony_ci mode = 3; 548c2ecf20Sopenharmony_ci break; 558c2ecf20Sopenharmony_ci default: 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return mode; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/** 638c2ecf20Sopenharmony_ci * get_indexed_reg - Get indexed register 648c2ecf20Sopenharmony_ci * @hwif: for the port address 658c2ecf20Sopenharmony_ci * @index: index of the indexed register 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistatic u8 get_indexed_reg(ide_hwif_t *hwif, u8 index) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci u8 value; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci outb(index, hwif->dma_base + 1); 728c2ecf20Sopenharmony_ci value = inb(hwif->dma_base + 3); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci DBG("index[%02X] value[%02X]\n", index, value); 758c2ecf20Sopenharmony_ci return value; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/** 798c2ecf20Sopenharmony_ci * set_indexed_reg - Set indexed register 808c2ecf20Sopenharmony_ci * @hwif: for the port address 818c2ecf20Sopenharmony_ci * @index: index of the indexed register 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_cistatic void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci outb(index, hwif->dma_base + 1); 868c2ecf20Sopenharmony_ci outb(value, hwif->dma_base + 3); 878c2ecf20Sopenharmony_ci DBG("index[%02X] value[%02X]\n", index, value); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* 918c2ecf20Sopenharmony_ci * ATA Timing Tables based on 133 MHz PLL output clock. 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * If the PLL outputs 100 MHz clock, the ASIC hardware will set 948c2ecf20Sopenharmony_ci * the timing registers automatically when "set features" command is 958c2ecf20Sopenharmony_ci * issued to the device. However, if the PLL output clock is 133 MHz, 968c2ecf20Sopenharmony_ci * the following tables must be used. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_cistatic struct pio_timing { 998c2ecf20Sopenharmony_ci u8 reg0c, reg0d, reg13; 1008c2ecf20Sopenharmony_ci} pio_timings [] = { 1018c2ecf20Sopenharmony_ci { 0xfb, 0x2b, 0xac }, /* PIO mode 0, IORDY off, Prefetch off */ 1028c2ecf20Sopenharmony_ci { 0x46, 0x29, 0xa4 }, /* PIO mode 1, IORDY off, Prefetch off */ 1038c2ecf20Sopenharmony_ci { 0x23, 0x26, 0x64 }, /* PIO mode 2, IORDY off, Prefetch off */ 1048c2ecf20Sopenharmony_ci { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */ 1058c2ecf20Sopenharmony_ci { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */ 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic struct mwdma_timing { 1098c2ecf20Sopenharmony_ci u8 reg0e, reg0f; 1108c2ecf20Sopenharmony_ci} mwdma_timings [] = { 1118c2ecf20Sopenharmony_ci { 0xdf, 0x5f }, /* MWDMA mode 0 */ 1128c2ecf20Sopenharmony_ci { 0x6b, 0x27 }, /* MWDMA mode 1 */ 1138c2ecf20Sopenharmony_ci { 0x69, 0x25 }, /* MWDMA mode 2 */ 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic struct udma_timing { 1178c2ecf20Sopenharmony_ci u8 reg10, reg11, reg12; 1188c2ecf20Sopenharmony_ci} udma_timings [] = { 1198c2ecf20Sopenharmony_ci { 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */ 1208c2ecf20Sopenharmony_ci { 0x3a, 0x0a, 0xd0 }, /* UDMA mode 1 */ 1218c2ecf20Sopenharmony_ci { 0x2a, 0x07, 0xcd }, /* UDMA mode 2 */ 1228c2ecf20Sopenharmony_ci { 0x1a, 0x05, 0xcd }, /* UDMA mode 3 */ 1238c2ecf20Sopenharmony_ci { 0x1a, 0x03, 0xcd }, /* UDMA mode 4 */ 1248c2ecf20Sopenharmony_ci { 0x1a, 0x02, 0xcb }, /* UDMA mode 5 */ 1258c2ecf20Sopenharmony_ci { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */ 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic void pdcnew_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 1318c2ecf20Sopenharmony_ci u8 adj = (drive->dn & 1) ? 0x08 : 0x00; 1328c2ecf20Sopenharmony_ci const u8 speed = drive->dma_mode; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* 1358c2ecf20Sopenharmony_ci * IDE core issues SETFEATURES_XFER to the drive first (thanks to 1368c2ecf20Sopenharmony_ci * IDE_HFLAG_POST_SET_MODE in ->host_flags). PDC202xx hardware will 1378c2ecf20Sopenharmony_ci * automatically set the timing registers based on 100 MHz PLL output. 1388c2ecf20Sopenharmony_ci * 1398c2ecf20Sopenharmony_ci * As we set up the PLL to output 133 MHz for UltraDMA/133 capable 1408c2ecf20Sopenharmony_ci * chips, we must override the default register settings... 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci if (max_dma_rate(dev) == 4) { 1438c2ecf20Sopenharmony_ci u8 mode = speed & 0x07; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (speed >= XFER_UDMA_0) { 1468c2ecf20Sopenharmony_ci set_indexed_reg(hwif, 0x10 + adj, 1478c2ecf20Sopenharmony_ci udma_timings[mode].reg10); 1488c2ecf20Sopenharmony_ci set_indexed_reg(hwif, 0x11 + adj, 1498c2ecf20Sopenharmony_ci udma_timings[mode].reg11); 1508c2ecf20Sopenharmony_ci set_indexed_reg(hwif, 0x12 + adj, 1518c2ecf20Sopenharmony_ci udma_timings[mode].reg12); 1528c2ecf20Sopenharmony_ci } else { 1538c2ecf20Sopenharmony_ci set_indexed_reg(hwif, 0x0e + adj, 1548c2ecf20Sopenharmony_ci mwdma_timings[mode].reg0e); 1558c2ecf20Sopenharmony_ci set_indexed_reg(hwif, 0x0f + adj, 1568c2ecf20Sopenharmony_ci mwdma_timings[mode].reg0f); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci } else if (speed == XFER_UDMA_2) { 1598c2ecf20Sopenharmony_ci /* Set tHOLD bit to 0 if using UDMA mode 2 */ 1608c2ecf20Sopenharmony_ci u8 tmp = get_indexed_reg(hwif, 0x10 + adj); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci set_indexed_reg(hwif, 0x10 + adj, tmp & 0x7f); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void pdcnew_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 1698c2ecf20Sopenharmony_ci u8 adj = (drive->dn & 1) ? 0x08 : 0x00; 1708c2ecf20Sopenharmony_ci const u8 pio = drive->pio_mode - XFER_PIO_0; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (max_dma_rate(dev) == 4) { 1738c2ecf20Sopenharmony_ci set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c); 1748c2ecf20Sopenharmony_ci set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d); 1758c2ecf20Sopenharmony_ci set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13); 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic u8 pdcnew_cable_detect(ide_hwif_t *hwif) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci if (get_indexed_reg(hwif, 0x0b) & 0x04) 1828c2ecf20Sopenharmony_ci return ATA_CBL_PATA40; 1838c2ecf20Sopenharmony_ci else 1848c2ecf20Sopenharmony_ci return ATA_CBL_PATA80; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic void pdcnew_reset(ide_drive_t *drive) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci /* 1908c2ecf20Sopenharmony_ci * Deleted this because it is redundant from the caller. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci printk(KERN_WARNING "pdc202xx_new: %s channel reset.\n", 1938c2ecf20Sopenharmony_ci drive->hwif->channel ? "Secondary" : "Primary"); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/** 1978c2ecf20Sopenharmony_ci * read_counter - Read the byte count registers 1988c2ecf20Sopenharmony_ci * @dma_base: for the port address 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_cistatic long read_counter(u32 dma_base) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci u32 pri_dma_base = dma_base, sec_dma_base = dma_base + 0x08; 2038c2ecf20Sopenharmony_ci u8 cnt0, cnt1, cnt2, cnt3; 2048c2ecf20Sopenharmony_ci long count = 0, last; 2058c2ecf20Sopenharmony_ci int retry = 3; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci do { 2088c2ecf20Sopenharmony_ci last = count; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* Read the current count */ 2118c2ecf20Sopenharmony_ci outb(0x20, pri_dma_base + 0x01); 2128c2ecf20Sopenharmony_ci cnt0 = inb(pri_dma_base + 0x03); 2138c2ecf20Sopenharmony_ci outb(0x21, pri_dma_base + 0x01); 2148c2ecf20Sopenharmony_ci cnt1 = inb(pri_dma_base + 0x03); 2158c2ecf20Sopenharmony_ci outb(0x20, sec_dma_base + 0x01); 2168c2ecf20Sopenharmony_ci cnt2 = inb(sec_dma_base + 0x03); 2178c2ecf20Sopenharmony_ci outb(0x21, sec_dma_base + 0x01); 2188c2ecf20Sopenharmony_ci cnt3 = inb(sec_dma_base + 0x03); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci count = (cnt3 << 23) | (cnt2 << 15) | (cnt1 << 8) | cnt0; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* 2238c2ecf20Sopenharmony_ci * The 30-bit decrementing counter is read in 4 pieces. 2248c2ecf20Sopenharmony_ci * Incorrect value may be read when the most significant bytes 2258c2ecf20Sopenharmony_ci * are changing... 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_ci } while (retry-- && (((last ^ count) & 0x3fff8000) || last < count)); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci DBG("cnt0[%02X] cnt1[%02X] cnt2[%02X] cnt3[%02X]\n", 2308c2ecf20Sopenharmony_ci cnt0, cnt1, cnt2, cnt3); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return count; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/** 2368c2ecf20Sopenharmony_ci * detect_pll_input_clock - Detect the PLL input clock in Hz. 2378c2ecf20Sopenharmony_ci * @dma_base: for the port address 2388c2ecf20Sopenharmony_ci * E.g. 16949000 on 33 MHz PCI bus, i.e. half of the PCI clock. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_cistatic long detect_pll_input_clock(unsigned long dma_base) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci ktime_t start_time, end_time; 2438c2ecf20Sopenharmony_ci long start_count, end_count; 2448c2ecf20Sopenharmony_ci long pll_input, usec_elapsed; 2458c2ecf20Sopenharmony_ci u8 scr1; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci start_count = read_counter(dma_base); 2488c2ecf20Sopenharmony_ci start_time = ktime_get(); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* Start the test mode */ 2518c2ecf20Sopenharmony_ci outb(0x01, dma_base + 0x01); 2528c2ecf20Sopenharmony_ci scr1 = inb(dma_base + 0x03); 2538c2ecf20Sopenharmony_ci DBG("scr1[%02X]\n", scr1); 2548c2ecf20Sopenharmony_ci outb(scr1 | 0x40, dma_base + 0x03); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* Let the counter run for 10 ms. */ 2578c2ecf20Sopenharmony_ci mdelay(10); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci end_count = read_counter(dma_base); 2608c2ecf20Sopenharmony_ci end_time = ktime_get(); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Stop the test mode */ 2638c2ecf20Sopenharmony_ci outb(0x01, dma_base + 0x01); 2648c2ecf20Sopenharmony_ci scr1 = inb(dma_base + 0x03); 2658c2ecf20Sopenharmony_ci DBG("scr1[%02X]\n", scr1); 2668c2ecf20Sopenharmony_ci outb(scr1 & ~0x40, dma_base + 0x03); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * Calculate the input clock in Hz 2708c2ecf20Sopenharmony_ci * (the clock counter is 30 bit wide and counts down) 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci usec_elapsed = ktime_us_delta(end_time, start_time); 2738c2ecf20Sopenharmony_ci pll_input = ((start_count - end_count) & 0x3fffffff) / 10 * 2748c2ecf20Sopenharmony_ci (10000000 / usec_elapsed); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci DBG("start[%ld] end[%ld]\n", start_count, end_count); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return pll_input; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 2828c2ecf20Sopenharmony_cistatic void apple_kiwi_init(struct pci_dev *pdev) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct device_node *np = pci_device_to_OF_node(pdev); 2858c2ecf20Sopenharmony_ci u8 conf; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (np == NULL || !of_device_is_compatible(np, "kiwi-root")) 2888c2ecf20Sopenharmony_ci return; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (pdev->revision >= 0x03) { 2918c2ecf20Sopenharmony_ci /* Setup chip magic config stuff (from darwin) */ 2928c2ecf20Sopenharmony_ci pci_read_config_byte (pdev, 0x40, &conf); 2938c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, 0x40, (conf | 0x01)); 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_PMAC */ 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int init_chipset_pdcnew(struct pci_dev *dev) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci const char *name = DRV_NAME; 3018c2ecf20Sopenharmony_ci unsigned long dma_base = pci_resource_start(dev, 4); 3028c2ecf20Sopenharmony_ci unsigned long sec_dma_base = dma_base + 0x08; 3038c2ecf20Sopenharmony_ci long pll_input, pll_output, ratio; 3048c2ecf20Sopenharmony_ci int f, r; 3058c2ecf20Sopenharmony_ci u8 pll_ctl0, pll_ctl1; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (dma_base == 0) 3088c2ecf20Sopenharmony_ci return -EFAULT; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 3118c2ecf20Sopenharmony_ci apple_kiwi_init(dev); 3128c2ecf20Sopenharmony_ci#endif 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* Calculate the required PLL output frequency */ 3158c2ecf20Sopenharmony_ci switch(max_dma_rate(dev)) { 3168c2ecf20Sopenharmony_ci case 4: /* it's 133 MHz for Ultra133 chips */ 3178c2ecf20Sopenharmony_ci pll_output = 133333333; 3188c2ecf20Sopenharmony_ci break; 3198c2ecf20Sopenharmony_ci case 3: /* and 100 MHz for Ultra100 chips */ 3208c2ecf20Sopenharmony_ci default: 3218c2ecf20Sopenharmony_ci pll_output = 100000000; 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* 3268c2ecf20Sopenharmony_ci * Detect PLL input clock. 3278c2ecf20Sopenharmony_ci * On some systems, where PCI bus is running at non-standard clock rate 3288c2ecf20Sopenharmony_ci * (e.g. 25 or 40 MHz), we have to adjust the cycle time. 3298c2ecf20Sopenharmony_ci * PDC20268 and newer chips employ PLL circuit to help correct timing 3308c2ecf20Sopenharmony_ci * registers setting. 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ci pll_input = detect_pll_input_clock(dma_base); 3338c2ecf20Sopenharmony_ci printk(KERN_INFO "%s %s: PLL input clock is %ld kHz\n", 3348c2ecf20Sopenharmony_ci name, pci_name(dev), pll_input / 1000); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* Sanity check */ 3378c2ecf20Sopenharmony_ci if (unlikely(pll_input < 5000000L || pll_input > 70000000L)) { 3388c2ecf20Sopenharmony_ci printk(KERN_ERR "%s %s: Bad PLL input clock %ld Hz, giving up!" 3398c2ecf20Sopenharmony_ci "\n", name, pci_name(dev), pll_input); 3408c2ecf20Sopenharmony_ci goto out; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci#ifdef DEBUG 3448c2ecf20Sopenharmony_ci DBG("pll_output is %ld Hz\n", pll_output); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* Show the current clock value of PLL control register 3478c2ecf20Sopenharmony_ci * (maybe already configured by the BIOS) 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ci outb(0x02, sec_dma_base + 0x01); 3508c2ecf20Sopenharmony_ci pll_ctl0 = inb(sec_dma_base + 0x03); 3518c2ecf20Sopenharmony_ci outb(0x03, sec_dma_base + 0x01); 3528c2ecf20Sopenharmony_ci pll_ctl1 = inb(sec_dma_base + 0x03); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1); 3558c2ecf20Sopenharmony_ci#endif 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* 3588c2ecf20Sopenharmony_ci * Calculate the ratio of F, R and NO 3598c2ecf20Sopenharmony_ci * POUT = (F + 2) / (( R + 2) * NO) 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci ratio = pll_output / (pll_input / 1000); 3628c2ecf20Sopenharmony_ci if (ratio < 8600L) { /* 8.6x */ 3638c2ecf20Sopenharmony_ci /* Using NO = 0x01, R = 0x0d */ 3648c2ecf20Sopenharmony_ci r = 0x0d; 3658c2ecf20Sopenharmony_ci } else if (ratio < 12900L) { /* 12.9x */ 3668c2ecf20Sopenharmony_ci /* Using NO = 0x01, R = 0x08 */ 3678c2ecf20Sopenharmony_ci r = 0x08; 3688c2ecf20Sopenharmony_ci } else if (ratio < 16100L) { /* 16.1x */ 3698c2ecf20Sopenharmony_ci /* Using NO = 0x01, R = 0x06 */ 3708c2ecf20Sopenharmony_ci r = 0x06; 3718c2ecf20Sopenharmony_ci } else if (ratio < 64000L) { /* 64x */ 3728c2ecf20Sopenharmony_ci r = 0x00; 3738c2ecf20Sopenharmony_ci } else { 3748c2ecf20Sopenharmony_ci /* Invalid ratio */ 3758c2ecf20Sopenharmony_ci printk(KERN_ERR "%s %s: Bad ratio %ld, giving up!\n", 3768c2ecf20Sopenharmony_ci name, pci_name(dev), ratio); 3778c2ecf20Sopenharmony_ci goto out; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci f = (ratio * (r + 2)) / 1000 - 2; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci DBG("F[%d] R[%d] ratio*1000[%ld]\n", f, r, ratio); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (unlikely(f < 0 || f > 127)) { 3858c2ecf20Sopenharmony_ci /* Invalid F */ 3868c2ecf20Sopenharmony_ci printk(KERN_ERR "%s %s: F[%d] invalid!\n", 3878c2ecf20Sopenharmony_ci name, pci_name(dev), f); 3888c2ecf20Sopenharmony_ci goto out; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci pll_ctl0 = (u8) f; 3928c2ecf20Sopenharmony_ci pll_ctl1 = (u8) r; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci DBG("Writing pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci outb(0x02, sec_dma_base + 0x01); 3978c2ecf20Sopenharmony_ci outb(pll_ctl0, sec_dma_base + 0x03); 3988c2ecf20Sopenharmony_ci outb(0x03, sec_dma_base + 0x01); 3998c2ecf20Sopenharmony_ci outb(pll_ctl1, sec_dma_base + 0x03); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Wait the PLL circuit to be stable */ 4028c2ecf20Sopenharmony_ci mdelay(30); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci#ifdef DEBUG 4058c2ecf20Sopenharmony_ci /* 4068c2ecf20Sopenharmony_ci * Show the current clock value of PLL control register 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_ci outb(0x02, sec_dma_base + 0x01); 4098c2ecf20Sopenharmony_ci pll_ctl0 = inb(sec_dma_base + 0x03); 4108c2ecf20Sopenharmony_ci outb(0x03, sec_dma_base + 0x01); 4118c2ecf20Sopenharmony_ci pll_ctl1 = inb(sec_dma_base + 0x03); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1); 4148c2ecf20Sopenharmony_ci#endif 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci out: 4178c2ecf20Sopenharmony_ci return 0; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic struct pci_dev *pdc20270_get_dev2(struct pci_dev *dev) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct pci_dev *dev2; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci dev2 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn) + 1, 4258c2ecf20Sopenharmony_ci PCI_FUNC(dev->devfn))); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (dev2 && 4288c2ecf20Sopenharmony_ci dev2->vendor == dev->vendor && 4298c2ecf20Sopenharmony_ci dev2->device == dev->device) { 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (dev2->irq != dev->irq) { 4328c2ecf20Sopenharmony_ci dev2->irq = dev->irq; 4338c2ecf20Sopenharmony_ci printk(KERN_INFO DRV_NAME " %s: PCI config space " 4348c2ecf20Sopenharmony_ci "interrupt fixed\n", pci_name(dev)); 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return dev2; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return NULL; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic const struct ide_port_ops pdcnew_port_ops = { 4448c2ecf20Sopenharmony_ci .set_pio_mode = pdcnew_set_pio_mode, 4458c2ecf20Sopenharmony_ci .set_dma_mode = pdcnew_set_dma_mode, 4468c2ecf20Sopenharmony_ci .resetproc = pdcnew_reset, 4478c2ecf20Sopenharmony_ci .cable_detect = pdcnew_cable_detect, 4488c2ecf20Sopenharmony_ci}; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci#define DECLARE_PDCNEW_DEV(udma) \ 4518c2ecf20Sopenharmony_ci { \ 4528c2ecf20Sopenharmony_ci .name = DRV_NAME, \ 4538c2ecf20Sopenharmony_ci .init_chipset = init_chipset_pdcnew, \ 4548c2ecf20Sopenharmony_ci .port_ops = &pdcnew_port_ops, \ 4558c2ecf20Sopenharmony_ci .host_flags = IDE_HFLAG_POST_SET_MODE | \ 4568c2ecf20Sopenharmony_ci IDE_HFLAG_ERROR_STOPS_FIFO | \ 4578c2ecf20Sopenharmony_ci IDE_HFLAG_OFF_BOARD, \ 4588c2ecf20Sopenharmony_ci .pio_mask = ATA_PIO4, \ 4598c2ecf20Sopenharmony_ci .mwdma_mask = ATA_MWDMA2, \ 4608c2ecf20Sopenharmony_ci .udma_mask = udma, \ 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic const struct ide_port_info pdcnew_chipsets[] = { 4648c2ecf20Sopenharmony_ci /* 0: PDC202{68,70} */ DECLARE_PDCNEW_DEV(ATA_UDMA5), 4658c2ecf20Sopenharmony_ci /* 1: PDC202{69,71,75,76,77} */ DECLARE_PDCNEW_DEV(ATA_UDMA6), 4668c2ecf20Sopenharmony_ci}; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci/** 4698c2ecf20Sopenharmony_ci * pdc202new_init_one - called when a pdc202xx is found 4708c2ecf20Sopenharmony_ci * @dev: the pdc202new device 4718c2ecf20Sopenharmony_ci * @id: the matching pci id 4728c2ecf20Sopenharmony_ci * 4738c2ecf20Sopenharmony_ci * Called when the PCI registration layer (or the IDE initialization) 4748c2ecf20Sopenharmony_ci * finds a device matching our IDE device tables. 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic int pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci const struct ide_port_info *d = &pdcnew_chipsets[id->driver_data]; 4808c2ecf20Sopenharmony_ci struct pci_dev *bridge = dev->bus->self; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (dev->device == PCI_DEVICE_ID_PROMISE_20270 && bridge && 4838c2ecf20Sopenharmony_ci bridge->vendor == PCI_VENDOR_ID_DEC && 4848c2ecf20Sopenharmony_ci bridge->device == PCI_DEVICE_ID_DEC_21150) { 4858c2ecf20Sopenharmony_ci struct pci_dev *dev2; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (PCI_SLOT(dev->devfn) & 2) 4888c2ecf20Sopenharmony_ci return -ENODEV; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci dev2 = pdc20270_get_dev2(dev); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (dev2) { 4938c2ecf20Sopenharmony_ci int ret = ide_pci_init_two(dev, dev2, d, NULL); 4948c2ecf20Sopenharmony_ci if (ret < 0) 4958c2ecf20Sopenharmony_ci pci_dev_put(dev2); 4968c2ecf20Sopenharmony_ci return ret; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (dev->device == PCI_DEVICE_ID_PROMISE_20276 && bridge && 5018c2ecf20Sopenharmony_ci bridge->vendor == PCI_VENDOR_ID_INTEL && 5028c2ecf20Sopenharmony_ci (bridge->device == PCI_DEVICE_ID_INTEL_I960 || 5038c2ecf20Sopenharmony_ci bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) { 5048c2ecf20Sopenharmony_ci printk(KERN_INFO DRV_NAME " %s: attached to I2O RAID controller," 5058c2ecf20Sopenharmony_ci " skipping\n", pci_name(dev)); 5068c2ecf20Sopenharmony_ci return -ENODEV; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return ide_pci_init_one(dev, d, NULL); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic void pdc202new_remove(struct pci_dev *dev) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci struct ide_host *host = pci_get_drvdata(dev); 5158c2ecf20Sopenharmony_ci struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci ide_pci_remove(dev); 5188c2ecf20Sopenharmony_ci pci_dev_put(dev2); 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic const struct pci_device_id pdc202new_pci_tbl[] = { 5228c2ecf20Sopenharmony_ci { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), 0 }, 5238c2ecf20Sopenharmony_ci { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), 1 }, 5248c2ecf20Sopenharmony_ci { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), 0 }, 5258c2ecf20Sopenharmony_ci { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), 1 }, 5268c2ecf20Sopenharmony_ci { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), 1 }, 5278c2ecf20Sopenharmony_ci { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), 1 }, 5288c2ecf20Sopenharmony_ci { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), 1 }, 5298c2ecf20Sopenharmony_ci { 0, }, 5308c2ecf20Sopenharmony_ci}; 5318c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic struct pci_driver pdc202new_pci_driver = { 5348c2ecf20Sopenharmony_ci .name = "Promise_IDE", 5358c2ecf20Sopenharmony_ci .id_table = pdc202new_pci_tbl, 5368c2ecf20Sopenharmony_ci .probe = pdc202new_init_one, 5378c2ecf20Sopenharmony_ci .remove = pdc202new_remove, 5388c2ecf20Sopenharmony_ci .suspend = ide_pci_suspend, 5398c2ecf20Sopenharmony_ci .resume = ide_pci_resume, 5408c2ecf20Sopenharmony_ci}; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int __init pdc202new_ide_init(void) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci return ide_pci_register_driver(&pdc202new_pci_driver); 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic void __exit pdc202new_ide_exit(void) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci pci_unregister_driver(&pdc202new_pci_driver); 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cimodule_init(pdc202new_ide_init); 5538c2ecf20Sopenharmony_cimodule_exit(pdc202new_ide_exit); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andre Hedrick, Frank Tiernan"); 5568c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PCI driver module for Promise PDC20268 and higher"); 5578c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 558