diff --strip-trailing-cr -u -r rockbox/trunk/apps/debug_menu.c rockbox-daily-20090108/apps/debug_menu.c --- rockbox/trunk/apps/debug_menu.c 2009-01-25 12:14:44.000000000 +0200 +++ rockbox-daily-20090108/apps/debug_menu.c 2009-01-25 12:25:43.000000000 +0200 @@ -1446,53 +1446,96 @@ } #endif +extern int sd_write_sectors_mod(int drive, unsigned long start, int count, const void* outbuf); +extern int sd_write_sectors (int drive, unsigned long start, int count, const void* outbuf); +extern int sd_read_sectors (int drive, unsigned long start, int count, void* buf); + +#if 0 /* use IRAM for write buffer */ +#define WR_BUF_SIZE 32768 +long *write_buffer = (long*)0x40018000; +#else /* use DRAM for write buffer */ +#define WR_BUF_SIZE 32768*4 +long write_buffer[WR_BUF_SIZE/4+50]; /* 128kB, 32bit aligned */ +#endif + +long read_buffer[WR_BUF_SIZE/4]; /* 128kB */ +unsigned int num_sect, num_ok, num_bad, time_wr, cid; +extern int wait_loop; + #ifdef HAVE_ADJUSTABLE_CPU_FREQ static bool dbg_cpufreq(void) { char buf[128]; - int line; - int button; + int line, cnt, boost=0; #ifdef HAVE_LCD_BITMAP lcd_setfont(FONT_SYSFIXED); #endif lcd_clear_display(); + /* init write buffer */ + for(line=0; line<(int)WR_BUF_SIZE; line++) + ((char*)write_buffer)[line] = (char)line; + + num_sect = 1; + num_ok = 0; + num_bad = 0; + while(1) { + time_wr = 0; + for(cnt=0; cnt<10; cnt++) + { + time_wr -= USEC_TIMER; + /* move the write_buffer on every write to assure real overwriting */ + sd_write_sectors_mod(cid, 0x50000+cnt*num_sect, num_sect, write_buffer+cnt); + time_wr += USEC_TIMER; + memset(read_buffer, 0, num_sect*512); /* invalidate read_buffer */ + sd_read_sectors (cid, 0x50000+cnt*num_sect, num_sect, read_buffer); + + if(memcmp(write_buffer+cnt, read_buffer, num_sect*512) != 0) + { +/* optionally write the buggy data to disk: + { int fd = open("/sectors.bin", O_WRONLY|O_CREAT|O_TRUNC); + write(fd, read_buffer, num_sect*512); + close(fd); + } */ + num_bad++; + } + else + num_ok++; + } + line = 0; - snprintf(buf, sizeof(buf), "Frequency: %ld", FREQ); - lcd_puts(0, line++, buf); + time_wr = (1000 * num_sect*512*10) / time_wr; // [kByte/sec] - snprintf(buf, sizeof(buf), "boost_counter: %d", get_cpu_boost_counter()); - lcd_puts(0, line++, buf); + snprintf(buf, sizeof(buf), "Frequen: %ld", FREQ); lcd_puts(0, line++, buf); + snprintf(buf, sizeof(buf), "CardType: %s", cid?"ext":"int"); lcd_puts(0, line++, buf); + snprintf(buf, sizeof(buf), "NumSects: %d", num_sect); lcd_puts(0, line++, buf); + snprintf(buf, sizeof(buf), "NumGoods: %d", num_ok); lcd_puts(0, line++, buf); + snprintf(buf, sizeof(buf), "NumBads: %d", num_bad); lcd_puts(0, line++, buf); + snprintf(buf, sizeof(buf), "AvgSpeed: %d [kB/s]", time_wr); lcd_puts(0, line++, buf); + snprintf(buf, sizeof(buf), "Delay %d [loop]", wait_loop);lcd_puts(0, line++, buf); lcd_update(); - button = get_action(CONTEXT_STD,HZ/10); - switch(button) + switch(get_action(CONTEXT_STD,HZ/10)) { - case ACTION_STD_PREV: - cpu_boost(true); - break; - - case ACTION_STD_NEXT: - cpu_boost(false); - break; - - case ACTION_STD_OK: - while (get_cpu_boost_counter() > 0) - cpu_boost(false); - set_cpu_frequency(CPUFREQ_DEFAULT); - break; - - case ACTION_STD_CANCEL: - lcd_setfont(FONT_UI); - return false; + case ACTION_STD_PREV: num_sect--; break; + case ACTION_STD_NEXT: num_sect++; break; + case ACTION_STD_CANCEL: wait_loop--; break; + case ACTION_STD_MENU: wait_loop++; break; + case ACTION_STD_OK: cpu_boost((boost^=1) ? true:false); break; + case ACTION_STD_CONTEXT:cid^=1; break; + case ACTION_STD_QUICKSCREEN: return false; } + if(num_sect == 0) num_sect = 1; + if(wait_loop < 0) wait_loop = 0; } - lcd_setfont(FONT_UI); + + cpu_boost(false); + return false; } #endif /* HAVE_ADJUSTABLE_CPU_FREQ */ diff --strip-trailing-cr -u -r rockbox/trunk/firmware/target/arm/ata-sd-pp.c rockbox-daily-20090108/firmware/target/arm/ata-sd-pp.c --- rockbox/trunk/firmware/target/arm/ata-sd-pp.c 2009-01-25 12:14:50.000000000 +0200 +++ rockbox-daily-20090108/firmware/target/arm/ata-sd-pp.c 2009-01-25 12:22:49.000000000 +0200 @@ -434,6 +434,26 @@ } while (--cnt > 0); /* tail loop is faster */ } +int wait_loop; + +static inline void copy_write_sectors_mod(const unsigned char** buf) +{ + int cnt = FIFO_LEN; + unsigned t1, t2; + + /* Write one chunk of 16 words: t >= 16*8cycles */ + asm volatile ( + "1: \n" + "ldrb %[t1], [%[buf]], #1 \n" /* t1 = *(*buf)++; */ + "ldrb %[t2], [%[buf]], #1 \n" /* t2 = *(*buf)++; */ + "orr %[t1], %[t1], %[t2], lsl #8 \n" /* t1 = t1 | (t2 << 8); */ + "str %[t1], [%[data]] \n" /* DATA_REG = t1; */ + "subs %[cnt], %[cnt], #1 \n" /* cnt = cnt - 1; */ + "bgt 1b \n" /* if(cnt>0) goto 1; */ + : [cnt]"+&r"(cnt), [buf]"+&r"(*buf), [t1]"=&r"(t1), [t2]"=&r"(t2) + : [data]"r"(&DATA_REG) ); +} + static int sd_select_bank(unsigned char bank) { unsigned char card_data[512]; @@ -989,6 +1009,141 @@ } } +int sd_write_sectors_mod(IF_MV2(int drive,) unsigned long start, int count, + const void* outbuf) +{ +/* Write support is not finished yet */ +/* TODO: The standard suggests using ACMD23 prior to writing multiple blocks + to improve performance */ +#ifndef HAVE_MULTIVOLUME + const int drive = 0; +#endif + int ret; + const unsigned char *buf, *buf_end; + int bank; + + mutex_lock(&sd_mtx); + sd_enable(true); + sd_led(true); + +sd_write_retry: + if (drive != 0 && !card_detect_target()) + { + /* no external sd-card inserted */ + ret = -EC_NOCARD; + goto sd_write_error; + } + + sd_select_device(drive); + + if (currcard->initialized < 0) + { + ret = currcard->initialized; + goto sd_write_error; + } + + /* Only switch banks with non-SDHC cards */ + if((currcard->ocr & (1<<30))==0) + { + bank = start / BLOCKS_PER_BANK; + + if (currcard->current_bank != bank) + { + ret = sd_select_bank(bank); + if (ret < 0) + goto sd_write_error; + } + + start -= bank * BLOCKS_PER_BANK; + } + + check_time[EC_WRITE_TIMEOUT] = USEC_TIMER; + + ret = sd_wait_for_state(SD_TRAN, EC_TRAN_WRITE_ENTRY); + if (ret < 0) + goto sd_write_error; + + BLOCK_COUNT_REG = count; + +#ifdef HAVE_HOTSWAP + if(currcard->ocr & (1<<30) ) + { + /* SDHC */ + ret = sd_command(SD_WRITE_MULTIPLE_BLOCK, start, NULL, 0xd); + } + else +#endif + { + ret = sd_command(SD_WRITE_MULTIPLE_BLOCK, start*BLOCK_SIZE, NULL, 0xd); + } + if (ret < 0) + goto sd_write_error; + + buf_end = outbuf + count * currcard->block_size - 2*FIFO_LEN; + + for (buf = outbuf; buf <= buf_end;) + { + if (buf == buf_end) + { + /* Set SD_STATE_REG to SD_PRG for the last buffer fill */ + SD_STATE_REG = SD_PRG; + } + + { int cnt = wait_loop; + + asm volatile ( + "1: \n" + "subs %[cnt], %[cnt], #1 \n" + "bgt 1b \n" + : [cnt]"+&r"(cnt) ); + } + + copy_write_sectors_mod(&buf); /* Copy one chunk of 16 words */ + /* TODO: Switch bank if necessary */ + + /* Wait for the FIFO to empty */ + if(sd_poll_status(FIFO_EMPTY, 0x80000) == 0) + { + ret = -EC_FIFO_WR_EMPTY; + goto sd_write_error; + } + } + + last_disk_activity = current_tick; + + if (!sd_poll_status(DATA_DONE, 0x80000)) + { + ret = -EC_FIFO_WR_DONE; + goto sd_write_error; + } + + ret = sd_command(SD_STOP_TRANSMISSION, 0, NULL, 1); + if (ret < 0) + goto sd_write_error; + + ret = sd_wait_for_state(SD_TRAN, EC_TRAN_WRITE_EXIT); + if (ret < 0) + goto sd_write_error; + + while (1) + { + sd_led(false); + sd_enable(false); + mutex_unlock(&sd_mtx); + + return ret; + +sd_write_error: + if (sd_status[drive].retry < sd_status[drive].retry_max + && ret != -EC_NOCARD) + { + sd_status[drive].retry++; + currcard->initialized = 0; + goto sd_write_retry; + } + } +} + static void sd_thread(void) __attribute__((noreturn)); static void sd_thread(void) {