1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2003 ATI Inc. <hyu@ati.com>
4*4882a593Smuzhiyun * Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/types.h>
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/pci.h>
11*4882a593Smuzhiyun #include <linux/ide.h>
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #define DRV_NAME "atiixp"
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #define ATIIXP_IDE_PIO_TIMING 0x40
17*4882a593Smuzhiyun #define ATIIXP_IDE_MDMA_TIMING 0x44
18*4882a593Smuzhiyun #define ATIIXP_IDE_PIO_CONTROL 0x48
19*4882a593Smuzhiyun #define ATIIXP_IDE_PIO_MODE 0x4a
20*4882a593Smuzhiyun #define ATIIXP_IDE_UDMA_CONTROL 0x54
21*4882a593Smuzhiyun #define ATIIXP_IDE_UDMA_MODE 0x56
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun struct atiixp_ide_timing {
24*4882a593Smuzhiyun u8 command_width;
25*4882a593Smuzhiyun u8 recover_width;
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun static struct atiixp_ide_timing pio_timing[] = {
29*4882a593Smuzhiyun { 0x05, 0x0d },
30*4882a593Smuzhiyun { 0x04, 0x07 },
31*4882a593Smuzhiyun { 0x03, 0x04 },
32*4882a593Smuzhiyun { 0x02, 0x02 },
33*4882a593Smuzhiyun { 0x02, 0x00 },
34*4882a593Smuzhiyun };
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun static struct atiixp_ide_timing mdma_timing[] = {
37*4882a593Smuzhiyun { 0x07, 0x07 },
38*4882a593Smuzhiyun { 0x02, 0x01 },
39*4882a593Smuzhiyun { 0x02, 0x00 },
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun static DEFINE_SPINLOCK(atiixp_lock);
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /**
45*4882a593Smuzhiyun * atiixp_set_pio_mode - set host controller for PIO mode
46*4882a593Smuzhiyun * @hwif: port
47*4882a593Smuzhiyun * @drive: drive
48*4882a593Smuzhiyun *
49*4882a593Smuzhiyun * Set the interface PIO mode.
50*4882a593Smuzhiyun */
51*4882a593Smuzhiyun
atiixp_set_pio_mode(ide_hwif_t * hwif,ide_drive_t * drive)52*4882a593Smuzhiyun static void atiixp_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun struct pci_dev *dev = to_pci_dev(hwif->dev);
55*4882a593Smuzhiyun unsigned long flags;
56*4882a593Smuzhiyun int timing_shift = (drive->dn ^ 1) * 8;
57*4882a593Smuzhiyun u32 pio_timing_data;
58*4882a593Smuzhiyun u16 pio_mode_data;
59*4882a593Smuzhiyun const u8 pio = drive->pio_mode - XFER_PIO_0;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun spin_lock_irqsave(&atiixp_lock, flags);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode_data);
64*4882a593Smuzhiyun pio_mode_data &= ~(0x07 << (drive->dn * 4));
65*4882a593Smuzhiyun pio_mode_data |= (pio << (drive->dn * 4));
66*4882a593Smuzhiyun pci_write_config_word(dev, ATIIXP_IDE_PIO_MODE, pio_mode_data);
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun pci_read_config_dword(dev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
69*4882a593Smuzhiyun pio_timing_data &= ~(0xff << timing_shift);
70*4882a593Smuzhiyun pio_timing_data |= (pio_timing[pio].recover_width << timing_shift) |
71*4882a593Smuzhiyun (pio_timing[pio].command_width << (timing_shift + 4));
72*4882a593Smuzhiyun pci_write_config_dword(dev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun spin_unlock_irqrestore(&atiixp_lock, flags);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /**
78*4882a593Smuzhiyun * atiixp_set_dma_mode - set host controller for DMA mode
79*4882a593Smuzhiyun * @hwif: port
80*4882a593Smuzhiyun * @drive: drive
81*4882a593Smuzhiyun *
82*4882a593Smuzhiyun * Set a ATIIXP host controller to the desired DMA mode. This involves
83*4882a593Smuzhiyun * programming the right timing data into the PCI configuration space.
84*4882a593Smuzhiyun */
85*4882a593Smuzhiyun
atiixp_set_dma_mode(ide_hwif_t * hwif,ide_drive_t * drive)86*4882a593Smuzhiyun static void atiixp_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun struct pci_dev *dev = to_pci_dev(hwif->dev);
89*4882a593Smuzhiyun unsigned long flags;
90*4882a593Smuzhiyun int timing_shift = (drive->dn ^ 1) * 8;
91*4882a593Smuzhiyun u32 tmp32;
92*4882a593Smuzhiyun u16 tmp16;
93*4882a593Smuzhiyun u16 udma_ctl = 0;
94*4882a593Smuzhiyun const u8 speed = drive->dma_mode;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun spin_lock_irqsave(&atiixp_lock, flags);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_ctl);
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun if (speed >= XFER_UDMA_0) {
101*4882a593Smuzhiyun pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16);
102*4882a593Smuzhiyun tmp16 &= ~(0x07 << (drive->dn * 4));
103*4882a593Smuzhiyun tmp16 |= ((speed & 0x07) << (drive->dn * 4));
104*4882a593Smuzhiyun pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16);
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun udma_ctl |= (1 << drive->dn);
107*4882a593Smuzhiyun } else if (speed >= XFER_MW_DMA_0) {
108*4882a593Smuzhiyun u8 i = speed & 0x03;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
111*4882a593Smuzhiyun tmp32 &= ~(0xff << timing_shift);
112*4882a593Smuzhiyun tmp32 |= (mdma_timing[i].recover_width << timing_shift) |
113*4882a593Smuzhiyun (mdma_timing[i].command_width << (timing_shift + 4));
114*4882a593Smuzhiyun pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun udma_ctl &= ~(1 << drive->dn);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, udma_ctl);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun spin_unlock_irqrestore(&atiixp_lock, flags);
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
atiixp_cable_detect(ide_hwif_t * hwif)124*4882a593Smuzhiyun static u8 atiixp_cable_detect(ide_hwif_t *hwif)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun struct pci_dev *pdev = to_pci_dev(hwif->dev);
127*4882a593Smuzhiyun u8 udma_mode = 0, ch = hwif->channel;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode);
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40)
132*4882a593Smuzhiyun return ATA_CBL_PATA80;
133*4882a593Smuzhiyun else
134*4882a593Smuzhiyun return ATA_CBL_PATA40;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun static const struct ide_port_ops atiixp_port_ops = {
138*4882a593Smuzhiyun .set_pio_mode = atiixp_set_pio_mode,
139*4882a593Smuzhiyun .set_dma_mode = atiixp_set_dma_mode,
140*4882a593Smuzhiyun .cable_detect = atiixp_cable_detect,
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun static const struct ide_port_info atiixp_pci_info[] = {
144*4882a593Smuzhiyun { /* 0: IXP200/300/400/700 */
145*4882a593Smuzhiyun .name = DRV_NAME,
146*4882a593Smuzhiyun .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
147*4882a593Smuzhiyun .port_ops = &atiixp_port_ops,
148*4882a593Smuzhiyun .pio_mask = ATA_PIO4,
149*4882a593Smuzhiyun .mwdma_mask = ATA_MWDMA2,
150*4882a593Smuzhiyun .udma_mask = ATA_UDMA5,
151*4882a593Smuzhiyun },
152*4882a593Smuzhiyun { /* 1: IXP600 */
153*4882a593Smuzhiyun .name = DRV_NAME,
154*4882a593Smuzhiyun .enablebits = {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
155*4882a593Smuzhiyun .port_ops = &atiixp_port_ops,
156*4882a593Smuzhiyun .host_flags = IDE_HFLAG_SINGLE,
157*4882a593Smuzhiyun .pio_mask = ATA_PIO4,
158*4882a593Smuzhiyun .mwdma_mask = ATA_MWDMA2,
159*4882a593Smuzhiyun .udma_mask = ATA_UDMA5,
160*4882a593Smuzhiyun },
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun /**
164*4882a593Smuzhiyun * atiixp_init_one - called when a ATIIXP is found
165*4882a593Smuzhiyun * @dev: the atiixp device
166*4882a593Smuzhiyun * @id: the matching pci id
167*4882a593Smuzhiyun *
168*4882a593Smuzhiyun * Called when the PCI registration layer (or the IDE initialization)
169*4882a593Smuzhiyun * finds a device matching our IDE device tables.
170*4882a593Smuzhiyun */
171*4882a593Smuzhiyun
atiixp_init_one(struct pci_dev * dev,const struct pci_device_id * id)172*4882a593Smuzhiyun static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun return ide_pci_init_one(dev, &atiixp_pci_info[id->driver_data], NULL);
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun static const struct pci_device_id atiixp_pci_tbl[] = {
178*4882a593Smuzhiyun { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), 0 },
179*4882a593Smuzhiyun { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), 0 },
180*4882a593Smuzhiyun { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), 0 },
181*4882a593Smuzhiyun { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), 1 },
182*4882a593Smuzhiyun { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), 0 },
183*4882a593Smuzhiyun { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_HUDSON2_IDE), 0 },
184*4882a593Smuzhiyun { 0, },
185*4882a593Smuzhiyun };
186*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun static struct pci_driver atiixp_pci_driver = {
189*4882a593Smuzhiyun .name = "ATIIXP_IDE",
190*4882a593Smuzhiyun .id_table = atiixp_pci_tbl,
191*4882a593Smuzhiyun .probe = atiixp_init_one,
192*4882a593Smuzhiyun .remove = ide_pci_remove,
193*4882a593Smuzhiyun .suspend = ide_pci_suspend,
194*4882a593Smuzhiyun .resume = ide_pci_resume,
195*4882a593Smuzhiyun };
196*4882a593Smuzhiyun
atiixp_ide_init(void)197*4882a593Smuzhiyun static int __init atiixp_ide_init(void)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun return ide_pci_register_driver(&atiixp_pci_driver);
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
atiixp_ide_exit(void)202*4882a593Smuzhiyun static void __exit atiixp_ide_exit(void)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun pci_unregister_driver(&atiixp_pci_driver);
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun module_init(atiixp_ide_init);
208*4882a593Smuzhiyun module_exit(atiixp_ide_exit);
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun MODULE_AUTHOR("HUI YU");
211*4882a593Smuzhiyun MODULE_DESCRIPTION("PCI driver module for ATI IXP IDE");
212*4882a593Smuzhiyun MODULE_LICENSE("GPL");
213