1 // SPDX-License-Identifier: GPL-2.0-only
3 * ixp4xx PATA/Compact Flash driver
4 * Copyright (C) 2006-07 Tower Technologies
5 * Author: Alessandro Zummo <a.zummo@towertech.it>
7 * An ATA driver to handle a Compact Flash connected
8 * to the ixp4xx expansion bus in TrueIDE mode. The CF
9 * must have it chip selects connected to two CS lines
10 * on the ixp4xx. In the irq is not available, you might
11 * want to modify both this driver and libata to run in
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/libata.h>
18 #include <linux/irq.h>
19 #include <linux/platform_device.h>
20 #include <scsi/scsi_host.h>
22 #define DRV_NAME "pata_ixp4xx_cf"
23 #define DRV_VERSION "0.2"
25 static int ixp4xx_set_mode(struct ata_link
*link
, struct ata_device
**error
)
27 struct ata_device
*dev
;
29 ata_for_each_dev(dev
, link
, ENABLED
) {
30 ata_dev_info(dev
, "configured for PIO0\n");
31 dev
->pio_mode
= XFER_PIO_0
;
32 dev
->xfer_mode
= XFER_PIO_0
;
33 dev
->xfer_shift
= ATA_SHIFT_PIO
;
34 dev
->flags
|= ATA_DFLAG_PIO
;
39 static unsigned int ixp4xx_mmio_data_xfer(struct ata_queued_cmd
*qc
,
40 unsigned char *buf
, unsigned int buflen
, int rw
)
43 unsigned int words
= buflen
>> 1;
44 u16
*buf16
= (u16
*) buf
;
45 struct ata_port
*ap
= qc
->dev
->link
->ap
;
46 void __iomem
*mmio
= ap
->ioaddr
.data_addr
;
47 struct ixp4xx_pata_data
*data
= dev_get_platdata(ap
->host
->dev
);
49 /* set the expansion bus in 16bit mode and restore
50 * 8 bit mode after the transaction.
52 *data
->cs0_cfg
&= ~(0x01);
55 /* Transfer multiple of 2 bytes */
57 for (i
= 0; i
< words
; i
++)
58 buf16
[i
] = readw(mmio
);
60 for (i
= 0; i
< words
; i
++)
61 writew(buf16
[i
], mmio
);
63 /* Transfer trailing 1 byte, if any. */
64 if (unlikely(buflen
& 0x01)) {
65 u16 align_buf
[1] = { 0 };
66 unsigned char *trailing_buf
= buf
+ buflen
- 1;
69 align_buf
[0] = readw(mmio
);
70 memcpy(trailing_buf
, align_buf
, 1);
72 memcpy(align_buf
, trailing_buf
, 1);
73 writew(align_buf
[0], mmio
);
79 *data
->cs0_cfg
|= 0x01;
84 static struct scsi_host_template ixp4xx_sht
= {
85 ATA_PIO_SHT(DRV_NAME
),
88 static struct ata_port_operations ixp4xx_port_ops
= {
89 .inherits
= &ata_sff_port_ops
,
90 .sff_data_xfer
= ixp4xx_mmio_data_xfer
,
91 .cable_detect
= ata_cable_40wire
,
92 .set_mode
= ixp4xx_set_mode
,
95 static void ixp4xx_setup_port(struct ata_port
*ap
,
96 struct ixp4xx_pata_data
*data
,
97 unsigned long raw_cs0
, unsigned long raw_cs1
)
99 struct ata_ioports
*ioaddr
= &ap
->ioaddr
;
100 unsigned long raw_cmd
= raw_cs0
;
101 unsigned long raw_ctl
= raw_cs1
+ 0x06;
103 ioaddr
->cmd_addr
= data
->cs0
;
104 ioaddr
->altstatus_addr
= data
->cs1
+ 0x06;
105 ioaddr
->ctl_addr
= data
->cs1
+ 0x06;
107 ata_sff_std_ports(ioaddr
);
111 /* adjust the addresses to handle the address swizzling of the
112 * ixp4xx in little endian mode.
115 *(unsigned long *)&ioaddr
->data_addr
^= 0x02;
116 *(unsigned long *)&ioaddr
->cmd_addr
^= 0x03;
117 *(unsigned long *)&ioaddr
->altstatus_addr
^= 0x03;
118 *(unsigned long *)&ioaddr
->ctl_addr
^= 0x03;
119 *(unsigned long *)&ioaddr
->error_addr
^= 0x03;
120 *(unsigned long *)&ioaddr
->feature_addr
^= 0x03;
121 *(unsigned long *)&ioaddr
->nsect_addr
^= 0x03;
122 *(unsigned long *)&ioaddr
->lbal_addr
^= 0x03;
123 *(unsigned long *)&ioaddr
->lbam_addr
^= 0x03;
124 *(unsigned long *)&ioaddr
->lbah_addr
^= 0x03;
125 *(unsigned long *)&ioaddr
->device_addr
^= 0x03;
126 *(unsigned long *)&ioaddr
->status_addr
^= 0x03;
127 *(unsigned long *)&ioaddr
->command_addr
^= 0x03;
133 ata_port_desc(ap
, "cmd 0x%lx ctl 0x%lx", raw_cmd
, raw_ctl
);
136 static int ixp4xx_pata_probe(struct platform_device
*pdev
)
139 struct resource
*cs0
, *cs1
;
140 struct ata_host
*host
;
142 struct ixp4xx_pata_data
*data
= dev_get_platdata(&pdev
->dev
);
145 cs0
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
146 cs1
= platform_get_resource(pdev
, IORESOURCE_MEM
, 1);
152 host
= ata_host_alloc(&pdev
->dev
, 1);
156 /* acquire resources and fill host */
157 ret
= dma_set_coherent_mask(&pdev
->dev
, DMA_BIT_MASK(32));
161 data
->cs0
= devm_ioremap(&pdev
->dev
, cs0
->start
, 0x1000);
162 data
->cs1
= devm_ioremap(&pdev
->dev
, cs1
->start
, 0x1000);
164 if (!data
->cs0
|| !data
->cs1
)
167 irq
= platform_get_irq(pdev
, 0);
169 irq_set_irq_type(irq
, IRQ_TYPE_EDGE_RISING
);
171 /* Setup expansion bus chip selects */
172 *data
->cs0_cfg
= data
->cs0_bits
;
173 *data
->cs1_cfg
= data
->cs1_bits
;
177 ap
->ops
= &ixp4xx_port_ops
;
178 ap
->pio_mask
= ATA_PIO4
;
179 ap
->flags
|= ATA_FLAG_NO_ATAPI
;
181 ixp4xx_setup_port(ap
, data
, cs0
->start
, cs1
->start
);
183 ata_print_version_once(&pdev
->dev
, DRV_VERSION
);
186 return ata_host_activate(host
, irq
, ata_sff_interrupt
, 0, &ixp4xx_sht
);
189 static struct platform_driver ixp4xx_pata_platform_driver
= {
193 .probe
= ixp4xx_pata_probe
,
194 .remove
= ata_platform_remove_one
,
197 module_platform_driver(ixp4xx_pata_platform_driver
);
199 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
200 MODULE_DESCRIPTION("low-level driver for ixp4xx Compact Flash PATA");
201 MODULE_LICENSE("GPL");
202 MODULE_VERSION(DRV_VERSION
);
203 MODULE_ALIAS("platform:" DRV_NAME
);