Add NAND flash/YAFFS2 patches for RB532 by David Goodenough
[openwrt.git] / target / linux / rb532-2.6 / patches / 120-cf.patch
1 diff -urN linux.old/drivers/block/Kconfig linux.dev/drivers/block/Kconfig
2 --- linux.old/drivers/block/Kconfig     2006-10-26 02:43:39.000000000 +0200
3 +++ linux.dev/drivers/block/Kconfig     2006-10-26 00:11:14.000000000 +0200
4 @@ -456,4 +456,12 @@
5         This driver provides Support for ATA over Ethernet block
6         devices like the Coraid EtherDrive (R) Storage Blade.
7  
8 +config BLK_DEV_CF_MIPS
9 +       bool "CF slot of RB532 board"
10 +       depends on MIKROTIK_RB500
11 +       default y
12 +       help
13 +         The Routerboard 532 has a CF slot on it. Enable the special block
14 +         device driver for it.
15 +
16  endmenu
17 diff -urN linux.old/drivers/block/Makefile linux.dev/drivers/block/Makefile
18 --- linux.old/drivers/block/Makefile    2006-06-18 03:49:35.000000000 +0200
19 +++ linux.dev/drivers/block/Makefile    2006-10-26 02:44:10.000000000 +0200
20 @@ -29,4 +29,5 @@
21  obj-$(CONFIG_VIODASD)          += viodasd.o
22  obj-$(CONFIG_BLK_DEV_SX8)      += sx8.o
23  obj-$(CONFIG_BLK_DEV_UB)       += ub.o
24 +obj-$(CONFIG_BLK_DEV_CF_MIPS)  += rb500/
25  
26 diff -urN linux.old/drivers/block/rb500/ata.c linux.dev/drivers/block/rb500/ata.c
27 --- linux.old/drivers/block/rb500/ata.c 1970-01-01 01:00:00.000000000 +0100
28 +++ linux.dev/drivers/block/rb500/ata.c 2006-10-26 00:11:14.000000000 +0200
29 @@ -0,0 +1,474 @@
30 +#include <linux/kernel.h>      /* printk() */
31 +#include <linux/module.h>      /* module to be loadable */
32 +#include <linux/delay.h>
33 +#include <linux/sched.h>
34 +#include <linux/pci.h>
35 +#include <linux/ioport.h>      /* request_mem_region() */
36 +#include <asm/unaligned.h>             /* ioremap() */
37 +#include <asm/io.h>            /* ioremap() */
38 +#include <asm/rc32434/rb.h>
39 +
40 +#include "ata.h"
41 +
42 +#define REQUEST_MEM_REGION 0
43 +#define DEBUG 1
44 +
45 +#if DEBUG
46 +#define DEBUGP printk
47 +#else
48 +#define DEBUGP(format, args...)
49 +#endif
50 +
51 +#define SECS   1000000         /* unit for wait_not_busy() is 1us */
52 +
53 +unsigned cf_head = 0;
54 +unsigned cf_cyl = 0;
55 +unsigned cf_spt = 0;
56 +unsigned cf_sectors = 0;
57 +static unsigned cf_block_size = 1;
58 +static void *baddr = 0;
59 +
60 +#define DBUF32 ((volatile u32 *)((unsigned long)dev->baddr | ATA_DBUF_OFFSET))
61 +
62 +
63 +static void cf_do_tasklet(unsigned long dev_l);
64 +
65 +
66 +static inline void wareg(u8 val, unsigned reg, struct cf_mips_dev* dev)
67 +{
68 +       writeb(val, dev->baddr + ATA_REG_OFFSET + reg);
69 +}
70 +
71 +static inline u8 rareg(unsigned reg, struct cf_mips_dev* dev)
72 +{
73 +       return readb(dev->baddr + ATA_REG_OFFSET + reg);
74 +}
75 +
76 +static inline int get_gpio_bit(gpio_func ofs, struct cf_mips_dev *dev)
77 +{
78 +       return (gpio_get(ofs) >> dev->pin) & 1;
79 +}
80 +
81 +static inline void set_gpio_bit(int bit, gpio_func ofs, struct cf_mips_dev *dev)
82 +{
83 +       gpio_set(ofs, (1 << dev->pin), ((bit & 1) << dev->pin));
84 +}
85 +
86 +static inline int cfrdy(struct cf_mips_dev *dev)
87 +{
88 +       return get_gpio_bit(DATA, dev);
89 +}
90 +
91 +static inline void prepare_cf_irq(struct cf_mips_dev *dev)
92 +{
93 +       set_gpio_bit(1, ILEVEL, dev);   /* interrupt on cf ready (not busy) */
94 +       set_gpio_bit(0, ISTAT, dev);    /* clear interrupt status */
95 +}
96 +
97 +static inline int cf_present(struct cf_mips_dev* dev)
98 +{
99 +       /* TODO: read and configure CIS into memory mapped mode
100 +        * TODO:   parse CISTPL_CONFIG on CF+ cards to get base address (0x200)
101 +        * TODO:   maybe adjust power saving setting for Hitachi Microdrive
102 +        */
103 +       int i;
104 +
105 +       /* setup CFRDY GPIO as input */
106 +       set_gpio_bit(0, FUNC, dev);
107 +       set_gpio_bit(0, CFG, dev);
108 +
109 +       for (i = 0; i < 0x10; ++i) {
110 +               if (rareg(i,dev) != 0xff)
111 +                       return 1;
112 +       }
113 +       return 0;
114 +}
115 +
116 +static inline int is_busy(struct cf_mips_dev *dev)
117 +{
118 +       return !cfrdy(dev);
119 +}
120 +
121 +static int wait_not_busy(int to_us, int wait_for_busy,struct cf_mips_dev *dev)
122 +{
123 +       int us_passed = 0;
124 +       if (wait_for_busy && !is_busy(dev)) {
125 +               /* busy must appear within 400ns,
126 +                * but it may dissapear before we see it
127 +                *  => must not wait for busy in a loop
128 +                */
129 +               ndelay(400);
130 +       }
131 +
132 +       do {
133 +               if (us_passed)
134 +                       udelay(1);      /* never reached in async mode */
135 +               if (!is_busy(dev)) {
136 +                       if (us_passed > 1 * SECS) {
137 +                               printk(KERN_WARNING "cf-mips:   not busy ok (after %dus)"
138 +                                      ", status 0x%02x\n", us_passed, (unsigned) rareg(ATA_REG_ST,dev));
139 +                       }
140 +                       return CF_TRANS_OK;
141 +               }
142 +               if (us_passed == 1 * SECS) {
143 +                       printk(KERN_WARNING "cf-mips: wait not busy %dus..\n", to_us);
144 +               }
145 +               if (dev->async_mode) {
146 +                       dev->to_timer.expires = jiffies + (to_us * HZ / SECS);
147 +                       dev->irq_enable_time = jiffies;
148 +                       prepare_cf_irq(dev);
149 +                       if (is_busy(dev)) {
150 +                               add_timer(&dev->to_timer);
151 +                               enable_irq(dev->irq);
152 +                               return CF_TRANS_IN_PROGRESS;
153 +                       }
154 +                       continue;
155 +               }
156 +               ++us_passed;
157 +       } while (us_passed < to_us);
158 +
159 +       printk(KERN_ERR "cf-mips:  wait not busy timeout (%dus)"
160 +              ", status 0x%02x, state %d\n",
161 +              to_us, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
162 +       return CF_TRANS_FAILED;
163 +}
164 +
165 +static irqreturn_t cf_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
166 +{
167 +       /* While tasklet has not disabled irq, irq will be retried all the time
168 +        * because of ILEVEL matching GPIO pin status => deadlock.
169 +        * To avoid this, we change ILEVEL to 0.
170 +        */
171 +       struct cf_mips_dev *dev=dev_id;
172 +       
173 +       set_gpio_bit(0, ILEVEL, dev);
174 +       set_gpio_bit(0, ISTAT, dev);
175 +       
176 +       del_timer(&dev->to_timer);
177 +       tasklet_schedule(&dev->tasklet);
178 +       return IRQ_HANDLED;
179 +}
180 +
181 +static int do_reset(struct cf_mips_dev *dev)
182 +{
183 +       printk(KERN_INFO "cf-mips: resetting..\n");
184 +
185 +       wareg(ATA_REG_DC_SRST, ATA_REG_DC,dev);
186 +       udelay(1);              /* FIXME: how long should we wait here? */
187 +       wareg(0, ATA_REG_DC,dev);
188 +
189 +       return wait_not_busy(30 * SECS, 1,dev);
190 +}
191 +
192 +static int set_multiple(struct cf_mips_dev *dev)
193 +{
194 +       if (dev->block_size <= 1)
195 +               return CF_TRANS_OK;
196 +
197 +       wareg(dev->block_size, ATA_REG_SC,dev);
198 +       wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
199 +       wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
200 +
201 +       return wait_not_busy(10 * SECS, 1,dev);
202 +}
203 +
204 +static int set_cmd(struct cf_mips_dev *dev)
205 +{
206 +       //DEBUGP(KERN_INFO "cf-mips: ata cmd 0x%02x\n", dev->tcmd);
207 +       // sector_count should be <=24 bits..
208 +       BUG_ON(dev->tsect_start>=0x10000000);
209 +       // This way, it addresses 2^24 * 512 = 128G
210 +
211 +       if (dev->tsector_count) {
212 +               wareg(dev->tsector_count & 0xff, ATA_REG_SC,dev);
213 +               wareg(dev->tsect_start & 0xff, ATA_REG_SN,dev);
214 +               wareg((dev->tsect_start >> 8) & 0xff, ATA_REG_CL,dev);
215 +               wareg((dev->tsect_start >> 16) & 0xff, ATA_REG_CH,dev);
216 +       }
217 +       wareg(((dev->tsect_start >> 24) & 0x0f) | ATA_REG_DH_BASE | ATA_REG_DH_LBA,
218 +             ATA_REG_DH,dev);  /* select drive on all commands */
219 +       wareg(dev->tcmd, ATA_REG_CMD,dev);
220 +       return wait_not_busy(10 * SECS, 1,dev);
221 +}
222 +
223 +static int do_trans(struct cf_mips_dev *dev)
224 +{
225 +       int res;
226 +       unsigned st;
227 +       int transfered;
228 +       
229 +       //printk("do_trans: %d sectors left\n",dev->tsectors_left);
230 +       while (dev->tsectors_left) {
231 +               transfered = 0;
232 +
233 +               st = rareg(ATA_REG_ST,dev);
234 +               if (!(st & ATA_REG_ST_DRQ)) {
235 +                       printk(KERN_ERR "cf-mips: do_trans without DRQ (status 0x%x)!\n", st);
236 +                       if (st & ATA_REG_ST_ERR) {
237 +                               int errId = rareg(ATA_REG_ERR,dev);
238 +                               printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
239 +                                      (dev->tread ? "read" : "write"), st, errId);
240 +                       }
241 +                       return CF_TRANS_FAILED;
242 +               }
243 +               do { /* Fill/read the buffer one block */
244 +                       u32 *qbuf, *qend;
245 +                       qbuf = (u32 *)dev->tbuf;
246 +                       qend = qbuf + CF_SECT_SIZE / sizeof(u32);
247 +                       if (dev->tread) {
248 +                           while (qbuf!=qend)
249 +                               put_unaligned(*DBUF32,qbuf++);
250 +                               //*(qbuf++) = *DBUF32;
251 +                       }
252 +                       else {
253 +                           while(qbuf!=qend)
254 +                               *DBUF32 = get_unaligned(qbuf++);
255 +                       }
256 +
257 +                       dev->tsectors_left--;
258 +                       dev->tbuf += CF_SECT_SIZE;
259 +                       dev->tbuf_size -= CF_SECT_SIZE;
260 +                       transfered++;
261 +               } while (transfered != dev->block_size && dev->tsectors_left > 0);
262 +
263 +               res = wait_not_busy(10 * SECS, 1,dev);
264 +               if (res != CF_TRANS_OK)
265 +                       return res;
266 +       };
267 +
268 +       st = rareg(ATA_REG_ST,dev);
269 +       if (st & (ATA_REG_ST_DRQ | ATA_REG_ST_DWF | ATA_REG_ST_ERR)) {
270 +               if (st & ATA_REG_ST_DRQ) {
271 +                       printk(KERN_ERR "cf-mips: DRQ after all %d sectors are %s"
272 +                              ", status 0x%x\n", dev->tsector_count, (dev->tread ? "read" : "written"), st);
273 +               } else if (st & ATA_REG_ST_DWF) {
274 +                       printk(KERN_ERR "cf-mips: write fault, status 0x%x\n", st);
275 +               } else {
276 +                       int errId = rareg(ATA_REG_ERR,dev);
277 +                       printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
278 +                              (dev->tread ? "read" : "write"), st, errId);
279 +               }
280 +               return CF_TRANS_FAILED;
281 +       }
282 +       return CF_TRANS_OK;
283 +}
284 +
285 +static int cf_do_state(struct cf_mips_dev *dev)
286 +{
287 +       int res;
288 +       switch (dev->tstate) {  /* fall through everywhere */
289 +       case TS_IDLE:
290 +               dev->tstate = TS_READY;
291 +               if (is_busy(dev)) {
292 +                       dev->tstate = TS_AFTER_RESET;
293 +                       res = do_reset(dev);
294 +                       if (res != CF_TRANS_OK)
295 +                               break;
296 +               }
297 +       case TS_AFTER_RESET:
298 +               if (dev->tstate == TS_AFTER_RESET) {
299 +                       dev->tstate = TS_READY;
300 +                       res = set_multiple(dev);
301 +                       if (res != CF_TRANS_OK)
302 +                               break;
303 +               }
304 +       case TS_READY:
305 +               dev->tstate = TS_CMD;
306 +               res = set_cmd(dev);
307 +               if (res != CF_TRANS_OK)
308 +                       break;;
309 +       case TS_CMD:
310 +               dev->tstate = TS_TRANS;
311 +       case TS_TRANS:
312 +               res = do_trans(dev);
313 +               break;
314 +       default:
315 +               printk(KERN_ERR "cf-mips: BUG: unknown tstate %d\n", dev->tstate);
316 +               return CF_TRANS_FAILED;
317 +       }
318 +       if (res != CF_TRANS_IN_PROGRESS)
319 +               dev->tstate = TS_IDLE;
320 +       return res;
321 +}
322 +
323 +static void cf_do_tasklet(unsigned long dev_l)
324 +{
325 +       struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
326 +       int res;
327 +
328 +       disable_irq(dev->irq);
329 +
330 +       if (dev->tstate == TS_IDLE)
331 +               return;         /* can happen when irq is first registered */
332 +
333 +#if 0
334 +       DEBUGP(KERN_WARNING "cf-mips:   not busy ok (tasklet)  status 0x%02x\n",
335 +              (unsigned) rareg(ATA_REG_ST,dev));
336 +#endif
337 +
338 +       res = cf_do_state(dev);
339 +       if (res == CF_TRANS_IN_PROGRESS)
340 +               return;
341 +       cf_async_trans_done(dev,res);
342 +}
343 +
344 +static void cf_async_timeout(unsigned long dev_l)
345 +{
346 +       struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
347 +       disable_irq(dev->irq);
348 +       /* Perhaps send abort to the device? */
349 +       printk(KERN_ERR "cf-mips:  wait not busy timeout (%lus)"
350 +              ", status 0x%02x, state %d\n",
351 +              jiffies - dev->irq_enable_time, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
352 +       dev->tstate = TS_IDLE;
353 +       cf_async_trans_done(dev,CF_TRANS_FAILED);
354 +}
355 +
356 +int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect, 
357 +       char* buffer, int is_write)
358 +{
359 +       BUG_ON(dev->tstate!=TS_IDLE);
360 +       if (nsect > ATA_MAX_SECT_PER_CMD) {
361 +               printk(KERN_WARNING "cf-mips: sector count %lu out of range\n",nsect);
362 +               return CF_TRANS_FAILED;
363 +       }
364 +       if (sector + nsect > dev->sectors) {
365 +               printk(KERN_WARNING "cf-mips: sector %lu out of range\n",sector);
366 +               return CF_TRANS_FAILED;
367 +       }
368 +       dev->tbuf = buffer;
369 +       dev->tbuf_size = nsect*512;
370 +       dev->tsect_start = sector;
371 +       dev->tsector_count = nsect;
372 +       dev->tsectors_left = dev->tsector_count;
373 +       dev->tread = (is_write)?0:1;
374 +       
375 +       dev->tcmd = (dev->block_size == 1 ?
376 +               (is_write ? ATA_CMD_WRITE_SECTORS : ATA_CMD_READ_SECTORS) :
377 +               (is_write ? ATA_CMD_WRITE_MULTIPLE : ATA_CMD_READ_MULTIPLE));
378 +
379 +       return cf_do_state(dev);
380 +}
381 +
382 +static int do_identify(struct cf_mips_dev *dev)
383 +{
384 +       u16 sbuf[CF_SECT_SIZE >> 1];
385 +       int res;
386 +       char tstr[17]; //serial
387 +       BUG_ON(dev->tstate!=TS_IDLE);
388 +       dev->tbuf = (char *) sbuf;
389 +       dev->tbuf_size = CF_SECT_SIZE;
390 +       dev->tsect_start = 0;
391 +       dev->tsector_count = 0;
392 +       dev->tsectors_left = 1;
393 +       dev->tread = 1;
394 +       dev->tcmd = ATA_CMD_IDENTIFY_DRIVE;
395 +
396 +       DEBUGP(KERN_INFO "cf-mips: identify drive..\n");
397 +       res = cf_do_state(dev);
398 +       if (res == CF_TRANS_IN_PROGRESS) {
399 +               printk(KERN_ERR "cf-mips: BUG: async identify cmd\n");
400 +               return CF_TRANS_FAILED;
401 +       }
402 +       if (res != CF_TRANS_OK)
403 +               return 0;
404 +
405 +       dev->head = sbuf[3];
406 +       dev->cyl = sbuf[1];
407 +       dev->spt = sbuf[6];
408 +       dev->sectors = ((unsigned long) sbuf[7] << 16) | sbuf[8];
409 +       dev->dtype=sbuf[0];
410 +       memcpy(tstr,&sbuf[12],16);
411 +       tstr[16]=0;
412 +       printk(KERN_INFO "cf-mips: %s detected, C/H/S=%d/%d/%d sectors=%u (%uMB) Serial=%s\n",
413 +              (sbuf[0] == 0x848A ? "CF card" : "ATA drive"), dev->cyl, dev->head,
414 +              dev->spt, dev->sectors, dev->sectors >> 11,tstr);
415 +       return 1;
416 +}
417 +
418 +static void init_multiple(struct cf_mips_dev * dev)
419 +{
420 +       int res;
421 +       DEBUGP(KERN_INFO "cf-mips: detecting block size\n");
422 +
423 +       dev->block_size = 128;  /* max block size = 128 sectors (64KB) */
424 +       do {
425 +               wareg(dev->block_size, ATA_REG_SC,dev);
426 +               wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
427 +               wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
428 +
429 +               res = wait_not_busy(10 * SECS, 1,dev);
430 +               if (res != CF_TRANS_OK) {
431 +                       printk(KERN_ERR "cf-mips: failed to detect block size: busy!\n");
432 +                       dev->block_size = 1;
433 +                       return;
434 +               }
435 +               if ((rareg(ATA_REG_ST,dev) & ATA_REG_ST_ERR) == 0)
436 +                       break;
437 +               dev->block_size /= 2;
438 +       } while (dev->block_size > 1);
439 +
440 +       printk(KERN_INFO "cf-mips: multiple sectors = %d\n", dev->block_size);
441 +}
442 +
443 +int cf_init(struct cf_mips_dev *dev)
444 +{
445 +       tasklet_init(&dev->tasklet,cf_do_tasklet,(unsigned long)dev);
446 +       dev->baddr = ioremap_nocache((unsigned long)dev->base, CFDEV_BUF_SIZE);
447 +       if (!dev->baddr) {
448 +               printk(KERN_ERR "cf-mips: cf_init: ioremap for (%lx,%x) failed\n",
449 +                      (unsigned long) dev->base, CFDEV_BUF_SIZE);
450 +               return -EBUSY;
451 +       }
452 +
453 +       if (!cf_present(dev)) {
454 +               printk(KERN_WARNING "cf-mips: cf card not present\n");
455 +               iounmap(dev->baddr);
456 +               return -ENODEV;
457 +       }
458 +
459 +       if (do_reset(dev) != CF_TRANS_OK) {
460 +               printk(KERN_ERR "cf-mips: cf reset failed\n");
461 +               iounmap(dev->baddr);
462 +               return -EBUSY;
463 +       }
464 +
465 +       if (!do_identify(dev)) {
466 +               printk(KERN_ERR "cf-mips: cf identify failed\n");
467 +               iounmap(dev->baddr);
468 +               return -EBUSY;
469 +       }
470 +
471 +/*     set_apm_level(ATA_APM_WITH_STANDBY); */
472 +       init_multiple(dev);
473 +
474 +       init_timer(&dev->to_timer);
475 +       dev->to_timer.function = cf_async_timeout;
476 +       dev->to_timer.data = (unsigned long)dev;
477 +
478 +       prepare_cf_irq(dev);
479 +       if (request_irq(dev->irq, cf_irq_handler, 0, "CF Mips", dev)) {
480 +               printk(KERN_ERR "cf-mips: failed to get irq\n");
481 +               iounmap(dev->baddr);
482 +               return -EBUSY;
483 +       }
484 +       /* Disable below would be odd, because request will enable, and the tasklet
485 +         will disable it itself */
486 +       //disable_irq(dev->irq);
487 +       
488 +       dev->async_mode = 1;
489 +
490 +       return 0;
491 +}
492 +
493 +void cf_cleanup(struct cf_mips_dev *dev)
494 +{
495 +       iounmap(dev->baddr);
496 +       free_irq(dev->irq, NULL);
497 +#if REQUEST_MEM_REGION
498 +       release_mem_region((unsigned long)dev->base, CFDEV_BUF_SIZE);
499 +#endif
500 +}
501 +
502 +
503 +/*eof*/
504 diff -urN linux.old/drivers/block/rb500/ata.h linux.dev/drivers/block/rb500/ata.h
505 --- linux.old/drivers/block/rb500/ata.h 1970-01-01 01:00:00.000000000 +0100
506 +++ linux.dev/drivers/block/rb500/ata.h 2006-10-26 00:11:14.000000000 +0200
507 @@ -0,0 +1,132 @@
508 +#ifndef __CFMIPS_ATA_H__
509 +#define __CFMIPS_ATA_H__
510 +
511 +#include <linux/interrupt.h>
512 +
513 +#define CFG_DC_DEV1    (void*)0xb8010010
514 +#define   CFG_DC_DEVBASE       0x0
515 +#define   CFG_DC_DEVMASK       0x4
516 +#define   CFG_DC_DEVC          0x8
517 +#define   CFG_DC_DEVTC         0xC
518 +
519 +#define CFDEV_BUF_SIZE 0x1000
520 +#define ATA_CIS_OFFSET 0x200
521 +#define ATA_REG_OFFSET 0x800
522 +#define ATA_DBUF_OFFSET        0xC00
523 +
524 +#define ATA_REG_FEAT   0x1
525 +#define ATA_REG_SC     0x2
526 +#define ATA_REG_SN     0x3
527 +#define ATA_REG_CL     0x4
528 +#define ATA_REG_CH     0x5
529 +#define ATA_REG_DH     0x6
530 +#define   ATA_REG_DH_BASE      0xa0
531 +#define   ATA_REG_DH_LBA       0x40
532 +#define   ATA_REG_DH_DRV       0x10
533 +#define ATA_REG_CMD    0x7
534 +#define ATA_REG_ST     0x7
535 +#define   ATA_REG_ST_BUSY      0x80
536 +#define   ATA_REG_ST_RDY       0x40
537 +#define   ATA_REG_ST_DWF       0x20
538 +#define   ATA_REG_ST_DSC       0x10
539 +#define   ATA_REG_ST_DRQ       0x08
540 +#define   ATA_REG_ST_CORR      0x04
541 +#define   ATA_REG_ST_ERR       0x01
542 +#define ATA_REG_ERR    0xd
543 +#define ATA_REG_DC     0xe
544 +#define   ATA_REG_DC_IEN       0x02
545 +#define   ATA_REG_DC_SRST      0x04
546 +
547 +#define ATA_CMD_READ_SECTORS   0x20
548 +#define ATA_CMD_WRITE_SECTORS  0x30
549 +#define ATA_CMD_EXEC_DRIVE_DIAG        0x90
550 +#define ATA_CMD_READ_MULTIPLE  0xC4
551 +#define ATA_CMD_WRITE_MULTIPLE 0xC5
552 +#define ATA_CMD_SET_MULTIPLE   0xC6
553 +#define ATA_CMD_IDENTIFY_DRIVE 0xEC
554 +#define ATA_CMD_SET_FEATURES   0xEF
555 +
556 +#define ATA_FEATURE_ENABLE_APM 0x05
557 +#define ATA_FEATURE_DISABLE_APM        0x85
558 +#define ATA_APM_DISABLED       0x00
559 +#define ATA_APM_MIN_POWER      0x01
560 +#define ATA_APM_WITH_STANDBY   0x7f
561 +#define ATA_APM_WITHOUT_STANDBY        0x80
562 +#define ATA_APM_MAX_PERFORMANCE        0xfe
563 +
564 +#define CF_SECT_SIZE   0x200
565 +/* That is the ratio CF_SECT_SIZE/512 (the kernel sector size) */
566 +#define CF_KERNEL_MUL  1
567 +#define ATA_MAX_SECT_PER_CMD   0x100
568 +
569 +#define CF_TRANS_FAILED                0
570 +#define CF_TRANS_OK            1
571 +#define CF_TRANS_IN_PROGRESS   2
572 +
573 +
574 +enum trans_state {
575 +       TS_IDLE = 0,
576 +       TS_AFTER_RESET,
577 +       TS_READY,
578 +       TS_CMD,
579 +       TS_TRANS
580 +};
581 +
582 +// 
583 +// #if DEBUG
584 +// static unsigned long busy_time;
585 +// #endif
586 +
587 +/** Struct to hold the cfdev
588 +Actually, all the data here only has one instance. However, for 
589 +reasons of programming conformity, it is passed around as a pointer
590 +*/
591 +struct cf_mips_dev {
592 +       void *base; /* base address for I/O */
593 +       void *baddr; /* remapped address */
594 +
595 +       int pin; /* gpio pin */
596 +       int irq; /* gpio irq */
597 +       
598 +       unsigned head;
599 +       unsigned cyl;
600 +       unsigned spt;
601 +       unsigned sectors;
602 +       
603 +       unsigned short block_size;
604 +       unsigned dtype ; // ATA or CF
605 +       struct request_queue *queue;
606 +       struct gendisk  *gd;
607 +       
608 +       /* Transaction state */
609 +       enum trans_state tstate;
610 +       char *tbuf;
611 +       unsigned long tbuf_size;
612 +       sector_t tsect_start;
613 +       unsigned tsector_count;
614 +       unsigned tsectors_left;
615 +       int tread;
616 +       unsigned tcmd;
617 +       int async_mode;
618 +       unsigned long irq_enable_time;
619 +       
620 +       struct request *active_req; /* A request is being carried out. Is that different from tstate? */
621 +       int users;
622 +       struct timer_list to_timer;
623 +       struct tasklet_struct tasklet;
624 +
625 +       /** This lock ensures that the requests to this device are all done
626 +       atomically. Transfers can run in parallel, requests are all queued
627 +       one-by-one */
628 +       spinlock_t lock;
629 +};
630 +
631 +int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect, 
632 +       char* buffer, int is_write);
633 +int cf_init(struct cf_mips_dev* dev);
634 +void cf_cleanup(struct cf_mips_dev* dev);
635 +
636 +void cf_async_trans_done(struct cf_mips_dev* dev, int result);
637 +// void *cf_get_next_buf(unsigned long *buf_size);
638 +
639 +#endif
640 diff -urN linux.old/drivers/block/rb500/bdev.c linux.dev/drivers/block/rb500/bdev.c
641 --- linux.old/drivers/block/rb500/bdev.c        1970-01-01 01:00:00.000000000 +0100
642 +++ linux.dev/drivers/block/rb500/bdev.c        2006-10-26 00:11:14.000000000 +0200
643 @@ -0,0 +1,340 @@
644 +/* CF-mips driver
645 +   This is a block driver for the direct (mmaped) interface to the CF-slot,
646 +   found in Routerboard.com's RB532 board
647 +   See SDK provided from routerboard.com.
648 +   
649 +   Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6.
650 +   Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org>
651 +
652 +   This work is redistributed under the terms of the GNU General Public License.
653 +*/
654 +
655 +#include <linux/kernel.h>
656 +#include <linux/module.h>
657 +#include <linux/init.h>
658 +#include <linux/time.h>
659 +#include <linux/wait.h>
660 +#include <linux/fs.h>
661 +#include <linux/genhd.h>
662 +#include <linux/blkdev.h>
663 +#include <linux/blkpg.h>
664 +#include <linux/hdreg.h>
665 +#include <linux/platform_device.h>
666 +
667 +#include <asm/uaccess.h>
668 +#include <asm/io.h>
669 +
670 +#include <asm/rc32434/rb.h>
671 +
672 +#ifdef DEBUG
673 +#define DEBUGP printk
674 +#define DLEVEL 1
675 +#else
676 +#define DEBUGP(format, args...)
677 +#define DLEVEL 0
678 +#endif
679 +
680 +#define CF_MIPS_MAJOR 13
681 +#define MAJOR_NR       CF_MIPS_MAJOR
682 +#define CF_MAX_PART    16              /* max 15 partitions */
683 +
684 +#include "ata.h"
685 +
686 +//extern struct block_device_operations cf_bdops;
687 +
688 +// static struct hd_struct cf_parts[CF_MAX_PART];
689 +// static int cf_part_sizes[CF_MAX_PART];
690 +// static int cf_hsect_sizes[CF_MAX_PART];
691 +// static int cf_max_sectors[CF_MAX_PART];
692 +// static int cf_blksize_sizes[CF_MAX_PART];
693 +
694 +// static spinlock_t lock = SPIN_LOCK_UNLOCKED;
695 +
696 +// volatile int cf_busy = 0;
697 +
698 +static struct request *active_req = NULL;
699 +
700 +static int cf_open (struct inode *, struct file *);
701 +static int cf_release (struct inode *, struct file *);
702 +static int cf_ioctl (struct inode *, struct file *, unsigned, unsigned long);
703 +
704 +static void cf_request(request_queue_t * q);
705 +static int cf_transfer(const struct request *req);
706 +
707 +/*long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
708 +long (*compat_ioctl) (struct file *, unsigned, unsigned long);*/
709 +// int (*direct_access) (struct block_device *, sector_t, unsigned long *);
710 +// int (*media_changed) (struct gendisk *);
711 +// int (*revalidate_disk) (struct gendisk *);
712 +
713 +static struct block_device_operations cf_bdops = {
714 +      .owner = THIS_MODULE,
715 +      .open = cf_open,
716 +      .release = cf_release,
717 +      .ioctl = cf_ioctl,
718 +      .media_changed = NULL,
719 +      .unlocked_ioctl = NULL,
720 +      .revalidate_disk = NULL,
721 +      .compat_ioctl = NULL,
722 +      .direct_access = NULL
723 +};
724 +
725 +
726 +int cf_mips_probe(struct platform_device *pdev)
727 +{
728 +       struct gendisk* cf_gendisk=NULL;
729 +       struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data;
730 +       struct cf_mips_dev *dev;
731 +       struct resource *r;
732 +       int reg_result;
733 +
734 +       reg_result = register_blkdev(MAJOR_NR, "cf-mips");
735 +       if (reg_result < 0) {
736 +               printk(KERN_WARNING "cf-mips: can't get major %d\n", MAJOR_NR);
737 +               return reg_result;
738 +       }
739 +
740 +       dev = (struct cf_mips_dev *)kmalloc(sizeof(struct cf_mips_dev),GFP_KERNEL);
741 +       if (!dev)
742 +               goto out_err;
743 +       memset(dev, 0, sizeof(struct cf_mips_dev));
744 +       cdev->dev = dev;
745 +       
746 +       dev->pin = cdev->gpio_pin;
747 +       dev->irq = platform_get_irq_byname(pdev, "cf_irq");
748 +       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cf_membase");
749 +       dev->base = (void *) r->start;
750 +       
751 +       if (cf_init(dev)) goto out_err;
752 +       printk("init done");
753 +       
754 +       spin_lock_init(&dev->lock);
755 +       dev->queue = blk_init_queue(cf_request,&dev->lock);
756 +       if (!dev->queue){
757 +               printk(KERN_ERR "cf-mips: no mem for queue\n");
758 +               goto out_err;
759 +       }
760 +       blk_queue_max_sectors(dev->queue,ATA_MAX_SECT_PER_CMD);
761 +
762 +       /* For memory devices, it is always better to avoid crossing segments
763 +       inside the same request. */
764 +/*     if (dev->dtype==0x848A){
765 +               printk(KERN_INFO "Setting boundary for cf to 0x%x",(dev->block_size*512)-1);
766 +               blk_queue_segment_boundary(dev->queue, (dev->block_size*512)-1);
767 +       }*/
768 +
769 +       dev->gd = alloc_disk(CF_MAX_PART);
770 +       cf_gendisk = dev->gd;
771 +       cdev->gd = dev->gd;
772 +       if (!cf_gendisk) goto out_err; /* Last of these goto's */
773 +       
774 +       cf_gendisk->major = MAJOR_NR;
775 +       cf_gendisk->first_minor = 0;
776 +       cf_gendisk->queue=dev->queue;
777 +       BUG_ON(cf_gendisk->minors != CF_MAX_PART);
778 +       strcpy(cf_gendisk->disk_name,"cfa");
779 +       strcpy(cf_gendisk->devfs_name,"cf/card0");
780 +       cf_gendisk->fops = &cf_bdops;
781 +       cf_gendisk->flags = 0 ; /* is not yet GENHD_FL_REMOVABLE */
782 +       cf_gendisk->private_data=dev;
783 +       
784 +       set_capacity(cf_gendisk,dev->sectors * CF_KERNEL_MUL);
785 +       
786 +       /* Let the disk go live */
787 +       add_disk(cf_gendisk);
788 +#if 0
789 +       result = cf_init();
790 +       
791 +       /* default cfg for all partitions */
792 +       memset(cf_parts, 0, sizeof (cf_parts[0]) * CF_MAX_PART);
793 +       memset(cf_part_sizes, 0, sizeof (cf_part_sizes[0]) * CF_MAX_PART);
794 +       for (i = 0; i < CF_MAX_PART; ++i) {
795 +               cf_hsect_sizes[i] = CF_SECT_SIZE;
796 +               cf_max_sectors[i] = ATA_MAX_SECT_PER_CMD;
797 +               cf_blksize_sizes[i] = BLOCK_SIZE;
798 +       }
799 +
800 +       /* setup info for whole disk (partition 0) */
801 +       cf_part_sizes[0] = cf_sectors / 2;
802 +       cf_parts[0].nr_sects = cf_sectors;
803 +
804 +       blk_size[MAJOR_NR] = cf_part_sizes;
805 +       blksize_size[MAJOR_NR] = cf_blksize_sizes;
806 +       max_sectors[MAJOR_NR] = cf_max_sectors;
807 +       hardsect_size[MAJOR_NR] = cf_hsect_sizes;
808 +       read_ahead[MAJOR_NR] = 8;       /* (4kB) */
809 +
810 +       blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
811 +
812 +       add_gendisk(&cf_gendisk);
813 +#endif
814 +//     printk(KERN_INFO "cf-mips partition check: \n");
815 +//     register_disk(cf_gendisk, MKDEV(MAJOR_NR, 0), CF_MAX_PART,
816 +//                   &cf_bdops, dev->sectors);
817 +       return 0;
818 +
819 +out_err:
820 +       if (dev->queue){
821 +               blk_cleanup_queue(dev->queue);
822 +       }
823 +       if (reg_result) {
824 +               unregister_blkdev(MAJOR_NR, "cf-mips");
825 +               return reg_result;
826 +       }
827 +       if (dev){
828 +               cf_cleanup(dev);
829 +               kfree(dev);
830 +       }
831 +       return 1;
832 +}
833 +
834 +static int
835 +cf_mips_remove(struct platform_device *pdev)
836 +{
837 +       struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data;
838 +       struct cf_mips_dev *dev = (struct cf_mips_dev *) cdev->dev;
839 +       
840 +       unregister_blkdev(MAJOR_NR, "cf-mips");
841 +       blk_cleanup_queue(dev->queue);
842 +
843 +       del_gendisk(dev->gd);
844 +       cf_cleanup(dev);
845 +       return 0;
846 +}
847 +
848 +
849 +static struct platform_driver cf_driver = {
850 +       .driver.name = "rb500-cf",
851 +       .probe = cf_mips_probe,
852 +       .remove = cf_mips_remove,
853 +};
854 +
855 +static int __init cf_mips_init(void)
856 +{
857 +       printk(KERN_INFO "cf-mips module loaded\n");
858 +       return platform_driver_register(&cf_driver);
859 +}
860 +
861 +static void cf_mips_cleanup(void)
862 +{
863 +       platform_driver_unregister(&cf_driver);
864 +       printk(KERN_INFO "cf-mips module removed\n");
865 +}
866 +
867 +module_init(cf_mips_init);
868 +module_exit(cf_mips_cleanup);
869 +
870 +MODULE_LICENSE("GPL");
871 +MODULE_ALIAS_BLOCKDEV_MAJOR(CF_MIPS_MAJOR);
872 +
873 +
874 +static int cf_open(struct inode *inode, struct file *filp)
875 +{
876 +       struct cf_mips_dev  *dev=inode->i_bdev->bd_disk->private_data;
877 +       int minor = MINOR(inode->i_rdev);
878 +       
879 +       if (minor >= CF_MAX_PART)
880 +               return -ENODEV;
881 +       //DEBUGP(KERN_INFO "cf-mips module opened, minor %d\n", minor);
882 +       spin_lock(&dev->lock);
883 +       dev->users++;
884 +       spin_unlock(&dev->lock);
885 +       filp->private_data=dev;
886 +       
887 +       /* dirty workaround to set CFRDY GPIO as an input when some other
888 +          program sets it as an output */
889 +       gpio_set(CFG, (1 << dev->pin), 0);
890 +       return 0;               /* success */
891 +}
892 +
893 +static int cf_release(struct inode *inode, struct file *filp)
894 +{
895 +       int minor = MINOR(inode->i_rdev);
896 +       struct cf_mips_dev  *dev=inode->i_bdev->bd_disk->private_data;
897 +       spin_lock(&dev->lock);
898 +       dev->users--;
899 +       spin_unlock(&dev->lock);
900 +       return 0;
901 +}
902 +
903 +static int cf_ioctl(struct inode *inode, struct file *filp,
904 +        unsigned int cmd, unsigned long arg)
905 +{
906 +       unsigned minor = MINOR(inode->i_rdev);
907 +       struct cf_mips_dev  *dev=inode->i_bdev->bd_disk->private_data;
908 +
909 +       DEBUGP(KERN_INFO "cf_ioctl cmd %u\n", cmd);
910 +       switch (cmd) {
911 +       case BLKRRPART: /* re-read partition table */
912 +               if (!capable(CAP_SYS_ADMIN))
913 +                       return -EACCES;
914 +               printk(KERN_INFO "cf-mips partition check: \n");
915 +               register_disk(dev->gd);
916 +               return 0;
917 +
918 +       case HDIO_GETGEO:
919 +               {
920 +                       struct hd_geometry geo;
921 +                       geo.cylinders = dev->cyl;
922 +                       geo.heads = dev->head;
923 +                       geo.sectors = dev->spt;
924 +                       geo.start = (*dev->gd->part)[minor].start_sect;
925 +                       if (copy_to_user((void *) arg, &geo, sizeof (geo)))
926 +                               return -EFAULT;
927 +               }
928 +               return 0;
929 +       }
930 +
931 +       return -EINVAL;         /* unknown command */
932 +}
933 +
934 +static void cf_request(request_queue_t * q)
935 +{
936 +       struct cf_mips_dev* dev;
937 +       
938 +       struct request * req;
939 +       int status;
940 +
941 +       /* We could have q->queuedata = dev , but haven't yet. */
942 +       if (active_req)
943 +               return;
944 +
945 +       while ((req=elv_next_request(q))!=NULL){
946 +               dev=req->rq_disk->private_data;
947 +               status=cf_transfer(req);
948 +               if (status==CF_TRANS_IN_PROGRESS){
949 +                       active_req=req;
950 +                       return;
951 +               }
952 +               end_request(req,status);
953 +       }
954 +}
955 +
956 +static int cf_transfer(const struct request *req)
957 +{
958 +       struct cf_mips_dev* dev=req->rq_disk->private_data;
959 +
960 +       if (!blk_fs_request(req)){      
961 +               if (printk_ratelimit())
962 +                       printk(KERN_WARNING "cf-mips: skipping non-fs request 0x%x\n",req->cmd[0]);
963 +               return CF_TRANS_FAILED;
964 +       }
965 +       
966 +       return cf_do_transfer(dev,req->sector,req->current_nr_sectors,req->buffer,rq_data_dir(req));
967 +}
968 +
969 +void cf_async_trans_done(struct cf_mips_dev * dev,int result)
970 +{
971 +       struct request *req;
972 +       
973 +       spin_lock(&dev->lock);
974 +       req=active_req;
975 +       active_req=NULL;
976 +       end_request(req,result);
977 +       spin_unlock(&dev->lock);
978 +
979 +       spin_lock(&dev->lock);
980 +       cf_request(dev->queue);
981 +       spin_unlock(&dev->lock);
982 +}
983 +
984 diff -urN linux.old/drivers/block/rb500/Makefile linux.dev/drivers/block/rb500/Makefile
985 --- linux.old/drivers/block/rb500/Makefile      1970-01-01 01:00:00.000000000 +0100
986 +++ linux.dev/drivers/block/rb500/Makefile      2006-10-26 00:11:14.000000000 +0200
987 @@ -0,0 +1,3 @@
988 +## Makefile for the RB532 CF port
989 +
990 +obj-y          += bdev.o ata.o