OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [or32/] [drivers/] [sd_card.c] - Blame information for rev 19

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 16 xianfeng
/*
2
 *
3
 * Block driver for spiMaster to drive SD card
4
 *
5
 * Copyright (c) 2008 by:
6
 *      Xianfeng Zeng <xianfeng.zeng@gmail.com>
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the BSD Licence, GNU General Public License
10
 * as published by the Free Software Foundation; either version 2 of the
11
 * License, or (at your option) any later version
12
 *
13
 * ChangeLog:
14
 *      2009-11-28 15:11:18   Xianfeng Zeng
15
 *          Init.
16
 *
17
 */
18
 
19
#include <linux/version.h>
20
#include <linux/module.h>
21
#include <linux/init.h>
22
#include <linux/kernel.h>
23
#include <linux/sched.h>
24
#include <linux/fs.h>
25
#include <linux/genhd.h>
26
#include <linux/delay.h>
27
 
28
#include <linux/slab.h>         /* kmalloc() */
29
#include <linux/errno.h>        /* error codes */
30
#include <linux/timer.h>
31
#include <linux/types.h>        /* size_t */
32
#include <linux/fcntl.h>        /* O_ACCMODE */
33
#include <linux/hdreg.h>        /* HDIO_GETGEO */
34
#include <linux/kdev_t.h>
35
#include <linux/vmalloc.h>
36
#include <linux/genhd.h>
37
#include <linux/blkdev.h>
38
#include <linux/buffer_head.h>  /* invalidate_bdev */
39
#include <linux/bio.h>
40
 
41
 
42
#include "sd_card.h"
43
 
44 19 xianfeng
//#define SDC_DEBUG 1
45 16 xianfeng
 
46
#ifdef SDC_DEBUG
47
#       define SDC_PRINTK(fmt, args...) printk( KERN_WARNING "sd_card:" fmt, ## args)
48
#else
49
#       define SDC_PRINTK(fmt, args...)
50
#endif
51
 
52 18 xianfeng
#define DRIVER_NAME     "sd_card"
53
#define SD_CARD_MINORS  8
54
#define SD_CARD_SIZE    1995440128
55 19 xianfeng
//(512*1024*1024)
56
//1995440128
57 16 xianfeng
 
58
static int major = 8;
59
 
60
 
61
/**
62
 * ============================================================
63
 *
64
 * ============================================================
65
 */
66
int spiMaster_init(void *vbase)
67
{
68
        unsigned char data;
69
        int   i;
70
 
71
        SDC_PRINTK("spiMaster_init begin\n");
72
 
73
        for (i = 0; i < 5; i++) {
74
                REG8(vbase + SD_TRANS_TYPE_REG) = SD_INIT_SD;
75
                REG8(vbase + SD_TRANS_CTRL_REG) = 1; // TRANS_START;
76
 
77
                mdelay(1);
78
 
79
                while (REG8(vbase + SD_TRANS_STS_REG) & 0x1) { // exit while !TRABS_BUSY
80
                        ;
81
                }
82
 
83
                data = REG8(vbase + SD_TRANS_ERROR_REG) & 0x3;
84
 
85
                if (data == 0) {
86
                        SDC_PRINTK("spiMaster_init done\n");
87
                        return 0;
88
                }
89
        }
90
 
91
        SDC_PRINTK("spiMaster_init failed\n");
92
 
93
        return data;
94
}
95
 
96
/**
97
 * ============================================================
98
 *             Request Handling
99
 * ============================================================
100
 */
101
 
102
static int read_sd_block(void *sd_vbase, unsigned long sector,
103
                unsigned long nsect, char *buffer)
