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