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
Compare Revisions
- This comparison shows the changes necessary to convert path
/or1k_soc_on_altera_embedded_dev_kit/trunk
- from Rev 13 to Rev 16
- ↔ Reverse comparison
Rev 13 → Rev 16
/linux-2.6/linux-2.6.24/arch/or32/drivers/sd_card.c
0,0 → 1,380
/* |
* |
* Block driver for spiMaster to drive SD card |
* |
* Copyright (c) 2008 by: |
* Xianfeng Zeng <xianfeng.zeng@gmail.com> |
* |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the BSD Licence, GNU General Public License |
* as published by the Free Software Foundation; either version 2 of the |
* License, or (at your option) any later version |
* |
* ChangeLog: |
* 2009-11-28 15:11:18 Xianfeng Zeng |
* Init. |
* |
*/ |
|
#include <linux/version.h> |
#include <linux/module.h> |
#include <linux/init.h> |
#include <linux/kernel.h> |
#include <linux/sched.h> |
#include <linux/fs.h> |
#include <linux/genhd.h> |
#include <linux/delay.h> |
|
#include <linux/slab.h> /* kmalloc() */ |
#include <linux/errno.h> /* error codes */ |
#include <linux/timer.h> |
#include <linux/types.h> /* size_t */ |
#include <linux/fcntl.h> /* O_ACCMODE */ |
#include <linux/hdreg.h> /* HDIO_GETGEO */ |
#include <linux/kdev_t.h> |
#include <linux/vmalloc.h> |
#include <linux/genhd.h> |
#include <linux/blkdev.h> |
#include <linux/buffer_head.h> /* invalidate_bdev */ |
#include <linux/bio.h> |
|
|
#include "sd_card.h" |
|
#define SDC_DEBUG 1 |
|
#ifdef SDC_DEBUG |
# define SDC_PRINTK(fmt, args...) printk( KERN_WARNING "sd_card:" fmt, ## args) |
#else |
# define SDC_PRINTK(fmt, args...) |
#endif |
|
#define DRIVER_NAME "sd_card" |
#define SD_CARD_MINORS 16 |
|
static int major = 8; |
|
|
/** |
* ============================================================ |
* |
* ============================================================ |
*/ |
int spiMaster_init(void *vbase) |
{ |
unsigned char data; |
int i; |
|
SDC_PRINTK("spiMaster_init begin\n"); |
|
REG8(vbase + SD_TX_FIFO_CONTROL_REG) = 0x10; |
|
for (i = 0; i < 5; i++) { |
REG8(vbase + SD_TRANS_TYPE_REG) = SD_INIT_SD; |
REG8(vbase + SD_TRANS_CTRL_REG) = 1; // TRANS_START; |
|
mdelay(1); |
|
while (REG8(vbase + SD_TRANS_STS_REG) & 0x1) { // exit while !TRABS_BUSY |
; |
} |
|
data = REG8(vbase + SD_TRANS_ERROR_REG) & 0x3; |
|
if (data == 0) { |
SDC_PRINTK("spiMaster_init done\n"); |
return 0; |
} |
} |
|
SDC_PRINTK("spiMaster_init failed\n"); |
|
return data; |
} |
|
/** |
* ============================================================ |
* Request Handling |
* ============================================================ |
*/ |
|
static int read_sd_block(void *sd_vbase, unsigned long sector, |
unsigned long nsect, char *buffer) |
{ |
unsigned char data; |
unsigned char transError; |
int i; |
unsigned int buffer_offset = 0; |
unsigned int blockCnt; |
|
SDC_PRINTK("read_sd_block begin: sector=%d, nsect=%d\n", sector, nsect); |
|
for (blockCnt = 0; blockCnt < nsect; blockCnt++) { |
REG8(sd_vbase + SD_ADDR_7_0_REG) = 0; |
REG8(sd_vbase + SD_ADDR_15_8_REG) = (unsigned char) ((sector >> 8) & 0xff); |
REG8(sd_vbase + SD_ADDR_23_16_REG) = (unsigned char) ((sector >> 16) & 0xff); |
REG8(sd_vbase + SD_ADDR_31_24_REG) = (unsigned char) ((sector >> 24) & 0xff); |
|
REG8(sd_vbase + SD_TRANS_TYPE_REG) = SD_RW_READ_SD_BLOCK; |
REG8(sd_vbase + SD_RX_FIFO_CONTROL_REG) = 0x1; // Clean the RX FIFO |
REG8(sd_vbase + SD_TRANS_CTRL_REG) = 0x1; //TRANS_START |
while (REG8(sd_vbase + SD_TRANS_STS_REG) & 0x1) { // exit while !TRABS_BUSY |
; |
} |
|
transError = REG8(sd_vbase + SD_TRANS_ERROR_REG) & 0xc; |
if ( transError == SD_READ_NO_ERROR) { |
for (i = 0; i < 512; i++) { |
data = REG8(sd_vbase + SD_RX_FIFO_DATA_REG) ; |
REG8(buffer + buffer_offset + i) = data ; |
} |
buffer_offset += 512; |
sector += 512; |
} else { |
SDC_PRINTK("read_sd_block failed. Re-try\n"); |
spiMaster_init(sd_vbase); /* Init again and retry */ |
blockCnt--; /* read the same block again */ |
} |
} |
|
SDC_PRINTK("read_sd_block done\n"); |
|
return 0; |
} |
|
|
/* |
* Handle an I/O request. |
*/ |
static void sd_card_transfer(struct sd_card_dev *dev, unsigned long sector, |
unsigned long nsect, char *buffer, int write) |
{ |
unsigned long offset = sector*512; |
unsigned long nbytes = nsect*512; |
|
if ((offset + nbytes) > dev->size) { |
printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes); |
return; |
} |
if (write) |
printk(KERN_WARNING "Sorry, we are still working on sd block write\n"); |
else |
read_sd_block(dev->vir_base, sector, nsect, buffer); |
} |
|
|
/* |
* The simple form of the request function. |
*/ |
static void sd_card_request(request_queue_t *q) |
{ |
struct request *req; |
|
while ((req = elv_next_request(q)) != NULL) { |
struct sd_card_dev *dev = req->rq_disk->private_data; |
if (! blk_fs_request(req)) { |
printk (KERN_NOTICE "Skip non-fs request\n"); |
end_request(req, 0); |
continue; |
} |
// printk (KERN_NOTICE "Req dev %d dir %ld sec %ld, nr %d f %lx\n", |
// dev - Devices, rq_data_dir(req), |
// req->sector, req->current_nr_sectors, |
// req->flags); |
sd_card_transfer(dev, req->sector, req->current_nr_sectors, |
req->buffer, rq_data_dir(req)); |
end_request(req, 1); |
} |
} |
|
/** |
* ============================================================ |
* Block device operations |
* ============================================================ |
*/ |
static int sd_card_open(struct inode *inode, struct file *filp) |
{ |
struct sd_card_dev *dev = inode->i_bdev->bd_disk->private_data; |
|
SDC_PRINTK("sd_card_open beging\n"); |
|
filp->private_data = dev; |
spin_lock(&dev->lock); |
if (! dev->users) |
check_disk_change(inode->i_bdev); |
|
/* Init SD card controller */ |
spiMaster_init(dev->vir_base); |
|
dev->users++; |
spin_unlock(&dev->lock); |
|
SDC_PRINTK("sd_card_open done\n"); |
|
return 0; |
} |
|
static int sd_card_release(struct inode *inode, struct file *filp) |
{ |
struct sd_card_dev *dev = inode->i_bdev->bd_disk->private_data; |
|
SDC_PRINTK("sd_card_release beging\n"); |
|
spin_lock(&dev->lock); |
dev->users--; |
|
spin_unlock(&dev->lock); |
|
SDC_PRINTK("sd_card_release done\n"); |
|
return 0; |
} |
|
/* |
* Look for a (simulated) media change. |
*/ |
int sd_card_media_changed(struct gendisk *gd) |
{ |
//struct sd_card_dev *dev = gd->private_data; |
|
return 0; //dev->media_change; |
} |
|
/* |
* Revalidate. WE DO NOT TAKE THE LOCK HERE, for fear of deadlocking |
* with open. That needs to be reevaluated. |
*/ |
int sd_card_revalidate(struct gendisk *gd) |
{ |
struct sd_card_dev *dev = gd->private_data; |
|
if (dev->media_change) { |
dev->media_change = 0; |
// memset (dev->data, 0, dev->size); |
} |
return 0; |
} |
|
|
/* |
* The ioctl() implementation |
*/ |
|
int sd_card_ioctl (struct inode *inode, struct file *filp, |
unsigned int cmd, unsigned long arg) |
{ |
long size; |
struct hd_geometry geo; |
struct sd_card_dev *dev = filp->private_data; |
|
switch(cmd) { |
case HDIO_GETGEO: |
/* |
* Get geometry: since we are a virtual device, we have to make |
* up something plausible. So we claim 16 sectors, four heads, |
* and calculate the corresponding number of cylinders. We set the |
* start of data at sector four. |
*/ |
size = dev->size; |
geo.cylinders = 1010; //984; |
geo.heads = 8; //32; |
geo.sectors = 62; //63; |
geo.start = 0; |
if (copy_to_user((void __user *) arg, &geo, sizeof(geo))) |
return -EFAULT; |
return 0; |
} |
|
return -ENOTTY; /* unknown command */ |
} |
|
|
/* |
* The device operations structure. |
*/ |
static struct block_device_operations sd_card_ops = { |
.owner = THIS_MODULE, |
.open = sd_card_open, |
.release = sd_card_release, |
.media_changed = sd_card_media_changed, |
.revalidate_disk = sd_card_revalidate, |
.ioctl = sd_card_ioctl |
}; |
|
/** |
* ============================================================ |
* Driver Entry and clean up |
* ============================================================ |
*/ |
static int __init sd_card_init(void) |
{ |
int ret; |
struct sd_card_dev *dev; |
|
/* Put the init code here */ |
printk(KERN_INFO "SD Card Driver Enter.\n"); |
|
dev = (struct sd_card_dev *)kmalloc(sizeof(struct sd_card_dev), GFP_KERNEL); |
if (dev < 0) { |
printk(KERN_WARNING "lack of memory\n"); |
return -1; |
} |
memset(dev, 0, sizeof(struct sd_card_dev)); |
|
ret = register_blkdev(major, DRIVER_NAME); |
if (ret <0) { |
printk(KERN_WARNING "sd_card: unable to get major number\n"); |
kfree(dev); |
return -EBUSY; |
} |
|
dev->size = 256638976; //1015808000; /* 1GB */ |
spin_lock_init(&dev->lock); |
dev->queue = blk_init_queue(sd_card_request, &dev->lock); |
blk_queue_hardsect_size(dev->queue, 512); |
|
dev->vir_base = ioremap(SD_BASE_ADD, 0x2000); |
|
/* allocate gendsik and init it */ |
dev->gd = alloc_disk(SD_CARD_MINORS); |
if (!dev->gd) { |
printk(KERN_WARNING "alloc_disk failed\n"); |
kfree(dev); |
unregister_blkdev(major, DRIVER_NAME); |
return -1; |
} |
dev->gd->major = major; |
dev->gd->first_minor = 0; |
dev->gd->fops = &sd_card_ops; |
dev->gd->queue = dev->queue; |
dev->gd->private_data = dev; |
snprintf(dev->gd->disk_name, 32, "sd%c", 'a'); |
|
set_capacity(dev->gd, dev->size/512); |
|
add_disk(dev->gd); |
|
SDC_PRINTK("sd_card_init done\n"); |
|
return 0; |
} |
|
|
static void __exit sd_card_exit(void) |
{ |
/* Put the driver clean up code here */ |
|
unregister_blkdev(major, DRIVER_NAME); |
|
printk(KERN_INFO "SD Card Driver Exit.\n"); |
} |
|
//module_init(sd_card_init); |
late_initcall(sd_card_init); |
module_exit(sd_card_exit); |
|
MODULE_LICENSE("Dual BSD/GPL"); |
MODULE_AUTHOR("Xianfeng Zeng - Xianfeng.zeng@SierraAtlantic.com, http://www.LinuxExperts.cn"); |
MODULE_DESCRIPTION("spiMaster driver"); |
MODULE_VERSION("0.1"); |
|
/linux-2.6/linux-2.6.24/arch/or32/drivers/sd_card.h
0,0 → 1,59
#ifndef __SD_CARD_H__ |
#define __SD_CARD_H__ |
|
|
#define SD_BASE_ADD 0x50000000 |
|
#define SD_TRANS_TYPE_REG 0x2 |
#define SD_TRANS_CTRL_REG 0x3 |
#define SD_TRANS_STS_REG 0x4 |
#define SD_TRANS_ERROR_REG 0x5 |
#define SD_DIRECT_ACCESS_DATA_REG 0x6 |
#define SD_ADDR_7_0_REG 0x7 |
#define SD_ADDR_15_8_REG 0x8 |
#define SD_ADDR_23_16_REG 0x9 |
#define SD_ADDR_31_24_REG 0xa |
#define SD_CLK_DEL_REG 0xb |
#define SD_RX_FIFO_DATA_REG 0x10 |
#define SD_RX_FIFO_DATA_COUNT_MSB 0x12 |
#define SD_RX_FIFO_DATA_COUNT_LSB 0x13 |
#define SD_RX_FIFO_CONTROL_REG 0x14 |
#define SD_TX_FIFO_DATA_REG 0x20 |
#define SD_TX_FIFO_CONTROL_REG 0x24 |
|
#define SD_DIRECT_ACCESS 0 |
#define SD_INIT_SD 1 |
#define SD_RW_READ_SD_BLOCK 2 |
#define SD_RW_WRITE_SD_BLOCK 3 |
|
#define SD_WRITE_NO_ERROR 0 |
#define SD_WRITE_CMD_ERROR 1 |
#define SD_WRITE_DATA_ERROR 2 |
#define SD_WRITE_BUSY_ERROR 3 |
|
#define SD_READ_NO_ERROR 0 |
#define SD_READ_CMD_ERROR 1 |
#define SD_READ_TOKEN_ERROR 2 |
|
#define SD_INIT_NO_ERROR 0 |
#define SD_INIT_CMD0_ERROR 1 |
#define SD_INIT_CMD1_ERROR 2 |
|
#define REG8(add) *((volatile unsigned char *) (add)) |
#define REG16(add) *((volatile unsigned short *) (add)) |
#define REG32(add) *((volatile unsigned long *) (add)) |
|
struct sd_card_dev { |
void *vir_base; /* Virtual address for spiMaster */ |
int size; /* the size of the SD Card */ |
short users; /* How many users are using me */ |
short media_change; /* a flag to save the media change */ |
spinlock_t lock; /* lock for request queue */ |
struct request_queue *queue; /* request queue */ |
struct gendisk *gd; /* gendisk */ |
}; |
|
|
|
#endif /* __SD_CARD_H__ */ |
|
/linux-2.6/linux-2.6.24/arch/or32/drivers/Makefile
3,4 → 3,5
# |
|
obj-$(CONFIG_OETH) += open_eth.o |
#obj-y += sd_card.o |
|