From 7478cfcbf70c0d1378fe492a5eacf08d59d403b2 Mon Sep 17 00:00:00 2001 From: Rafaël Carré Date: Wed, 13 Jan 2010 06:44:45 +0000 Subject: Sansa as3525v2: move SD embryo code to a common dir Select it based on as3535/as3525v2 so Clip+/Fuzev2 will be able to use it too git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24222 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 6 +- firmware/target/arm/as3525/ata_sd-as3535v2.c | 777 +++++++++++++++++++++ .../target/arm/as3525/sansa-clipv2/sd-clipv2.c | 777 --------------------- 3 files changed, 780 insertions(+), 780 deletions(-) create mode 100644 firmware/target/arm/as3525/ata_sd-as3535v2.c delete mode 100644 firmware/target/arm/as3525/sansa-clipv2/sd-clipv2.c diff --git a/firmware/SOURCES b/firmware/SOURCES index 064c8fe650..90b20f3747 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -407,8 +407,10 @@ target/arm/pnx0101/timer-pnx0101.c target/arm/as3525/system-as3525.c target/arm/as3525/kernel-as3525.c target/arm/as3525/timer-as3525.c -#ifndef SANSA_CLIPV2 +#if CONFIG_CPU == AS3525 target/arm/as3525/ata_sd_as3525.c +#else /* AS3535v2 */ +target/arm/as3525/ata_sd-as3525v2.c #endif target/arm/as3525/power-as3525.c target/arm/as3525/usb-as3525.c @@ -1205,8 +1207,6 @@ target/arm/tcc77x/c100/audio-c100.c #ifndef SIMULATOR target/arm/as3525/sansa-clip/lcd-ssd1303.c target/arm/as3525/sansa-clip/lcd-as-clip.S - -target/arm/as3525/sansa-clipv2/sd-clipv2.c target/arm/as3525/sansa-clipv2/button-clip.c target/arm/as3525/sansa-clipv2/backlight-clip.c #ifndef BOOTLOADER diff --git a/firmware/target/arm/as3525/ata_sd-as3535v2.c b/firmware/target/arm/as3525/ata_sd-as3535v2.c new file mode 100644 index 0000000000..70c0477431 --- /dev/null +++ b/firmware/target/arm/as3525/ata_sd-as3535v2.c @@ -0,0 +1,777 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Daniel Ankers + * 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 + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" /* for HAVE_MULTIVOLUME */ +#include "fat.h" +#include "thread.h" +#include "hotswap.h" +#include "system.h" +#include "kernel.h" +#include "cpu.h" +#include +#include +#include +#include "as3525v2.h" +#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" + +#include "lcd.h" +#include +#include "sysfont.h" + +static int line = 0; +static void printf(const char *format, ...) +{ + char buf[50]; + int len; + va_list ap; + va_start(ap, format); + + len = vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + + lcd_puts(0, line++, buf); + lcd_update(); + if(line >= LCD_HEIGHT/SYSFONT_HEIGHT) + line = 0; +} + +/* command flags */ +#define MCI_NO_RESP (0<<0) +#define MCI_RESP (1<<0) +#define MCI_LONG_RESP (1<<1) + +/* controller registers */ +#define SD_BASE 0xC6070000 + +/* + * REGISTERS + * + * m = modify (orr/bic), r = read, w = write + * + * 00 m/r/w + * 04 m/w + * 08 m + * 0C ? + * 10 r/w + * 14 w + * 18 m + * 1C w ==> set a bit before transfer (sometimes) ! + * 20 w ==> set a bit before transfer ! + * 24 w irq mask ? + * 28 w arg + * 2C r/w cmd + * 30 r resp0 + * 34 r resp1 + * 38 r resp2 + * 3C r resp3 + * 40 r irq status (only read in isr) + * 44 m/w irq clear + * 48 r + * 4C m + * 64 w + * 70 r + * 100 FIFO + */ + +/* + * STATUS register + * & 0xBA80 + * & 8 + * & 0x428 + * & 0x418 + */ + +/* + * INFO on CMD register + * + * if(cmd >= 200) cmd -= 200; (>= 200 = acmd?) + * + * COMMANDS (| (x<<16) BITS RESPONSE + * + * 1 ? reserved & ~0x80, | 0x40, | 0x8000 ? + * 5 ? reserved for I/O cards & ~0x80, | 0x40 ? + * 11 ? reserved & ~0x80, | 0x40, | 0x2200, | 0x800 ? + * 14 ? reserved & ~0x80, | 0x40, | 0x2200, ~0x1000 ? + * 19 ? reserved & ~0x80, |0x40, | 0x2700, & ~0x1000 ? + * 20 ? reserved & ~0x80, |0x40, | 0x2700, | 0x800 ? + * 23 ? reserved & ~0x80, | 0x40 ? + * 39 ? reserved & ~0x80, | 0x40 ? + * 51 ? reserved & ~0x80, | 0x40, | 0x2000, | 0x200 ? + * 52 ? reserved for I/O & ~0x80, | 0x40 ? + * 53 ? reserved for I/O & ~0x80, | 0x40, | 0x2200, & ~0x1000 ? + * 253 ? & ~0x80, |0x40, | 0x2700, & ~0x1000 ? + * + * 0 GO IDLE STATE & ~0x4000, & ~0xC0, | 0x4000 no + * 2 ALL SEND CID & ~0x4000, |0xC0 r2 + * 3 SEND RCA & ~0x80, | 0x40 r6 + * 6 SWITCH_FUNC & ~0x80, | 0x40 r1 + * 7 SELECT CARD & ~0x80, | 0x40 r1b + * 8 SEND IF COND & ~0x80, | 0x40, | 0x2200, & ~0x1000 r7 + * 9 SEND CSD & ~0x4000, | 0xc0 r2 + * 12 STOP TRANSMISSION & ~0x80, | 0x40, | 0x4000 r1b + * 13 SEND STATUS & ~0x80, | 0x40 r1 + * 15 GO INACTIVE STATE & ~0x4000, & ~0xC0 no + * 16 SET BLOCKLEN & ~0x80, | 0x40 r1 + * 17 READ SINGLE BLOCK & ~0x80, | 0x40, | 0x2200 r1 + * 18 READ MULTIPLE BLOCK & ~0x80, | 0x40, | 0x2200 r1 + * 24 WRITE BLOCK & ~0x80, |0x40, | 0x2700 r1 + * 25 WRITE MULTIPLE BLOCK & ~0x80, |0x40, | 0x2700 r1 + * 41 SEND APP OP COND & ~0x80, | 0x40 r3 + * 42 LOCK UNLOCK & ~0x80, |0x40, | 0x2700 r1 + * 55 APP CMD & ~0x80, | 0x40 r1 + * 206 SET BUS WIDTH & ~0x80, | 0x40, | 0x2000 r1 + * 207 SELECT CARD ? & ~0x4000, & ~0xC0 r1b + * + * + * bits 5:0 = cmd + * bit 6 (0x40) = response + * bit 7 (0x80) = long response + * => like pl180 <= + * BIT SET IN COMANDS: + * + * bit 8 (0x100) ? write block, write multi_block, lock/unlock + * bit 9 (0x200) ? send if cond, read block, read multi_block, write block, write multi_block, lock/unlock + * bit 10 (0x400) ? write block, write multi_block, lock/unlock + * bit 11 (0x800) ? + * bit 12 (0x1000) ? + * bit 13 (0x2000) ? send if cond, read block, read multi_block, write block, write multi_block, lock/unlock, set bus width + * bit 14 (0x4000) ? go idle state, stop transmission + * bit 15 (0x8000) ? + * + */ + +/* FIXME */ +#define MCI_POWER +#define MCI_CLOCK +#define MCI_ARGUMENT (*(volatile unsigned long *) (SD_BASE+0x28)) +#define MCI_COMMAND (*(volatile unsigned long *) (SD_BASE+0x2C)) +#define MCI_RESPCMD +#define MCI_RESP0 (*(volatile unsigned long *) (SD_BASE+0x30)) +#define MCI_RESP1 (*(volatile unsigned long *) (SD_BASE+0x34)) +#define MCI_RESP2 (*(volatile unsigned long *) (SD_BASE+0x38)) +#define MCI_RESP3 (*(volatile unsigned long *) (SD_BASE+0x3C)) +#define MCI_DATA_TIMER +#define MCI_DATA_LENGTH +#define MCI_DATA_CTRL +#define MCI_STATUS (*(volatile unsigned long *) (SD_BASE+0x40)) +#define MCI_CLEAR (*(volatile unsigned long *) (SD_BASE+0x44)) +#define MCI_MASK (*(volatile unsigned long *) (SD_BASE+0x24)) +#define MCI_SELECT + +#define MCI_ERROR 0 /* FIXME */ + +#define MCI_FIFO ((unsigned long *) (SD_BASE+0x100)) + +#define MCI_COMMAND_ENABLE (1<<31) +#define MCI_COMMAND_ACTIVE MCI_COMMAND_ENABLE +#define MCI_COMMAND_RESPONSE (1<<6) +#define MCI_COMMAND_LONG_RESPONSE (1<<7) + + + +static int sd_init_card(void); +static void init_controller(void); + +static tCardInfo card_info; + +/* for compatibility */ +static long last_disk_activity = -1; + +#define MIN_YIELD_PERIOD 5 /* ticks */ +static long next_yield = 0; + +static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x200)/sizeof(long)]; +static const char sd_thread_name[] = "ata/sd"; +static struct mutex sd_mtx SHAREDBSS_ATTR; +static struct event_queue sd_queue; +#ifndef BOOTLOADER +static bool sd_enabled = false; +#endif + +static struct wakeup transfer_completion_signal; +static volatile bool retry; + +static inline void mci_delay(void) { int i = 0xffff; while(i--) ; } + +void INT_NAND(void) +{ + (*(volatile unsigned long *) (SD_BASE+0x0)) &= ~0x10; // ? + const int status = MCI_STATUS; + +#if 0 + if(status & MCI_ERROR) + retry = true; +#endif + +// wakeup_signal(&transfer_completion_signal); + MCI_CLEAR = status; + + static int x = 0; + switch(status) + { + case 0x4: /* cmd received ? */ + case 0x104: /* ? 1 time in init (10th interrupt) */ + case 0x2000: /* ? after cmd read_mul_blocks | 0x2200 */ + + case 0x820: /* ? 1 time while copy from FIFO (not DMA) */ + case 0x20: /* ? rx fifo empty */ + break; + default: + printf("%2d NAND 0x%x", ++x, status); + int delay = 0x100000; while(delay--) ; + } + /* + * 0x48 = some kind of status + * 0x106 + * 0x4106 + * 1B906 + * 1F906 + * 1B906 + * 1F906 + * 1F906 + * 1906 + * ... + * 6906 + * 6D06 (dma) + * + * read resp (6, 7, 12, 42) : while bit 9 is unset ; + * + */ + printf("%x %x", status, (*(volatile unsigned long *) (SD_BASE+0x48))); + //while(!button_read_device()); + //while(button_read_device()); + + (*(volatile unsigned long *) (SD_BASE+0x0)) |= 0x10; // ? +} + +static bool send_cmd(const int cmd, const int arg, const int flags, + unsigned long *response) +{ + int val; + val = cmd | MCI_COMMAND_ENABLE; + if(flags & MCI_RESP) + { + val |= MCI_COMMAND_RESPONSE; + if(flags & MCI_LONG_RESP) + val |= MCI_COMMAND_LONG_RESPONSE; + } + + if(cmd == 18) /* r */ + val |= 0x2200; + else if(cmd == 25) /* w */ + val |= 0x2700; + + int tmp = (*(volatile unsigned long *) (SD_BASE+0x10)); + (*(volatile unsigned long *) (SD_BASE+0x10)) = 0; + + MCI_COMMAND = 0x80202000; + MCI_ARGUMENT = 0; + int max = 10; + while(max-- && MCI_COMMAND & MCI_COMMAND_ACTIVE); + + (*(volatile unsigned long *) (SD_BASE+0x08)) &= ~0xff; + (*(volatile unsigned long *) (SD_BASE+0x08)) |= 0; + + MCI_COMMAND = 0x80202000; + MCI_ARGUMENT = 0; + max = 10; + while(max-- && MCI_COMMAND & MCI_COMMAND_ACTIVE); + + (*(volatile unsigned long *) (SD_BASE+0x10)) = tmp; + + MCI_COMMAND = 0x80202000; + MCI_ARGUMENT = 0; + max = 10; + while(max-- && MCI_COMMAND & MCI_COMMAND_ACTIVE); + + mci_delay(); + + MCI_ARGUMENT = arg; + MCI_COMMAND = val; + + (*(volatile unsigned long *) (SD_BASE+0x00)) |= 0x10; + + max = 1000; + while(max-- && MCI_COMMAND & MCI_COMMAND_ACTIVE); /* wait for cmd completion */ + if(!max) + return false; + + if(flags & MCI_RESP) + { + if(flags & MCI_LONG_RESP) + { + /* store the response in little endian order for the words */ + response[0] = MCI_RESP3; + response[1] = MCI_RESP2; + response[2] = MCI_RESP1; + response[3] = MCI_RESP0; + } + else + response[0] = MCI_RESP0; + } + return true; +} + +static int sd_init_card(void) +{ + unsigned long response; + unsigned long temp_reg[4]; + int max_tries = 100; /* max acmd41 attemps */ + bool sdhc; + int i; + + if(!send_cmd(SD_GO_IDLE_STATE, 0, MCI_NO_RESP, NULL)) + return -1; + + mci_delay(); + + sdhc = false; + if(send_cmd(SD_SEND_IF_COND, 0x1AA, MCI_RESP, &response)) + if((response & 0xFFF) == 0x1AA) + sdhc = true; + + do { + /* some MicroSD cards seems to need more delays, so play safe */ + mci_delay(); + mci_delay(); + mci_delay(); + + /* app_cmd */ + if( !send_cmd(SD_APP_CMD, 0, MCI_RESP, &response) /*|| + !(response & (1<<5))*/ ) + { + return -2; + } + + /* acmd41 */ + if(!send_cmd(SD_APP_OP_COND, (sdhc ? 0x40FF8000 : (1<<23)), + MCI_RESP, &card_info.ocr)) + return -3; + } while(!(card_info.ocr & (1<<31)) && max_tries--); + + if(max_tries < 0) + return -4; + + mci_delay(); + mci_delay(); + mci_delay(); + + /* send CID */ + if(!send_cmd(SD_ALL_SEND_CID, 0, MCI_RESP|MCI_LONG_RESP, card_info.cid)) + return -5; + + /* send RCA */ + if(!send_cmd(SD_SEND_RELATIVE_ADDR, 0, MCI_RESP, &card_info.rca)) + return -6; + + /* send CSD */ + if(!send_cmd(SD_SEND_CSD, card_info.rca, + MCI_RESP|MCI_LONG_RESP, temp_reg)) + return -7; + + for(i=0; i<4; i++) + card_info.csd[3-i] = temp_reg[i]; + + sd_parse_csd(&card_info); + + if(!send_cmd(SD_APP_CMD, 0, MCI_RESP, &response) || + !send_cmd(42, 0, MCI_NO_RESP, NULL)) /* disconnect the 50 KOhm pull-up + resistor on CD/DAT3 */ + return -13; + + if(!send_cmd(SD_APP_CMD, card_info.rca, MCI_NO_RESP, NULL)) + return -10; + + if(!send_cmd(SD_SET_BUS_WIDTH, card_info.rca | 2, MCI_NO_RESP, NULL)) + return -11; + + (*(volatile unsigned long *) (SD_BASE+0x18)) &= ~(0x10001); + (*(volatile unsigned long *) (SD_BASE+0x18)) |= 0x1; + + if(!send_cmd(SD_SELECT_CARD, card_info.rca, MCI_NO_RESP, NULL)) + return -9; + + /* not sent in init_card() by OF */ + if(!send_cmd(SD_SET_BLOCKLEN, card_info.blocksize, MCI_NO_RESP, + NULL)) + return -12; + + card_info.initialized = 1; + + return 0; +} + +static void sd_thread(void) __attribute__((noreturn)); +static void sd_thread(void) +{ + struct queue_event ev; + bool idle_notified = false; + + while (1) + { + queue_wait_w_tmo(&sd_queue, &ev, HZ); + + switch ( ev.id ) + { + case SYS_TIMEOUT: + if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) + { + idle_notified = false; + } + else + { + /* never let a timer wrap confuse us */ + next_yield = current_tick; + + if (!idle_notified) + { + call_storage_idle_notifys(false); + idle_notified = true; + } + } + break; +#if 0 + case SYS_USB_CONNECTED: + usb_acknowledge(SYS_USB_CONNECTED_ACK); + /* Wait until the USB cable is extracted again */ + usb_wait_for_disconnect(&sd_queue); + + break; + case SYS_USB_DISCONNECTED: + usb_acknowledge(SYS_USB_DISCONNECTED_ACK); + break; +#endif + } + } +} + +static void init_controller(void) +{ + int tmp = (*(volatile unsigned long *) (SD_BASE+0x70)); + int shift = 1 + ((tmp << 26) >> 27); + + (*(volatile unsigned long *) (SD_BASE+0x04)) &= ~((1 << shift) -1); + (*(volatile unsigned long *) (SD_BASE+0x04)) = (1 << shift) -1; + + mci_delay(); + + (*(volatile unsigned long *) (SD_BASE+0x00)) |= 1; + int max = 1000; + while(max-- && !(*(volatile unsigned long *) (SD_BASE+0x00)) & 1) + ; + + MCI_CLEAR = 0xffffffff; + MCI_MASK = 0xffffbffe; + + (*(volatile unsigned long *) (SD_BASE+0x00)) |= 0x10; + (*(volatile unsigned long *) (SD_BASE+0x14)) = 0xffffffff; + + (*(volatile unsigned long *) (SD_BASE+0x10)) = (1<sector_size=card_info.blocksize; + info->num_sectors=card_info.numblocks; + info->vendor="Rockbox"; + info->product = "Internal Storage"; + info->revision="0.00"; +} +#endif + +static int sd_wait_for_state(unsigned int state) +{ + unsigned long response; + unsigned int timeout = 100; /* ticks */ + long t = current_tick; + + while (1) + { + long tick; + + if(!send_cmd(SD_SEND_STATUS, card_info.rca, + MCI_RESP, &response)) + return -1; + + if (((response >> 9) & 0xf) == state) + return 0; + + if(TIME_AFTER(current_tick, t + timeout)) + return -10 * ((response >> 9) & 0xf); + + if (TIME_AFTER((tick = current_tick), next_yield)) + { + yield(); + timeout += current_tick - tick; + next_yield = tick + MIN_YIELD_PERIOD; + } + } +} + +static int sd_transfer_sectors(unsigned long start, int count, void* buf, bool write) +{ + int ret = 0; + + if((int)buf & 3) + panicf("unaligned transfer"); + + /* skip SanDisk OF */ + start += 0xf000; + + mutex_lock(&sd_mtx); +#ifndef BOOTLOADER + sd_enable(true); +#endif + + if (card_info.initialized <= 0) + { + ret = sd_init_card(); + if (!(card_info.initialized)) + { + panicf("card not initialised (%d)", ret); + goto sd_transfer_error; + } + } + + last_disk_activity = current_tick; + ret = sd_wait_for_state(SD_TRAN); + if (ret < 0) + { + static const char *st[9] = { + "IDLE", "RDY", "IDENT", "STBY", "TRAN", "DATA", "RCV", "PRG", "DIS" + }; + if(ret <= -10) + panicf("wait for state failed (%s)", st[(-ret / 10) % 9]); + else + panicf("wait for state failed"); + goto sd_transfer_error; + } + + dma_retain(); + + while(count) + { + /* Interrupt handler might set this to true during transfer */ + retry = false; + /* 128 * 512 = 2^16, and doesn't fit in the 16 bits of DATA_LENGTH + * register, so we have to transfer maximum 127 sectors at a time. */ + //unsigned int transfer = (count >= 128) ? 127 : count; /* sectors */ + unsigned int transfer = count; + + const int cmd = + write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK; + + (*(volatile unsigned long *) (SD_BASE+0x00)) |= 2; + while(( *(volatile unsigned long *) (SD_BASE+0x00)) & 2) ; + + //(*(volatile unsigned long *) (SD_BASE+0x1c)) = 512; + (*(volatile unsigned long *) (SD_BASE+0x20)) = transfer * 512; + + (*(volatile unsigned long *) (SD_BASE+0x00)) |= 2; + while(( *(volatile unsigned long *) (SD_BASE+0x00)) & 2) ; + + (*(volatile unsigned long *) (SD_BASE+0x4c)) &= ~0x7fff0fff; + + if(0) + { + (*(volatile unsigned long *) (SD_BASE+0x00)) |= 0x20; + MCI_MASK = 0xBE8C; + (*(volatile unsigned long *) (SD_BASE+0x4c)) |= 0x503f0080; + } + else + { + MCI_MASK = 0xBEB8; + (*(volatile unsigned long *) (SD_BASE+0x4c)) |= 0x3f0030; + } + + if(card_info.ocr & (1<<30) ) /* SDHC */ + ret = send_cmd(cmd, start, MCI_NO_RESP, NULL); + else + ret = send_cmd(cmd, start * SD_BLOCK_SIZE, + MCI_NO_RESP, NULL); + + if (ret < 0) + panicf("transfer multiple blocks failed (%d)", ret); + + if(write) + dma_enable_channel(0, buf, MCI_FIFO, DMA_PERI_SD, + DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL); + else + dma_enable_channel(0, MCI_FIFO, buf, DMA_PERI_SD, + DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8, NULL); + + line = 0; + lcd_clear_display(); + printf("dma ->"); + + wakeup_wait(&transfer_completion_signal, TIMEOUT_BLOCK); + + printf("dma <-"); + int delay = 0x1000000; while(delay--) ; + + if(!retry) + { + buf += transfer * SECTOR_SIZE; + start += transfer; + count -= transfer; + } + + last_disk_activity = current_tick; + + if(!send_cmd(SD_STOP_TRANSMISSION, 0, MCI_NO_RESP, NULL)) + { + ret = -666; + panicf("STOP TRANSMISSION failed"); + goto sd_transfer_error; + } + + ret = sd_wait_for_state(SD_TRAN); + if (ret < 0) + { + panicf(" wait for state TRAN failed (%d)", ret); + goto sd_transfer_error; + } + } + + dma_release(); + +#ifndef BOOTLOADER + sd_enable(false); +#endif + mutex_unlock(&sd_mtx); + return 0; + +sd_transfer_error: + panicf("transfer error : %d",ret); + card_info.initialized = 0; + return ret; +} + +int sd_read_sectors(unsigned long start, int count, void* buf) +{ + return sd_transfer_sectors(start, count, buf, false); +} + +int sd_write_sectors(unsigned long start, int count, const void* buf) +{ +#if defined(BOOTLOADER) /* we don't need write support in bootloader */ + (void) start; + (void) count; + (void) buf; + return -1; +#else + return sd_transfer_sectors(start, count, (void*)buf, true); +#endif +} + +#ifndef BOOTLOADER +void sd_sleep(void) +{ +} + +void sd_spin(void) +{ +} + +void sd_spindown(int seconds) +{ + (void)seconds; +} + +long sd_last_disk_activity(void) +{ + return last_disk_activity; +} + +void sd_enable(bool on) +{ + /* TODO */ + (void)on; + return; +} + +tCardInfo *card_get_info_target(int card_no) +{ + (void)card_no; + return &card_info; +} + +#endif /* BOOTLOADER */ diff --git a/firmware/target/arm/as3525/sansa-clipv2/sd-clipv2.c b/firmware/target/arm/as3525/sansa-clipv2/sd-clipv2.c deleted file mode 100644 index 70c0477431..0000000000 --- a/firmware/target/arm/as3525/sansa-clipv2/sd-clipv2.c +++ /dev/null @@ -1,777 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2006 Daniel Ankers - * 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 - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "config.h" /* for HAVE_MULTIVOLUME */ -#include "fat.h" -#include "thread.h" -#include "hotswap.h" -#include "system.h" -#include "kernel.h" -#include "cpu.h" -#include -#include -#include -#include "as3525v2.h" -#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" - -#include "lcd.h" -#include -#include "sysfont.h" - -static int line = 0; -static void printf(const char *format, ...) -{ - char buf[50]; - int len; - va_list ap; - va_start(ap, format); - - len = vsnprintf(buf, sizeof(buf), format, ap); - va_end(ap); - - lcd_puts(0, line++, buf); - lcd_update(); - if(line >= LCD_HEIGHT/SYSFONT_HEIGHT) - line = 0; -} - -/* command flags */ -#define MCI_NO_RESP (0<<0) -#define MCI_RESP (1<<0) -#define MCI_LONG_RESP (1<<1) - -/* controller registers */ -#define SD_BASE 0xC6070000 - -/* - * REGISTERS - * - * m = modify (orr/bic), r = read, w = write - * - * 00 m/r/w - * 04 m/w - * 08 m - * 0C ? - * 10 r/w - * 14 w - * 18 m - * 1C w ==> set a bit before transfer (sometimes) ! - * 20 w ==> set a bit before transfer ! - * 24 w irq mask ? - * 28 w arg - * 2C r/w cmd - * 30 r resp0 - * 34 r resp1 - * 38 r resp2 - * 3C r resp3 - * 40 r irq status (only read in isr) - * 44 m/w irq clear - * 48 r - * 4C m - * 64 w - * 70 r - * 100 FIFO - */ - -/* - * STATUS register - * & 0xBA80 - * & 8 - * & 0x428 - * & 0x418 - */ - -/* - * INFO on CMD register - * - * if(cmd >= 200) cmd -= 200; (>= 200 = acmd?) - * - * COMMANDS (| (x<<16) BITS RESPONSE - * - * 1 ? reserved & ~0x80, | 0x40, | 0x8000 ? - * 5 ? reserved for I/O cards & ~0x80, | 0x40 ? - * 11 ? reserved & ~0x80, | 0x40, | 0x2200, | 0x800 ? - * 14 ? reserved & ~0x80, | 0x40, | 0x2200, ~0x1000 ? - * 19 ? reserved & ~0x80, |0x40, | 0x2700, & ~0x1000 ? - * 20 ? reserved & ~0x80, |0x40, | 0x2700, | 0x800 ? - * 23 ? reserved & ~0x80, | 0x40 ? - * 39 ? reserved & ~0x80, | 0x40 ? - * 51 ? reserved & ~0x80, | 0x40, | 0x2000, | 0x200 ? - * 52 ? reserved for I/O & ~0x80, | 0x40 ? - * 53 ? reserved for I/O & ~0x80, | 0x40, | 0x2200, & ~0x1000 ? - * 253 ? & ~0x80, |0x40, | 0x2700, & ~0x1000 ? - * - * 0 GO IDLE STATE & ~0x4000, & ~0xC0, | 0x4000 no - * 2 ALL SEND CID & ~0x4000, |0xC0 r2 - * 3 SEND RCA & ~0x80, | 0x40 r6 - * 6 SWITCH_FUNC & ~0x80, | 0x40 r1 - * 7 SELECT CARD & ~0x80, | 0x40 r1b - * 8 SEND IF COND & ~0x80, | 0x40, | 0x2200, & ~0x1000 r7 - * 9 SEND CSD & ~0x4000, | 0xc0 r2 - * 12 STOP TRANSMISSION & ~0x80, | 0x40, | 0x4000 r1b - * 13 SEND STATUS & ~0x80, | 0x40 r1 - * 15 GO INACTIVE STATE & ~0x4000, & ~0xC0 no - * 16 SET BLOCKLEN & ~0x80, | 0x40 r1 - * 17 READ SINGLE BLOCK & ~0x80, | 0x40, | 0x2200 r1 - * 18 READ MULTIPLE BLOCK & ~0x80, | 0x40, | 0x2200 r1 - * 24 WRITE BLOCK & ~0x80, |0x40, | 0x2700 r1 - * 25 WRITE MULTIPLE BLOCK & ~0x80, |0x40, | 0x2700 r1 - * 41 SEND APP OP COND & ~0x80, | 0x40 r3 - * 42 LOCK UNLOCK & ~0x80, |0x40, | 0x2700 r1 - * 55 APP CMD & ~0x80, | 0x40 r1 - * 206 SET BUS WIDTH & ~0x80, | 0x40, | 0x2000 r1 - * 207 SELECT CARD ? & ~0x4000, & ~0xC0 r1b - * - * - * bits 5:0 = cmd - * bit 6 (0x40) = response - * bit 7 (0x80) = long response - * => like pl180 <= - * BIT SET IN COMANDS: - * - * bit 8 (0x100) ? write block, write multi_block, lock/unlock - * bit 9 (0x200) ? send if cond, read block, read multi_block, write block, write multi_block, lock/unlock - * bit 10 (0x400) ? write block, write multi_block, lock/unlock - * bit 11 (0x800) ? - * bit 12 (0x1000) ? - * bit 13 (0x2000) ? send if cond, read block, read multi_block, write block, write multi_block, lock/unlock, set bus width - * bit 14 (0x4000) ? go idle state, stop transmission - * bit 15 (0x8000) ? - * - */ - -/* FIXME */ -#define MCI_POWER -#define MCI_CLOCK -#define MCI_ARGUMENT (*(volatile unsigned long *) (SD_BASE+0x28)) -#define MCI_COMMAND (*(volatile unsigned long *) (SD_BASE+0x2C)) -#define MCI_RESPCMD -#define MCI_RESP0 (*(volatile unsigned long *) (SD_BASE+0x30)) -#define MCI_RESP1 (*(volatile unsigned long *) (SD_BASE+0x34)) -#define MCI_RESP2 (*(volatile unsigned long *) (SD_BASE+0x38)) -#define MCI_RESP3 (*(volatile unsigned long *) (SD_BASE+0x3C)) -#define MCI_DATA_TIMER -#define MCI_DATA_LENGTH -#define MCI_DATA_CTRL -#define MCI_STATUS (*(volatile unsigned long *) (SD_BASE+0x40)) -#define MCI_CLEAR (*(volatile unsigned long *) (SD_BASE+0x44)) -#define MCI_MASK (*(volatile unsigned long *) (SD_BASE+0x24)) -#define MCI_SELECT - -#define MCI_ERROR 0 /* FIXME */ - -#define MCI_FIFO ((unsigned long *) (SD_BASE+0x100)) - -#define MCI_COMMAND_ENABLE (1<<31) -#define MCI_COMMAND_ACTIVE MCI_COMMAND_ENABLE -#define MCI_COMMAND_RESPONSE (1<<6) -#define MCI_COMMAND_LONG_RESPONSE (1<<7) - - - -static int sd_init_card(void); -static void init_controller(void); - -static tCardInfo card_info; - -/* for compatibility */ -static long last_disk_activity = -1; - -#define MIN_YIELD_PERIOD 5 /* ticks */ -static long next_yield = 0; - -static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x200)/sizeof(long)]; -static const char sd_thread_name[] = "ata/sd"; -static struct mutex sd_mtx SHAREDBSS_ATTR; -static struct event_queue sd_queue; -#ifndef BOOTLOADER -static bool sd_enabled = false; -#endif - -static struct wakeup transfer_completion_signal; -static volatile bool retry; - -static inline void mci_delay(void) { int i = 0xffff; while(i--) ; } - -void INT_NAND(void) -{ - (*(volatile unsigned long *) (SD_BASE+0x0)) &= ~0x10; // ? - const int status = MCI_STATUS; - -#if 0 - if(status & MCI_ERROR) - retry = true; -#endif - -// wakeup_signal(&transfer_completion_signal); - MCI_CLEAR = status; - - static int x = 0; - switch(status) - { - case 0x4: /* cmd received ? */ - case 0x104: /* ? 1 time in init (10th interrupt) */ - case 0x2000: /* ? after cmd read_mul_blocks | 0x2200 */ - - case 0x820: /* ? 1 time while copy from FIFO (not DMA) */ - case 0x20: /* ? rx fifo empty */ - break; - default: - printf("%2d NAND 0x%x", ++x, status); - int delay = 0x100000; while(delay--) ; - } - /* - * 0x48 = some kind of status - * 0x106 - * 0x4106 - * 1B906 - * 1F906 - * 1B906 - * 1F906 - * 1F906 - * 1906 - * ... - * 6906 - * 6D06 (dma) - * - * read resp (6, 7, 12, 42) : while bit 9 is unset ; - * - */ - printf("%x %x", status, (*(volatile unsigned long *) (SD_BASE+0x48))); - //while(!button_read_device()); - //while(button_read_device()); - - (*(volatile unsigned long *) (SD_BASE+0x0)) |= 0x10; // ? -} - -static bool send_cmd(const int cmd, const int arg, const int flags, - unsigned long *response) -{ - int val; - val = cmd | MCI_COMMAND_ENABLE; - if(flags & MCI_RESP) - { - val |= MCI_COMMAND_RESPONSE; - if(flags & MCI_LONG_RESP) - val |= MCI_COMMAND_LONG_RESPONSE; - } - - if(cmd == 18) /* r */ - val |= 0x2200; - else if(cmd == 25) /* w */ - val |= 0x2700; - - int tmp = (*(volatile unsigned long *) (SD_BASE+0x10)); - (*(volatile unsigned long *) (SD_BASE+0x10)) = 0; - - MCI_COMMAND = 0x80202000; - MCI_ARGUMENT = 0; - int max = 10; - while(max-- && MCI_COMMAND & MCI_COMMAND_ACTIVE); - - (*(volatile unsigned long *) (SD_BASE+0x08)) &= ~0xff; - (*(volatile unsigned long *) (SD_BASE+0x08)) |= 0; - - MCI_COMMAND = 0x80202000; - MCI_ARGUMENT = 0; - max = 10; - while(max-- && MCI_COMMAND & MCI_COMMAND_ACTIVE); - - (*(volatile unsigned long *) (SD_BASE+0x10)) = tmp; - - MCI_COMMAND = 0x80202000; - MCI_ARGUMENT = 0; - max = 10; - while(max-- && MCI_COMMAND & MCI_COMMAND_ACTIVE); - - mci_delay(); - - MCI_ARGUMENT = arg; - MCI_COMMAND = val; - - (*(volatile unsigned long *) (SD_BASE+0x00)) |= 0x10; - - max = 1000; - while(max-- && MCI_COMMAND & MCI_COMMAND_ACTIVE); /* wait for cmd completion */ - if(!max) - return false; - - if(flags & MCI_RESP) - { - if(flags & MCI_LONG_RESP) - { - /* store the response in little endian order for the words */ - response[0] = MCI_RESP3; - response[1] = MCI_RESP2; - response[2] = MCI_RESP1; - response[3] = MCI_RESP0; - } - else - response[0] = MCI_RESP0; - } - return true; -} - -static int sd_init_card(void) -{ - unsigned long response; - unsigned long temp_reg[4]; - int max_tries = 100; /* max acmd41 attemps */ - bool sdhc; - int i; - - if(!send_cmd(SD_GO_IDLE_STATE, 0, MCI_NO_RESP, NULL)) - return -1; - - mci_delay(); - - sdhc = false; - if(send_cmd(SD_SEND_IF_COND, 0x1AA, MCI_RESP, &response)) - if((response & 0xFFF) == 0x1AA) - sdhc = true; - - do { - /* some MicroSD cards seems to need more delays, so play safe */ - mci_delay(); - mci_delay(); - mci_delay(); - - /* app_cmd */ - if( !send_cmd(SD_APP_CMD, 0, MCI_RESP, &response) /*|| - !(response & (1<<5))*/ ) - { - return -2; - } - - /* acmd41 */ - if(!send_cmd(SD_APP_OP_COND, (sdhc ? 0x40FF8000 : (1<<23)), - MCI_RESP, &card_info.ocr)) - return -3; - } while(!(card_info.ocr & (1<<31)) && max_tries--); - - if(max_tries < 0) - return -4; - - mci_delay(); - mci_delay(); - mci_delay(); - - /* send CID */ - if(!send_cmd(SD_ALL_SEND_CID, 0, MCI_RESP|MCI_LONG_RESP, card_info.cid)) - return -5; - - /* send RCA */ - if(!send_cmd(SD_SEND_RELATIVE_ADDR, 0, MCI_RESP, &card_info.rca)) - return -6; - - /* send CSD */ - if(!send_cmd(SD_SEND_CSD, card_info.rca, - MCI_RESP|MCI_LONG_RESP, temp_reg)) - return -7; - - for(i=0; i<4; i++) - card_info.csd[3-i] = temp_reg[i]; - - sd_parse_csd(&card_info); - - if(!send_cmd(SD_APP_CMD, 0, MCI_RESP, &response) || - !send_cmd(42, 0, MCI_NO_RESP, NULL)) /* disconnect the 50 KOhm pull-up - resistor on CD/DAT3 */ - return -13; - - if(!send_cmd(SD_APP_CMD, card_info.rca, MCI_NO_RESP, NULL)) - return -10; - - if(!send_cmd(SD_SET_BUS_WIDTH, card_info.rca | 2, MCI_NO_RESP, NULL)) - return -11; - - (*(volatile unsigned long *) (SD_BASE+0x18)) &= ~(0x10001); - (*(volatile unsigned long *) (SD_BASE+0x18)) |= 0x1; - - if(!send_cmd(SD_SELECT_CARD, card_info.rca, MCI_NO_RESP, NULL)) - return -9; - - /* not sent in init_card() by OF */ - if(!send_cmd(SD_SET_BLOCKLEN, card_info.blocksize, MCI_NO_RESP, - NULL)) - return -12; - - card_info.initialized = 1; - - return 0; -} - -static void sd_thread(void) __attribute__((noreturn)); -static void sd_thread(void) -{ - struct queue_event ev; - bool idle_notified = false; - - while (1) - { - queue_wait_w_tmo(&sd_queue, &ev, HZ); - - switch ( ev.id ) - { - case SYS_TIMEOUT: - if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) - { - idle_notified = false; - } - else - { - /* never let a timer wrap confuse us */ - next_yield = current_tick; - - if (!idle_notified) - { - call_storage_idle_notifys(false); - idle_notified = true; - } - } - break; -#if 0 - case SYS_USB_CONNECTED: - usb_acknowledge(SYS_USB_CONNECTED_ACK); - /* Wait until the USB cable is extracted again */ - usb_wait_for_disconnect(&sd_queue); - - break; - case SYS_USB_DISCONNECTED: - usb_acknowledge(SYS_USB_DISCONNECTED_ACK); - break; -#endif - } - } -} - -static void init_controller(void) -{ - int tmp = (*(volatile unsigned long *) (SD_BASE+0x70)); - int shift = 1 + ((tmp << 26) >> 27); - - (*(volatile unsigned long *) (SD_BASE+0x04)) &= ~((1 << shift) -1); - (*(volatile unsigned long *) (SD_BASE+0x04)) = (1 << shift) -1; - - mci_delay(); - - (*(volatile unsigned long *) (SD_BASE+0x00)) |= 1; - int max = 1000; - while(max-- && !(*(volatile unsigned long *) (SD_BASE+0x00)) & 1) - ; - - MCI_CLEAR = 0xffffffff; - MCI_MASK = 0xffffbffe; - - (*(volatile unsigned long *) (SD_BASE+0x00)) |= 0x10; - (*(volatile unsigned long *) (SD_BASE+0x14)) = 0xffffffff; - - (*(volatile unsigned long *) (SD_BASE+0x10)) = (1<sector_size=card_info.blocksize; - info->num_sectors=card_info.numblocks; - info->vendor="Rockbox"; - info->product = "Internal Storage"; - info->revision="0.00"; -} -#endif - -static int sd_wait_for_state(unsigned int state) -{ - unsigned long response; - unsigned int timeout = 100; /* ticks */ - long t = current_tick; - - while (1) - { - long tick; - - if(!send_cmd(SD_SEND_STATUS, card_info.rca, - MCI_RESP, &response)) - return -1; - - if (((response >> 9) & 0xf) == state) - return 0; - - if(TIME_AFTER(current_tick, t + timeout)) - return -10 * ((response >> 9) & 0xf); - - if (TIME_AFTER((tick = current_tick), next_yield)) - { - yield(); - timeout += current_tick - tick; - next_yield = tick + MIN_YIELD_PERIOD; - } - } -} - -static int sd_transfer_sectors(unsigned long start, int count, void* buf, bool write) -{ - int ret = 0; - - if((int)buf & 3) - panicf("unaligned transfer"); - - /* skip SanDisk OF */ - start += 0xf000; - - mutex_lock(&sd_mtx); -#ifndef BOOTLOADER - sd_enable(true); -#endif - - if (card_info.initialized <= 0) - { - ret = sd_init_card(); - if (!(card_info.initialized)) - { - panicf("card not initialised (%d)", ret); - goto sd_transfer_error; - } - } - - last_disk_activity = current_tick; - ret = sd_wait_for_state(SD_TRAN); - if (ret < 0) - { - static const char *st[9] = { - "IDLE", "RDY", "IDENT", "STBY", "TRAN", "DATA", "RCV", "PRG", "DIS" - }; - if(ret <= -10) - panicf("wait for state failed (%s)", st[(-ret / 10) % 9]); - else - panicf("wait for state failed"); - goto sd_transfer_error; - } - - dma_retain(); - - while(count) - { - /* Interrupt handler might set this to true during transfer */ - retry = false; - /* 128 * 512 = 2^16, and doesn't fit in the 16 bits of DATA_LENGTH - * register, so we have to transfer maximum 127 sectors at a time. */ - //unsigned int transfer = (count >= 128) ? 127 : count; /* sectors */ - unsigned int transfer = count; - - const int cmd = - write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK; - - (*(volatile unsigned long *) (SD_BASE+0x00)) |= 2; - while(( *(volatile unsigned long *) (SD_BASE+0x00)) & 2) ; - - //(*(volatile unsigned long *) (SD_BASE+0x1c)) = 512; - (*(volatile unsigned long *) (SD_BASE+0x20)) = transfer * 512; - - (*(volatile unsigned long *) (SD_BASE+0x00)) |= 2; - while(( *(volatile unsigned long *) (SD_BASE+0x00)) & 2) ; - - (*(volatile unsigned long *) (SD_BASE+0x4c)) &= ~0x7fff0fff; - - if(0) - { - (*(volatile unsigned long *) (SD_BASE+0x00)) |= 0x20; - MCI_MASK = 0xBE8C; - (*(volatile unsigned long *) (SD_BASE+0x4c)) |= 0x503f0080; - } - else - { - MCI_MASK = 0xBEB8; - (*(volatile unsigned long *) (SD_BASE+0x4c)) |= 0x3f0030; - } - - if(card_info.ocr & (1<<30) ) /* SDHC */ - ret = send_cmd(cmd, start, MCI_NO_RESP, NULL); - else - ret = send_cmd(cmd, start * SD_BLOCK_SIZE, - MCI_NO_RESP, NULL); - - if (ret < 0) - panicf("transfer multiple blocks failed (%d)", ret); - - if(write) - dma_enable_channel(0, buf, MCI_FIFO, DMA_PERI_SD, - DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL); - else - dma_enable_channel(0, MCI_FIFO, buf, DMA_PERI_SD, - DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8, NULL); - - line = 0; - lcd_clear_display(); - printf("dma ->"); - - wakeup_wait(&transfer_completion_signal, TIMEOUT_BLOCK); - - printf("dma <-"); - int delay = 0x1000000; while(delay--) ; - - if(!retry) - { - buf += transfer * SECTOR_SIZE; - start += transfer; - count -= transfer; - } - - last_disk_activity = current_tick; - - if(!send_cmd(SD_STOP_TRANSMISSION, 0, MCI_NO_RESP, NULL)) - { - ret = -666; - panicf("STOP TRANSMISSION failed"); - goto sd_transfer_error; - } - - ret = sd_wait_for_state(SD_TRAN); - if (ret < 0) - { - panicf(" wait for state TRAN failed (%d)", ret); - goto sd_transfer_error; - } - } - - dma_release(); - -#ifndef BOOTLOADER - sd_enable(false); -#endif - mutex_unlock(&sd_mtx); - return 0; - -sd_transfer_error: - panicf("transfer error : %d",ret); - card_info.initialized = 0; - return ret; -} - -int sd_read_sectors(unsigned long start, int count, void* buf) -{ - return sd_transfer_sectors(start, count, buf, false); -} - -int sd_write_sectors(unsigned long start, int count, const void* buf) -{ -#if defined(BOOTLOADER) /* we don't need write support in bootloader */ - (void) start; - (void) count; - (void) buf; - return -1; -#else - return sd_transfer_sectors(start, count, (void*)buf, true); -#endif -} - -#ifndef BOOTLOADER -void sd_sleep(void) -{ -} - -void sd_spin(void) -{ -} - -void sd_spindown(int seconds) -{ - (void)seconds; -} - -long sd_last_disk_activity(void) -{ - return last_disk_activity; -} - -void sd_enable(bool on) -{ - /* TODO */ - (void)on; - return; -} - -tCardInfo *card_get_info_target(int card_no) -{ - (void)card_no; - return &card_info; -} - -#endif /* BOOTLOADER */ -- cgit v1.2.3