18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ITE 8213 IDE driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006 Jack Lee 68c2ecf20Sopenharmony_ci * Copyright (C) 2006 Alan Cox 78c2ecf20Sopenharmony_ci * Copyright (C) 2007 Bartlomiej Zolnierkiewicz 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/pci.h> 148c2ecf20Sopenharmony_ci#include <linux/ide.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define DRV_NAME "it8213" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/** 208c2ecf20Sopenharmony_ci * it8213_set_pio_mode - set host controller for PIO mode 218c2ecf20Sopenharmony_ci * @hwif: port 228c2ecf20Sopenharmony_ci * @drive: drive 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Set the interface PIO mode. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic void it8213_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 308c2ecf20Sopenharmony_ci int is_slave = drive->dn & 1; 318c2ecf20Sopenharmony_ci int master_port = 0x40; 328c2ecf20Sopenharmony_ci int slave_port = 0x44; 338c2ecf20Sopenharmony_ci unsigned long flags; 348c2ecf20Sopenharmony_ci u16 master_data; 358c2ecf20Sopenharmony_ci u8 slave_data; 368c2ecf20Sopenharmony_ci static DEFINE_SPINLOCK(tune_lock); 378c2ecf20Sopenharmony_ci int control = 0; 388c2ecf20Sopenharmony_ci const u8 pio = drive->pio_mode - XFER_PIO_0; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci static const u8 timings[][2] = { 418c2ecf20Sopenharmony_ci { 0, 0 }, 428c2ecf20Sopenharmony_ci { 0, 0 }, 438c2ecf20Sopenharmony_ci { 1, 0 }, 448c2ecf20Sopenharmony_ci { 2, 1 }, 458c2ecf20Sopenharmony_ci { 2, 3 }, }; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci spin_lock_irqsave(&tune_lock, flags); 488c2ecf20Sopenharmony_ci pci_read_config_word(dev, master_port, &master_data); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (pio > 1) 518c2ecf20Sopenharmony_ci control |= 1; /* Programmable timing on */ 528c2ecf20Sopenharmony_ci if (drive->media != ide_disk) 538c2ecf20Sopenharmony_ci control |= 4; /* ATAPI */ 548c2ecf20Sopenharmony_ci if (ide_pio_need_iordy(drive, pio)) 558c2ecf20Sopenharmony_ci control |= 2; /* IORDY */ 568c2ecf20Sopenharmony_ci if (is_slave) { 578c2ecf20Sopenharmony_ci master_data |= 0x4000; 588c2ecf20Sopenharmony_ci master_data &= ~0x0070; 598c2ecf20Sopenharmony_ci if (pio > 1) 608c2ecf20Sopenharmony_ci master_data = master_data | (control << 4); 618c2ecf20Sopenharmony_ci pci_read_config_byte(dev, slave_port, &slave_data); 628c2ecf20Sopenharmony_ci slave_data = slave_data & 0xf0; 638c2ecf20Sopenharmony_ci slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1]; 648c2ecf20Sopenharmony_ci } else { 658c2ecf20Sopenharmony_ci master_data &= ~0x3307; 668c2ecf20Sopenharmony_ci if (pio > 1) 678c2ecf20Sopenharmony_ci master_data = master_data | control; 688c2ecf20Sopenharmony_ci master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci pci_write_config_word(dev, master_port, master_data); 718c2ecf20Sopenharmony_ci if (is_slave) 728c2ecf20Sopenharmony_ci pci_write_config_byte(dev, slave_port, slave_data); 738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tune_lock, flags); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/** 778c2ecf20Sopenharmony_ci * it8213_set_dma_mode - set host controller for DMA mode 788c2ecf20Sopenharmony_ci * @hwif: port 798c2ecf20Sopenharmony_ci * @drive: drive 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * Tune the ITE chipset for the DMA mode. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic void it8213_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 878c2ecf20Sopenharmony_ci u8 maslave = 0x40; 888c2ecf20Sopenharmony_ci int a_speed = 3 << (drive->dn * 4); 898c2ecf20Sopenharmony_ci int u_flag = 1 << drive->dn; 908c2ecf20Sopenharmony_ci int v_flag = 0x01 << drive->dn; 918c2ecf20Sopenharmony_ci int w_flag = 0x10 << drive->dn; 928c2ecf20Sopenharmony_ci int u_speed = 0; 938c2ecf20Sopenharmony_ci u16 reg4042, reg4a; 948c2ecf20Sopenharmony_ci u8 reg48, reg54, reg55; 958c2ecf20Sopenharmony_ci const u8 speed = drive->dma_mode; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci pci_read_config_word(dev, maslave, ®4042); 988c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x48, ®48); 998c2ecf20Sopenharmony_ci pci_read_config_word(dev, 0x4a, ®4a); 1008c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x54, ®54); 1018c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x55, ®55); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (speed >= XFER_UDMA_0) { 1048c2ecf20Sopenharmony_ci u8 udma = speed - XFER_UDMA_0; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (!(reg48 & u_flag)) 1098c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x48, reg48 | u_flag); 1108c2ecf20Sopenharmony_ci if (speed >= XFER_UDMA_5) 1118c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); 1128c2ecf20Sopenharmony_ci else 1138c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if ((reg4a & a_speed) != u_speed) 1168c2ecf20Sopenharmony_ci pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); 1178c2ecf20Sopenharmony_ci if (speed > XFER_UDMA_2) { 1188c2ecf20Sopenharmony_ci if (!(reg54 & v_flag)) 1198c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x54, reg54 | v_flag); 1208c2ecf20Sopenharmony_ci } else 1218c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); 1228c2ecf20Sopenharmony_ci } else { 1238c2ecf20Sopenharmony_ci const u8 mwdma_to_pio[] = { 0, 3, 4 }; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (reg48 & u_flag) 1268c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); 1278c2ecf20Sopenharmony_ci if (reg4a & a_speed) 1288c2ecf20Sopenharmony_ci pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); 1298c2ecf20Sopenharmony_ci if (reg54 & v_flag) 1308c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); 1318c2ecf20Sopenharmony_ci if (reg55 & w_flag) 1328c2ecf20Sopenharmony_ci pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (speed >= XFER_MW_DMA_0) 1358c2ecf20Sopenharmony_ci drive->pio_mode = 1368c2ecf20Sopenharmony_ci mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0; 1378c2ecf20Sopenharmony_ci else 1388c2ecf20Sopenharmony_ci drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */ 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci it8213_set_pio_mode(hwif, drive); 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic u8 it8213_cable_detect(ide_hwif_t *hwif) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct pci_dev *dev = to_pci_dev(hwif->dev); 1478c2ecf20Sopenharmony_ci u8 reg42h = 0; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x42, ®42h); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic const struct ide_port_ops it8213_port_ops = { 1558c2ecf20Sopenharmony_ci .set_pio_mode = it8213_set_pio_mode, 1568c2ecf20Sopenharmony_ci .set_dma_mode = it8213_set_dma_mode, 1578c2ecf20Sopenharmony_ci .cable_detect = it8213_cable_detect, 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic const struct ide_port_info it8213_chipset = { 1618c2ecf20Sopenharmony_ci .name = DRV_NAME, 1628c2ecf20Sopenharmony_ci .enablebits = { {0x41, 0x80, 0x80} }, 1638c2ecf20Sopenharmony_ci .port_ops = &it8213_port_ops, 1648c2ecf20Sopenharmony_ci .host_flags = IDE_HFLAG_SINGLE, 1658c2ecf20Sopenharmony_ci .pio_mask = ATA_PIO4, 1668c2ecf20Sopenharmony_ci .swdma_mask = ATA_SWDMA2_ONLY, 1678c2ecf20Sopenharmony_ci .mwdma_mask = ATA_MWDMA12_ONLY, 1688c2ecf20Sopenharmony_ci .udma_mask = ATA_UDMA6, 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/** 1728c2ecf20Sopenharmony_ci * it8213_init_one - pci layer discovery entry 1738c2ecf20Sopenharmony_ci * @dev: PCI device 1748c2ecf20Sopenharmony_ci * @id: ident table entry 1758c2ecf20Sopenharmony_ci * 1768c2ecf20Sopenharmony_ci * Called by the PCI code when it finds an ITE8213 controller. As 1778c2ecf20Sopenharmony_ci * this device follows the standard interfaces we can use the 1788c2ecf20Sopenharmony_ci * standard helper functions to do almost all the work for us. 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci return ide_pci_init_one(dev, &it8213_chipset, NULL); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic const struct pci_device_id it8213_pci_tbl[] = { 1878c2ecf20Sopenharmony_ci { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8213), 0 }, 1888c2ecf20Sopenharmony_ci { 0, }, 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, it8213_pci_tbl); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic struct pci_driver it8213_pci_driver = { 1948c2ecf20Sopenharmony_ci .name = "ITE8213_IDE", 1958c2ecf20Sopenharmony_ci .id_table = it8213_pci_tbl, 1968c2ecf20Sopenharmony_ci .probe = it8213_init_one, 1978c2ecf20Sopenharmony_ci .remove = ide_pci_remove, 1988c2ecf20Sopenharmony_ci .suspend = ide_pci_suspend, 1998c2ecf20Sopenharmony_ci .resume = ide_pci_resume, 2008c2ecf20Sopenharmony_ci}; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int __init it8213_ide_init(void) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci return ide_pci_register_driver(&it8213_pci_driver); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic void __exit it8213_ide_exit(void) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci pci_unregister_driver(&it8213_pci_driver); 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cimodule_init(it8213_ide_init); 2138c2ecf20Sopenharmony_cimodule_exit(it8213_ide_exit); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jack Lee, Alan Cox"); 2168c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PCI driver module for the ITE 8213"); 2178c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 218