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