104
{
105
        unsigned char data;
106
        unsigned char transError;
107
        int i;
108
        unsigned int buffer_offset = 0;
109
        unsigned int blockCnt;
110 19 xianfeng
        unsigned int start = sector << 9; /* x512*/
111 16 xianfeng
 
112 19 xianfeng
        SDC_PRINTK("read_sd_block begin: sector=%ld, nsect=%ld\n", sector, nsect);
113 16 xianfeng
 
114
        for (blockCnt = 0; blockCnt < nsect; blockCnt++) {
115
                REG8(sd_vbase + SD_ADDR_7_0_REG)   = 0;
116 19 xianfeng
                REG8(sd_vbase + SD_ADDR_15_8_REG)  = (unsigned char) ((start >> 8) & 0xff);
117
                REG8(sd_vbase + SD_ADDR_23_16_REG) = (unsigned char) ((start >> 16) & 0xff);
118
                REG8(sd_vbase + SD_ADDR_31_24_REG) = (unsigned char) ((start >> 24) & 0xff);
119 16 xianfeng
 
120
                REG8(sd_vbase + SD_TRANS_TYPE_REG) = SD_RW_READ_SD_BLOCK;
121 18 xianfeng
                REG8(sd_vbase + SD_RX_FIFO_CONTROL_REG) = 0x1; /* Clean the RX FIFO */
122
                REG8(sd_vbase + SD_TRANS_CTRL_REG) = 0x1; /* TRANS_START */
123 19 xianfeng
 
124
 
125 18 xianfeng
                while (REG8(sd_vbase + SD_TRANS_STS_REG) & 0x1) { /* exit while !TRABS_BUSY */
126 16 xianfeng
                        ;
127
                }
128
 
129
                transError = REG8(sd_vbase + SD_TRANS_ERROR_REG) & 0xc;
130
                if ( transError == SD_READ_NO_ERROR) {
131
                        for (i = 0; i < 512; i++) {
132
                                data = REG8(sd_vbase + SD_RX_FIFO_DATA_REG) ;
133 19 xianfeng
                                //REG8(buffer + buffer_offset + i) = data ;
134
                                buffer[buffer_offset + i] = data ;
135
//                              printk("%x\t",data);
136
//                              if (i%16 == 0) {
137
//                                      printk("\n");
138
//                              }
139 16 xianfeng
                        }
140 19 xianfeng
//                      printk("\n");
141 16 xianfeng
                        buffer_offset += 512;
142 19 xianfeng
                        start += 512;
143 16 xianfeng
                } else {
144
                        SDC_PRINTK("read_sd_block failed. Re-try\n");
145
                        spiMaster_init(sd_vbase); /* Init again and retry */
146
                        blockCnt--; /* read the same block again */
147
                }
148
        }
149
 
150
        SDC_PRINTK("read_sd_block done\n");
151
 
152
        return 0;
153
}
154
 
155 18 xianfeng
static int write_sd_block(void *sd_vbase, unsigned long sector,
156
                unsigned long nsect, char *buffer)
157
{
158
        int i;
159
        unsigned char data;
160
        unsigned int blockCnt;
161
        char *p = buffer;
162 19 xianfeng
        unsigned int start = sector << 9; /* x512*/
163 16 xianfeng
 
164 18 xianfeng
 
165 19 xianfeng
        SDC_PRINTK("write_sd_block begin: sector=%ld, nsect=%ld\n", sector, nsect);
166
 
167 18 xianfeng
        for (blockCnt = 0; blockCnt < nsect; blockCnt++) {
168
 
169
                /* Clean the TX FIFO */
170
                REG8(sd_vbase + SD_TX_FIFO_CONTROL_REG) = 0x1;
171
 
172
                REG8(sd_vbase + SD_ADDR_7_0_REG)   = 0;
173 19 xianfeng
                REG8(sd_vbase + SD_ADDR_15_8_REG)  = (unsigned char) ((start >> 8) & 0xff);
174
                REG8(sd_vbase + SD_ADDR_23_16_REG) = (unsigned char) ((start >> 16) & 0xff);
175
                REG8(sd_vbase + SD_ADDR_31_24_REG) = (unsigned char) ((start >> 24) & 0xff);
176 18 xianfeng
 
177
 
178
                // Write data to TX_FIFO_DATA_REG
179
                for (i = 0; i < 512; i++) {
180
                        REG8(sd_vbase + SD_TX_FIFO_DATA_REG) = p[i];
181
                }
182
 
183
                REG8(sd_vbase + SD_TRANS_TYPE_REG) = SD_RW_WRITE_SD_BLOCK;
184
                REG8(sd_vbase + SD_TRANS_CTRL_REG) = 1; /* TRANS_START */
185
 
186 19 xianfeng
                udelay(10);
187 18 xianfeng
                while (REG8(sd_vbase + SD_TRANS_STS_REG) & 0x1) { /* exit while !TRABS_BUSY */
188
                        ;
189
                }
190
 
191
                data = REG8(sd_vbase + SD_TRANS_ERROR_REG) & 0x30;
192
                if (data == 1) {
193 19 xianfeng
                        printk("sd_card:WRITE_CMD_ERROR\n\r");
194 18 xianfeng
                } else if (data == 2) {
195 19 xianfeng
                        printk("sd_card:WRITE_DATA_ERROR\n\r");
196 18 xianfeng
                } else if (data == 3) {
197 19 xianfeng
                        printk("sd_card:WRITE_BUSY_ERROR\n\r");
198 18 xianfeng
                }
199
 
200 19 xianfeng
                start += 512;
201 18 xianfeng
                p += 512;
202
        }
203
 
204
        SDC_PRINTK("write_sd_block done\n");
205
        return 0;
206
}
207
 
208 16 xianfeng
/*
209
 * Handle an I/O request.
210
 */
211
static void sd_card_transfer(struct sd_card_dev *dev, unsigned long sector,
212
                unsigned long nsect, char *buffer, int write)
213
{
214
        unsigned long offset = sector*512;
215
        unsigned long nbytes = nsect*512;
216
 
217
        if ((offset + nbytes) > dev->size) {
218
                printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);
219
                return;
220
        }
221
        if (write)
222 18 xianfeng
                write_sd_block(dev->vir_base, sector, nsect, buffer);
223 16 xianfeng
        else
224
                read_sd_block(dev->vir_base, sector, nsect, buffer);
225
}
226
 
227
 
228
/*
229
 * The simple form of the request function.
230
 */
231
static void sd_card_request(request_queue_t *q)
232
{
233
        struct request *req;
234
 
235
        while ((req = elv_next_request(q)) != NULL) {
236
                struct sd_card_dev *dev = req->rq_disk->private_data;
237
                if (! blk_fs_request(req)) {
238
                        printk (KERN_NOTICE "Skip non-fs request\n");
239
                        end_request(req, 0);
240
                        continue;
241
                }
242
    //          printk (KERN_NOTICE "Req dev %d dir %ld sec %ld, nr %d f %lx\n",
243
    //                          dev - Devices, rq_data_dir(req),
244
    //                          req->sector, req->current_nr_sectors,
245
    //                          req->flags);
246
                sd_card_transfer(dev, req->sector, req->current_nr_sectors,
247
                                req->buffer, rq_data_dir(req));
248
                end_request(req, 1);
249
        }
250
}
251
 
252
/**
253
 * ============================================================
254
 *             Block device operations
255
 * ============================================================
256
 */
257
static int sd_card_open(struct inode *inode, struct file *filp)
258
{
259
        struct sd_card_dev *dev = inode->i_bdev->bd_disk->private_data;
260
 
261
        SDC_PRINTK("sd_card_open beging\n");
262
 
263
        filp->private_data = dev;
264
        spin_lock(&dev->lock);
265
        if (! dev->users)
266
                check_disk_change(inode->i_bdev);
267
 
268
        /* Init SD card controller */
269
        spiMaster_init(dev->vir_base);
270
 
271
        dev->users++;
272
        spin_unlock(&dev->lock);
273
 
274
        SDC_PRINTK("sd_card_open done\n");
275
 
276
        return 0;
277
}
278
 
279
static int sd_card_release(struct inode *inode, struct file *filp)
280
{
281
        struct sd_card_dev *dev = inode->i_bdev->bd_disk->private_data;
282
 
283
        SDC_PRINTK("sd_card_release beging\n");
284
 
285
        spin_lock(&dev->lock);
286
        dev->users--;
287
 
288
        spin_unlock(&dev->lock);
289
 
290
        SDC_PRINTK("sd_card_release done\n");
291
 
292
        return 0;
293
}
294
 
295
/*
296
 * Look for a (simulated) media change.
297
 */
298
int sd_card_media_changed(struct gendisk *gd)
299
{
300
        //struct sd_card_dev *dev = gd->private_data;
301
 
302
        return 0; //dev->media_change;
303
}
304
 
305
/*
306
 * Revalidate.  WE DO NOT TAKE THE LOCK HERE, for fear of deadlocking
307
 * with open.  That needs to be reevaluated.
308
 */
309
int sd_card_revalidate(struct gendisk *gd)
310
{
311
        struct sd_card_dev *dev = gd->private_data;
312
 
313
        if (dev->media_change) {
314
                dev->media_change = 0;
315
//              memset (dev->data, 0, dev->size);
316
        }
317
        return 0;
318
}
319
 
320
 
321
/*
322
 * The ioctl() implementation
323
 */
324
 
325 19 xianfeng
static int sd_card_getgeo(struct block_device *bdev,
326
                struct hd_geometry *geo)
327
{
328
        /*
329
         * capacity        heads        sectors        cylinders
330
         * 0~16M             1             1           0~32768
331
         * 16M~512M          1             32          1024~32768
332
         * 512M~16G          32            32          1024~32768
333
         * 16G~...           255           63          2088~...
334
         */
335
        if (SD_CARD_SIZE < 16 * 1024 * 1024) {
336
                geo->heads = 1;
337
                geo->sectors = 1;
338
 
339
        } else if (SD_CARD_SIZE < 512 * 1024 * 1024) {
340
                geo->heads = 1;
341
                geo->sectors = 32;
342
        } else if (SD_CARD_SIZE < 16ULL * 1024 * 1024 * 1024) {
343
                geo->heads = 32;
344
                geo->sectors = 32;
345
        } else {
346
                geo->heads = 255;
347
                geo->sectors = 63;
348
        }
349
 
350
        geo->cylinders = SD_CARD_SIZE>>9/geo->heads/geo->sectors;
351
 
352
        return 0;
353
}
354
 
355 16 xianfeng
int sd_card_ioctl (struct inode *inode, struct file *filp,
356
                 unsigned int cmd, unsigned long arg)
357
{
358
        long size;
359
        struct hd_geometry geo;
360
        struct sd_card_dev *dev = filp->private_data;
361
 
362
        switch(cmd) {
363
            case HDIO_GETGEO:
364
                /*
365
                 * Get geometry: since we are a virtual device, we have to make
366
                 * up something plausible.  So we claim 16 sectors, four heads,
367
                 * and calculate the corresponding number of cylinders.  We set the
368
                 * start of data at sector four.
369
                 */
370
                size = dev->size;
371 18 xianfeng
                geo.cylinders = (size & ~0x3f) >> 6;
372
                geo.heads = 62; //32;
373 16 xianfeng
                geo.sectors = 62; //63;
374 18 xianfeng
                geo.start = get_start_sect(inode->i_bdev);
375 16 xianfeng
                if (copy_to_user((void __user *) arg, &geo, sizeof(geo)))
376
                        return -EFAULT;
377
                return 0;
378
        }
379
 
380
        return -ENOTTY; /* unknown command */
381
}
382
 
383
 
384
/*
385
 * The device operations structure.
386
 */
