1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * pata-cs5530.c - CS5530 PATA for new ATA layer |
4 | * (C) 2005 Red Hat Inc |
5 | * |
6 | * based upon cs5530.c by Mark Lord. |
7 | * |
8 | * Loosely based on the piix & svwks drivers. |
9 | * |
10 | * Documentation: |
11 | * Available from AMD web site. |
12 | */ |
13 | |
14 | #include <linux/kernel.h> |
15 | #include <linux/module.h> |
16 | #include <linux/pci.h> |
17 | #include <linux/blkdev.h> |
18 | #include <linux/delay.h> |
19 | #include <scsi/scsi_host.h> |
20 | #include <linux/libata.h> |
21 | #include <linux/dmi.h> |
22 | |
23 | #define DRV_NAME "pata_cs5530" |
24 | #define DRV_VERSION "0.7.4" |
25 | |
26 | static void __iomem *cs5530_port_base(struct ata_port *ap) |
27 | { |
28 | unsigned long bmdma = (unsigned long)ap->ioaddr.bmdma_addr; |
29 | |
30 | return (void __iomem *)((bmdma & ~0x0F) + 0x20 + 0x10 * ap->port_no); |
31 | } |
32 | |
33 | /** |
34 | * cs5530_set_piomode - PIO setup |
35 | * @ap: ATA interface |
36 | * @adev: device on the interface |
37 | * |
38 | * Set our PIO requirements. This is fairly simple on the CS5530 |
39 | * chips. |
40 | */ |
41 | |
42 | static void cs5530_set_piomode(struct ata_port *ap, struct ata_device *adev) |
43 | { |
44 | static const unsigned int cs5530_pio_timings[2][5] = { |
45 | {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, |
46 | {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010} |
47 | }; |
48 | void __iomem *base = cs5530_port_base(ap); |
49 | u32 tuning; |
50 | int format; |
51 | |
52 | /* Find out which table to use */ |
53 | tuning = ioread32(base + 0x04); |
54 | format = (tuning & 0x80000000UL) ? 1 : 0; |
55 | |
56 | /* Now load the right timing register */ |
57 | if (adev->devno) |
58 | base += 0x08; |
59 | |
60 | iowrite32(cs5530_pio_timings[format][adev->pio_mode - XFER_PIO_0], base); |
61 | } |
62 | |
63 | /** |
64 | * cs5530_set_dmamode - DMA timing setup |
65 | * @ap: ATA interface |
66 | * @adev: Device being configured |
67 | * |
68 | * We cannot mix MWDMA and UDMA without reloading timings each switch |
69 | * master to slave. We track the last DMA setup in order to minimise |
70 | * reloads. |
71 | */ |
72 | |
73 | static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev) |
74 | { |
75 | void __iomem *base = cs5530_port_base(ap); |
76 | u32 tuning, timing = 0; |
77 | u8 reg; |
78 | |
79 | /* Find out which table to use */ |
80 | tuning = ioread32(base + 0x04); |
81 | |
82 | switch(adev->dma_mode) { |
83 | case XFER_UDMA_0: |
84 | timing = 0x00921250;break; |
85 | case XFER_UDMA_1: |
86 | timing = 0x00911140;break; |
87 | case XFER_UDMA_2: |
88 | timing = 0x00911030;break; |
89 | case XFER_MW_DMA_0: |
90 | timing = 0x00077771;break; |
91 | case XFER_MW_DMA_1: |
92 | timing = 0x00012121;break; |
93 | case XFER_MW_DMA_2: |
94 | timing = 0x00002020;break; |
95 | default: |
96 | BUG(); |
97 | } |
98 | /* Merge in the PIO format bit */ |
99 | timing |= (tuning & 0x80000000UL); |
100 | if (adev->devno == 0) /* Master */ |
101 | iowrite32(timing, base + 0x04); |
102 | else { |
103 | if (timing & 0x00100000) |
104 | tuning |= 0x00100000; /* UDMA for both */ |
105 | else |
106 | tuning &= ~0x00100000; /* MWDMA for both */ |
107 | iowrite32(tuning, base + 0x04); |
108 | iowrite32(timing, base + 0x0C); |
109 | } |
110 | |
111 | /* Set the DMA capable bit in the BMDMA area */ |
112 | reg = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); |
113 | reg |= (1 << (5 + adev->devno)); |
114 | iowrite8(reg, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); |
115 | |
116 | /* Remember the last DMA setup we did */ |
117 | |
118 | ap->private_data = adev; |
119 | } |
120 | |
121 | /** |
122 | * cs5530_qc_issue - command issue |
123 | * @qc: command pending |
124 | * |
125 | * Called when the libata layer is about to issue a command. We wrap |
126 | * this interface so that we can load the correct ATA timings if |
127 | * necessary. Specifically we have a problem that there is only |
128 | * one MWDMA/UDMA bit. |
129 | */ |
130 | |
131 | static unsigned int cs5530_qc_issue(struct ata_queued_cmd *qc) |
132 | { |
133 | struct ata_port *ap = qc->ap; |
134 | struct ata_device *adev = qc->dev; |
135 | struct ata_device *prev = ap->private_data; |
136 | |
137 | /* See if the DMA settings could be wrong */ |
138 | if (ata_dma_enabled(adev) && adev != prev && prev != NULL) { |
139 | /* Maybe, but do the channels match MWDMA/UDMA ? */ |
140 | if ((ata_using_udma(adev) && !ata_using_udma(adev: prev)) || |
141 | (ata_using_udma(adev: prev) && !ata_using_udma(adev))) |
142 | /* Switch the mode bits */ |
143 | cs5530_set_dmamode(ap, adev); |
144 | } |
145 | |
146 | return ata_bmdma_qc_issue(qc); |
147 | } |
148 | |
149 | static const struct scsi_host_template cs5530_sht = { |
150 | ATA_BASE_SHT(DRV_NAME), |
151 | .sg_tablesize = LIBATA_DUMB_MAX_PRD, |
152 | .dma_boundary = ATA_DMA_BOUNDARY, |
153 | }; |
154 | |
155 | static struct ata_port_operations cs5530_port_ops = { |
156 | .inherits = &ata_bmdma_port_ops, |
157 | |
158 | .qc_prep = ata_bmdma_dumb_qc_prep, |
159 | .qc_issue = cs5530_qc_issue, |
160 | |
161 | .cable_detect = ata_cable_40wire, |
162 | .set_piomode = cs5530_set_piomode, |
163 | .set_dmamode = cs5530_set_dmamode, |
164 | }; |
165 | |
166 | static const struct dmi_system_id palmax_dmi_table[] = { |
167 | { |
168 | .ident = "Palmax PD1100" , |
169 | .matches = { |
170 | DMI_MATCH(DMI_SYS_VENDOR, "Cyrix" ), |
171 | DMI_MATCH(DMI_PRODUCT_NAME, "Caddis" ), |
172 | }, |
173 | }, |
174 | { } |
175 | }; |
176 | |
177 | static int cs5530_is_palmax(void) |
178 | { |
179 | if (dmi_check_system(list: palmax_dmi_table)) { |
180 | printk(KERN_INFO "Palmax PD1100: Disabling DMA on docking port.\n" ); |
181 | return 1; |
182 | } |
183 | return 0; |
184 | } |
185 | |
186 | |
187 | /** |
188 | * cs5530_init_chip - Chipset init |
189 | * |
190 | * Perform the chip initialisation work that is shared between both |
191 | * setup and resume paths |
192 | */ |
193 | |
194 | static int cs5530_init_chip(void) |
195 | { |
196 | struct pci_dev *master_0 = NULL, *cs5530_0 = NULL, *dev = NULL; |
197 | |
198 | while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, from: dev)) != NULL) { |
199 | switch (dev->device) { |
200 | case PCI_DEVICE_ID_CYRIX_PCI_MASTER: |
201 | master_0 = pci_dev_get(dev); |
202 | break; |
203 | case PCI_DEVICE_ID_CYRIX_5530_LEGACY: |
204 | cs5530_0 = pci_dev_get(dev); |
205 | break; |
206 | } |
207 | } |
208 | if (!master_0) { |
209 | printk(KERN_ERR DRV_NAME ": unable to locate PCI MASTER function\n" ); |
210 | goto fail_put; |
211 | } |
212 | if (!cs5530_0) { |
213 | printk(KERN_ERR DRV_NAME ": unable to locate CS5530 LEGACY function\n" ); |
214 | goto fail_put; |
215 | } |
216 | |
217 | pci_set_master(dev: cs5530_0); |
218 | pci_try_set_mwi(dev: cs5530_0); |
219 | |
220 | /* |
221 | * Set PCI CacheLineSize to 16-bytes: |
222 | * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530 |
223 | * |
224 | * Note: This value is constant because the 5530 is only a Geode companion |
225 | */ |
226 | |
227 | pci_write_config_byte(dev: cs5530_0, PCI_CACHE_LINE_SIZE, val: 0x04); |
228 | |
229 | /* |
230 | * Disable trapping of UDMA register accesses (Win98 hack): |
231 | * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530 |
232 | */ |
233 | |
234 | pci_write_config_word(dev: cs5530_0, where: 0xd0, val: 0x5006); |
235 | |
236 | /* |
237 | * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus: |
238 | * The other settings are what is necessary to get the register |
239 | * into a sane state for IDE DMA operation. |
240 | */ |
241 | |
242 | pci_write_config_byte(dev: master_0, where: 0x40, val: 0x1e); |
243 | |
244 | /* |
245 | * Set max PCI burst size (16-bytes seems to work best): |
246 | * 16bytes: set bit-1 at 0x41 (reg value of 0x16) |
247 | * all others: clear bit-1 at 0x41, and do: |
248 | * 128bytes: OR 0x00 at 0x41 |
249 | * 256bytes: OR 0x04 at 0x41 |
250 | * 512bytes: OR 0x08 at 0x41 |
251 | * 1024bytes: OR 0x0c at 0x41 |
252 | */ |
253 | |
254 | pci_write_config_byte(dev: master_0, where: 0x41, val: 0x14); |
255 | |
256 | /* |
257 | * These settings are necessary to get the chip |
258 | * into a sane state for IDE DMA operation. |
259 | */ |
260 | |
261 | pci_write_config_byte(dev: master_0, where: 0x42, val: 0x00); |
262 | pci_write_config_byte(dev: master_0, where: 0x43, val: 0xc1); |
263 | |
264 | pci_dev_put(dev: master_0); |
265 | pci_dev_put(dev: cs5530_0); |
266 | return 0; |
267 | fail_put: |
268 | pci_dev_put(dev: master_0); |
269 | pci_dev_put(dev: cs5530_0); |
270 | return -ENODEV; |
271 | } |
272 | |
273 | /** |
274 | * cs5530_init_one - Initialise a CS5530 |
275 | * @pdev: PCI device |
276 | * @id: Entry in match table |
277 | * |
278 | * Install a driver for the newly found CS5530 companion chip. Most of |
279 | * this is just housekeeping. We have to set the chip up correctly and |
280 | * turn off various bits of emulation magic. |
281 | */ |
282 | |
283 | static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id) |
284 | { |
285 | static const struct ata_port_info info = { |
286 | .flags = ATA_FLAG_SLAVE_POSS, |
287 | .pio_mask = ATA_PIO4, |
288 | .mwdma_mask = ATA_MWDMA2, |
289 | .udma_mask = ATA_UDMA2, |
290 | .port_ops = &cs5530_port_ops |
291 | }; |
292 | /* The docking connector doesn't do UDMA, and it seems not MWDMA */ |
293 | static const struct ata_port_info info_palmax_secondary = { |
294 | .flags = ATA_FLAG_SLAVE_POSS, |
295 | .pio_mask = ATA_PIO4, |
296 | .port_ops = &cs5530_port_ops |
297 | }; |
298 | const struct ata_port_info *ppi[] = { &info, NULL }; |
299 | int rc; |
300 | |
301 | rc = pcim_enable_device(pdev); |
302 | if (rc) |
303 | return rc; |
304 | |
305 | /* Chip initialisation */ |
306 | if (cs5530_init_chip()) |
307 | return -ENODEV; |
308 | |
309 | if (cs5530_is_palmax()) |
310 | ppi[1] = &info_palmax_secondary; |
311 | |
312 | /* Now kick off ATA set up */ |
313 | return ata_pci_bmdma_init_one(pdev, ppi, sht: &cs5530_sht, NULL, hflags: 0); |
314 | } |
315 | |
316 | #ifdef CONFIG_PM_SLEEP |
317 | static int cs5530_reinit_one(struct pci_dev *pdev) |
318 | { |
319 | struct ata_host *host = pci_get_drvdata(pdev); |
320 | int rc; |
321 | |
322 | rc = ata_pci_device_do_resume(pdev); |
323 | if (rc) |
324 | return rc; |
325 | |
326 | /* If we fail on resume we are doomed */ |
327 | if (cs5530_init_chip()) |
328 | return -EIO; |
329 | |
330 | ata_host_resume(host); |
331 | return 0; |
332 | } |
333 | #endif /* CONFIG_PM_SLEEP */ |
334 | |
335 | static const struct pci_device_id cs5530[] = { |
336 | { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), }, |
337 | |
338 | { }, |
339 | }; |
340 | |
341 | static struct pci_driver cs5530_pci_driver = { |
342 | .name = DRV_NAME, |
343 | .id_table = cs5530, |
344 | .probe = cs5530_init_one, |
345 | .remove = ata_pci_remove_one, |
346 | #ifdef CONFIG_PM_SLEEP |
347 | .suspend = ata_pci_device_suspend, |
348 | .resume = cs5530_reinit_one, |
349 | #endif |
350 | }; |
351 | |
352 | module_pci_driver(cs5530_pci_driver); |
353 | |
354 | MODULE_AUTHOR("Alan Cox" ); |
355 | MODULE_DESCRIPTION("low-level driver for the Cyrix/NS/AMD 5530" ); |
356 | MODULE_LICENSE("GPL" ); |
357 | MODULE_DEVICE_TABLE(pci, cs5530); |
358 | MODULE_VERSION(DRV_VERSION); |
359 | |