static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data) { u32 dcon, imsk, stoptries=3; /* write DCON register */ if (!data) { writel(0, host->base + S3C2410_SDIDCON); return 0; } while(readl(host->base + S3C2410_SDIDSTA) & (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) { dbg(host, dbg_err, "mci_setup_data() transfer stillin progress.\n"); writel(0, host->base + S3C2410_SDIDCON); s3cmci_reset(host); if (0 == (stoptries--)) { #ifdef CONFIG_MMC_DEBUG dbg_dumpregs(host, "DRF"); #endif return -EINVAL; } } dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK; if (host->dodma) { dcon |= S3C2410_SDIDCON_DMAEN; } if (host->bus_width == MMC_BUS_WIDTH_4) { dcon |= S3C2410_SDIDCON_WIDEBUS; } if (!(data->flags & MMC_DATA_STREAM)) { dcon |= S3C2410_SDIDCON_BLOCKMODE; } if (data->flags & MMC_DATA_WRITE) { dcon |= S3C2410_SDIDCON_TXAFTERRESP; dcon |= S3C2410_SDIDCON_XFER_TXSTART; } if (data->flags & MMC_DATA_READ) { dcon |= S3C2410_SDIDCON_RXAFTERCMD; dcon |= S3C2410_SDIDCON_XFER_RXSTART; } if (host->is2440) { dcon |= S3C2440_SDIDCON_DS_WORD; dcon |= S3C2440_SDIDCON_DATSTART; } writel(dcon, host->base + S3C2410_SDIDCON); /* write BSIZE register */ writel(data->blksz, host->base + S3C2410_SDIBSIZE); /* add to IMASK register */ imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC | S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH; enable_imask(host, imsk); /* write TIMER register */ if (host->is2440) { writel(0x007FFFFF, host->base + S3C2410_SDITIMER); } else { writel(0x0000FFFF, host->base + S3C2410_SDITIMER); //FIX: set slow clock to prevent timeouts on read if (data->flags & MMC_DATA_READ) { writel(0xFF, host->base + S3C2410_SDIPRE); } } //debug_dump_registers(host, "Data setup:"); return 0; }
static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data) { u32 dcon, imsk, stoptries = 3; /* write DCON register */ if (!data) { writel(0, host->base + S3C2410_SDIDCON); return 0; } if ((data->blksz & 3) != 0) { /* We cannot deal with unaligned blocks with more than * one block being transfered. */ if (data->blocks > 1) return -EINVAL; /* No support yet for non-word block transfers. */ return -EINVAL; } while (readl(host->base + S3C2410_SDIDSTA) & (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) { dbg(host, dbg_err, "mci_setup_data() transfer stillin progress.\n"); writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); s3cmci_reset(host); if ((stoptries--) == 0) { dbg_dumpregs(host, "DRF"); return -EINVAL; } } dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK; if (host->dodma) dcon |= S3C2410_SDIDCON_DMAEN; if (host->bus_width == MMC_BUS_WIDTH_4) dcon |= S3C2410_SDIDCON_WIDEBUS; if (!(data->flags & MMC_DATA_STREAM)) dcon |= S3C2410_SDIDCON_BLOCKMODE; if (data->flags & MMC_DATA_WRITE) { dcon |= S3C2410_SDIDCON_TXAFTERRESP; dcon |= S3C2410_SDIDCON_XFER_TXSTART; } if (data->flags & MMC_DATA_READ) { dcon |= S3C2410_SDIDCON_RXAFTERCMD; dcon |= S3C2410_SDIDCON_XFER_RXSTART; } if (host->is2440) { dcon |= S3C2440_SDIDCON_DS_WORD; dcon |= S3C2440_SDIDCON_DATSTART; } writel(dcon, host->base + S3C2410_SDIDCON); /* write BSIZE register */ writel(data->blksz, host->base + S3C2410_SDIBSIZE); /* add to IMASK register */ imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC | S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH; enable_imask(host, imsk); /* write TIMER register */ if (host->is2440) { writel(0x007FFFFF, host->base + S3C2410_SDITIMER); } else { writel(0x0000FFFF, host->base + S3C2410_SDITIMER); /* FIX: set slow clock to prevent timeouts on read */ if (data->flags & MMC_DATA_READ) writel(0xFF, host->base + S3C2410_SDIPRE); } return 0; }