387
static struct block_device_operations sd_card_ops = {
388
        .owner           = THIS_MODULE,
389
        .open            = sd_card_open,
390
        .release         = sd_card_release,
391
        .media_changed   = sd_card_media_changed,
392
        .revalidate_disk = sd_card_revalidate,
393 19 xianfeng
//      .ioctl           = sd_card_ioctl,
394
        .getgeo          = sd_card_getgeo
395 16 xianfeng
};
396
 
397
/**
398
 * ============================================================
399
 *                 Driver Entry and clean up
400
 * ============================================================
401
 */
402
static int __init sd_card_init(void)
403
{
404
        int ret;
405
        struct sd_card_dev  *dev;
406
 
407
        /* Put the init code here */
408
        printk(KERN_INFO "SD Card Driver Enter.\n");
409
 
410
        dev = (struct sd_card_dev *)kmalloc(sizeof(struct sd_card_dev), GFP_KERNEL);
411
        if (dev < 0) {
412
                printk(KERN_WARNING "lack of memory\n");
413
                return -1;
414
        }
415
        memset(dev, 0, sizeof(struct sd_card_dev));
416
 
417
        ret = register_blkdev(major, DRIVER_NAME);
418
        if (ret <0) {
419
                printk(KERN_WARNING "sd_card: unable to get major number\n");
420
                kfree(dev);
421
                return -EBUSY;
422
        }
423
 
424 18 xianfeng
        dev->size = SD_CARD_SIZE; //1015808000; /* 1GB */
425 16 xianfeng
        spin_lock_init(&dev->lock);
426
        dev->queue = blk_init_queue(sd_card_request, &dev->lock);
427
        blk_queue_hardsect_size(dev->queue, 512);
428
 
429
        dev->vir_base = ioremap(SD_BASE_ADD, 0x2000);
430
 
431 18 xianfeng
        /* Reset spiMaster controller */
432
        REG8(dev->vir_base + SD_TRANS_CTRL_REG) = 0x1;  /* reset spiMaster */
433
        mdelay(1);
434
        REG8(dev->vir_base + SD_TRANS_CTRL_REG) = 0x0;
435
        REG8(dev->vir_base + SD_CLK_DEL_REG) = 0x1;
436
 
437 16 xianfeng
        /* allocate gendsik and init it */
438
        dev->gd = alloc_disk(SD_CARD_MINORS);
439
        if (!dev->gd) {
440
                printk(KERN_WARNING "alloc_disk failed\n");
441
                kfree(dev);
442
                unregister_blkdev(major, DRIVER_NAME);
443
                return -1;
444
        }
445
        dev->gd->major          = major;
446
        dev->gd->first_minor    = 0;
447
        dev->gd->fops           = &sd_card_ops;
448
        dev->gd->queue          = dev->queue;
449
        dev->gd->private_data   = dev;
450
        snprintf(dev->gd->disk_name, 32, "sd%c", 'a');
451
 
452
        set_capacity(dev->gd, dev->size/512);
453
 
454
        add_disk(dev->gd);
455
 
456
        SDC_PRINTK("sd_card_init done\n");
457
 
458
        return 0;
459
}
460
 
461
 
462
static void __exit sd_card_exit(void)
463
{
464
        /* Put the driver clean up code here */
465
 
466
        unregister_blkdev(major, DRIVER_NAME);
467
 
468
        printk(KERN_INFO "SD Card Driver Exit.\n");
469
}
470
 
471
//module_init(sd_card_init);
472
late_initcall(sd_card_init);
473
module_exit(sd_card_exit);
474
 
475
MODULE_LICENSE("Dual BSD/GPL");
476
MODULE_AUTHOR("Xianfeng Zeng - Xianfeng.zeng@SierraAtlantic.com, http://www.LinuxExperts.cn");
477
MODULE_DESCRIPTION("spiMaster driver");
478
MODULE_VERSION("0.1");
479
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.