forked from len0rd/rockbox
Initial NAND driver for Sansa. This has had limited testing, and no testing on 6 or 8Gb models
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11567 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
2502e68113
commit
e7b025ba10
2 changed files with 607 additions and 75 deletions
|
@ -7,7 +7,7 @@
|
|||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 Daniel Stenberg
|
||||
* Copyright (C) 2006 Daniel Ankers
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
|
@ -16,106 +16,461 @@
|
|||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* TODO: Add ATA Callback support */
|
||||
#include "lcd.h"
|
||||
#include "ata.h"
|
||||
#include "ata-target.h"
|
||||
#include "cpu.h"
|
||||
#include "system.h"
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "kernel.h"
|
||||
#include "thread.h"
|
||||
|
||||
#define NOINLINE_ATTR __attribute__((noinline)) /* don't inline the loops */
|
||||
|
||||
#define BLOCK_SIZE (512)
|
||||
#define SECTOR_SIZE (512)
|
||||
|
||||
#define STATUS_REG (*(volatile unsigned int *)(0x70008204))
|
||||
#define REG_1 (*(volatile unsigned int *)(0x70008208))
|
||||
#define UNKNOWN (*(volatile unsigned int *)(0x70008210))
|
||||
#define BLOCK_SIZE_REG (*(volatile unsigned int *)(0x7000821c))
|
||||
#define BLOCK_COUNT_REG (*(volatile unsigned int *)(0x70008220))
|
||||
#define REG_5 (*(volatile unsigned int *)(0x70008224))
|
||||
#define CMD_REG0 (*(volatile unsigned int *)(0x70008228))
|
||||
#define CMD_REG1 (*(volatile unsigned int *)(0x7000822c))
|
||||
#define CMD_REG2 (*(volatile unsigned int *)(0x70008230))
|
||||
#define RESPONSE_REG (*(volatile unsigned int *)(0x70008234))
|
||||
#define SD_STATE_REG (*(volatile unsigned int *)(0x70008238))
|
||||
#define REG_11 (*(volatile unsigned int *)(0x70008240))
|
||||
#define REG_12 (*(volatile unsigned int *)(0x70008244))
|
||||
#define DATA_REG (*(volatile unsigned int *)(0x70008280))
|
||||
|
||||
#define DATA_DONE (1 << 12)
|
||||
#define CMD_DONE (1 << 13)
|
||||
#define ERROR_BITS (0x3f)
|
||||
#define FIFO_FULL (1 << 7)
|
||||
#define FIFO_EMPTY (1 << 6)
|
||||
|
||||
/* SD States */
|
||||
#define IDLE 0
|
||||
#define READY 1
|
||||
#define IDENT 2
|
||||
#define STBY 3
|
||||
#define TRAN 4
|
||||
#define DATA 5
|
||||
#define RCV 6
|
||||
#define PRG 7
|
||||
#define DIS 8
|
||||
|
||||
#define FIFO_SIZE 16 /* FIFO is 16 words deep */
|
||||
|
||||
/* SD Commands */
|
||||
#define GO_IDLE_STATE 0
|
||||
#define ALL_SEND_CID 2
|
||||
#define SEND_RELATIVE_ADDR 3
|
||||
#define SET_DSR 4
|
||||
#define SWITCH_FUNC 6
|
||||
#define SELECT_CARD 7
|
||||
#define DESELECT_CARD 7
|
||||
#define SEND_CSD 9
|
||||
#define SEND_CID 10
|
||||
#define STOP_TRANSMISSION 12
|
||||
#define SEND_STATUS 13
|
||||
#define GO_INACTIVE_STATE 15
|
||||
#define SET_BLOCKLEN 16
|
||||
#define READ_SINGLE_BLOCK 17
|
||||
#define READ_MULTIPLE_BLOCK 18
|
||||
#define WRITE_BLOCK 24
|
||||
#define WRITE_MULTIPLE_BLOCK 25
|
||||
#define ERASE_WR_BLK_START 32
|
||||
#define ERASE_WR_BLK_END 33
|
||||
#define ERASE 38
|
||||
|
||||
/* Application Specific commands */
|
||||
#define SET_BUS_WIDTH 6
|
||||
#define SD_APP_OP_COND 41
|
||||
|
||||
#define READ_TIMEOUT 5*HZ
|
||||
#define WRITE_TIMEOUT 0.5*HZ
|
||||
|
||||
static unsigned short identify_info[SECTOR_SIZE];
|
||||
int ata_spinup_time = 0;
|
||||
long last_disk_activity = -1;
|
||||
static bool delayed_write = false;
|
||||
|
||||
void flash_select_chip(int no, int sel)
|
||||
static unsigned char current_bank = 0; /* The bank that we are working with */
|
||||
|
||||
static tSDCardInfo card_info[2];
|
||||
|
||||
/* For multi volume support */
|
||||
static int current_card = 0;
|
||||
|
||||
static struct mutex ata_mtx;
|
||||
|
||||
/* Private Functions */
|
||||
|
||||
bool sd_send_command(unsigned int cmd, unsigned long arg1, unsigned int arg2)
|
||||
{
|
||||
|
||||
bool result = false;
|
||||
unsigned char cbuf[32];
|
||||
do
|
||||
{
|
||||
CMD_REG0 = cmd;
|
||||
CMD_REG1 = (unsigned int)((arg1 & 0xffff0000) >> 16);
|
||||
CMD_REG2 = (unsigned int)((arg1 & 0xffff));
|
||||
UNKNOWN = arg2;
|
||||
while ((STATUS_REG & CMD_DONE) == 0)
|
||||
{
|
||||
/* Busy wait */
|
||||
}
|
||||
if ((STATUS_REG & ERROR_BITS) == 0)
|
||||
{
|
||||
result = true;
|
||||
} else {
|
||||
snprintf(cbuf, sizeof(cbuf), "%x", (STATUS_REG & ERROR_BITS));
|
||||
lcd_puts(0,10,cbuf);
|
||||
lcd_update();
|
||||
}
|
||||
} while ((STATUS_REG & ERROR_BITS) != 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned char flash_read_data(void)
|
||||
void sd_read_response(unsigned int *response, int type)
|
||||
{
|
||||
int i;
|
||||
int words; /* Number of 16 bit words to read from RESPONSE_REG */
|
||||
unsigned int response_from_card[9];
|
||||
if(type == 2)
|
||||
{
|
||||
words = 9; /* R2 types are 8.5 16-bit words long */
|
||||
} else {
|
||||
words = 3;
|
||||
}
|
||||
|
||||
for (i = 0; i < words; i++) /* RESPONSE_REG is read MSB first */
|
||||
{
|
||||
response_from_card[i] = RESPONSE_REG; /* Read most significant 16-bit word */
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 1:
|
||||
/* Response type 1 has the following structure:
|
||||
Start bit
|
||||
Transmission bit
|
||||
Command index (6 bits)
|
||||
Card Status (32 bits)
|
||||
CRC7 (7 bits)
|
||||
Stop bit
|
||||
*/
|
||||
/* TODO: Sanity checks */
|
||||
response[0] = ((response_from_card[0] & 0xff) << 24)
|
||||
+ (response_from_card[1] << 8)
|
||||
+ ((response_from_card[2] & 0xff00) >> 8);
|
||||
break;
|
||||
case 2:
|
||||
/* Response type 2 has the following structure:
|
||||
Start bit
|
||||
Transmission bit
|
||||
Reserved (6 bits)
|
||||
CSD/CID register (127 bits)
|
||||
Stop bit
|
||||
*/
|
||||
response[3] = ((response_from_card[0]&0xff)<<24) +
|
||||
(response_from_card[1]<<8) +
|
||||
((response_from_card[2]&0xff00)>>8);
|
||||
response[2] = ((response_from_card[2]&0xff)<<24) +
|
||||
(response_from_card[3]<<8) +
|
||||
((response_from_card[4]&0xff00)>>8);
|
||||
response[1] = ((response_from_card[4]&0xff)<<24) +
|
||||
(response_from_card[5]<<8) +
|
||||
((response_from_card[6]&0xff00)>>8);
|
||||
response[0] = ((response_from_card[6]&0xff)<<24) +
|
||||
(response_from_card[7]<<8) +
|
||||
((response_from_card[8]&0xff00)>>8);
|
||||
break;
|
||||
case 3:
|
||||
/* Response type 3 has the following structure:
|
||||
Start bit
|
||||
Transmission bit
|
||||
Reserved (6 bits)
|
||||
OCR register (32 bits)
|
||||
Reserved (7 bits)
|
||||
Stop bit
|
||||
*/
|
||||
response[0] = ((response_from_card[0] & 0xff) << 24)
|
||||
+ (response_from_card[1] << 8)
|
||||
+ ((response_from_card[2] & 0xff00) >> 8);
|
||||
/* Types 4-6 not supported yet */
|
||||
}
|
||||
}
|
||||
|
||||
void flash_write_data(unsigned char data)
|
||||
bool sd_send_acommand(unsigned int cmd, unsigned long arg1, unsigned int arg2)
|
||||
{
|
||||
|
||||
unsigned int returncode;
|
||||
if (sd_send_command(55, (card_info[current_card].rca)<<16, 1) == false)
|
||||
return false;
|
||||
sd_read_response(&returncode, 1);
|
||||
if (sd_send_command(cmd, arg1, arg2) == false)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void flash_write_cmd(unsigned char cmd)
|
||||
void sd_wait_for_state(tSDCardInfo* card, unsigned int state)
|
||||
{
|
||||
|
||||
unsigned int response = 0;
|
||||
while(((response >> 9) & 0xf) != state)
|
||||
{
|
||||
sd_send_command(SEND_STATUS, (card->rca) << 16, 1);
|
||||
sd_read_response(&response, 1);
|
||||
/* TODO: Add a timeout and error handling */
|
||||
}
|
||||
SD_STATE_REG = state;
|
||||
}
|
||||
|
||||
void flash_write_addr(unsigned char addr)
|
||||
{
|
||||
|
||||
static void copy_read_sectors(unsigned char* buf, int wordcount)
|
||||
NOINLINE_ATTR ICODE_ATTR;
|
||||
|
||||
static void copy_read_sectors(unsigned char* buf, int wordcount)
|
||||
{
|
||||
unsigned int tmp = 0;
|
||||
|
||||
if ( (unsigned long)buf & 1)
|
||||
{ /* not 16-bit aligned, copy byte by byte */
|
||||
unsigned char* bufend = buf + wordcount*2;
|
||||
do
|
||||
{
|
||||
tmp = DATA_REG;
|
||||
*buf++ = tmp & 0xff;
|
||||
*buf++ = tmp >> 8;
|
||||
} while (buf < bufend); /* tail loop is faster */
|
||||
}
|
||||
else
|
||||
{ /* 16-bit aligned, can do faster copy */
|
||||
unsigned short* wbuf = (unsigned short*)buf;
|
||||
unsigned short* wbufend = wbuf + wordcount;
|
||||
do
|
||||
{
|
||||
*wbuf = DATA_REG;
|
||||
} while (++wbuf < wbufend); /* tail loop is faster */
|
||||
}
|
||||
}
|
||||
|
||||
void flash_wait_ready(void)
|
||||
{
|
||||
static void copy_write_sectors(const unsigned char* buf, int wordcount)
|
||||
NOINLINE_ATTR ICODE_ATTR;
|
||||
|
||||
static void copy_write_sectors(const unsigned char* buf, int wordcount)
|
||||
{
|
||||
if ( (unsigned long)buf & 1)
|
||||
{ /* not 16-bit aligned, copy byte by byte */
|
||||
unsigned short tmp = 0;
|
||||
const unsigned char* bufend = buf + wordcount*2;
|
||||
do
|
||||
{
|
||||
tmp = (unsigned short) *buf++;
|
||||
tmp |= (unsigned short) *buf++ << 8;
|
||||
DATA_REG = tmp;
|
||||
} while (buf < bufend); /* tail loop is faster */
|
||||
}
|
||||
else
|
||||
{ /* 16-bit aligned, can do faster copy */
|
||||
unsigned short* wbuf = (unsigned short*)buf;
|
||||
unsigned short* wbufend = wbuf + wordcount;
|
||||
do
|
||||
{
|
||||
lcd_update();
|
||||
DATA_REG = *wbuf;
|
||||
} while (++wbuf < wbufend); /* tail loop is faster */
|
||||
}
|
||||
}
|
||||
|
||||
int flash_map_sector(int sector, int* chip, int* chip_sector)
|
||||
{
|
||||
|
||||
void sd_select_bank(unsigned char bank)
|
||||
{
|
||||
unsigned int response;
|
||||
unsigned char card_data[512];
|
||||
unsigned char* write_buf;
|
||||
int i;
|
||||
tSDCardInfo *card = &card_info[0]; /* Bank selection will only be done on
|
||||
the onboard flash */
|
||||
if (current_bank != bank)
|
||||
{
|
||||
memset(card_data, 0, 512);
|
||||
sd_wait_for_state(card, TRAN);
|
||||
BLOCK_SIZE_REG = 512;
|
||||
BLOCK_COUNT_REG = 1;
|
||||
sd_send_command(35, 0, 0x1c0d); /* CMD35 is vendor specific */
|
||||
sd_read_response(&response, 1);
|
||||
SD_STATE_REG = PRG;
|
||||
|
||||
card_data[0] = bank;
|
||||
|
||||
/* Write the card data */
|
||||
write_buf = card_data;
|
||||
for (i = 0; i < BLOCK_SIZE / 2; i += FIFO_SIZE)
|
||||
{
|
||||
/* Wait for the FIFO to be empty */
|
||||
while((STATUS_REG & FIFO_EMPTY) == 0) {} /* Erm... is this right? */
|
||||
|
||||
copy_write_sectors(write_buf, FIFO_SIZE);
|
||||
|
||||
write_buf += FIFO_SIZE*2; /* Advance one chunk of 16 words */
|
||||
}
|
||||
|
||||
while((STATUS_REG & DATA_DONE) == 0) {}
|
||||
current_bank = bank;
|
||||
}
|
||||
}
|
||||
|
||||
int flash_read_id(int no)
|
||||
void sd_init_device(void)
|
||||
{
|
||||
/* SD Protocol registers */
|
||||
unsigned int dummy;
|
||||
int i;
|
||||
|
||||
static unsigned int read_bl_len = 0;
|
||||
static unsigned int c_size = 0;
|
||||
static unsigned int c_size_mult = 0;
|
||||
static unsigned long mult = 0;
|
||||
|
||||
unsigned char carddata[512];
|
||||
unsigned char *dataptr;
|
||||
tSDCardInfo *card = &card_info[0]; /* Init onboard flash only */
|
||||
|
||||
/* Initialise card data as blank */
|
||||
card->initialized = false;
|
||||
card->ocr = 0;
|
||||
card->csd[0] = 0;
|
||||
card->csd[1] = 0;
|
||||
card->csd[2] = 0;
|
||||
card->cid[0] = 0;
|
||||
card->cid[1] = 0;
|
||||
card->cid[2] = 0;
|
||||
card->rca = 0;
|
||||
|
||||
card->capacity = 0;
|
||||
card->numblocks = 0;
|
||||
card->block_size = 0;
|
||||
card->block_exp = 0;
|
||||
|
||||
/* Enable and initialise controller */
|
||||
GPIOG_ENABLE |= (0x3 << 5);
|
||||
GPIOG_OUTPUT_EN |= (0x3 << 5);
|
||||
GPIOG_OUTPUT_VAL |= (0x3 << 5);
|
||||
outl(inl(0x70000088) & ~(0x4), 0x70000088);
|
||||
outl(inl(0x7000008c) & ~(0x4), 0x7000008c);
|
||||
outl(inl(0x70000080) | 0x4, 0x70000080);
|
||||
outl(inl(0x70000084) | 0x4, 0x70000084);
|
||||
REG_1 = 6;
|
||||
outl(inl(0x70000014) & ~(0x3ffff), 0x70000014);
|
||||
outl((inl(0x70000014) & ~(0x3ffff)) | 0x255aa, 0x70000014);
|
||||
outl(0x1010, 0x70000034);
|
||||
|
||||
GPIOA_ENABLE |= (1 << 7);
|
||||
GPIOA_OUTPUT_EN &= ~(1 << 7);
|
||||
GPIOD_ENABLE |= (0x1f);
|
||||
GPIOD_OUTPUT_EN |= (0x1f);
|
||||
GPIOD_OUTPUT_VAL |= (0x1f);
|
||||
outl(inl(0x6000600c) | (1 << 14), 0x6000600c);
|
||||
outl(inl(0x60006004) | (1 << 14), 0x60006004);
|
||||
outl(inl(0x60006004) & ~(1 << 14), 0x60006004); /* Reset Controller? */
|
||||
outl(0, 0x6000b000);
|
||||
outl(0, 0x6000a000); /* Init DMA controller? */
|
||||
|
||||
/* Init NAND */
|
||||
REG_11 |= (1 << 15);
|
||||
REG_12 |= (1 << 15);
|
||||
REG_12 &= ~(3 << 12);
|
||||
REG_12 |= (1 << 13);
|
||||
REG_11 &= ~(3 << 12);
|
||||
REG_11 |= (1 << 13);
|
||||
|
||||
SD_STATE_REG = TRAN;
|
||||
REG_5 = 0xf;
|
||||
|
||||
sd_send_command(GO_IDLE_STATE, 0, 256);
|
||||
while ((card->ocr & (1 << 31)) == 0) /* Loop until the card is powered up */
|
||||
{
|
||||
sd_send_acommand(SD_APP_OP_COND, 0x100000, 3);
|
||||
sd_read_response(&(card->ocr), 3);
|
||||
|
||||
if (card->ocr == 0)
|
||||
{
|
||||
/* TODO: Handle failure */
|
||||
while (1) {};
|
||||
}
|
||||
}
|
||||
|
||||
sd_send_command(ALL_SEND_CID, 0, 2);
|
||||
sd_read_response(card->cid, 2);
|
||||
sd_send_command(SEND_RELATIVE_ADDR, 0, 1);
|
||||
sd_read_response(&card->rca, 1);
|
||||
card->rca >>= 16; /* The Relative Card Address is the top 16 bits of the
|
||||
32 bits returned. Whenever it is used, it gets
|
||||
shifted left by 16 bits, so this step could possibly
|
||||
be skipped. */
|
||||
|
||||
sd_send_command(SEND_CSD, card->rca << 16, 2);
|
||||
sd_read_response(card->csd, 2);
|
||||
|
||||
/* Parse disk geometry */
|
||||
/* These calculations come from the Sandisk SD card product manual */
|
||||
read_bl_len = ((card->csd[2] >> 16) & 0xf);
|
||||
c_size = ((card->csd[2] & (0x3ff)) << 2) +
|
||||
((card->csd[1] & (0xc0000000)) >> 30);
|
||||
c_size_mult = ((card->csd[1] >> 15) & 0x7);
|
||||
mult = (1<<(c_size_mult + 2));
|
||||
card->max_read_bl_len = (1<<read_bl_len);
|
||||
card->block_size = BLOCK_SIZE; /* Always use 512 byte blocks */
|
||||
card->numblocks = (c_size + 1) * mult * (card->max_read_bl_len / 512);
|
||||
card->capacity = card->numblocks * card->block_size;
|
||||
|
||||
REG_1 = 0;
|
||||
sd_send_command(SELECT_CARD, card->rca << 16, 129);
|
||||
sd_read_response(&dummy, 1); /* I don't think we use the result from this */
|
||||
sd_send_acommand(SET_BUS_WIDTH, (card->rca << 16) | 2, 1);
|
||||
sd_read_response(&dummy, 1); /* 4 bit wide bus */
|
||||
sd_send_command(SET_BLOCKLEN, card->block_size, 1);
|
||||
sd_read_response(&dummy, 1);
|
||||
BLOCK_SIZE_REG = card->block_size;
|
||||
|
||||
/* If this card is > 4Gb, then we need to enable bank switching */
|
||||
if(card->numblocks > 0x7a77ff)
|
||||
{
|
||||
SD_STATE_REG = TRAN;
|
||||
BLOCK_COUNT_REG = 1;
|
||||
sd_send_command(SWITCH_FUNC, 0x80ffffef, 0x1c05);
|
||||
sd_read_response(&dummy, 1);
|
||||
/* Read 512 bytes from the card.
|
||||
The first 512 bits contain the status information
|
||||
TODO: Do something useful with this! */
|
||||
dataptr = carddata;
|
||||
for (i = 0; i < BLOCK_SIZE / 2; i += FIFO_SIZE)
|
||||
{
|
||||
/* Wait for the FIFO to be full */
|
||||
while((STATUS_REG & FIFO_FULL) == 0) {}
|
||||
|
||||
copy_read_sectors(dataptr, FIFO_SIZE);
|
||||
|
||||
dataptr += (FIFO_SIZE*2); /* Advance one chunk of 16 words */
|
||||
}
|
||||
}
|
||||
mutex_init(&ata_mtx);
|
||||
}
|
||||
|
||||
int flash_read_sector(int sector, unsigned char* buf,
|
||||
unsigned char* oob)
|
||||
{
|
||||
/* API Functions */
|
||||
|
||||
void ata_led(bool onoff)
|
||||
{
|
||||
(void)onoff;
|
||||
}
|
||||
|
||||
int flash_read_sector_oob(int sector, unsigned char* oob)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int flash_get_n_segments(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int flash_get_n_phblocks(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int flash_get_n_sectors_in_block(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int flash_phblock_to_sector(int segment, int block)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int flash_is_bad_block(unsigned char* oob)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int flash_disk_scan(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int flash_disk_find_block(int block)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int flash_disk_read_sectors(unsigned long start,
|
||||
int count,
|
||||
void* buf)
|
||||
/* write the delayed sector to volume 0 */
|
||||
extern void ata_flush(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -125,21 +480,161 @@ int ata_read_sectors(IF_MV2(int drive,)
|
|||
int incount,
|
||||
void* inbuf)
|
||||
{
|
||||
int ret = 0;
|
||||
long timeout;
|
||||
int count;
|
||||
void* buf;
|
||||
long spinup_start;
|
||||
unsigned int dummy;
|
||||
unsigned int response;
|
||||
unsigned int i;
|
||||
tSDCardInfo *card = &card_info[current_card];
|
||||
|
||||
/* TODO: Add DMA support. */
|
||||
|
||||
#ifdef HAVE_MULTIVOLUME
|
||||
(void)drive; /* unused for now */
|
||||
#endif
|
||||
mutex_lock(&ata_mtx);
|
||||
|
||||
last_disk_activity = current_tick;
|
||||
spinup_start = current_tick;
|
||||
|
||||
ata_led(true);
|
||||
|
||||
timeout = current_tick + READ_TIMEOUT;
|
||||
|
||||
/* TODO: Select device */
|
||||
if(current_card == 0)
|
||||
{
|
||||
if(start > 0x7a77ff)
|
||||
{
|
||||
sd_select_bank(1);
|
||||
start-=0x7a77ff;
|
||||
} else {
|
||||
sd_select_bank(0);
|
||||
}
|
||||
}
|
||||
|
||||
buf = inbuf;
|
||||
count = incount;
|
||||
while (TIME_BEFORE(current_tick, timeout)) {
|
||||
ret = 0;
|
||||
last_disk_activity = current_tick;
|
||||
|
||||
SD_STATE_REG = TRAN;
|
||||
BLOCK_COUNT_REG = count;
|
||||
sd_send_command(READ_MULTIPLE_BLOCK, start * BLOCK_SIZE, 0x1c25);
|
||||
sd_read_response(&dummy, 1);
|
||||
/* TODO: Don't assume BLOCK_SIZE == SECTOR_SIZE */
|
||||
|
||||
for (i = 0; i < count * card->block_size / 2; i += FIFO_SIZE)
|
||||
{
|
||||
/* Wait for the FIFO to be full */
|
||||
while((STATUS_REG & FIFO_FULL) == 0) {}
|
||||
|
||||
copy_read_sectors(buf, FIFO_SIZE);
|
||||
|
||||
buf += FIFO_SIZE*2; /* Advance one chunk of 16 words */
|
||||
|
||||
/* TODO: Switch bank if necessary */
|
||||
|
||||
last_disk_activity = current_tick;
|
||||
}
|
||||
udelay(75);
|
||||
sd_send_command(STOP_TRANSMISSION, 0, 1);
|
||||
sd_read_response(&dummy, 1);
|
||||
|
||||
response = 0;
|
||||
sd_wait_for_state(card, TRAN);
|
||||
break;
|
||||
}
|
||||
ata_led(false);
|
||||
|
||||
mutex_unlock(&ata_mtx);
|
||||
|
||||
/* only flush if reading went ok */
|
||||
if ( (ret == 0) && delayed_write )
|
||||
ata_flush();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int ata_write_sectors(IF_MV2(int drive,)
|
||||
unsigned long start,
|
||||
int count,
|
||||
const void* buf)
|
||||
{
|
||||
(void)start;
|
||||
(void)count;
|
||||
(void)buf;
|
||||
return -1;
|
||||
/* Write support is not finished yet */
|
||||
/* TODO: The standard suggests using ACMD23 prior to writing multiple blocks
|
||||
to improve performance */
|
||||
unsigned int response;
|
||||
void const* write_buf;
|
||||
int ret = 0;
|
||||
unsigned int i;
|
||||
long timeout;
|
||||
tSDCardInfo *card = &card_info[current_card];
|
||||
|
||||
mutex_lock(&ata_mtx);
|
||||
ata_led(true);
|
||||
if(current_card == 0)
|
||||
{
|
||||
if(start <= 0x7a77ff)
|
||||
{
|
||||
sd_select_bank(0);
|
||||
} else {
|
||||
sd_select_bank(1);
|
||||
start -= 0x7a77ff;
|
||||
}
|
||||
}
|
||||
|
||||
retry:
|
||||
sd_wait_for_state(card, TRAN);
|
||||
BLOCK_COUNT_REG = count;
|
||||
sd_send_command(WRITE_MULTIPLE_BLOCK, start * SECTOR_SIZE, 0x1c2d);
|
||||
sd_read_response(&response, 1);
|
||||
write_buf = buf;
|
||||
for (i = 0; i < count * card->block_size / 2; i += FIFO_SIZE)
|
||||
{
|
||||
if(i >= (count * card->block_size / 2)-FIFO_SIZE)
|
||||
{
|
||||
/* Set SD_STATE_REG to PRG for the last buffer fill */
|
||||
SD_STATE_REG = PRG;
|
||||
}
|
||||
|
||||
/* Wait for the FIFO to be empty */
|
||||
while((STATUS_REG & FIFO_EMPTY) == 0) {}
|
||||
/* Perhaps we could use bit 8 of card status (READY_FOR_DATA)? */
|
||||
|
||||
copy_write_sectors(write_buf, FIFO_SIZE);
|
||||
|
||||
write_buf += FIFO_SIZE*2; /* Advance one chunk of 16 words */
|
||||
/* TODO: Switch bank if necessary */
|
||||
|
||||
last_disk_activity = current_tick;
|
||||
}
|
||||
|
||||
timeout = current_tick + WRITE_TIMEOUT;
|
||||
|
||||
while((STATUS_REG & DATA_DONE) == 0) {
|
||||
if(current_tick >= timeout)
|
||||
{
|
||||
sd_send_command(STOP_TRANSMISSION, 0, 1);
|
||||
sd_read_response(&response, 1);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
sd_send_command(STOP_TRANSMISSION, 0, 1);
|
||||
sd_read_response(&response, 1);
|
||||
|
||||
sd_wait_for_state(card, TRAN);
|
||||
mutex_unlock(&ata_mtx);
|
||||
ata_led(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* schedule a single sector write, executed with the the next spinup
|
||||
/* schedule a single sector write, executed with the the next spinup
|
||||
(volume 0 only, used for config sector) */
|
||||
extern void ata_delayed_write(unsigned long sector, const void* buf)
|
||||
{
|
||||
|
@ -147,12 +642,6 @@ extern void ata_delayed_write(unsigned long sector, const void* buf)
|
|||
(void)buf;
|
||||
}
|
||||
|
||||
/* write the delayed sector to volume 0 */
|
||||
extern void ata_flush(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ata_spindown(int seconds)
|
||||
{
|
||||
(void)seconds;
|
||||
|
@ -189,10 +678,11 @@ void ata_enable(bool on)
|
|||
|
||||
unsigned short* ata_get_identify(void)
|
||||
{
|
||||
|
||||
return identify_info;
|
||||
}
|
||||
|
||||
int ata_init(void)
|
||||
{
|
||||
sd_init_device();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1 +1,43 @@
|
|||
/* nothing here yet */
|
||||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 by Daniel Ankers
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef ATA_TARGET_H
|
||||
#define ATA_TARGET_H
|
||||
|
||||
#include "inttypes.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool initialized;
|
||||
|
||||
unsigned int ocr; /* OCR register */
|
||||
unsigned int csd[4]; /* CSD register */
|
||||
unsigned int cid[4]; /* CID register */
|
||||
unsigned int rca;
|
||||
|
||||
uint64_t capacity; /* size in bytes */
|
||||
unsigned long numblocks; /* size in flash blocks */
|
||||
unsigned int block_size; /* block size in bytes */
|
||||
unsigned int max_read_bl_len;/* max read data block length */
|
||||
unsigned int block_exp; /* block size exponent */
|
||||
} tSDCardInfo;
|
||||
|
||||
tSDCardInfo *sd_card_info(int card_no);
|
||||
bool sd_touched(void);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue