1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * ixp4xx PATA/Compact Flash driver |
4 | * Copyright (C) 2006-07 Tower Technologies |
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> |
6 | * |
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 |
12 | * polling mode. |
13 | */ |
14 | |
15 | #include <linux/kernel.h> |
16 | #include <linux/mfd/syscon.h> |
17 | #include <linux/module.h> |
18 | #include <linux/libata.h> |
19 | #include <linux/irq.h> |
20 | #include <linux/of.h> |
21 | #include <linux/platform_device.h> |
22 | #include <linux/regmap.h> |
23 | #include <scsi/scsi_host.h> |
24 | |
25 | #define DRV_NAME "pata_ixp4xx_cf" |
26 | #define DRV_VERSION "1.0" |
27 | |
28 | struct ixp4xx_pata { |
29 | struct ata_host *host; |
30 | struct regmap *rmap; |
31 | u32 cmd_csreg; |
32 | void __iomem *cmd; |
33 | void __iomem *ctl; |
34 | }; |
35 | |
36 | #define IXP4XX_EXP_TIMING_STRIDE 0x04 |
37 | /* The timings for the chipselect is in bits 29..16 */ |
38 | #define IXP4XX_EXP_T1_T5_MASK GENMASK(29, 16) |
39 | #define IXP4XX_EXP_PIO_0_8 0x0a470000 |
40 | #define IXP4XX_EXP_PIO_1_8 0x06430000 |
41 | #define IXP4XX_EXP_PIO_2_8 0x02410000 |
42 | #define IXP4XX_EXP_PIO_3_8 0x00820000 |
43 | #define IXP4XX_EXP_PIO_4_8 0x00400000 |
44 | #define IXP4XX_EXP_PIO_0_16 0x29640000 |
45 | #define IXP4XX_EXP_PIO_1_16 0x05030000 |
46 | #define IXP4XX_EXP_PIO_2_16 0x00b20000 |
47 | #define IXP4XX_EXP_PIO_3_16 0x00820000 |
48 | #define IXP4XX_EXP_PIO_4_16 0x00400000 |
49 | #define IXP4XX_EXP_BW_MASK (BIT(6)|BIT(0)) |
50 | #define IXP4XX_EXP_BYTE_RD16 BIT(6) /* Byte reads on half-word devices */ |
51 | #define IXP4XX_EXP_BYTE_EN BIT(0) /* Use 8bit data bus if set */ |
52 | |
53 | static void ixp4xx_set_8bit_timing(struct ixp4xx_pata *ixpp, u8 pio_mode) |
54 | { |
55 | switch (pio_mode) { |
56 | case XFER_PIO_0: |
57 | regmap_update_bits(map: ixpp->rmap, reg: ixpp->cmd_csreg, |
58 | IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_0_8); |
59 | break; |
60 | case XFER_PIO_1: |
61 | regmap_update_bits(map: ixpp->rmap, reg: ixpp->cmd_csreg, |
62 | IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_1_8); |
63 | break; |
64 | case XFER_PIO_2: |
65 | regmap_update_bits(map: ixpp->rmap, reg: ixpp->cmd_csreg, |
66 | IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_2_8); |
67 | break; |
68 | case XFER_PIO_3: |
69 | regmap_update_bits(map: ixpp->rmap, reg: ixpp->cmd_csreg, |
70 | IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_3_8); |
71 | break; |
72 | case XFER_PIO_4: |
73 | regmap_update_bits(map: ixpp->rmap, reg: ixpp->cmd_csreg, |
74 | IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_4_8); |
75 | break; |
76 | default: |
77 | break; |
78 | } |
79 | regmap_update_bits(map: ixpp->rmap, reg: ixpp->cmd_csreg, |
80 | IXP4XX_EXP_BW_MASK, IXP4XX_EXP_BYTE_RD16|IXP4XX_EXP_BYTE_EN); |
81 | } |
82 | |
83 | static void ixp4xx_set_16bit_timing(struct ixp4xx_pata *ixpp, u8 pio_mode) |
84 | { |
85 | switch (pio_mode){ |
86 | case XFER_PIO_0: |
87 | regmap_update_bits(map: ixpp->rmap, reg: ixpp->cmd_csreg, |
88 | IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_0_16); |
89 | break; |
90 | case XFER_PIO_1: |
91 | regmap_update_bits(map: ixpp->rmap, reg: ixpp->cmd_csreg, |
92 | IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_1_16); |
93 | break; |
94 | case XFER_PIO_2: |
95 | regmap_update_bits(map: ixpp->rmap, reg: ixpp->cmd_csreg, |
96 | IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_2_16); |
97 | break; |
98 | case XFER_PIO_3: |
99 | regmap_update_bits(map: ixpp->rmap, reg: ixpp->cmd_csreg, |
100 | IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_3_16); |
101 | break; |
102 | case XFER_PIO_4: |
103 | regmap_update_bits(map: ixpp->rmap, reg: ixpp->cmd_csreg, |
104 | IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_4_16); |
105 | break; |
106 | default: |
107 | break; |
108 | } |
109 | regmap_update_bits(map: ixpp->rmap, reg: ixpp->cmd_csreg, |
110 | IXP4XX_EXP_BW_MASK, IXP4XX_EXP_BYTE_RD16); |
111 | } |
112 | |
113 | /* This sets up the timing on the chipselect CMD accordingly */ |
114 | static void ixp4xx_set_piomode(struct ata_port *ap, struct ata_device *adev) |
115 | { |
116 | struct ixp4xx_pata *ixpp = ap->host->private_data; |
117 | |
118 | ata_dev_info(adev, "configured for PIO%d 8bit\n" , |
119 | adev->pio_mode - XFER_PIO_0); |
120 | ixp4xx_set_8bit_timing(ixpp, pio_mode: adev->pio_mode); |
121 | } |
122 | |
123 | |
124 | static unsigned int ixp4xx_mmio_data_xfer(struct ata_queued_cmd *qc, |
125 | unsigned char *buf, unsigned int buflen, int rw) |
126 | { |
127 | unsigned int i; |
128 | unsigned int words = buflen >> 1; |
129 | u16 *buf16 = (u16 *) buf; |
130 | struct ata_device *adev = qc->dev; |
131 | struct ata_port *ap = qc->dev->link->ap; |
132 | void __iomem *mmio = ap->ioaddr.data_addr; |
133 | struct ixp4xx_pata *ixpp = ap->host->private_data; |
134 | unsigned long flags; |
135 | |
136 | ata_dev_dbg(adev, "%s %d bytes\n" , (rw == READ) ? "READ" : "WRITE" , |
137 | buflen); |
138 | spin_lock_irqsave(ap->lock, flags); |
139 | |
140 | /* set the expansion bus in 16bit mode and restore |
141 | * 8 bit mode after the transaction. |
142 | */ |
143 | ixp4xx_set_16bit_timing(ixpp, pio_mode: adev->pio_mode); |
144 | udelay(5); |
145 | |
146 | /* Transfer multiple of 2 bytes */ |
147 | if (rw == READ) |
148 | for (i = 0; i < words; i++) |
149 | buf16[i] = readw(addr: mmio); |
150 | else |
151 | for (i = 0; i < words; i++) |
152 | writew(val: buf16[i], addr: mmio); |
153 | |
154 | /* Transfer trailing 1 byte, if any. */ |
155 | if (unlikely(buflen & 0x01)) { |
156 | u16 align_buf[1] = { 0 }; |
157 | unsigned char *trailing_buf = buf + buflen - 1; |
158 | |
159 | if (rw == READ) { |
160 | align_buf[0] = readw(addr: mmio); |
161 | memcpy(trailing_buf, align_buf, 1); |
162 | } else { |
163 | memcpy(align_buf, trailing_buf, 1); |
164 | writew(val: align_buf[0], addr: mmio); |
165 | } |
166 | words++; |
167 | } |
168 | |
169 | ixp4xx_set_8bit_timing(ixpp, pio_mode: adev->pio_mode); |
170 | udelay(5); |
171 | |
172 | spin_unlock_irqrestore(lock: ap->lock, flags); |
173 | |
174 | return words << 1; |
175 | } |
176 | |
177 | static const struct scsi_host_template ixp4xx_sht = { |
178 | ATA_PIO_SHT(DRV_NAME), |
179 | }; |
180 | |
181 | static struct ata_port_operations ixp4xx_port_ops = { |
182 | .inherits = &ata_sff_port_ops, |
183 | .sff_data_xfer = ixp4xx_mmio_data_xfer, |
184 | .cable_detect = ata_cable_40wire, |
185 | .set_piomode = ixp4xx_set_piomode, |
186 | }; |
187 | |
188 | static struct ata_port_info ixp4xx_port_info = { |
189 | .flags = ATA_FLAG_NO_ATAPI, |
190 | .pio_mask = ATA_PIO4, |
191 | .port_ops = &ixp4xx_port_ops, |
192 | }; |
193 | |
194 | static void ixp4xx_setup_port(struct ata_port *ap, |
195 | struct ixp4xx_pata *ixpp, |
196 | unsigned long raw_cmd, unsigned long raw_ctl) |
197 | { |
198 | struct ata_ioports *ioaddr = &ap->ioaddr; |
199 | |
200 | raw_ctl += 0x06; |
201 | ioaddr->cmd_addr = ixpp->cmd; |
202 | ioaddr->altstatus_addr = ixpp->ctl + 0x06; |
203 | ioaddr->ctl_addr = ixpp->ctl + 0x06; |
204 | |
205 | ata_sff_std_ports(ioaddr); |
206 | |
207 | if (!IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) { |
208 | /* adjust the addresses to handle the address swizzling of the |
209 | * ixp4xx in little endian mode. |
210 | */ |
211 | |
212 | *(unsigned long *)&ioaddr->data_addr ^= 0x02; |
213 | *(unsigned long *)&ioaddr->cmd_addr ^= 0x03; |
214 | *(unsigned long *)&ioaddr->altstatus_addr ^= 0x03; |
215 | *(unsigned long *)&ioaddr->ctl_addr ^= 0x03; |
216 | *(unsigned long *)&ioaddr->error_addr ^= 0x03; |
217 | *(unsigned long *)&ioaddr->feature_addr ^= 0x03; |
218 | *(unsigned long *)&ioaddr->nsect_addr ^= 0x03; |
219 | *(unsigned long *)&ioaddr->lbal_addr ^= 0x03; |
220 | *(unsigned long *)&ioaddr->lbam_addr ^= 0x03; |
221 | *(unsigned long *)&ioaddr->lbah_addr ^= 0x03; |
222 | *(unsigned long *)&ioaddr->device_addr ^= 0x03; |
223 | *(unsigned long *)&ioaddr->status_addr ^= 0x03; |
224 | *(unsigned long *)&ioaddr->command_addr ^= 0x03; |
225 | |
226 | raw_cmd ^= 0x03; |
227 | raw_ctl ^= 0x03; |
228 | } |
229 | |
230 | ata_port_desc(ap, fmt: "cmd 0x%lx ctl 0x%lx" , raw_cmd, raw_ctl); |
231 | } |
232 | |
233 | static int ixp4xx_pata_probe(struct platform_device *pdev) |
234 | { |
235 | struct resource *cmd, *ctl; |
236 | struct ata_port_info pi = ixp4xx_port_info; |
237 | const struct ata_port_info *ppi[] = { &pi, NULL }; |
238 | struct device *dev = &pdev->dev; |
239 | struct device_node *np = dev->of_node; |
240 | struct ixp4xx_pata *ixpp; |
241 | u32 csindex; |
242 | int ret; |
243 | int irq; |
244 | |
245 | ixpp = devm_kzalloc(dev, size: sizeof(*ixpp), GFP_KERNEL); |
246 | if (!ixpp) |
247 | return -ENOMEM; |
248 | |
249 | ixpp->rmap = syscon_node_to_regmap(np: np->parent); |
250 | if (IS_ERR(ptr: ixpp->rmap)) |
251 | return dev_err_probe(dev, err: PTR_ERR(ptr: ixpp->rmap), fmt: "no regmap\n" ); |
252 | /* Inspect our address to figure out what chipselect the CMD is on */ |
253 | ret = of_property_read_u32_index(np, propname: "reg" , index: 0, out_value: &csindex); |
254 | if (ret) |
255 | return dev_err_probe(dev, err: ret, fmt: "can't inspect CMD address\n" ); |
256 | dev_info(dev, "using CS%d for PIO timing configuration\n" , csindex); |
257 | ixpp->cmd_csreg = csindex * IXP4XX_EXP_TIMING_STRIDE; |
258 | |
259 | ixpp->host = ata_host_alloc_pinfo(dev, ppi, n_ports: 1); |
260 | if (!ixpp->host) |
261 | return -ENOMEM; |
262 | ixpp->host->private_data = ixpp; |
263 | |
264 | ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); |
265 | if (ret) |
266 | return ret; |
267 | |
268 | ixpp->cmd = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &cmd); |
269 | if (IS_ERR(ptr: ixpp->cmd)) |
270 | return PTR_ERR(ptr: ixpp->cmd); |
271 | |
272 | ixpp->ctl = devm_platform_get_and_ioremap_resource(pdev, index: 1, res: &ctl); |
273 | if (IS_ERR(ptr: ixpp->ctl)) |
274 | return PTR_ERR(ptr: ixpp->ctl); |
275 | |
276 | irq = platform_get_irq(pdev, 0); |
277 | if (irq < 0) |
278 | return irq; |
279 | irq_set_irq_type(irq, type: IRQ_TYPE_EDGE_RISING); |
280 | |
281 | /* Just one port to set up */ |
282 | ixp4xx_setup_port(ap: ixpp->host->ports[0], ixpp, raw_cmd: cmd->start, raw_ctl: ctl->start); |
283 | |
284 | ata_print_version_once(dev, DRV_VERSION); |
285 | |
286 | return ata_host_activate(host: ixpp->host, irq, irq_handler: ata_sff_interrupt, irq_flags: 0, sht: &ixp4xx_sht); |
287 | } |
288 | |
289 | static const struct of_device_id ixp4xx_pata_of_match[] = { |
290 | { .compatible = "intel,ixp4xx-compact-flash" , }, |
291 | { /* sentinel */ } |
292 | }; |
293 | |
294 | static struct platform_driver ixp4xx_pata_platform_driver = { |
295 | .driver = { |
296 | .name = DRV_NAME, |
297 | .of_match_table = ixp4xx_pata_of_match, |
298 | }, |
299 | .probe = ixp4xx_pata_probe, |
300 | .remove_new = ata_platform_remove_one, |
301 | }; |
302 | |
303 | module_platform_driver(ixp4xx_pata_platform_driver); |
304 | |
305 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>" ); |
306 | MODULE_DESCRIPTION("low-level driver for ixp4xx Compact Flash PATA" ); |
307 | MODULE_LICENSE("GPL" ); |
308 | MODULE_VERSION(DRV_VERSION); |
309 | MODULE_ALIAS("platform:" DRV_NAME); |
310 | |