[adm5120] add Edimax BR-61x4WG board support to the LED driver, thanks to scream_...
[openwrt.git] / target / linux / adm5120 / files / drivers / block / rb1xx / ata.c
1 /* CF-mips driver
2 This is a block driver for the direct (mmaped) interface to the CF-slot,
3 found in Routerboard.com's RB532 board
4 See SDK provided from routerboard.com.
5
6 Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6.
7 Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org>
8
9 This work is redistributed under the terms of the GNU General Public License.
10 */
11
12 #include <linux/kernel.h> /* printk() */
13 #include <linux/module.h> /* module to be loadable */
14 #include <linux/delay.h>
15 #include <linux/sched.h>
16 #include <linux/pci.h>
17 #include <linux/ioport.h> /* request_mem_region() */
18
19 #include <asm/unaligned.h>
20 #include <asm/io.h>
21 #include <asm/gpio.h>
22
23 #include <gpio.h>
24 #include <adm5120_defs.h>
25 #include <adm5120_irq.h>
26 #include <adm5120_switch.h>
27 #include <adm5120_intc.h>
28 #include <adm5120_mpmc.h>
29 #include <adm5120_cf.h>
30
31 #include "ata.h"
32
33 #define REQUEST_MEM_REGION 0
34 #define DEBUG 1
35
36 #if DEBUG
37 #define DEBUGP printk
38 #else
39 #define DEBUGP(format, args...)
40 #endif
41
42 #define SECS 1000000 /* unit for wait_not_busy() is 1us */
43
44 unsigned cf_head = 0;
45 unsigned cf_cyl = 0;
46 unsigned cf_spt = 0;
47 unsigned cf_sectors = 0;
48 static unsigned cf_block_size = 1;
49
50 #define DBUF32 ((volatile u32 *)((unsigned long)dev->baddr | ATA_DBUF_OFFSET))
51
52 #define INTC_WRITE(reg, val) __raw_writel((val), \
53 (void __iomem *)(KSEG1ADDR(ADM5120_INTC_BASE) + reg))
54
55 #define INTC_READ(reg) __raw_readl(\
56 (void __iomem *)(KSEG1ADDR(ADM5120_INTC_BASE) + reg))
57
58 static void cf_do_tasklet(unsigned long dev_l);
59
60
61 static inline void wareg(u8 val, unsigned reg, struct cf_mips_dev* dev)
62 {
63 writeb(val, dev->baddr + ATA_REG_OFFSET + reg);
64 }
65
66 static inline u8 rareg(unsigned reg, struct cf_mips_dev* dev)
67 {
68 return readb(dev->baddr + ATA_REG_OFFSET + reg);
69 }
70
71 static inline int cfrdy(struct cf_mips_dev *dev)
72 {
73 return gpio_get_value(12);
74 }
75
76 static inline void prepare_cf_irq(struct cf_mips_dev *dev)
77 {
78 /* interrupt on cf ready (not busy) */
79 INTC_WRITE(INTC_REG_INT_LEVEL, INTC_READ(INTC_REG_INT_LEVEL) | ADM5120_CF_IRQ_LEVEL_BIT);
80
81 /* FIXME: how to clear interrupt status? */
82 }
83
84 static inline int cf_present(struct cf_mips_dev* dev)
85 {
86 /* TODO: read and configure CIS into memory mapped mode
87 * TODO: parse CISTPL_CONFIG on CF+ cards to get base address (0x200)
88 * TODO: maybe adjust power saving setting for Hitachi Microdrive
89 */
90
91 /* FIXME: enabling of EXTIO will be done by BIOS in future */
92 unsigned cmd = EXTIO_CS0_INT0_EN;
93 int i;
94
95 /* on RB100 WAIT is LOW all the time => read will hang */
96 if (gpio_get_value(8))
97 cmd |= EXTIO_WAIT_EN;
98
99 SW_WRITE_REG(GPIO_CONF2, cmd);
100 SW_WRITE_REG(GPIO_CONF0, (SW_READ_REG(GPIO_CONF0) & ~(1 << (16 + ADM5120_CF_GPIO_NUM))));
101
102 /* FIXME: timings will be set by BIOS in future - remove this */
103 MPMC_WRITE_REG(SC2, 0x88);
104 MPMC_WRITE_REG(WEN2, 0x02);
105 MPMC_WRITE_REG(OEN2, 0x03);
106 MPMC_WRITE_REG(RD2, 0x1a);
107 MPMC_WRITE_REG(PG2, 0x1d);
108 MPMC_WRITE_REG(WR2, 0x14);
109 MPMC_WRITE_REG(TN2, 0x09);
110
111 for (i = 0; i < 0x10; ++i) {
112 if (rareg(i,dev) != 0xff)
113 return 1;
114 }
115 return 0;
116 }
117
118 static inline int is_busy(struct cf_mips_dev *dev)
119 {
120 return !cfrdy(dev);
121 }
122
123 static int wait_not_busy(int to_us, int wait_for_busy,struct cf_mips_dev *dev)
124 {
125 int us_passed = 0;
126 if (wait_for_busy && !is_busy(dev)) {
127 /* busy must appear within 400ns,
128 * but it may dissapear before we see it
129 * => must not wait for busy in a loop
130 */
131 ndelay(400);
132 }
133
134 do {
135 if (us_passed)
136 udelay(1); /* never reached in async mode */
137 if (!is_busy(dev)) {
138 if (us_passed > 1 * SECS) {
139 printk(KERN_WARNING "cf-mips: not busy ok (after %dus)"
140 ", status 0x%02x\n", us_passed, (unsigned) rareg(ATA_REG_ST,dev));
141 }
142 return CF_TRANS_OK;
143 }
144 if (us_passed == 1 * SECS) {
145 printk(KERN_WARNING "cf-mips: wait not busy %dus..\n", to_us);
146 }
147 if (dev->async_mode) {
148 dev->to_timer.expires = jiffies + (to_us * HZ / SECS);
149 dev->irq_enable_time = jiffies;
150 prepare_cf_irq(dev);
151 if (is_busy(dev)) {
152 add_timer(&dev->to_timer);
153 enable_irq(dev->irq);
154 return CF_TRANS_IN_PROGRESS;
155 }
156 continue;
157 }
158 ++us_passed;
159 } while (us_passed < to_us);
160
161 printk(KERN_ERR "cf-mips: wait not busy timeout (%dus)"
162 ", status 0x%02x, state %d\n",
163 to_us, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
164 return CF_TRANS_FAILED;
165 }
166
167 static irqreturn_t cf_irq_handler(int irq, void *dev_id)
168 {
169 /* While tasklet has not disabled irq, irq will be retried all the time
170 * because of ILEVEL matching GPIO pin status => deadlock.
171 * To avoid this, we change ILEVEL to 0.
172 */
173
174 struct cf_mips_dev *dev=dev_id;
175
176 if (!cfrdy(dev))
177 return; // false interrupt (only for ADM5120)
178
179 INTC_WRITE(INTC_REG_INT_LEVEL, (INTC_READ(INTC_REG_INT_LEVEL) & (~ADM5120_CF_IRQ_LEVEL_BIT)));
180
181 del_timer(&dev->to_timer);
182 tasklet_schedule(&dev->tasklet);
183 return IRQ_HANDLED;
184 }
185
186 static int do_reset(struct cf_mips_dev *dev)
187 {
188 printk(KERN_INFO "cf-mips: resetting..\n");
189
190 wareg(ATA_REG_DC_SRST, ATA_REG_DC,dev);
191 udelay(1); /* FIXME: how long should we wait here? */
192 wareg(0, ATA_REG_DC,dev);
193
194 return wait_not_busy(30 * SECS, 1,dev);
195 }
196
197 static int set_multiple(struct cf_mips_dev *dev)
198 {
199 if (dev->block_size <= 1)
200 return CF_TRANS_OK;
201
202 wareg(dev->block_size, ATA_REG_SC,dev);
203 wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
204 wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
205
206 return wait_not_busy(10 * SECS, 1,dev);
207 }
208
209 static int set_cmd(struct cf_mips_dev *dev)
210 {
211 //DEBUGP(KERN_INFO "cf-mips: ata cmd 0x%02x\n", dev->tcmd);
212 // sector_count should be <=24 bits..
213 BUG_ON(dev->tsect_start>=0x10000000);
214 // This way, it addresses 2^24 * 512 = 128G
215
216 if (dev->tsector_count) {
217 wareg(dev->tsector_count & 0xff, ATA_REG_SC,dev);
218 wareg(dev->tsect_start & 0xff, ATA_REG_SN,dev);
219 wareg((dev->tsect_start >> 8) & 0xff, ATA_REG_CL,dev);
220 wareg((dev->tsect_start >> 16) & 0xff, ATA_REG_CH,dev);
221 }
222 wareg(((dev->tsect_start >> 24) & 0x0f) | ATA_REG_DH_BASE | ATA_REG_DH_LBA,
223 ATA_REG_DH,dev); /* select drive on all commands */
224 wareg(dev->tcmd, ATA_REG_CMD,dev);
225 return wait_not_busy(10 * SECS, 1,dev);
226 }
227
228 static int do_trans(struct cf_mips_dev *dev)
229 {
230 int res;
231 unsigned st;
232 int transfered;
233
234 //printk("do_trans: %d sectors left\n",dev->tsectors_left);
235 while (dev->tsectors_left) {
236 transfered = 0;
237
238 st = rareg(ATA_REG_ST,dev);
239 if (!(st & ATA_REG_ST_DRQ)) {
240 printk(KERN_ERR "cf-mips: do_trans without DRQ (status 0x%x)!\n", st);
241 if (st & ATA_REG_ST_ERR) {
242 int errId = rareg(ATA_REG_ERR,dev);
243 printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
244 (dev->tread ? "read" : "write"), st, errId);
245 }
246 return CF_TRANS_FAILED;
247 }
248 do { /* Fill/read the buffer one block */
249 u32 *qbuf, *qend;
250 qbuf = (u32 *)dev->tbuf;
251 qend = qbuf + CF_SECT_SIZE / sizeof(u32);
252 if (dev->tread) {
253 while (qbuf!=qend)
254 put_unaligned(*DBUF32,qbuf++);
255 //*(qbuf++) = *DBUF32;
256 }
257 else {
258 while(qbuf!=qend)
259 *DBUF32 = get_unaligned(qbuf++);
260 }
261
262 dev->tsectors_left--;
263 dev->tbuf += CF_SECT_SIZE;
264 dev->tbuf_size -= CF_SECT_SIZE;
265 transfered++;
266 } while (transfered != dev->block_size && dev->tsectors_left > 0);
267
268 res = wait_not_busy(10 * SECS, 1,dev);
269 if (res != CF_TRANS_OK)
270 return res;
271 };
272
273 st = rareg(ATA_REG_ST,dev);
274 if (st & (ATA_REG_ST_DRQ | ATA_REG_ST_DWF | ATA_REG_ST_ERR)) {
275 if (st & ATA_REG_ST_DRQ) {
276 printk(KERN_ERR "cf-mips: DRQ after all %d sectors are %s"
277 ", status 0x%x\n", dev->tsector_count, (dev->tread ? "read" : "written"), st);
278 } else if (st & ATA_REG_ST_DWF) {
279 printk(KERN_ERR "cf-mips: write fault, status 0x%x\n", st);
280 } else {
281 int errId = rareg(ATA_REG_ERR,dev);
282 printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
283 (dev->tread ? "read" : "write"), st, errId);
284 }
285 return CF_TRANS_FAILED;
286 }
287 return CF_TRANS_OK;
288 }
289
290 static int cf_do_state(struct cf_mips_dev *dev)
291 {
292 int res;
293 switch (dev->tstate) { /* fall through everywhere */
294 case TS_IDLE:
295 dev->tstate = TS_READY;
296 if (is_busy(dev)) {
297 dev->tstate = TS_AFTER_RESET;
298 res = do_reset(dev);
299 if (res != CF_TRANS_OK)
300 break;
301 }
302 case TS_AFTER_RESET:
303 if (dev->tstate == TS_AFTER_RESET) {
304 dev->tstate = TS_READY;
305 res = set_multiple(dev);
306 if (res != CF_TRANS_OK)
307 break;
308 }
309 case TS_READY:
310 dev->tstate = TS_CMD;
311 res = set_cmd(dev);
312 if (res != CF_TRANS_OK)
313 break;;
314 case TS_CMD:
315 dev->tstate = TS_TRANS;
316 case TS_TRANS:
317 res = do_trans(dev);
318 break;
319 default:
320 printk(KERN_ERR "cf-mips: BUG: unknown tstate %d\n", dev->tstate);
321 return CF_TRANS_FAILED;
322 }
323 if (res != CF_TRANS_IN_PROGRESS)
324 dev->tstate = TS_IDLE;
325 return res;
326 }
327
328 static void cf_do_tasklet(unsigned long dev_l)
329 {
330 struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
331 int res;
332
333 disable_irq(dev->irq);
334
335 if (dev->tstate == TS_IDLE)
336 return; /* can happen when irq is first registered */
337
338 #if 0
339 DEBUGP(KERN_WARNING "cf-mips: not busy ok (tasklet) status 0x%02x\n",
340 (unsigned) rareg(ATA_REG_ST,dev));
341 #endif
342
343 res = cf_do_state(dev);
344 if (res == CF_TRANS_IN_PROGRESS)
345 return;
346 cf_async_trans_done(dev,res);
347 }
348
349 static void cf_async_timeout(unsigned long dev_l)
350 {
351 struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
352 disable_irq(dev->irq);
353 /* Perhaps send abort to the device? */
354 printk(KERN_ERR "cf-mips: wait not busy timeout (%lus)"
355 ", status 0x%02x, state %d\n",
356 jiffies - dev->irq_enable_time, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
357 dev->tstate = TS_IDLE;
358 cf_async_trans_done(dev,CF_TRANS_FAILED);
359 }
360
361 int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect,
362 char* buffer, int is_write)
363 {
364 BUG_ON(dev->tstate!=TS_IDLE);
365 if (nsect > ATA_MAX_SECT_PER_CMD) {
366 printk(KERN_WARNING "cf-mips: sector count %lu out of range\n",nsect);
367 return CF_TRANS_FAILED;
368 }
369 if (sector + nsect > dev->sectors) {
370 printk(KERN_WARNING "cf-mips: sector %lu out of range\n",sector);
371 return CF_TRANS_FAILED;
372 }
373 dev->tbuf = buffer;
374 dev->tbuf_size = nsect*512;
375 dev->tsect_start = sector;
376 dev->tsector_count = nsect;
377 dev->tsectors_left = dev->tsector_count;
378 dev->tread = (is_write)?0:1;
379
380 dev->tcmd = (dev->block_size == 1 ?
381 (is_write ? ATA_CMD_WRITE_SECTORS : ATA_CMD_READ_SECTORS) :
382 (is_write ? ATA_CMD_WRITE_MULTIPLE : ATA_CMD_READ_MULTIPLE));
383
384 return cf_do_state(dev);
385 }
386
387 static int do_identify(struct cf_mips_dev *dev)
388 {
389 u16 sbuf[CF_SECT_SIZE >> 1];
390 int res;
391 char tstr[17]; //serial
392 BUG_ON(dev->tstate!=TS_IDLE);
393 dev->tbuf = (char *) sbuf;
394 dev->tbuf_size = CF_SECT_SIZE;
395 dev->tsect_start = 0;
396 dev->tsector_count = 0;
397 dev->tsectors_left = 1;
398 dev->tread = 1;
399 dev->tcmd = ATA_CMD_IDENTIFY_DRIVE;
400
401 DEBUGP(KERN_INFO "cf-mips: identify drive..\n");
402 res = cf_do_state(dev);
403 if (res == CF_TRANS_IN_PROGRESS) {
404 printk(KERN_ERR "cf-mips: BUG: async identify cmd\n");
405 return CF_TRANS_FAILED;
406 }
407 if (res != CF_TRANS_OK)
408 return 0;
409
410 dev->head = sbuf[3];
411 dev->cyl = sbuf[1];
412 dev->spt = sbuf[6];
413 dev->sectors = ((unsigned long) sbuf[7] << 16) | sbuf[8];
414 dev->dtype=sbuf[0];
415 memcpy(tstr,&sbuf[12],16);
416 tstr[16]=0;
417 printk(KERN_INFO "cf-mips: %s detected, C/H/S=%d/%d/%d sectors=%u (%uMB) Serial=%s\n",
418 (sbuf[0] == 0x848A ? "CF card" : "ATA drive"), dev->cyl, dev->head,
419 dev->spt, dev->sectors, dev->sectors >> 11,tstr);
420 return 1;
421 }
422
423 static void init_multiple(struct cf_mips_dev * dev)
424 {
425 int res;
426 DEBUGP(KERN_INFO "cf-mips: detecting block size\n");
427
428 dev->block_size = 128; /* max block size = 128 sectors (64KB) */
429 do {
430 wareg(dev->block_size, ATA_REG_SC,dev);
431 wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
432 wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
433
434 res = wait_not_busy(10 * SECS, 1,dev);
435 if (res != CF_TRANS_OK) {
436 printk(KERN_ERR "cf-mips: failed to detect block size: busy!\n");
437 dev->block_size = 1;
438 return;
439 }
440 if ((rareg(ATA_REG_ST,dev) & ATA_REG_ST_ERR) == 0)
441 break;
442 dev->block_size /= 2;
443 } while (dev->block_size > 1);
444
445 printk(KERN_INFO "cf-mips: multiple sectors = %d\n", dev->block_size);
446 }
447
448 int cf_init(struct cf_mips_dev *dev)
449 {
450 tasklet_init(&dev->tasklet,cf_do_tasklet,(unsigned long)dev);
451 dev->baddr = ioremap_nocache((unsigned long)dev->base, CFDEV_BUF_SIZE);
452 if (!dev->baddr) {
453 printk(KERN_ERR "cf-mips: cf_init: ioremap for (%lx,%x) failed\n",
454 (unsigned long) dev->base, CFDEV_BUF_SIZE);
455 return -EBUSY;
456 }
457
458 if (!cf_present(dev)) {
459 printk(KERN_WARNING "cf-mips: cf card not present\n");
460 iounmap(dev->baddr);
461 return -ENODEV;
462 }
463
464 if (do_reset(dev) != CF_TRANS_OK) {
465 printk(KERN_ERR "cf-mips: cf reset failed\n");
466 iounmap(dev->baddr);
467 return -EBUSY;
468 }
469
470 if (!do_identify(dev)) {
471 printk(KERN_ERR "cf-mips: cf identify failed\n");
472 iounmap(dev->baddr);
473 return -EBUSY;
474 }
475
476 /* set_apm_level(ATA_APM_WITH_STANDBY); */
477 init_multiple(dev);
478
479 init_timer(&dev->to_timer);
480 dev->to_timer.function = cf_async_timeout;
481 dev->to_timer.data = (unsigned long)dev;
482
483 prepare_cf_irq(dev);
484 if (request_irq(dev->irq, cf_irq_handler, 0, "CF Mips", dev)) {
485 printk(KERN_ERR "cf-mips: failed to get irq\n");
486 iounmap(dev->baddr);
487 return -EBUSY;
488 }
489 /* Disable below would be odd, because request will enable, and the tasklet
490 will disable it itself */
491 //disable_irq(dev->irq);
492
493 dev->async_mode = 1;
494
495 return 0;
496 }
497
498 void cf_cleanup(struct cf_mips_dev *dev)
499 {
500 iounmap(dev->baddr);
501 free_irq(dev->irq, NULL);
502 #if REQUEST_MEM_REGION
503 release_mem_region((unsigned long)dev->base, CFDEV_BUF_SIZE);
504 #endif
505 }
506
507
508 /*eof*/
This page took 0.085289 seconds and 5 git commands to generate.