Add NAND flash/YAFFS2 patches for RB532 by David Goodenough
[openwrt/svn-archive/archive.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