From dc859ebd51b74c4487e43a54b65c9ed7649c1cc5 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Mon, 30 Mar 2009 13:26:05 +0000 Subject: [PATCH] =?UTF-8?q?FS#10053=20-=20Sansa=20AMS=20>2GB=20support=20b?= =?UTF-8?q?y=20Rafa=C3=ABl=20Carr=C3=A9.=20Enables=20bank=20switching=20on?= =?UTF-8?q?=20the=20AMS=20sansas,=20which=20solves=20the=20">2GB=20problem?= =?UTF-8?q?"=20(the=20problem=20that=20we=20could=20not=20access=20data=20?= =?UTF-8?q?past=201GB=20on=20devices=20having=20more=20than=202GB=20intern?= =?UTF-8?q?al=20storage).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20577 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/arm/as3525/ata_sd_as3525.c | 131 +++++++++++++++++---- 1 file changed, 109 insertions(+), 22 deletions(-) diff --git a/firmware/target/arm/as3525/ata_sd_as3525.c b/firmware/target/arm/as3525/ata_sd_as3525.c index da455ce1d6..042af3b5a1 100644 --- a/firmware/target/arm/as3525/ata_sd_as3525.c +++ b/firmware/target/arm/as3525/ata_sd_as3525.c @@ -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; }