mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-09 05:05:20 -05:00
FS#10053 - Sansa AMS >2GB support by Rafaël Carré. Enables bank switching on
the AMS sansas, which solves the ">2GB problem" (the problem that we could not access data past 1GB on devices having more than 2GB internal storage). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20577 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
d5df2816e6
commit
dc859ebd51
1 changed files with 109 additions and 22 deletions
|
|
@ -8,7 +8,7 @@
|
|||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 Daniel Ankers
|
||||
* Copyright © 2008 Rafaël Carré
|
||||
* Copyright © 2008-2009 Rafaël Carré
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
/* Driver for the ARM PL180 SD/MMC controller inside AS3525 SoC */
|
||||
|
||||
/* TODO: Find the real capacity of >2GB models (will be useful for USB) */
|
||||
|
||||
#include "config.h" /* for HAVE_MULTIVOLUME */
|
||||
#include "fat.h"
|
||||
#include "thread.h"
|
||||
|
|
@ -36,7 +38,6 @@
|
|||
#include "pl081.h" /* DMA controller */
|
||||
#include "dma-target.h" /* DMA request lines */
|
||||
#include "clock-target.h"
|
||||
#include "panic.h"
|
||||
#include "stdbool.h"
|
||||
#include "ata_idle_notify.h"
|
||||
#include "sd.h"
|
||||
|
|
@ -87,11 +88,13 @@ static const int pl180_base[NUM_VOLUMES] = {
|
|||
#endif
|
||||
};
|
||||
|
||||
static int sd_select_bank(signed char bank);
|
||||
static int sd_init_card(const int drive);
|
||||
static void init_pl180_controller(const int drive);
|
||||
/* TODO : BLOCK_SIZE != SECTOR_SIZE ? */
|
||||
#define BLOCK_SIZE 512
|
||||
#define SECTOR_SIZE 512
|
||||
#define BLOCKS_PER_BANK 0x7a7800
|
||||
|
||||
static tSDCardInfo card_info[NUM_VOLUMES];
|
||||
|
||||
|
|
@ -347,6 +350,19 @@ static int sd_init_card(const int drive)
|
|||
|
||||
mci_set_clock_divider(drive, 1); /* full speed */
|
||||
|
||||
/*
|
||||
* enable bank switching
|
||||
* without issuing this command, we only have access to 1/4 of the blocks
|
||||
* of the first bank (0x1E9E00 blocks, which is the size reported in the
|
||||
* CSD register)
|
||||
*/
|
||||
if(drive == INTERNAL_AS3525)
|
||||
{
|
||||
const int ret = sd_select_bank(-1);
|
||||
if(ret < 0)
|
||||
return ret - 13;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -488,7 +504,7 @@ int sd_init(void)
|
|||
CCU_IO &= ~(1<<3); /* bits 3:2 = 01, xpd is SD interface */
|
||||
CCU_IO |= (1<<2);
|
||||
#endif
|
||||
|
||||
|
||||
wakeup_init(&transfer_completion_signal);
|
||||
|
||||
init_pl180_controller(INTERNAL_AS3525);
|
||||
|
|
@ -563,7 +579,7 @@ static int sd_wait_for_state(const int drive, unsigned int state)
|
|||
return 0;
|
||||
|
||||
if(TIME_AFTER(current_tick, t + timeout))
|
||||
return -1;
|
||||
return -2;
|
||||
|
||||
if (TIME_AFTER((tick = current_tick), next_yield))
|
||||
{
|
||||
|
|
@ -574,6 +590,61 @@ static int sd_wait_for_state(const int drive, unsigned int state)
|
|||
}
|
||||
}
|
||||
|
||||
static int sd_select_bank(signed char bank)
|
||||
{
|
||||
unsigned char card_data[512];
|
||||
int ret;
|
||||
|
||||
ret = sd_wait_for_state(INTERNAL_AS3525, SD_TRAN);
|
||||
if (ret < 0)
|
||||
return ret - 2;
|
||||
|
||||
if(!send_cmd(INTERNAL_AS3525, SD_SWITCH_FUNC, 0x80ffffef, MCI_ARG, NULL))
|
||||
return -1;
|
||||
|
||||
mci_delay();
|
||||
|
||||
if(!send_cmd(INTERNAL_AS3525, 35, 0, MCI_NO_FLAGS, NULL))
|
||||
return -2;
|
||||
|
||||
mci_delay();
|
||||
|
||||
memset(card_data, 0, 512);
|
||||
if(bank == -1)
|
||||
{ /* enable bank switching */
|
||||
card_data[0] = 16;
|
||||
card_data[1] = 1;
|
||||
card_data[2] = 10;
|
||||
}
|
||||
else
|
||||
card_data[0] = bank;
|
||||
|
||||
dma_retain();
|
||||
dma_enable_channel(0, card_data, MCI_FIFO(INTERNAL_AS3525), DMA_PERI_SD,
|
||||
DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL);
|
||||
|
||||
MCI_DATA_TIMER(INTERNAL_AS3525) = 0x1000000; /* FIXME: arbitrary */
|
||||
MCI_DATA_LENGTH(INTERNAL_AS3525) = 512;
|
||||
MCI_DATA_CTRL(INTERNAL_AS3525) = (1<<0) /* enable */ |
|
||||
(0<<1) /* transfer direction */ |
|
||||
(1<<3) /* DMA */ |
|
||||
(9<<4) /* 2^9 = 512 */ ;
|
||||
|
||||
wakeup_wait(&transfer_completion_signal, TIMEOUT_BLOCK);
|
||||
|
||||
dma_release();
|
||||
|
||||
mci_delay();
|
||||
|
||||
ret = sd_wait_for_state(INTERNAL_AS3525, SD_TRAN);
|
||||
if (ret < 0)
|
||||
return ret - 4;
|
||||
|
||||
card_info[INTERNAL_AS3525].current_bank = (bank == -1) ? 0 : bank;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
|
||||
int count, void* buf, bool write)
|
||||
{
|
||||
|
|
@ -581,13 +652,14 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
|
|||
const int drive = 0;
|
||||
#endif
|
||||
int ret = 0;
|
||||
int bank;
|
||||
|
||||
/* skip SanDisk OF */
|
||||
if (drive == INTERNAL_AS3525)
|
||||
#if defined(SANSA_E200V2) || defined(SANSA_FUZE)
|
||||
start += 61440;
|
||||
start += 0xf000;
|
||||
#else
|
||||
start += 20480;
|
||||
start += 0x5000;
|
||||
#endif
|
||||
|
||||
mutex_lock(&sd_mtx);
|
||||
|
|
@ -599,17 +671,34 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
|
|||
{
|
||||
ret = sd_init_card(drive);
|
||||
if (!(card_info[drive].initialized))
|
||||
{
|
||||
panicf("card not initialised (%d)", ret);
|
||||
goto sd_transfer_error;
|
||||
}
|
||||
}
|
||||
|
||||
last_disk_activity = current_tick;
|
||||
|
||||
/* Only switch banks for internal storage */
|
||||
if(drive == INTERNAL_AS3525)
|
||||
{
|
||||
bank = start / BLOCKS_PER_BANK;
|
||||
|
||||
if(card_info[INTERNAL_AS3525].current_bank != bank)
|
||||
{
|
||||
ret = sd_select_bank(bank);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret -= 20;
|
||||
goto sd_transfer_error;
|
||||
}
|
||||
}
|
||||
|
||||
start -= bank * BLOCKS_PER_BANK;
|
||||
}
|
||||
|
||||
|
||||
ret = sd_wait_for_state(drive, SD_TRAN);
|
||||
if (ret < 0)
|
||||
{
|
||||
panicf("wait for state failed on drive %d", drive);
|
||||
ret -= 2*20;
|
||||
goto sd_transfer_error;
|
||||
}
|
||||
|
||||
|
|
@ -624,15 +713,15 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
|
|||
unsigned int transfer = (count >= 128) ? 127 : count; /* sectors */
|
||||
const int cmd =
|
||||
write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK;
|
||||
int arg = start;
|
||||
if(!(card_info[drive].ocr & (1<<30))) /* not SDHC */
|
||||
arg *= BLOCK_SIZE;
|
||||
|
||||
if(card_info[drive].ocr & (1<<30) ) /* SDHC */
|
||||
ret = send_cmd(drive, cmd, start, MCI_ARG, NULL);
|
||||
else
|
||||
ret = send_cmd(drive, cmd, start * BLOCK_SIZE,
|
||||
MCI_ARG, NULL);
|
||||
|
||||
if (ret < 0)
|
||||
panicf("transfer multiple blocks failed (%d)", ret);
|
||||
if(!send_cmd(drive, cmd, arg, MCI_ARG, NULL))
|
||||
{
|
||||
ret -= 3*20;
|
||||
goto sd_transfer_error;
|
||||
}
|
||||
|
||||
if(write)
|
||||
dma_enable_channel(0, buf, MCI_FIFO(drive),
|
||||
|
|
@ -663,15 +752,14 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
|
|||
|
||||
if(!send_cmd(drive, SD_STOP_TRANSMISSION, 0, MCI_NO_FLAGS, NULL))
|
||||
{
|
||||
ret = -666;
|
||||
panicf("STOP TRANSMISSION failed");
|
||||
ret = -4*20;
|
||||
goto sd_transfer_error;
|
||||
}
|
||||
|
||||
ret = sd_wait_for_state(drive, SD_TRAN);
|
||||
if (ret < 0)
|
||||
{
|
||||
panicf(" wait for state TRAN failed (%d)", ret);
|
||||
ret -= 5*20;
|
||||
goto sd_transfer_error;
|
||||
}
|
||||
}
|
||||
|
|
@ -685,7 +773,6 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
|
|||
return 0;
|
||||
|
||||
sd_transfer_error:
|
||||
panicf("transfer error : %d",ret);
|
||||
card_info[drive].initialized = 0;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue