48d2d44ee66735cbbaa69f905776bec55f10207f
[openwrt.git] / target / linux / ppc40x / patches / 101-pata-magicbox-cf-driver.patch
1 --- a/drivers/ata/Kconfig
2 +++ b/drivers/ata/Kconfig
3 @@ -697,6 +697,16 @@ config PATA_IXP4XX_CF
4  
5           If unsure, say N.
6  
7 +config PATA_MAGICBOX_CF
8 +       tristate "Magicbox/OpenRB Compact lash support"
9 +       depends on MAGICBOXV2 || OPENRB_LIGHT
10 +       help
11 +         This option enables supoort for a Compatc Flash connected on
12 +         the ppc405ep expansion bus. This driver had been written for
13 +         the Magicbox v2 and OpenRB boards.
14 +
15 +         If unsure, say N.
16 +
17  config PATA_SCC
18         tristate "Toshiba's Cell Reference Set IDE support"
19         depends on PCI && PPC_CELLEB
20 --- a/drivers/ata/Makefile
21 +++ b/drivers/ata/Makefile
22 @@ -48,6 +48,7 @@ obj-$(CONFIG_PATA_OPTI)               += pata_opti.o
23  obj-$(CONFIG_PATA_OPTIDMA)     += pata_optidma.o
24  obj-$(CONFIG_PATA_MPC52xx)     += pata_mpc52xx.o
25  obj-$(CONFIG_PATA_MARVELL)     += pata_marvell.o
26 +obj-$(CONFIG_PATA_MAGICBOX_CF) += pata_magicbox_cf.o
27  obj-$(CONFIG_PATA_MPIIX)       += pata_mpiix.o
28  obj-$(CONFIG_PATA_OLDPIIX)     += pata_oldpiix.o
29  obj-$(CONFIG_PATA_PCMCIA)      += pata_pcmcia.o
30 --- /dev/null
31 +++ b/drivers/ata/pata_magicbox_cf.c
32 @@ -0,0 +1,406 @@
33 +/*
34 + *  PATA/CompactFlash driver for the MagicBox v2/OpenRB boards.
35 + *
36 + *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
37 + *
38 + *  Based on the IDE driver by Wojtek Kaniewski <wojtekka@toxygen.net>
39 + *
40 + *  This program is free software; you can redistribute it and/or modify it
41 + *  under the terms of the GNU General Public License version 2 as published
42 + *  by the Free Software Foundation.
43 + */
44 +
45 +#include <linux/kernel.h>
46 +#include <linux/module.h>
47 +#include <linux/types.h>
48 +#include <linux/ioport.h>
49 +#include <linux/libata.h>
50 +#include <linux/irq.h>
51 +#include <linux/of.h>
52 +#include <linux/of_device.h>
53 +#include <linux/of_platform.h>
54 +#include <scsi/scsi_host.h>
55 +
56 +#define DRV_DESC       "PATA/CompactFlash driver for Magicbox/OpenRB boards"
57 +#define DRV_NAME       "pata_magicbox_cf"
58 +#define DRV_VERSION    "0.1.0"
59 +
60 +#define MAGICBOX_CF_REG_CMD            (2 * ATA_REG_CMD)
61 +#define MAGICBOX_CF_REG_DATA           (2 * ATA_REG_DATA)
62 +#define MAGICBOX_CF_REG_ERR            (2 * ATA_REG_ERR)
63 +#define MAGICBOX_CF_REG_FEATURE        (2 * ATA_REG_FEATURE)
64 +#define MAGICBOX_CF_REG_NSECT          (2 * ATA_REG_NSECT)
65 +#define MAGICBOX_CF_REG_LBAL           (2 * ATA_REG_LBAL)
66 +#define MAGICBOX_CF_REG_LBAM           (2 * ATA_REG_LBAM)
67 +#define MAGICBOX_CF_REG_LBAH           (2 * ATA_REG_LBAH)
68 +#define MAGICBOX_CF_REG_DEVICE         (2 * ATA_REG_DEVICE)
69 +#define MAGICBOX_CF_REG_STATUS         (2 * ATA_REG_STATUS)
70 +#define MAGICBOX_CF_REG_ALTSTATUS      (2 * 6)
71 +#define MAGICBOX_CF_REG_CTL            (2 * 6)
72 +
73 +#define MAGICBOX_CF_MAXPORTS   1
74 +
75 +struct magicbox_cf_info {
76 +       void __iomem    *base;
77 +       void __iomem    *ctrl;
78 +};
79 +
80 +static inline u8 magicbox_cf_inb(void __iomem *port)
81 +{
82 +       return (u8) (readw(port) >> 8) & 0xff;
83 +}
84 +
85 +static inline void magicbox_cf_outb(void __iomem *port, u8 value)
86 +{
87 +       writew(value << 8, port);
88 +}
89 +
90 +static int magicbox_cf_set_mode(struct ata_link *link,
91 +                               struct ata_device **error)
92 +{
93 +       struct ata_device *dev;
94 +
95 +       ata_link_for_each_dev(dev, link) {
96 +               if (ata_dev_enabled(dev)) {
97 +                       ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
98 +                       dev->pio_mode = XFER_PIO_0;
99 +                       dev->xfer_mode = XFER_PIO_0;
100 +                       dev->xfer_shift = ATA_SHIFT_PIO;
101 +                       dev->flags |= ATA_DFLAG_PIO;
102 +               }
103 +       }
104 +
105 +       return 0;
106 +}
107 +
108 +static void magicbox_cf_exec_command(struct ata_port *ap,
109 +                                    const struct ata_taskfile *tf)
110 +{
111 +       DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
112 +
113 +       magicbox_cf_outb(ap->ioaddr.command_addr, tf->command);
114 +       ata_sff_pause(ap);
115 +}
116 +
117 +static u8 magicbox_cf_check_status(struct ata_port *ap)
118 +{
119 +       u8 status;
120 +
121 +       status = magicbox_cf_inb(ap->ioaddr.status_addr);
122 +
123 +       DPRINTK("ata%u: status 0x%X, from %p\n", ap->print_id, status,
124 +               ap->ioaddr.status_addr);
125 +
126 +       return status;
127 +}
128 +
129 +static u8 magicbox_cf_check_altstatus(struct ata_port *ap)
130 +{
131 +       u8 altstatus;
132 +
133 +       altstatus = magicbox_cf_inb(ap->ioaddr.altstatus_addr);
134 +
135 +       DPRINTK("ata%u: altstatus 0x%X, from %p\n", ap->print_id,
136 +               altstatus, ap->ioaddr.altstatus_addr);
137 +
138 +       return altstatus;
139 +}
140 +
141 +static void magicbox_cf_dev_select(struct ata_port *ap, unsigned int device)
142 +{
143 +       /* Nothing to do. We are supporting one device only. */
144 +}
145 +
146 +static void magicbox_cf_tf_load(struct ata_port *ap,
147 +                               const struct ata_taskfile *tf)
148 +{
149 +       struct ata_ioports *ioaddr = &ap->ioaddr;
150 +       unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
151 +
152 +       if (tf->ctl != ap->last_ctl) {
153 +               magicbox_cf_outb(ioaddr->ctl_addr, tf->ctl);
154 +               ap->last_ctl = tf->ctl;
155 +               ata_wait_idle(ap);
156 +       }
157 +
158 +       if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
159 +               magicbox_cf_outb(ioaddr->feature_addr, tf->hob_feature);
160 +               magicbox_cf_outb(ioaddr->nsect_addr, tf->hob_nsect);
161 +               magicbox_cf_outb(ioaddr->lbal_addr, tf->hob_lbal);
162 +               magicbox_cf_outb(ioaddr->lbam_addr, tf->hob_lbam);
163 +               magicbox_cf_outb(ioaddr->lbah_addr, tf->hob_lbah);
164 +               VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
165 +                       tf->hob_feature,
166 +                       tf->hob_nsect,
167 +                       tf->hob_lbal,
168 +                       tf->hob_lbam,
169 +                       tf->hob_lbah);
170 +       }
171 +
172 +       if (is_addr) {
173 +               magicbox_cf_outb(ioaddr->feature_addr, tf->feature);
174 +               magicbox_cf_outb(ioaddr->nsect_addr, tf->nsect);
175 +               magicbox_cf_outb(ioaddr->lbal_addr, tf->lbal);
176 +               magicbox_cf_outb(ioaddr->lbam_addr, tf->lbam);
177 +               magicbox_cf_outb(ioaddr->lbah_addr, tf->lbah);
178 +               VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
179 +                       tf->feature,
180 +                       tf->nsect,
181 +                       tf->lbal,
182 +                       tf->lbam,
183 +                       tf->lbah);
184 +       }
185 +
186 +       if (tf->flags & ATA_TFLAG_DEVICE) {
187 +               magicbox_cf_outb(ioaddr->device_addr, tf->device);
188 +               VPRINTK("device 0x%X\n", tf->device);
189 +       }
190 +
191 +       ata_wait_idle(ap);
192 +}
193 +
194 +static void magicbox_cf_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
195 +{
196 +       struct ata_ioports *ioaddr = &ap->ioaddr;
197 +
198 +       tf->command = magicbox_cf_inb(ap->ioaddr.status_addr);
199 +       tf->feature = magicbox_cf_inb(ioaddr->error_addr);
200 +       tf->nsect = magicbox_cf_inb(ioaddr->nsect_addr);
201 +       tf->lbal = magicbox_cf_inb(ioaddr->lbal_addr);
202 +       tf->lbam = magicbox_cf_inb(ioaddr->lbam_addr);
203 +       tf->lbah = magicbox_cf_inb(ioaddr->lbah_addr);
204 +       tf->device = magicbox_cf_inb(ioaddr->device_addr);
205 +       VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
206 +               tf->feature,
207 +               tf->nsect,
208 +               tf->lbal,
209 +               tf->lbam,
210 +               tf->lbah);
211 +
212 +       if (tf->flags & ATA_TFLAG_LBA48) {
213 +               magicbox_cf_outb(ioaddr->ctl_addr, tf->ctl | ATA_HOB);
214 +               tf->hob_feature = magicbox_cf_inb(ioaddr->error_addr);
215 +               tf->hob_nsect = magicbox_cf_inb(ioaddr->nsect_addr);
216 +               tf->hob_lbal = magicbox_cf_inb(ioaddr->lbal_addr);
217 +               tf->hob_lbam = magicbox_cf_inb(ioaddr->lbam_addr);
218 +               tf->hob_lbah = magicbox_cf_inb(ioaddr->lbah_addr);
219 +               magicbox_cf_outb(ioaddr->ctl_addr, tf->ctl);
220 +               ap->last_ctl = tf->ctl;
221 +               VPRINTK("hob: feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
222 +                       tf->feature,
223 +                       tf->nsect,
224 +                       tf->lbal,
225 +                       tf->lbam,
226 +                       tf->lbah);
227 +       }
228 +}
229 +
230 +static unsigned int magicbox_cf_data_xfer(struct ata_device *dev,
231 +                                         unsigned char *buf,
232 +                                         unsigned int buflen, int rw)
233 +{
234 +       struct ata_port *ap = dev->link->ap;
235 +       unsigned int words = buflen >> 1;
236 +       unsigned int i;
237 +       u16 *buf16 = (u16 *) buf;
238 +       void __iomem *mmio = ap->ioaddr.data_addr;
239 +
240 +       /* Transfer multiple of 2 bytes */
241 +       if (rw == READ)
242 +               for (i = 0; i < words; i++)
243 +                       buf16[i] = readw(mmio);
244 +       else
245 +               for (i = 0; i < words; i++)
246 +                       writew(buf16[i], mmio);
247 +
248 +       /* Transfer trailing 1 byte, if any. */
249 +       if (unlikely(buflen & 0x01)) {
250 +               u16 align_buf[1] = { 0 };
251 +               unsigned char *trailing_buf = buf + buflen - 1;
252 +
253 +               if (rw == READ) {
254 +                       align_buf[0] = readw(mmio);
255 +                       memcpy(trailing_buf, align_buf, 1);
256 +               } else {
257 +                       memcpy(align_buf, trailing_buf, 1);
258 +                       writew(align_buf[0], mmio);
259 +               }
260 +               words++;
261 +       }
262 +
263 +       return words << 1;
264 +}
265 +
266 +static u8 magicbox_cf_irq_on(struct ata_port *ap)
267 +{
268 +       /* Nothing to do. */
269 +       return 0;
270 +}
271 +
272 +static void magicbox_cf_irq_clear(struct ata_port *ap)
273 +{
274 +       /* Nothing to do. */
275 +}
276 +
277 +static struct ata_port_operations magicbox_cf_port_ops = {
278 +       .inherits               = &ata_sff_port_ops,
279 +
280 +       .cable_detect           = ata_cable_40wire,
281 +       .set_mode               = magicbox_cf_set_mode,
282 +
283 +       .sff_exec_command       = magicbox_cf_exec_command,
284 +       .sff_check_status       = magicbox_cf_check_status,
285 +       .sff_check_altstatus    = magicbox_cf_check_altstatus,
286 +       .sff_dev_select         = magicbox_cf_dev_select,
287 +       .sff_tf_load            = magicbox_cf_tf_load,
288 +       .sff_tf_read            = magicbox_cf_tf_read,
289 +       .sff_data_xfer          = magicbox_cf_data_xfer,
290 +
291 +       .sff_irq_on             = magicbox_cf_irq_on,
292 +       .sff_irq_clear          = magicbox_cf_irq_clear,
293 +
294 +       .port_start             = ATA_OP_NULL,
295 +};
296 +
297 +static struct scsi_host_template magicbox_cf_sht = {
298 +       ATA_PIO_SHT(DRV_NAME),
299 +};
300 +
301 +static inline void magicbox_cf_setup_port(struct ata_host *host)
302 +{
303 +       struct magicbox_cf_info *info = host->private_data;
304 +       struct ata_port *ap;
305 +
306 +       ap = host->ports[0];
307 +
308 +       ap->ops = &magicbox_cf_port_ops;
309 +       ap->pio_mask = ATA_PIO4;
310 +       ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI;
311 +
312 +       ap->ioaddr.cmd_addr = info->base + MAGICBOX_CF_REG_CMD;
313 +       ap->ioaddr.data_addr = info->base + MAGICBOX_CF_REG_DATA;
314 +       ap->ioaddr.error_addr = info->base + MAGICBOX_CF_REG_ERR;
315 +       ap->ioaddr.feature_addr = info->base + MAGICBOX_CF_REG_FEATURE;
316 +       ap->ioaddr.nsect_addr = info->base + MAGICBOX_CF_REG_NSECT;
317 +       ap->ioaddr.lbal_addr = info->base + MAGICBOX_CF_REG_LBAL;
318 +       ap->ioaddr.lbam_addr = info->base + MAGICBOX_CF_REG_LBAM;
319 +       ap->ioaddr.lbah_addr = info->base + MAGICBOX_CF_REG_LBAH;
320 +       ap->ioaddr.device_addr = info->base + MAGICBOX_CF_REG_DEVICE;
321 +       ap->ioaddr.status_addr = info->base + MAGICBOX_CF_REG_STATUS;
322 +       ap->ioaddr.command_addr = info->base + MAGICBOX_CF_REG_CMD;
323 +
324 +       ap->ioaddr.altstatus_addr = info->ctrl + MAGICBOX_CF_REG_ALTSTATUS;
325 +       ap->ioaddr.ctl_addr = info->ctrl + MAGICBOX_CF_REG_CTL;
326 +
327 +       ata_port_desc(ap, "cmd 0x%p ctl 0x%p", ap->ioaddr.cmd_addr,
328 +                     ap->ioaddr.ctl_addr);
329 +}
330 +
331 +static int __devinit magicbox_cf_of_probe(struct of_device *op,
332 +                                          const struct of_device_id *match)
333 +{
334 +       struct magicbox_cf_info *info;
335 +       struct ata_host *host;
336 +       int irq;
337 +       int ret = 0;
338 +
339 +       info = kzalloc(sizeof(struct magicbox_cf_info), GFP_KERNEL);
340 +       if (info == NULL) {
341 +               ret = -ENOMEM;
342 +               goto err_exit;
343 +       }
344 +
345 +       irq = irq_of_parse_and_map(op->node, 0);
346 +       if (irq < 0) {
347 +               dev_err(&op->dev, "invalid irq\n");
348 +               ret = -EINVAL;
349 +               goto err_free_info;
350 +       }
351 +
352 +       info->base = of_iomap(op->node, 0);
353 +       if (info->base == NULL) {
354 +               ret = -ENOMEM;
355 +               goto err_free_info;
356 +       }
357 +
358 +       info->ctrl = of_iomap(op->node, 1);
359 +       if (info->ctrl == NULL) {
360 +               ret = -ENOMEM;
361 +               goto err_unmap_base;
362 +       }
363 +
364 +       host = ata_host_alloc(&op->dev, MAGICBOX_CF_MAXPORTS);
365 +       if (host == NULL) {
366 +               ret = -ENOMEM;
367 +               goto err_unmap_ctrl;
368 +       }
369 +
370 +       host->private_data = info;
371 +       magicbox_cf_setup_port(host);
372 +
373 +       ret = ata_host_activate(host, irq, ata_sff_interrupt,
374 +                               IRQF_TRIGGER_RISING, &magicbox_cf_sht);
375 +       if (ret)
376 +               goto err_unmap_ctrl;
377 +
378 +       dev_set_drvdata(&op->dev, host);
379 +       return 0;
380 +
381 + err_unmap_ctrl:
382 +       iounmap(info->ctrl);
383 + err_unmap_base:
384 +       iounmap(info->base);
385 + err_free_info:
386 +       kfree(info);
387 + err_exit:
388 +       return ret;
389 +}
390 +
391 +static __devexit int magicbox_cf_of_remove(struct of_device *op)
392 +{
393 +       struct ata_host *host = dev_get_drvdata(&op->dev);
394 +       struct magicbox_cf_info *info = host->private_data;
395 +
396 +       ata_host_detach(host);
397 +       iounmap(info->ctrl);
398 +       iounmap(info->base);
399 +       kfree(info);
400 +
401 +       return 0;
402 +}
403 +
404 +static struct of_device_id magicbox_cf_of_match[] = {
405 +       { .compatible = "pata-magicbox-cf", },
406 +       {},
407 +};
408 +
409 +static struct of_platform_driver magicbox_cf_of_platform_driver = {
410 +       .owner          = THIS_MODULE,
411 +       .name           = DRV_NAME,
412 +       .match_table    = magicbox_cf_of_match,
413 +       .probe          = magicbox_cf_of_probe,
414 +       .remove         = __devexit_p(magicbox_cf_of_remove),
415 +       .driver         = {
416 +               .name   = DRV_NAME,
417 +               .owner  = THIS_MODULE,
418 +       },
419 +};
420 +
421 +static int __init magicbox_cf_init(void)
422 +{
423 +       return of_register_platform_driver(&magicbox_cf_of_platform_driver);
424 +}
425 +
426 +static void __exit magicbox_cf_exit(void)
427 +{
428 +       of_unregister_platform_driver(&magicbox_cf_of_platform_driver);
429 +}
430 +
431 +module_init(magicbox_cf_init);
432 +module_exit(magicbox_cf_exit);
433 +
434 +MODULE_DESCRIPTION(DRV_DESC);
435 +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
436 +MODULE_LICENSE("GPL v2");
437 +MODULE_VERSION(DRV_VERSION);
438 +MODULE_DEVICE_TABLE(of, magicbox_cf_of_match);