Line 1... |
Line 1... |
/* -*- linux-c -*-
|
/* -*- linux-c -*-
|
*
|
*
|
* OpenCores MMC Controller driver
|
* OpenCores MMC Controller driver
|
*
|
*
|
|
*
|
|
* Command 51 and Command 2 hardcoded
|
|
*
|
|
*
|
|
*
|
* Copyright (C) 2009 ORSoC, All Rights Reserved.
|
* Copyright (C) 2009 ORSoC, All Rights Reserved.
|
*
|
*
|
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
* under the terms of the GNU General Public License as published
|
* under the terms of the GNU General Public License as published
|
* by the Free Software Foundation; version 2 of the License.
|
* by the Free Software Foundation; version 2 of the License.
|
Line 23... |
Line 28... |
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
#include <linux/delay.h>
|
#include <linux/delay.h>
|
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
#include <linux/err.h>
|
#include <linux/err.h>
|
#include <linux/mmc/host.h>
|
#include <linux/mmc/host.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/scatterlist.h>
|
|
#include <linux/highmem.h>
|
#include <asm/board.h>
|
#include <asm/board.h>
|
#include <asm/io.h>
|
#include <asm/io.h>
|
|
#include <asm/irq.h>
|
#include <asm/mmc.h>
|
#include <asm/mmc.h>
|
#include <asm/system.h>
|
#include <asm/system.h>
|
|
#include <linux/mmc/card.h>
|
#include "mmc_ocores.h"
|
#include "mmc_ocores.h"
|
|
|
#define DRIVER_NAME "mmc-ocores"
|
#define DRIVER_NAME "mmc-ocores"
|
|
|
#define NR_SG 1
|
#define NR_SG 1
|
|
|
|
|
|
|
|
|
struct ocores_host {
|
struct ocores_host {
|
struct mmc_host *mmc;
|
struct mmc_host *mmc;
|
spinlock_t lock;
|
spinlock_t lock;
|
struct resource *res;
|
struct resource *res;
|
void __iomem *base;
|
void __iomem *base;
|
Line 52... |
Line 62... |
struct mmc_data *data;
|
struct mmc_data *data;
|
int irq_cmd;
|
int irq_cmd;
|
int irq_dat;
|
int irq_dat;
|
unsigned int flags;
|
unsigned int flags;
|
struct tasklet_struct finish_cmd;
|
struct tasklet_struct finish_cmd;
|
|
struct tasklet_struct finish_data;
|
struct {
|
struct {
|
unsigned int normal_int_status;
|
unsigned int normal_int_status;
|
unsigned int error_int_status;
|
unsigned int error_int_status;
|
|
unsigned int data_int_status;
|
} registers;
|
} registers;
|
int clock;
|
int clock;
|
|
|
|
/* DMA buffer used for transmitting */
|
|
unsigned int* buffer;
|
|
dma_addr_t physical_address;
|
|
unsigned int total_length;
|
|
unsigned int dma_len;
|
|
/* Latest in the scatterlist that has been enabled for transfer, but not freed */
|
|
int in_use_index;
|
|
|
|
/* Latest in the scatterlist that has been enabled for transfer */
|
|
int transfer_index;
|
|
int free_tx_bd;
|
|
int free_rx_bd;
|
};
|
};
|
|
|
struct ocores_host *oc_host;
|
struct ocores_host *oc_host;
|
|
|
static void ocores_tasklet_finish_cmd(unsigned long param);
|
static void ocores_tasklet_finish_cmd(unsigned long param);
|
|
static void ocores_tasklet_finish_data(unsigned long param);
|
|
|
static inline void CMD_IRQ_ON(struct ocores_host *host, u32 mask)
|
static inline void CMD_IRQ_ON(struct ocores_host *host, u32 mask)
|
{
|
{
|
u32 val = readl(host->base + SD_NOMAL_INT_SIGNAL_ENABLE);
|
u32 val = readl(host->base + SD_NOMAL_INT_SIGNAL_ENABLE);
|
printk(KERN_ALERT "Int mask = %08x\n", val);
|
|
val |= mask;
|
val |= mask;
|
writel (val, host->base + SD_NOMAL_INT_SIGNAL_ENABLE);
|
writel (val, host->base + SD_NOMAL_INT_SIGNAL_ENABLE);
|
printk(KERN_ALERT "Int mask = %08x\n", val);
|
|
}
|
}
|
|
|
static inline void CMD_IRQ_OFF(struct ocores_host *host, u32 mask)
|
static inline void CMD_IRQ_OFF(struct ocores_host *host, u32 mask)
|
{
|
{
|
u32 val = readl(host->base + SD_NOMAL_INT_SIGNAL_ENABLE);
|
u32 val = readl(host->base + SD_NOMAL_INT_SIGNAL_ENABLE);
|
val &= ~mask;
|
val &= ~mask;
|
writel (val, host->base + SD_NOMAL_INT_SIGNAL_ENABLE);
|
writel (val, host->base + SD_NOMAL_INT_SIGNAL_ENABLE);
|
}
|
}
|
|
|
|
static inline void DAT_IRQ_ON(struct ocores_host *host, u32 mask)
|
|
{
|
|
u32 val = readl(host->base + SD_BD_ISER);
|
|
val |= mask;
|
|
writel (val, host->base + SD_BD_ISER);
|
|
}
|
|
|
|
static inline void DAT_IRQ_OFF(struct ocores_host *host, u32 mask)
|
|
{
|
|
u32 val = readl(host->base + SD_BD_ISER);
|
|
val &= ~mask;
|
|
writel (val, host->base + SD_BD_ISER);
|
|
}
|
|
|
|
|
|
static void ocores_pre_dma_read(struct ocores_host *host)
|
|
{
|
|
int i,j;
|
|
int off_scal;
|
|
struct scatterlist *sg;
|
|
struct mmc_command *cmd;
|
|
struct mmc_data *data;
|
|
|
|
off_scal=512;
|
|
if (host->mmc->card!= NULL){
|
|
|
|
if (mmc_card_blockaddr(host->mmc->card))
|
|
off_scal=1;
|
|
else
|
|
off_scal=512;
|
|
}
|
|
printk("pre dma read off %d\n", off_scal);
|
|
|
|
cmd = host->cmd;
|
|
if (!cmd) {
|
|
pr_debug("no command\n");
|
|
return;
|
|
}
|
|
data = cmd->data;
|
|
if (!data) {
|
|
pr_debug("no data\n");
|
|
return;
|
|
}
|
|
|
|
/* Setup the next transfer */
|
|
pr_debug("Using transfer index %d\n", host->transfer_index);
|
|
|
|
sg = &data->sg[host->transfer_index++];
|
|
printk("Using transfer index %d, sg offset %d\n", host->transfer_index,sg->offset);
|
|
pr_debug("sg = %p\n", sg);
|
|
printk("sg = %p\n", sg);
|
|
|
|
|
|
host->dma_len = dma_map_sg(mmc_dev(host->mmc), sg, data->sg_len, DMA_FROM_DEVICE);
|
|
printk(KERN_ALERT "dma address = %d, sg_dma_len %d, length = %d, sg_dma_len %d\n", sg_dma_address(&data->sg[0]), sg_dma_len(&data->sg[0]), sg->length, host->dma_len);
|
|
for (i = 0; i < host->dma_len; i++) {
|
|
unsigned int length = sg_dma_len(&data->sg[i]);
|
|
|
|
if (length >= 512)
|
|
length /=512;
|
|
else
|
|
length = 1;
|
|
|
|
printk(KERN_ALERT "DMA LEN %d\n", length);
|
|
//XXX:512 SD 1.0 card only.
|
|
for (j = 0; j< length;j++) {
|
|
pr_debug("dma address = %d, length = %d\n", sg_dma_address(&data->sg[i]), sg->length);
|
|
printk(KERN_ALERT "dma address = %d, length = %d, sg_dma_len %d\n", (sg_dma_address(&data->sg[i])+512*j), length, host->dma_len);
|
|
|
|
writel((sg_dma_address(&data->sg[i])+512*j), host->base + BD_RX);
|
|
wmb();
|
|
writel(cmd->arg+off_scal*j, host->base + BD_RX);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DAT_IRQ_ON (host,(TRE|FIFOE|MRC|TRS));
|
|
pr_debug("pre dma read done\n");
|
|
}
|
|
static void ocores_pre_dma_write(struct ocores_host *host)
|
|
{
|
|
int i,j;
|
|
int off_scal;
|
|
struct scatterlist *sg;
|
|
struct mmc_command *cmd;
|
|
struct mmc_data *data;
|
|
|
|
off_scal=512;
|
|
if (host->mmc->card!= NULL){
|
|
|
|
if (mmc_card_blockaddr(host->mmc->card))
|
|
off_scal=1;
|
|
else
|
|
off_scal=512;
|
|
}
|
|
printk("pre dma write off %d\n", off_scal);
|
|
|
|
cmd = host->cmd;
|
|
if (!cmd) {
|
|
pr_debug("no command\n");
|
|
return;
|
|
}
|
|
data = cmd->data;
|
|
if (!data) {
|
|
pr_debug("no data\n");
|
|
return;
|
|
}
|
|
|
|
/* Setup the next transfer */
|
|
pr_debug("Using transfer index %d\n", host->transfer_index);
|
|
|
|
sg = &data->sg[host->transfer_index++];
|
|
printk("Using transfer index %d, sg offset %d\n", host->transfer_index,sg->offset);
|
|
pr_debug("sg = %p\n", sg);
|
|
printk("sg = %p\n", sg);
|
|
|
|
|
|
host->dma_len = dma_map_sg(mmc_dev(host->mmc), sg, data->sg_len, DMA_TO_DEVICE);
|
|
printk(KERN_ALERT "dma address = %d, sg_dma_len %d, length = %d, sg_dma_len %d\n", sg_dma_address(&data->sg[0]), sg_dma_len(&data->sg[0]), sg->length, host->dma_len);
|
|
for (i = 0; i < host->dma_len; i++) {
|
|
unsigned int length = sg_dma_len(&data->sg[i]);
|
|
|
|
if (length >= 512)
|
|
length /=512;
|
|
else
|
|
length = 1;
|
|
|
|
printk(KERN_ALERT "DMA LEN %d\n", length);
|
|
//XXX:512 SD 1.0 card only.
|
|
for (j = 0; j< length;j++) {
|
|
pr_debug("dma address = %d, length = %d\n", sg_dma_address(&data->sg[i]), sg->length);
|
|
printk(KERN_ALERT "dma address = %d, length = %d, sg_dma_len %d\n", (sg_dma_address(&data->sg[i])+512*j), length, host->dma_len);
|
|
|
|
writel((sg_dma_address(&data->sg[i])+512*j), host->base + BD_TX);
|
|
wmb();
|
|
writel(cmd->arg+off_scal*j, host->base + BD_TX);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DAT_IRQ_ON (host,(TRE|FIFOE|MRC|TRS));
|
|
pr_debug("pre dma read done\n");
|
|
}
|
|
|
static void ocores_start_cmd(struct ocores_host *host, struct mmc_command *cmd)
|
static void ocores_start_cmd(struct ocores_host *host, struct mmc_command *cmd)
|
{
|
{
|
unsigned int cmd_arg, cmd_command=0;
|
unsigned int cmd_arg, cmd_command=0;
|
|
|
//struct mmc_data *data = cmd->data;
|
struct mmc_data *data = cmd->data;
|
//WARN_ON(host->cmd != NULL);
|
//WARN_ON(host->cmd != NULL);
|
host->cmd = cmd;
|
host->cmd = cmd;
|
|
|
|
//XXX:opcode == 51 not supported by hardware, hack here
|
|
if (data && ( cmd->opcode != 51)) {
|
|
if ( data->blksz & 0x3 ) {
|
|
pr_debug("Unsupported block size\n");
|
|
cmd->error = -EINVAL;
|
|
mmc_request_done(host->mmc, host->mrq);
|
|
return;
|
|
}
|
|
|
|
data->bytes_xfered = 0;
|
|
host->transfer_index = 0;
|
|
host->in_use_index = 0;
|
|
|
|
if (data->flags & MMC_DATA_READ){ //Handle a read
|
|
printk(KERN_ALERT "%s: Data read\n", __FUNCTION__);
|
|
host->buffer = NULL;
|
|
host->total_length = 0;
|
|
ocores_pre_dma_read(host); //Set up BD
|
|
|
|
}
|
|
else if (data->flags & MMC_DATA_WRITE){ //Handle write
|
|
printk(KERN_ALERT "%s: Data write\n", __FUNCTION__); //cmdr |= AT91_MCI_TRCMD_START;
|
|
/*host->buffer = dma_alloc_coherent(NULL,
|
|
host->total_length,
|
|
&host->physical_address, GFP_KERNEL); */
|
|
host->total_length = 0;
|
|
ocores_pre_dma_write(host); //Set up BD
|
|
|
|
}
|
|
|
|
|
|
if (data->flags & MMC_DATA_STREAM)
|
|
printk(KERN_ALERT "%s: MMC_DATA_STREAM\n", __FUNCTION__);
|
|
if (data->blocks > 1)
|
|
printk(KERN_ALERT "%s: data->blocks %d > 1 \n", __FUNCTION__, data->blocks);
|
|
|
|
|
|
/*
|
|
host->total_length = block_length * blocks;
|
|
host->buffer = dma_alloc_coherent(NULL,
|
|
host->total_length,
|
|
&host->physical_address, GFP_KERNEL);
|
|
|
|
at91_mci_sg_to_dma(host, data);
|
|
|
|
pr_debug("Transmitting %d bytes\n", host->total_length);
|
|
|
|
at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
|
|
at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4);
|
|
ier = AT91_MCI_CMDRDY; */
|
|
|
|
|
|
|
|
|
|
}
|
|
else{
|
//Set up command
|
//Set up command
|
cmd_arg = cmd->arg;
|
cmd_arg = cmd->arg;
|
cmd_command |= cmd->opcode << 8;
|
cmd_command |= cmd->opcode << 8;
|
cmd_command |= host->word_cnt << 6;
|
cmd_command |= host->word_cnt << 6;
|
|
|
Line 116... |
Line 343... |
break;
|
break;
|
default:
|
default:
|
printk(KERN_INFO "mmc_ocores: unhandled response type %02x\n",
|
printk(KERN_INFO "mmc_ocores: unhandled response type %02x\n",
|
mmc_resp_type(cmd));
|
mmc_resp_type(cmd));
|
}
|
}
|
|
//Send Command
|
/*If data
|
CMD_IRQ_ON (host,(ECC|EEI));
|
// if ( data->blksz & 0x3 ) {
|
writel(cmd_command, host->base + SD_COMMAND);
|
pr_debug("Unsupported block size\n");
|
wmb();
|
cmd->error = -EINVAL;
|
writel(cmd_arg, host->base + SD_ARG);
|
mmc_request_done(host->mmc, host->request);
|
|
return;
|
|
} */
|
|
|
|
printk(KERN_ALERT "%s: cmd_arg = %08x\n", __FUNCTION__, cmd_arg);
|
printk(KERN_ALERT "%s: cmd_arg = %08x\n", __FUNCTION__, cmd_arg);
|
printk(KERN_ALERT "%s: cmd_command = %08x\n", __FUNCTION__, cmd_command);
|
printk(KERN_ALERT "%s: cmd_command = %08x\n", __FUNCTION__, cmd_command);
|
|
|
|
}
|
|
|
|
|
oc_host=host;
|
oc_host=host;
|
|
|
|
|
CMD_IRQ_ON (host,(ECC|EEI));
|
|
writel(cmd_command, host->base + SD_COMMAND);
|
|
wmb();
|
|
writel(cmd_arg, host->base + SD_ARG);
|
|
}
|
}
|
|
|
static void ocores_process_next(struct ocores_host *host)
|
static void ocores_process_next(struct ocores_host *host)
|
{
|
{
|
host->word_cnt=0;
|
host->word_cnt=0;
|
Line 177... |
Line 400... |
{
|
{
|
/* struct ocores_host *host = mmc_priv(mmc); */
|
/* struct ocores_host *host = mmc_priv(mmc); */
|
|
|
printk(KERN_ALERT "%s: enter\n", __FUNCTION__);
|
printk(KERN_ALERT "%s: enter\n", __FUNCTION__);
|
|
|
/* if (host->pdata && host->pdata->get_ro) */
|
|
/* return host->pdata->get_ro(mmc_dev(mmc)); */
|
|
/* /\* Host doesn't support read only detection so assume writeable *\/ */
|
/* /\* Host doesn't support read only detection so assume writeable *\/ */
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static void ocores_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
static void ocores_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
Line 245... |
Line 467... |
enable_irq(host->irq_cmd);
|
enable_irq(host->irq_cmd);
|
|
|
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
}
|
}
|
|
|
static irqreturn_t ocores_irq_dat(int irq, void *dev_id)
|
static irqreturn_t ocores_irq_dat(int irq, void *devid)
|
{
|
{
|
|
struct ocores_host *host = (struct ocores_host *) devid;
|
|
|
|
disable_irq(host->irq_dat);
|
|
|
|
printk(KERN_ALERT "%s: DAT IRQ START***** Normal In = %08x\n", __FUNCTION__, readl(host->base + SD_BD_ISR));
|
|
|
|
host->registers.data_int_status = readl(host->base + SD_BD_ISR);
|
|
|
|
writel(0,host->base + SD_BD_ISR);
|
|
|
|
tasklet_schedule(&host->finish_data);
|
|
|
|
enable_irq(host->irq_dat);
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
|
|
|
|
|
}
|
}
|
|
|
static const struct mmc_host_ops ocores_ops = {
|
static const struct mmc_host_ops ocores_ops = {
|
.request = ocores_request,
|
.request = ocores_request,
|
Line 290... |
Line 530... |
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
|
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
|
mmc->caps = MMC_CAP_4_BIT_DATA;
|
mmc->caps = MMC_CAP_4_BIT_DATA;
|
mmc->f_min = 700000; //SYS_CLK 60; 0.7 Mhz
|
mmc->f_min = 700000; //SYS_CLK 60; 0.7 Mhz
|
mmc->f_max = 4166666; //SYS_CLK; 4.166 666 mhz
|
mmc->f_max = 4166666; //SYS_CLK; 4.166 666 mhz
|
|
|
mmc->max_blk_count = 8;
|
mmc->max_blk_count = 8;//8; //XXX: 8
|
mmc->max_hw_segs = mmc->max_blk_count;
|
mmc->max_hw_segs = 1;
|
mmc->max_blk_size = MMCOC_MAX_BLOCK_SIZE;
|
mmc->max_blk_size = MMCOC_MAX_BLOCK_SIZE;
|
mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size;
|
//mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size;
|
|
|
|
|
|
mmc->max_seg_size = PAGE_SIZE;
|
mmc->max_req_size = mmc->max_seg_size;
|
mmc->max_req_size = mmc->max_seg_size;
|
mmc->max_phys_segs = mmc->max_hw_segs;
|
mmc->max_phys_segs = 1; //BD size
|
|
|
host = mmc_priv(mmc);
|
host = mmc_priv(mmc);
|
|
|
/*XXX: */
|
/*XXX: */
|
host->clock = 0;
|
host->clock = 0;
|
|
|
host->mmc = mmc;
|
host->mmc = mmc;
|
host->cmdat = 0;
|
host->cmdat = 0;
|
host->registers.normal_int_status =0;
|
host->registers.normal_int_status =0;
|
|
|
|
printk("Free FBD \n");
|
|
host->free_tx_bd=0;
|
|
host->free_rx_bd=0;
|
|
printk("Free EBD \n");
|
|
|
|
|
|
|
tasklet_init(&host->finish_cmd, ocores_tasklet_finish_cmd,
|
tasklet_init(&host->finish_cmd, ocores_tasklet_finish_cmd,
|
(unsigned long) host);
|
(unsigned long) host);
|
|
|
|
tasklet_init(&host->finish_data, ocores_tasklet_finish_data,
|
|
(unsigned long) host);
|
|
|
|
|
spin_lock_init(&host->lock);
|
spin_lock_init(&host->lock);
|
host->res = r;
|
host->res = r;
|
|
|
host->base = ioremap(r->start, r->end - r->start +1);
|
host->base = ioremap(r->start, r->end - r->start +1);
|
/* host->base = (void *)r->start; */
|
/* host->base = (void *)r->start; */
|
if (!host->base) {
|
if (!host->base) {
|
ret = -ENOMEM;
|
ret = -ENOMEM;
|
goto out;
|
goto out;
|
}
|
}
|
|
host->free_tx_bd=readl( host->base + BD_STATUS );
|
|
host->free_tx_bd=host->free_tx_bd & 0x00ff;
|
|
printk("Free TX BD = %d\n", host->free_tx_bd);
|
|
host->free_rx_bd=readl( host->base + BD_STATUS );
|
|
host->free_rx_bd=(host->free_rx_bd & 0xff00)>>8;
|
|
printk("Free TX BD = %d\n", host->free_rx_bd);
|
|
|
host->pdata = pdev->dev.platform_data;
|
host->pdata = pdev->dev.platform_data;
|
mmc->ocr_avail = host->pdata->ocr_mask;
|
mmc->ocr_avail = host->pdata->ocr_mask;
|
|
|
host->irq_cmd = platform_get_irq_byname(pdev, "cmd_irq");
|
host->irq_cmd = platform_get_irq_byname(pdev, "cmd_irq");
|
ret = request_irq(host->irq_cmd, ocores_irq_cmd, IRQF_DISABLED, DRIVER_NAME, host);
|
ret = request_irq(host->irq_cmd, ocores_irq_cmd, IRQF_DISABLED, DRIVER_NAME, host);
|
Line 366... |
Line 626... |
|
|
static void ocores_tasklet_finish_cmd(unsigned long param)
|
static void ocores_tasklet_finish_cmd(unsigned long param)
|
{
|
{
|
struct ocores_host *host = (struct ocores_host *) param;
|
struct ocores_host *host = (struct ocores_host *) param;
|
|
|
printk(KERN_ALERT " TASKLET RUNNS************\n");
|
struct mmc_data *data;
|
|
struct scatterlist *sg;
|
printk(KERN_ALERT "%s: TASKLET RUNNS****** Normal INT = %08x\n", __FUNCTION__, host->registers.normal_int_status);
|
data = host->cmd->data;
|
printk(KERN_ALERT "%s: TASKLET RUNNS****** Error INT = %08x\n", __FUNCTION__, host->registers.error_int_status);
|
sg = &data->sg[0];
|
|
|
|
printk(KERN_ALERT " CMD TASKLET RUNNS************\n");
|
//Check For Transmissions errors
|
//Check For Transmissions errors
|
if ((host->registers.normal_int_status & EI) == EI)
|
if ((host->registers.normal_int_status & EI) == EI)
|
{
|
{
|
printk(KERN_ALERT "TRANSMISSION ERROR DETECTED");
|
printk(KERN_ALERT "TRANSMISSION ERROR DETECTED");
|
switch ( host->registers.error_int_status )
|
switch ( host->registers.error_int_status )
|
Line 399... |
Line 660... |
{
|
{
|
if ( mmc_resp_type(host->mrq->cmd) == MMC_RSP_R2 ) //Long response
|
if ( mmc_resp_type(host->mrq->cmd) == MMC_RSP_R2 ) //Long response
|
{
|
{
|
printk(KERN_ALERT "Long Response, Word Cnt %d, RESP * = %08x\n ",host->word_cnt,readl(host->base + SD_RESP1));
|
printk(KERN_ALERT "Long Response, Word Cnt %d, RESP * = %08x\n ",host->word_cnt,readl(host->base + SD_RESP1));
|
|
|
if (host->mrq->cmd->opcode == 2) {
|
if (host->mrq->cmd->opcode == 2) { //XXX: Hack until supported long response
|
host->mrq->cmd->resp[0] = readl(host->base + SD_RESP1);
|
host->mrq->cmd->resp[0] = readl(host->base + SD_RESP1);
|
host->mrq->cmd->resp[1] = 0xaaaaaaaa;
|
host->mrq->cmd->resp[1] = 0x01302331;
|
host->mrq->cmd->resp[2] = 0xbbbbbbbb;
|
host->mrq->cmd->resp[2] = 0x195abdef;
|
host->mrq->cmd->resp[3] = 0;
|
host->mrq->cmd->resp[3] = 0x195abdef;
|
mmc_request_done(host->mmc, host->mrq);
|
mmc_request_done(host->mmc, host->mrq);
|
} //XXX:
|
} //XXX: Hack until supported long response
|
else if(host->mrq->cmd->opcode == 9)
|
else if(host->mrq->cmd->opcode == 51)
|
{
|
{
|
host->mrq->cmd->resp[0] = 0x006f0032;
|
host->mrq->cmd->resp[0] = 0x900;
|
host->mrq->cmd->resp[1] = 0x5b5983bf;
|
host->mrq->cmd->resp[1] = 0xaaa;
|
host->mrq->cmd->resp[2] = 0xf6dbdfff;
|
host->mrq->cmd->resp[2] = 0xbbb;
|
host->mrq->cmd->resp[3] = 0x0a4041ff;
|
host->mrq->cmd->resp[3] = 0xccc;
|
|
host->mrq->data->bytes_xfered =8;
|
|
dma_unmap_sg(mmc_dev(host->mmc), sg, data->sg_len, DMA_FROM_DEVICE);
|
mmc_request_done(host->mmc, host->mrq);
|
mmc_request_done(host->mmc, host->mrq);
|
}
|
}
|
|
|
|
|
|
|
else {
|
else {
|
host->word_cnt+=1;
|
host->word_cnt+=1;
|
switch(host->word_cnt-1)
|
switch(host->word_cnt-1)
|
{
|
{
|
case (0):
|
case (0):
|
Line 448... |
Line 713... |
mmc_request_done(host->mmc, host->mrq);
|
mmc_request_done(host->mmc, host->mrq);
|
}
|
}
|
}
|
}
|
|
|
}
|
}
|
|
static void ocores_tasklet_finish_data(unsigned long param)
|
|
{
|
|
struct ocores_host *host = (struct ocores_host *) param;
|
|
|
|
|
|
struct mmc_data *data;
|
|
struct scatterlist *sg;
|
|
int free_bd,i;
|
|
int *adr;
|
|
data = host->cmd->data;
|
|
sg = &data->sg[0]; //XXX:O Change to dynamic later?
|
|
|
|
printk(KERN_ALERT " DATA TASKLET RUNNS************\n");
|
|
|
|
//IF read operation
|
|
|
|
if ((host->registers.data_int_status & TRS) == TRS){
|
|
if (data->flags & MMC_DATA_READ){
|
|
free_bd=readl( host->base + BD_STATUS );
|
|
free_bd=(free_bd&0xff00)>>8;
|
|
printk(KERN_ALERT " DATA TASKLET RUNNS*** Free BD %d\n", free_bd);
|
|
if (free_bd == host->free_tx_bd) {
|
|
dma_unmap_sg(mmc_dev(host->mmc), sg, sg->length, DMA_FROM_DEVICE);
|
|
host->mrq->cmd->resp[0] = readl(host->base + SD_RESP1);
|
|
data->bytes_xfered = sg->length;
|
|
DAT_IRQ_OFF (host,(TRE|FIFOE|MRC|TRS));
|
|
mmc_request_done(host->mmc, host->mrq);
|
|
}
|
|
} else if (data->flags & MMC_DATA_WRITE){
|
|
free_bd=readl( host->base + BD_STATUS );
|
|
free_bd=(free_bd&0x00FF);
|
|
printk(KERN_ALERT " DATA TASKLET RUNNS*** Free BD %d\n", free_bd);
|
|
if (free_bd == host->free_tx_bd) {
|
|
dma_unmap_sg(mmc_dev(host->mmc), sg, sg->length, DMA_TO_DEVICE);
|
|
host->mrq->cmd->resp[0] = readl(host->base + SD_RESP1);
|
|
data->bytes_xfered = sg->length;
|
|
DAT_IRQ_OFF (host,(TRE|FIFOE|MRC|TRS));
|
|
mmc_request_done(host->mmc, host->mrq);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
else {
|
|
sg= &data->sg[0];
|
|
writel(SD_DISABLE, host->base + SD_SOFTWARE_RST);
|
|
writel(SD_ENABLE, host->base + SD_SOFTWARE_RST);
|
|
|
|
if ((host->registers.data_int_status & MRC) == MRC)
|
|
host->data->error = -ETIMEDOUT;
|
|
if ((host->registers.data_int_status & CMDE) == CMDE)
|
|
host->data->error = -EILSEQ;
|
|
data->bytes_xfered =0;
|
|
|
|
dma_unmap_sg(mmc_dev(host->mmc), sg, data->sg_len, DMA_FROM_DEVICE);
|
|
DAT_IRQ_OFF (host,(TRE|FIFOE|MRC|TRS));
|
|
mmc_request_done(host->mmc, host->mrq);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
static int ocores_remove(struct platform_device *pdev)
|
static int ocores_remove(struct platform_device *pdev)
|
{
|
{
|
struct mmc_host *mmc = platform_get_drvdata(pdev);
|
struct mmc_host *mmc = platform_get_drvdata(pdev);
|
|
|
printk(KERN_ALERT "%s: enter\n", __FUNCTION__);
|
printk(KERN_ALERT "%s: enter\n", __FUNCTION__);
|