diff --git a/apps/plugins/plugin.lds b/apps/plugins/plugin.lds index f27733a185..52a5cc32a5 100644 --- a/apps/plugins/plugin.lds +++ b/apps/plugins/plugin.lds @@ -36,6 +36,11 @@ OUTPUT_FORMAT(elf32-sh) #define DRAMORIG 0xc00000 + STUBOFFSET #define IRAMORIG 0x407000 #define IRAMSIZE 0x9000 +#elif CONFIG_CPU == S3C2440 +#define DRAMORIG 0x100 + STUBOFFSET +#define IRAMORIG DRAMORIG +#define IRAMSIZE 4K +#define IRAM DRAM #else #define DRAMORIG 0x09000000 + STUBOFFSET #endif @@ -73,7 +78,7 @@ SECTIONS .text : { *(.text*) -#if defined(CPU_PP) || (CONFIG_CPU==PNX0101) +#ifdef CPU_ARM *(.glue_7) *(.glue_7t) #endif diff --git a/bootloader/gigabeat.c b/bootloader/gigabeat.c index c04042cead..62c31310ae 100644 --- a/bootloader/gigabeat.c +++ b/bootloader/gigabeat.c @@ -17,12 +17,133 @@ #include "panic.h" #include "power.h" #include "file.h" +#include "button-target.h" + +void map_memory(void); + +int line = 0; char version[] = APPSVERSION; -void go_usb_mode(void) { +/* This section allows you to toggle bits of any memory location */ +/* Touchpad to move around the bits. Select to toggle the red bit */ +typedef struct { + unsigned int address; + char *desc; +} memlocation_struct; + +/* Just add any address and descriptions here */ +/* Must finish with 0xFFFFFFFF */ +const memlocation_struct memlocations[] = { +/* Address Description */ +{ 0x56000000, "GPACON" }, +{ 0x56000004, "GPADAT" }, +{ 0x56000010, "GPBCON" }, +{ 0x56000014, "GPBDAT" }, +{ 0x56000020, "GPCCON" }, +{ 0x56000024, "GPCDAT" }, +{ 0x56000030, "GPDCON" }, +{ 0x56000034, "GPDDAT" }, +{ 0x56000040, "GPECON" }, +{ 0x56000044, "GPEDAT" }, +{ 0x56000050, "GPFCON" }, +{ 0x56000054, "GPFDAT" }, +{ 0x56000060, "GPGCON" }, +{ 0x56000064, "GPGDAT" }, +{ 0x56000070, "GPHCON" }, +{ 0x56000074, "GPHDAT" }, +{ 0xFFFFFFFF, 0 } +}; + +void memdump(void) +{ + int i, j; + int current=0, bit=0; + char * bitval; + int data; + char tmp[40]; + + while(1) { + i = 0; + + while(memlocations[i].address != 0xFFFFFFFF) { + + data = *(volatile int *)memlocations[i].address; + + snprintf(tmp, sizeof(tmp), "%s %s 0x%08X", + (i==current) ? "*" : " ", + memlocations[i].desc, + data); + lcd_puts(0, i*2+5, tmp); + + /* print out in binary, current bit in red */ + for (j=31; j>=0; j--) { + if ((bit == j) && (current == i)) + lcd_set_foreground(LCD_RGBPACK(255,0,0)); + lcd_puts((31-j) + ((31-j) / 8), i*2+6, (data & (1 << j)) ? "1" : "0" ); + lcd_set_foreground(LCD_RGBPACK(0,0,0)); + } + + i++; + } + + data = *(volatile int *)memlocations[current].address; + bitval = (data & (1 << bit)) ? "1" : "0"; + snprintf(tmp, sizeof(tmp), "%s bit %ld = %s", memlocations[current].desc, bit, bitval); + lcd_puts(0, (i*2)+7, tmp); + + lcd_update(); + + /* touchpad controls */ + + /* Up */ + if (GPJDAT & 0x01) { + if (current > 0) + current--; + while(GPJDAT & 0x01); + } + + /* Down */ + if (GPJDAT & 0x40) { + if (current < (i-1)) + current++; + while(GPJDAT & 0x40); + } + + /* Left */ + if (GPJDAT & 0x80) { + if (bit < 31) + bit++; + while(GPJDAT & 0x80); + } + + /* Right */ + if (GPJDAT & 0x1000) { + if (bit > 0) + bit--; + while(GPJDAT & 0x1000); + } + + /* Centre - Toggle Bit */ + if (GPJDAT & 0x08) { + data = *(volatile int *)memlocations[current].address; + data = data ^ (1 << bit); + *(volatile int *)memlocations[current].address = data; + while(GPJDAT & 0x08); + } + + /* Bail out if the power button is pressed */ + if (GPGDAT & 1) { + break; + } + } +} + + +static void go_usb_mode(void) { /* Drop into USB mode. This does not check for disconnection. */ + int i; GPBDAT &= 0x7EF; @@ -34,17 +155,160 @@ void go_usb_mode(void) { for (i = 0; i < 10000000; i++) {continue;} GPBCON &= 0x2FFCFF; - GPBDAT |= 1<<5; + GPBDAT |= 1<<5; GPBDAT |= 1<<6; } + +/* Restores a factory kernel/bootloader from a known location */ +/* Restores the FWIMG01.DAT file back in the case of a bootloader failure */ +/* The factory or "good" bootloader must be in /GBSYSTEM/FWIMG/FWIMG01.DAT.ORIG */ +/* Returns non-zero on failure */ +int restore_fwimg01dat(void) +{ + int orig_file = 0, dest_file = 0; + int size = 0, size_read; + char buf[256]; + char lcd_buf[64]; + + orig_file = open("/GBSYSTEM/FWIMG/FWIMG01.DAT.ORIG", O_RDONLY); + if (orig_file < 0) { + /* Couldn't open source file */ + lcd_puts(0, line++, "Couldn't open FWIMG01.DAT.ORIG for reading"); + lcd_update(); + return(1); + } + + lcd_puts(0, line++, "FWIMG01.DAT.ORIG opened for reading"); + lcd_update(); + + dest_file = open("/GBSYSTEM/FWIMG/FWIMG01.DAT", O_RDWR); + if (dest_file < 0) { + /* Couldn't open destination file */ + lcd_puts(0, line++, "Couldn't open FWIMG01.DAT.ORIG for writing"); + lcd_update(); + close(orig_file); + return(2); + } + + lcd_puts(0, line++, "FWIMG01.DAT opened for writing"); + lcd_update(); + + do { + /* Copy in chunks */ + size_read = read(orig_file, buf, sizeof(buf)); + if (size_read != write(dest_file, buf, size_read)) { + close(orig_file); + close(dest_file); + return(3); + } + size += size_read; + + } while (size_read > 0); + + close(orig_file); + close(dest_file); + + snprintf(lcd_buf, sizeof(lcd_buf), "Finished copying %ld bytes from", size); + lcd_puts(0, line++, lcd_buf); + lcd_puts(0, line++, "FWIMG01.DAT.ORIG to FWIMG01.DAT"); + + return(0); +} + + +int load_rockbox(const char* file_name, unsigned char* buf, int buffer_size) +{ + int fd; + int rc; + int len; + char str[256]; + //unsigned long chksum; + //char model[5]; + //unsigned long sum; + //int i; + //char str[80]; + + fd = open("/.rockbox/" BOOTFILE, O_RDONLY); + if(fd < 0) + { + fd = open("/" BOOTFILE, O_RDONLY); + if(fd < 0) + return -1; + } + fd = open(file_name, O_RDONLY); + if(fd < 0) + return -2; + + len = filesize(fd); + + if (len > buffer_size) { + snprintf(str, sizeof(str), "len: %d buf: %d", len, buffer_size); + lcd_puts(0, line++, str); + lcd_update(); + return -6; + } + + /*lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET); + + rc = read(fd, &chksum, 4); + chksum=betoh32(chksum);*/ /* Rockbox checksums are big-endian */ + /*if(rc < 4) + return -2; + + rc = read(fd, model, 4); + if(rc < 4) + return -3; + + model[4] = 0; + + snprintf(str, 80, "Model: %s", model); + lcd_puts(0, line++, str); + snprintf(str, 80, "Checksum: %x", chksum); + lcd_puts(0, line++, str); + lcd_update(); + + lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET); +*/ + + rc = read(fd, buf, len); + if(rc < len) { + snprintf(str, sizeof(str), "len: %d rc: %d", len, rc); + lcd_puts(0, line++, str); + lcd_update(); + return -4; + } + + close(fd); + + /*sum = MODEL_NUMBER; + + for(i = 0;i < len;i++) { + sum += buf[i]; + } + + snprintf(str, 80, "Sum: %x", sum); + lcd_puts(0, line++, str); + lcd_update(); + + if(sum != chksum) + return -5;*/ + + return len; +} + void * main(void) { - int line = 0, i; + int i; char buf[256]; struct partinfo* pinfo; unsigned short* identify_info; - int testfile; + //int testfile; + unsigned char* loadbuffer; + int buffer_size; + bool load_original = false; + int rc; + int(*kernel_entry)(void); lcd_init(); lcd_setfont(FONT_SYSFIXED); @@ -57,7 +321,10 @@ void * main(void) */ lcd_puts(0, line++, "Hold MENU when booting for rescue mode."); + lcd_puts(0, line++, " \"VOL+\" button to restore original kernel"); + lcd_puts(0, line++, " \"A\" button to load original firmware"); lcd_update(); + sleep(1*HZ); /* hold MENU to enter rescue mode */ if (GPGDAT & 2) { @@ -67,12 +334,44 @@ void * main(void) while(1); } + sleep(5*HZ); + + if(GPGDAT & 0x10) { + load_original = true; + lcd_puts(0, line++, "Loading original firmware..."); + lcd_update(); + } + i = ata_init(); i = disk_mount_all(); snprintf(buf, sizeof(buf), "disk_mount_all: %d", i); lcd_puts(0, line++, buf); + /* hold VOL+ to enter rescue mode to copy old image */ + /* needs to be after ata_init and disk_mount_all */ + if (GPGDAT & 4) { + + /* Try to restore the original kernel/bootloader if a copy is found */ + lcd_puts(0, line++, "Restoring FWIMG01.DAT..."); + lcd_update(); + + if (!restore_fwimg01dat()) { + lcd_puts(0, line++, "Restoring FWIMG01.DAT successful."); + } else { + lcd_puts(0, line++, "Restoring FWIMG01.DAT failed."); + } + + lcd_puts(0, line++, "Now power cycle to boot original"); + lcd_update(); + while(1); + } + + /* Memory dump mode if Vol- pressed */ + if (GPGDAT & 8) { + memdump(); + } + identify_info = ata_get_identify(); for (i=0; i < 20; i++) @@ -96,16 +395,68 @@ void * main(void) lcd_puts(0, line++, buf); pinfo = disk_partinfo(0); - snprintf(buf, sizeof(buf), "Partition 0: 0x%02x %ld MB", + snprintf(buf, sizeof(buf), "Partition 0: 0x%02x %ld MB", pinfo->type, pinfo->size / 2048); lcd_puts(0, line++, buf); - - testfile = open("/boottest.txt", O_WRONLY|O_CREAT|O_TRUNC); - write(testfile, "It works!", 9); - close(testfile); - lcd_update(); + /* Load original firmware */ + if(load_original) { + loadbuffer = (unsigned char*)0x30008000; + buffer_size =(unsigned char*)0x31000000 - loadbuffer; + rc = load_rockbox("/rockbox.gigabeat", loadbuffer, buffer_size); + if (rc < 0) { + lcd_puts(0, line++, "failed to load original firmware. Loading rockbox"); + lcd_update(); + sleep(2*HZ); + goto load_rockbox; + } + + snprintf(buf, sizeof(buf), "Loaded: %d", rc); + lcd_puts(0, line++, buf); + lcd_update(); + sleep(2*HZ); + + + (*((int*)0x7000000)) = 333; + rc = *((int*)0x7000000+0x8000000); + snprintf(buf, sizeof(buf), "Bank0 mem test: %d", rc); + lcd_puts(0, line++, buf); + lcd_update(); + sleep(3*HZ); + + lcd_puts(0, line++, "Woops, should not return from firmware!"); + lcd_update(); + goto usb; + } + +load_rockbox: + map_memory(); + lcd_puts(0, line, "Loading Rockbox..."); + lcd_update(); + sleep(HZ*4); + + // TODO: read those values from somwhere + loadbuffer = (unsigned char*) 0x100; + buffer_size = (unsigned char*)0x400000 - loadbuffer; + rc=load_rockbox("/rockbox.gigabeat", loadbuffer, buffer_size); + if (rc < 0) { + snprintf(buf, sizeof(buf), "Rockbox error: %d",rc); + lcd_puts(0, line++, buf); + lcd_update(); + } else { + lcd_puts(0, line++, "Rockbox loaded."); + lcd_update(); + kernel_entry = (void*)0x100; + rc = kernel_entry(); + snprintf(buf, sizeof(buf), "Woops, should not return from firmware: %d", rc); + lcd_puts(0, line++, buf); + lcd_update(); + goto usb; + } + + +usb: /* now wait in USB mode so the bootloader can be updated */ go_usb_mode(); while(1); diff --git a/firmware/SOURCES b/firmware/SOURCES index 6a4f172e47..4f8e531a2e 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -136,6 +136,8 @@ drivers/rtc/rtc_pcf50606.c drivers/rtc/rtc_pcf50605.c #elif (CONFIG_RTC == RTC_E8564) drivers/rtc/rtc_e8564.c +#elif (CONFIG_RTC == RTC_S3C2440) +drivers/rtc/rtc_s3c2440.c #endif /* (CONFIG_RTC == RTC_) */ #endif /* SIMULATOR */ @@ -447,6 +449,12 @@ target/arm/gigabeat/meg-fx/power-meg-fx.c target/arm/gigabeat/meg-fx/sc606-meg-fx.c target/arm/gigabeat/meg-fx/usb-meg-fx.c target/arm/gigabeat/meg-fx/wmcodec-meg-fx.c +target/arm/gigabeat/meg-fx/dma_start.c +target/arm/gigabeat/meg-fx/system-meg-fx.c +target/arm/gigabeat/meg-fx/mmu-meg-fx.c +#ifndef BOOTLOADER +target/arm/gigabeat/meg-fx/pcm-meg-fx.c +#endif #endif /* SIMULATOR */ #endif /* GIGABEAT_F */ diff --git a/firmware/app.lds b/firmware/app.lds index 965d7950af..1053437106 100644 --- a/firmware/app.lds +++ b/firmware/app.lds @@ -45,9 +45,10 @@ INPUT(target/sh/crt0.o) #define IRAMORIG 0x400000 #define IRAMSIZE 0x7000 #elif CONFIG_CPU==S3C2440 -#define DRAMORIG 0x30000000 + STUBOFFSET -#define IRAMORIG 0x40000000 +#define DRAMORIG 0x100 + STUBOFFSET +#define IRAMORIG DRAMORIG #define IRAMSIZE 4K +#define IRAM DRAM #else #define DRAMORIG 0x09000000 + STUBOFFSET #define IRAMORIG 0x0f000000 @@ -63,7 +64,9 @@ INPUT(target/sh/crt0.o) MEMORY { DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE +#if CONFIG_CPU != S3C2440 IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE +#endif #if CONFIG_CPU==PNX0101 IRAM0 : ORIGIN = 0x0, LENGTH = IRAMSIZE #endif @@ -146,6 +149,8 @@ SECTIONS #if CONFIG_CPU==PNX0101 .iram IRAMORIG + SIZEOF(.vectors) : +#elif CONFIG_CPU==S3C2440 + .iram : #else .iram IRAMORIG : #endif @@ -200,7 +205,7 @@ SECTIONS #if defined(CPU_COLDFIRE) .bss ADDR(.data) + SIZEOF(.data) + SIZEOF(.iram): -#elif defined(CPU_ARM) +#elif defined(CPU_ARM) && CONFIG_CPU != S3C2440 .bss ADDR(.data) + SIZEOF(.data) + SIZEOF(.iram) + SIZEOF(.vectors): #else .bss : diff --git a/firmware/boot.lds b/firmware/boot.lds index 6c307bd4de..a8c8947f95 100644 --- a/firmware/boot.lds +++ b/firmware/boot.lds @@ -119,7 +119,7 @@ SECTIONS } #elif (CONFIG_CPU==S3C2440) { - . = DRAMORIG + 0x8000; + . = DRAMORIG + 0x1000000; .text : { *(.init.text) *(.text) diff --git a/firmware/export/config-gigabeat.h b/firmware/export/config-gigabeat.h index ea72c348ea..b458a0eccd 100644 --- a/firmware/export/config-gigabeat.h +++ b/firmware/export/config-gigabeat.h @@ -14,6 +14,12 @@ /* define this if you have a colour LCD */ #define HAVE_LCD_COLOR 1 +/* define this if you have access to the quickscreen */ +#define HAVE_QUICKSCREEN + +/* define this if you have access to the pitchscreen */ +#define HAVE_PITCHSCREEN + /* define this if you would like tagcache to build on this target */ #define HAVE_TAGCACHE @@ -30,14 +36,24 @@ #define CONFIG_CODEC SWCODEC /* define this if you have a real-time clock */ - -#if 0 /* TODO */ #define CONFIG_RTC RTC_S3C2440 -#endif + +/* define this if the unit can be powered or charged via USB */ +#define HAVE_USB_POWER /* Define this for LCD backlight available */ #define CONFIG_BACKLIGHT BL_GIGABEAT /* port controlled PWM */ +#define HAVE_BACKLIGHT_BRIGHTNESS + +/* Main LCD backlight brightness range and defaults */ +#define MIN_BRIGHTNESS_SETTING 0 /* 0.5 mA */ +#define MIN_ACTIVE_BRIGHTNESS_SETTING 16 /* lowest active brightness */ +#define MAX_DIM_BRIGHTNESS_SETTING 15 /* highest 'dimness' */ +#define MAX_BRIGHTNESS_SETTING 63 /* 32 mA */ +#define DEFAULT_BRIGHTNESS_SETTING 39 /* 20 mA */ +#define DEFAULT_DIMNESS_SETTING 9 /* 5 mA */ + /* Define this if you have a software controlled poweroff */ #define HAVE_SW_POWEROFF @@ -54,23 +70,27 @@ #ifndef SIMULATOR +/* The LCD on a Gigabeat is 240x320 - it is portrait */ +#define HAVE_PORTRAIT_LCD + /* Define this if you have a Motorola SCF5249 */ #define CONFIG_CPU S3C2440 /* Define this if you want to use coldfire's i2c interface */ #define CONFIG_I2C I2C_S3C2440 -/* Type of mobile power */ -#define CONFIG_BATTERY BATT_LIPOL1300 -#define BATTERY_CAPACITY_MIN 1300 /* min. capacity selectable */ -#define BATTERY_CAPACITY_MAX 3200 /* max. capacity selectable */ -#define BATTERY_CAPACITY_INC 50 /* capacity increment */ -#define BATTERY_TYPES_COUNT 1 /* only one type */ +/* Type of mobile power - check this out */ +#define CONFIG_BATTERY BATT_LIION830 /* could change this later */ +#define BATTERY_CAPACITY_MIN 750 /* min. capacity selectable */ +#define BATTERY_CAPACITY_MAX 850 /* max. capacity selectable */ +#define BATTERY_CAPACITY_INC 25 /* capacity increment */ +#define BATTERY_TYPES_COUNT 1 /* only one type */ -#define BATTERY_SCALE_FACTOR 6852 /* FIX: this value is picked at random */ +/* ADC[0] is (530) at discharge and 625 at full charge */ +#define BATTERY_SCALE_FACTOR 6450 -/* Hardware controlled charging? FIXME */ -#define CONFIG_CHARGING CHARGING_SIMPLE +/* Hardware controlled charging with monitoring */ +#define CONFIG_CHARGING CHARGING_MONITOR /* define this if the hardware can be powered off while charging */ #define HAVE_POWEROFF_WHILE_CHARGING @@ -82,9 +102,7 @@ #define CPU_FREQ 16934400 /* Define this if you have ATA power-off control */ -#if 0 /* TODO */ #define HAVE_ATA_POWER_OFF -#endif /* Virtual LED (icon) */ #define CONFIG_LED LED_VIRTUAL @@ -99,6 +117,7 @@ #define USB_GIGABEAT_STYLE +#define HAVE_HEADPHONE_DETECTION /* Define this if you have adjustable CPU frequency */ #if 0 /* TODO */ #define HAVE_ADJUSTABLE_CPU_FREQ @@ -107,8 +126,5 @@ #define BOOTFILE_EXT "gigabeat" #define BOOTFILE "rockbox." BOOTFILE_EXT -#if 0 /* TODO */ -#define HAVE_BACKLIGHT_BRIGHTNESS -#endif - + #endif diff --git a/firmware/export/config.h b/firmware/export/config.h index 68a4920d59..e37cc3f782 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -74,6 +74,7 @@ #define BATT_LIPOL1300 1300 /* the type used in iRiver h1x0 models */ #define BATT_LPCS355385 1550 /* iriver h10 20Gb - SKC LPCS355385 */ #define BATT_BP009 820 /* iriver H10 5/6Gb - iriver BP009 */ +#define BATT_LIION830 830 /* Toshiba Gigabeat Fxx and Xxx series MK11-2740 */ /* CONFIG_CHARGING */ #define CHARGING_SIMPLE 1 /* Simple, hardware controlled charging */ diff --git a/firmware/kernel.c b/firmware/kernel.c index 01adfcc57d..75c6604682 100644 --- a/firmware/kernel.c +++ b/firmware/kernel.c @@ -56,7 +56,7 @@ void kernel_init(void) void sleep(int ticks) { #if CONFIG_CPU == S3C2440 && defined(BOOTLOADER) - int counter; + volatile int counter; TCON &= ~(1 << 20); // stop timer 4 // TODO: this constant depends on dividers settings inherited from // firmware. Set them explicitly somwhere. @@ -76,7 +76,7 @@ void sleep(int ticks) void yield(void) { -#if (CONFIG_CPU == S3C2440 || defined(ELIO_TPJ1022) && defined(BOOTLOADER)) +#if ((CONFIG_CPU == S3C2440 || defined(ELIO_TPJ1022)) && defined(BOOTLOADER)) /* Some targets don't like yielding in the bootloader */ #else switch_thread(true, NULL); @@ -560,27 +560,34 @@ void tick_start(unsigned int interval_in_ms) #elif CONFIG_CPU == S3C2440 void tick_start(unsigned int interval_in_ms) { - unsigned long count; + TCON &= ~(1 << 20); // stop timer 4 + // TODO: this constant depends on dividers settings inherited from + // firmware. Set them explicitly somwhere. + TCNTB4 = 12193 * interval_in_ms / 1000; + TCON |= 1 << 21; // set manual bit + TCON &= ~(1 << 21); // reset manual bit + TCON |= 1 << 22; //interval mode + TCON |= (1 << 20); // start timer 4 - /* period = (n + 1) / 128 , n = tick time count (1~127)*/ - count = interval_in_ms / 1000 * 128 - 1; + INTMOD &= ~(1 << 14); // timer 4 to IRQ mode + INTMSK &= ~(1 << 14); // timer 4 unmask interrupts +} - if(count > 127) +void timer4(void) { + int i; + /* Run through the list of tick tasks */ + for(i = 0; i < MAX_NUM_TICK_TASKS; i++) { - panicf("Error! The tick interval is too long (%d ms)\n", - interval_in_ms); - return; + if(tick_funcs[i]) + { + tick_funcs[i](); + } } - /* Disable the tick */ - TICNT &= ~(1<<7); - /* Set the count value */ - TICNT |= count; - /* Start up the ticker */ - TICNT |= (1<<7); + current_tick++; - /* need interrupt handler ??? */ - + /* following needs to be fixed. */ + /*wake_up_thread();*/ } #endif diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index 92a4c3e5c7..2bff437ef0 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c @@ -59,46 +59,9 @@ void pcm_play_pause_unpause(void); /** Functions that require targeted implementation **/ -#ifndef CPU_COLDFIRE +#if !defined(CPU_COLDFIRE) && (CONFIG_CPU != S3C2440) -#if (CONFIG_CPU == S3C2440) - -/* TODO: Implement for Gigabeat - For now, just implement some dummy functions. -*/ -void pcm_init(void) -{ -} - -void pcm_play_dma_start(const void *addr, size_t size) -{ - (void)addr; - (void)size; -} - -void pcm_play_dma_stop(void) -{ -} - -void pcm_play_pause_pause(void) -{ -} - -void pcm_play_pause_unpause(void) -{ -} - -void pcm_set_frequency(unsigned int frequency) -{ - (void)frequency; -} - -size_t pcm_get_bytes_waiting(void) -{ - return 0; -} - -#elif (CONFIG_CPU == PNX0101) +#if (CONFIG_CPU == PNX0101) #define DMA_BUF_SAMPLES 0x100 diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c index c4582a7302..65dd42810e 100644 --- a/firmware/powermgmt.c +++ b/firmware/powermgmt.c @@ -191,6 +191,8 @@ static const unsigned int battery_level_dangerous[BATTERY_TYPES_COUNT] = 105, 115 #elif CONFIG_BATTERY == BATT_LIPOL1300 /* iRiver H1x0: LiPolymer */ 338 +#elif CONFIG_BATTERY == BATT_LIION830 /* Gigabeat F */ + 340 #elif CONFIG_BATTERY == BATT_IAUDIO_X5 /* iAudio X5 */ 354 #elif CONFIG_BATTERY == BATT_LPCS355385 /* iriver H10 20GB: LiPolymer*/ @@ -210,6 +212,8 @@ static const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = 270, 280 #elif CONFIG_BATTERY == BATT_LIPOL1300 /* iRiver Hxxx */ 299 +#elif CONFIG_BATTERY == BATT_LIION830 /* Gigabeat F */ + 338 #elif CONFIG_BATTERY == BATT_IAUDIO_X5 /* iAudio X5 */ 350 #elif CONFIG_BATTERY == BATT_LPCS355385 /* iriver H10 20GB */ @@ -252,6 +256,9 @@ static const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = /* May need recalibration. */ { 93, 108, 114, 118, 121, 125, 128, 132, 136, 142, 158 }, /* alkaline */ { 103, 118, 121, 123, 124, 125, 126, 127, 128, 129, 135 } /* NiMH */ +#elif CONFIG_BATTERY == BATT_LIION830 + /* Toshiba Gigabeat Li Ion 830mAH figured from discharge curve */ + { 342, 358, 361, 368, 371, 374, 377, 381, 387, 390, 397 } #else /* NiMH */ /* original values were taken directly after charging, but it should show 100% after turning off the device for some hours, too */ @@ -263,12 +270,16 @@ static const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = #ifdef CONFIG_CHARGING charger_input_state_type charger_input_state IDATA_ATTR; + /* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */ static const unsigned short percent_to_volt_charge[11] = { #if CONFIG_BATTERY == BATT_LIPOL1300 /* values measured over one full charging cycle */ 354, 386, 393, 398, 400, 402, 404, 408, 413, 418, 423 /* LiPo */ +#elif CONFIG_BATTERY == BATT_LIION830 + /* Toshiba Gigabeat Li Ion 830mAH */ + 347, 363, 366, 373, 376, 379, 382, 386, 393, 403, 411 #elif CONFIG_BATTERY == BATT_LPCS355385 /* iriver H10 20GB */ 399, 403, 406, 408, 410, 412, 415, 418, 422, 426, 431 diff --git a/firmware/system.c b/firmware/system.c index 2ec9ff7a41..2bbcd06378 100644 --- a/firmware/system.c +++ b/firmware/system.c @@ -86,7 +86,15 @@ void cpu_idle_mode(bool on_off) void system_reboot(void) { } -void system_init(void) { +void system_init(void) +{ + /* Turn off un-needed devices */ + + /* Turn off all of the UARTS */ + CLKCON &= ~( (1<<10) | (1<<11) |(1<<12) ); + + /* Turn off AC97 and Camera */ + CLKCON &= ~( (1<<19) | (1<<20) ); } #endif diff --git a/firmware/target/arm/crt0.S b/firmware/target/arm/crt0.S index 82b7c31f92..c552e44320 100644 --- a/firmware/target/arm/crt0.S +++ b/firmware/target/arm/crt0.S @@ -122,7 +122,26 @@ start: /* Code for ARM bootloader targets other than iPod go here */ #if CONFIG_CPU == S3C2440 - bl main + /* get the high part of our execute address */ + ldr r2, =0xffffff00 + and r4, pc, r2 + + /* Copy bootloader to safe area - 0x31000000 */ + mov r5, #0x30000000 + add r5, r5, #0x1000000 + ldr r6, = _dataend + sub r0, r6, r5 /* length of loader */ + add r0, r4, r0 /* r0 points to start of loader */ +1: + cmp r5, r6 + ldrcc r2, [r4], #4 + strcc r2, [r5], #4 + bcc 1b + + ldr pc, =start_loc /* jump to the relocated start_loc: */ + +start_loc: + bl main #endif #else /* BOOTLOADER */ @@ -201,7 +220,10 @@ prefetch_abort_handler: fiq_handler: @ Branch straight to FIQ handler in pcm_playback.c. This also handles the @ the correct return sequence. - ldr pc, =fiq + stmfd sp!, {r0-r7, r12, lr} + bl fiq + ldmfd sp!, {r0-r7, r12, lr} + subs pc, lr, #4 data_abort_handler: sub r0, lr, #8 @@ -210,9 +232,9 @@ data_abort_handler: irq_handler: #ifndef STUB - stmfd sp!, {r0-r3, r12, lr} + stmfd sp!, {r0-r11, r12, lr} bl irq - ldmfd sp!, {r0-r3, r12, lr} + ldmfd sp!, {r0-r11, r12, lr} #endif subs pc, lr, #4 diff --git a/firmware/target/arm/gigabeat/meg-fx/adc-meg-fx.c b/firmware/target/arm/gigabeat/meg-fx/adc-meg-fx.c index 78b9dea5b2..4c448c2e41 100644 --- a/firmware/target/arm/gigabeat/meg-fx/adc-meg-fx.c +++ b/firmware/target/arm/gigabeat/meg-fx/adc-meg-fx.c @@ -18,24 +18,67 @@ ****************************************************************************/ #include "cpu.h" #include "adc-target.h" +#include "kernel.h" -void adc_init(void) { - /* Turn on the ADC PCLK */ - CLKCON |= (1<<15); - /* Set channel 0, normal mode, disable "start by read" */ - ADCCON &= ~(0x3F); +static unsigned short adc_readings[NUM_ADC_CHANNELS]; - /* No start delay. Use nromal conversion mode. */ - ADCDLY |= 0x1; +/* prototypes */ +static unsigned short __adc_read(int channel); +static void adc_tick(void); - /* Set and enable the prescaler */ - ADCCON = (ADCCON & ~(0xff<<6)) | (0x19<<6); - ADCCON |= (1<<14); + + +void adc_init(void) +{ + int i; + + /* Turn on the ADC PCLK */ + CLKCON |= (1<<15); + + /* Set channel 0, normal mode, disable "start by read" */ + ADCCON &= ~(0x3F); + + /* No start delay. Use normal conversion mode. */ + ADCDLY = 0x1; + + /* Set and enable the prescaler */ + ADCCON = (ADCCON & ~(0xff<<6)) | (0x19<<6); + ADCCON |= (1<<14); + + /* prefill the adc channels */ + for (i = 0; i < NUM_ADC_CHANNELS; i++) + { + adc_readings[i] = __adc_read(i); + } + + /* start at zero so when the tick starts it is at zero */ + adc_readings[0] = __adc_read(0); + + /* attach the adc reading to the tick */ + tick_add_task(adc_tick); + + } -unsigned short adc_read(int channel) { + + +/* Called to get the recent ADC reading */ +inline unsigned short adc_read(int channel) +{ + return adc_readings[channel]; +} + + + +/** + * Read the ADC by polling + * @param channel The ADC channel to read + * @return 10bit reading from ADC channel or ADC_READ_ERROR if timeout + */ +static unsigned short __adc_read(int channel) +{ int i; /* Set the channel */ @@ -45,34 +88,57 @@ unsigned short adc_read(int channel) { ADCCON |= 0x1; /* Wait for a low Enable_start */ - i = 20000; - while(i > 0) { - if(ADCCON & 0x1) { - i--; - } - else { + for (i = 20000;;) { + if(0 == (ADCCON & 0x1)) { break; } - } - if(i == 0) { - /* Ran out of time */ - return(0); + else { + i--; + if (0 == i) { + /* Ran out of time */ + return ADC_READ_ERROR; + } + } } /* Wait for high End_of_Conversion */ - i = 20000; - while(i > 0) { - if(ADCCON & (1<<15)) { + for(i = 20000;;) { + if(ADCCON & (1<<15)) { break; } else { i--; + if(0 == i) { + /* Ran out of time */ + return ADC_READ_ERROR; + } } } - if(i == 0) { - /* Ran out of time */ - return(0); - } - return(ADCDAT0 & 0x3ff); + return (ADCDAT0 & 0x3ff); } + + + +/* add this to the tick so that the ADC converts are done in the background */ +static void adc_tick(void) +{ + static unsigned channel; + + /* Check if the End Of Conversion is set */ + if (ADCCON & (1<<15)) + { + adc_readings[channel] = (ADCDAT0 & 0x3FF); + if (++channel >= NUM_ADC_CHANNELS) + { + channel = 0; + } + + /* setup the next conversion and start it*/ + ADCCON = (ADCCON & ~(0x7<<3)) | (channel<<3) | 0x01; + } +} + + + + diff --git a/firmware/target/arm/gigabeat/meg-fx/adc-target.h b/firmware/target/arm/gigabeat/meg-fx/adc-target.h index 8ea02b33e6..8d2beaf320 100644 --- a/firmware/target/arm/gigabeat/meg-fx/adc-target.h +++ b/firmware/target/arm/gigabeat/meg-fx/adc-target.h @@ -19,12 +19,19 @@ #ifndef _ADC_TARGET_H_ #define _ADC_TARGET_H_ -#define NUM_ADC_CHANNELS 4 +/* only two channels used by the Gigabeat */ +#define NUM_ADC_CHANNELS 2 #define ADC_BATTERY 0 -#define ADC_UNKNOWN_2 1 +#define ADC_HPREMOTE 1 #define ADC_UNKNOWN_3 2 #define ADC_UNKNOWN_4 3 +#define ADC_UNKNOWN_5 4 +#define ADC_UNKNOWN_6 5 +#define ADC_UNKNOWN_7 6 +#define ADC_UNKNOWN_8 7 + #define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */ +#define ADC_READ_ERROR 0xFFFF #endif diff --git a/firmware/target/arm/gigabeat/meg-fx/ata-meg-fx.c b/firmware/target/arm/gigabeat/meg-fx/ata-meg-fx.c index 58fec1e6a3..ec0f3fe6ca 100644 --- a/firmware/target/arm/gigabeat/meg-fx/ata-meg-fx.c +++ b/firmware/target/arm/gigabeat/meg-fx/ata-meg-fx.c @@ -26,11 +26,18 @@ void ata_reset(void) { + GPGDAT &= ~(1 << 10); + sleep(1); /* > 25us */ + GPGDAT |= (1 << 10); + sleep(1); /* > 2ms */ } void ata_enable(bool on) { - (void)on; + if(on) + GPGDAT &= ~(1 << 12); + else + GPGDAT |= (1 << 12); } bool ata_is_coldstart(void) diff --git a/firmware/target/arm/gigabeat/meg-fx/ata-target.h b/firmware/target/arm/gigabeat/meg-fx/ata-target.h index 1d49a1b874..95b66ab1bd 100644 --- a/firmware/target/arm/gigabeat/meg-fx/ata-target.h +++ b/firmware/target/arm/gigabeat/meg-fx/ata-target.h @@ -20,6 +20,8 @@ #define ATA_TARGET_H /* Plain C read & write loops */ +#define PREFER_C_READING +#define PREFER_C_WRITING #define ATA_IOBASE 0x18000000 #define ATA_DATA (*((volatile unsigned short*)(ATA_IOBASE))) diff --git a/firmware/target/arm/gigabeat/meg-fx/backlight-meg-fx.c b/firmware/target/arm/gigabeat/meg-fx/backlight-meg-fx.c index 9abf34ccf9..ba98dba7d1 100644 --- a/firmware/target/arm/gigabeat/meg-fx/backlight-meg-fx.c +++ b/firmware/target/arm/gigabeat/meg-fx/backlight-meg-fx.c @@ -19,11 +19,16 @@ #include "config.h" #include "cpu.h" #include "system.h" +#include "backlight-target.h" #include "backlight.h" #include "lcd.h" #include "sc606-meg-fx.h" -int confval = SC606_LOW_FREQ; +static int confval = SC606_LOW_FREQ; + +void __backlight_init(void) +{ +} void __backlight_on(void) { diff --git a/firmware/target/arm/gigabeat/meg-fx/backlight-target.h b/firmware/target/arm/gigabeat/meg-fx/backlight-target.h index 3204293131..e72e863ebc 100644 --- a/firmware/target/arm/gigabeat/meg-fx/backlight-target.h +++ b/firmware/target/arm/gigabeat/meg-fx/backlight-target.h @@ -19,6 +19,7 @@ #ifndef BACKLIGHT_TARGET_H #define BACKLIGHT_TARGET_H +void __backlight_init(void); void __backlight_on(void); void __backlight_off(void); void __backlight_set_brightness(int val); diff --git a/firmware/target/arm/gigabeat/meg-fx/button-meg-fx.c b/firmware/target/arm/gigabeat/meg-fx/button-meg-fx.c index 88a1b4de09..210febb7db 100644 --- a/firmware/target/arm/gigabeat/meg-fx/button-meg-fx.c +++ b/firmware/target/arm/gigabeat/meg-fx/button-meg-fx.c @@ -27,58 +27,127 @@ #include "adc.h" #include "system.h" +static bool headphones_detect; + +static int const remote_buttons[] = +{ + BUTTON_NONE, /* Headphones connected - remote disconnected */ + BUTTON_SELECT, + BUTTON_MENU, /* could be changed to BUTTON_A */ + BUTTON_LEFT, + BUTTON_RIGHT, + BUTTON_UP, /* could be changed to BUTTON_VOL_UP */ + BUTTON_DOWN, /* could be changed to BUTTON_VOL_DOWN */ + BUTTON_NONE, /* Remote control attached - no buttons pressed */ + BUTTON_NONE, /* Nothing in the headphone socket */ +}; + + + + + void button_init_device(void) { /* Power, Remote Play & Hold switch */ } -bool button_hold(void) + + +inline bool button_hold(void) { return (GPGDAT & (1 << 15)); } + + int button_read_device(void) { - int btn = BUTTON_NONE; - int touchpad = GPJDAT; - int buttons = GPGDAT; + int btn; + int touchpad; + int buttons; + static int lastbutton; + unsigned short remote_adc; - /* Check for hold first */ - if (buttons & (1 << 15)) - return btn; + /* Check for hold first - exit if asserted with no button pressed */ + if (button_hold()) + return BUTTON_NONE; - /* the side buttons */ - if (buttons & (1 << 0)) - btn |= BUTTON_POWER; + /* See header for ADC values when remote control buttons are pressed */ + /* Only one button can be sensed at a time on the remote. */ + /* Need to filter the remote button because the ADC is so fast */ + remote_adc = adc_read(ADC_HPREMOTE); + btn = remote_buttons[(remote_adc + 64) / 128]; + if (btn != lastbutton) + { + /* if the buttons dont agree twice in a row, then its none */ + lastbutton = btn; + btn = BUTTON_NONE; + } + + /* + * Code can be added that overrides the side buttons when the remote is + * plugged in: Check for remote_adc > 64 && remote_adc < 930 then skip + * reading the side and touch volume buttons, right, left, up, down, etc. + * but keep reading the Power and 'A'. + * For now, the buttons from remote and side and touch are used together. + */ - if (buttons & (1 << 1)) - btn |= BUTTON_MENU; + + /* the side buttons - Check before doing all of the work on each bit */ + buttons = GPGDAT & 0x1F; + if (buttons) + { + if (buttons & (1 << 0)) + btn |= BUTTON_POWER; - if (buttons & (1 << 2)) - btn |= BUTTON_VOL_UP; + if (buttons & (1 << 1)) + btn |= BUTTON_MENU; - if (buttons & (1 << 3)) - btn |= BUTTON_VOL_DOWN; + if (buttons & (1 << 2)) + btn |= BUTTON_VOL_UP; - if (buttons & (1 << 4)) - btn |= BUTTON_A; + if (buttons & (1 << 3)) + btn |= BUTTON_VOL_DOWN; + if (buttons & (1 << 4)) + btn |= BUTTON_A; + } + /* the touchpad */ - if (touchpad & (1 << 0)) - btn |= BUTTON_UP; + touchpad = GPJDAT & 0x10C9; + if (touchpad) + { + if (touchpad & (1 << 0)) + btn |= BUTTON_UP; - if (touchpad & (1 << 12)) - btn |= BUTTON_RIGHT; + if (touchpad & (1 << 12)) + btn |= BUTTON_RIGHT; - if (touchpad & (1 << 6)) - btn |= BUTTON_DOWN; + if (touchpad & (1 << 6)) + btn |= BUTTON_DOWN; - if (touchpad & (1 << 7)) - btn |= BUTTON_LEFT; - - if (touchpad & (1 << 3)) - btn |= BUTTON_SELECT; + if (touchpad & (1 << 7)) + btn |= BUTTON_LEFT; + if (touchpad & (1 << 3)) + btn |= BUTTON_SELECT; + } + return btn; } + + +bool headphones_inserted(void) +{ + unsigned short remote_adc = adc_read(ADC_HPREMOTE); + if (remote_adc != ADC_READ_ERROR) + { + /* If there is nothing in the headphone socket, the ADC reads high */ + if (remote_adc < 940) + headphones_detect = true; + else + headphones_detect = false; + } + return headphones_detect; +} diff --git a/firmware/target/arm/gigabeat/meg-fx/button-target.h b/firmware/target/arm/gigabeat/meg-fx/button-target.h index 95fb72e601..ab68e8050f 100644 --- a/firmware/target/arm/gigabeat/meg-fx/button-target.h +++ b/firmware/target/arm/gigabeat/meg-fx/button-target.h @@ -45,6 +45,37 @@ int button_read_device(void); #define BUTTON_A 0x00000200 +/* Toshiba Gigabeat specific remote button ADC values */ +/* The remote control uses ADC 1 to emulate button pushes + Reading (approx) Button HP plugged in? Remote plugged in? + 0 N/A Yes No + 125 Play/Pause Cant tell Yes + 241 Speaker+ Cant tell Yes + 369 Rewind Cant tell Yes + 492 Fast Fwd Cant tell Yes + 616 Vol + Cant tell Yes + 742 Vol - Cant tell Yes + 864 None Cant tell Yes + 1023 N/A No No +*/ + +/* + Notes: + + Buttons on the remote are translated into equivalent button presses just + as if you were pressing them on the Gigabeat itself. + + We cannot tell if the hold is asserted on the remote. The Hold function on + the remote is to block the output of the buttons changing. + + Only one button can be sensed at a time. If another is pressed, the button + with the lowest reading is dominant. So, if Rewind and Vol + are pressed + at the same time, Rewind value is the one that is read. +*/ + + + + #define BUTTON_MAIN (BUTTON_POWER|BUTTON_MENU|BUTTON_LEFT|BUTTON_RIGHT\ |BUTTON_UP|BUTTON_DOWN|BUTTON_VOL_UP|BUTTON_VOL_DOWN\ |BUTTON_SELECT|BUTTON_A) diff --git a/firmware/target/arm/gigabeat/meg-fx/dma_start.c b/firmware/target/arm/gigabeat/meg-fx/dma_start.c new file mode 100644 index 0000000000..c1ab6c15cb --- /dev/null +++ b/firmware/target/arm/gigabeat/meg-fx/dma_start.c @@ -0,0 +1,8 @@ +#include + +void dma_start(const void* addr, size_t size) { + (void) addr; + (void) size; + //TODO: +} + diff --git a/firmware/target/arm/gigabeat/meg-fx/kernel-meg-fx.c b/firmware/target/arm/gigabeat/meg-fx/kernel-meg-fx.c new file mode 100644 index 0000000000..9df90a2344 --- /dev/null +++ b/firmware/target/arm/gigabeat/meg-fx/kernel-meg-fx.c @@ -0,0 +1,25 @@ +#include "kernel.h" +#include "thread.h" + +#include +#include "lcd.h" + +extern void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); + +void timer4(void) { + int i; + /* Run through the list of tick tasks */ + for(i = 0; i < MAX_NUM_TICK_TASKS; i++) + { + if(tick_funcs[i]) + { + tick_funcs[i](); + } + } + + current_tick++; + + /* following needs to be fixed. */ + /*wake_up_thread();*/ +} + diff --git a/firmware/target/arm/gigabeat/meg-fx/lcd-meg-fx.c b/firmware/target/arm/gigabeat/meg-fx/lcd-meg-fx.c index f193f9806d..df5be43551 100644 --- a/firmware/target/arm/gigabeat/meg-fx/lcd-meg-fx.c +++ b/firmware/target/arm/gigabeat/meg-fx/lcd-meg-fx.c @@ -1,27 +1,56 @@ #include "config.h" +#include #include "cpu.h" #include "lcd.h" #include "kernel.h" #include "system.h" -#include "string.h" void lcd_init_device(void); void lcd_update_rec(int, int, int, int); void lcd_update(void); +bool usedmablit = false; + /* LCD init */ void lcd_init_device(void) { + /* Switch from 555I mode to 565 mode */ + LCDCON5 |= 1 << 11; + } /* Update a fraction of the display. */ void lcd_update_rect(int x, int y, int width, int height) { (void)x; - (void)y; (void)width; - (void)height; - memcpy(FRAME, &lcd_framebuffer, sizeof(lcd_framebuffer)); + + if (usedmablit) + { + /* Spin waiting for DMA to become available */ + //while (DSTAT0 & (1<<20)) ; + if (DSTAT0 & (1<<20)) return; + + /* set DMA dest */ + DIDST0 = (int) FRAME + y * sizeof(fb_data) * LCD_WIDTH; + + /* FRAME on AHB buf, increment */ + DIDSTC0 = 0; + DCON0 = (((1<<30) | (1<<28) | (1<<27) | (1<<22) | (2<<20)) | ((height * sizeof(fb_data) * LCD_WIDTH) >> 4)); + + /* set DMA source and options */ + DISRC0 = (int) &lcd_framebuffer + (y * sizeof(fb_data) * LCD_WIDTH) + 0x30000000; + DISRCC0 = 0x00; /* memory is on AHB bus, increment addresses */ + + /* Activate the channel */ + DMASKTRIG0 = 0x2; + /* Start DMA */ + DMASKTRIG0 |= 0x1; + } + else + { + memcpy((void*)FRAME, &lcd_framebuffer, sizeof(lcd_framebuffer)); + } } /* Update the display. @@ -44,6 +73,138 @@ void lcd_update(void) #define ROUNDOFFS (127*257) +/* Performance function to blit a YUV bitmap directly to the LCD */ +/* For the Gigabeat - show it rotated */ +/* So the LCD_WIDTH is now the height */ +void lcd_yuv_blit(unsigned char * const src[3], + int src_x, int src_y, int stride, + int x, int y, int width, int height) +{ + width = (width + 1) & ~1; + fb_data *dst = (fb_data*)FRAME + x * LCD_WIDTH + (LCD_WIDTH - y) - 1; + fb_data *dst_last = dst - (height - 1); + + for (;;) + { + fb_data *dst_row = dst; + int count = width; + const unsigned char *ysrc = src[0] + stride * src_y + src_x; + int y, u, v; + int red, green, blue; + unsigned rbits, gbits, bbits; + + /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ + const unsigned char *usrc = src[1] + (stride/CSUB_X) * (src_y/CSUB_Y) + + (src_x/CSUB_X); + const unsigned char *vsrc = src[2] + (stride/CSUB_X) * (src_y/CSUB_Y) + + (src_x/CSUB_X); + int xphase = src_x % CSUB_X; + int rc, gc, bc; + + u = *usrc++ - 128; + v = *vsrc++ - 128; + rc = RVFAC * v + ROUNDOFFS; + gc = GVFAC * v + GUFAC * u + ROUNDOFFS; + bc = BUFAC * u + ROUNDOFFS; + + do + { + y = *ysrc++; + red = RYFAC * y + rc; + green = GYFAC * y + gc; + blue = BYFAC * y + bc; + + if ((unsigned)red > (RYFAC*255+ROUNDOFFS)) + { + if (red < 0) + red = 0; + else + red = (RYFAC*255+ROUNDOFFS); + } + if ((unsigned)green > (GYFAC*255+ROUNDOFFS)) + { + if (green < 0) + green = 0; + else + green = (GYFAC*255+ROUNDOFFS); + } + if ((unsigned)blue > (BYFAC*255+ROUNDOFFS)) + { + if (blue < 0) + blue = 0; + else + blue = (BYFAC*255+ROUNDOFFS); + } + rbits = ((unsigned)red) >> 16 ; + gbits = ((unsigned)green) >> 16 ; + bbits = ((unsigned)blue) >> 16 ; + + *dst_row = (rbits << 11) | (gbits << 5) | bbits; + + /* next pixel - since rotated, add WIDTH */ + dst_row += LCD_WIDTH; + + if (++xphase >= CSUB_X) + { + u = *usrc++ - 128; + v = *vsrc++ - 128; + rc = RVFAC * v + ROUNDOFFS; + gc = GVFAC * v + GUFAC * u + ROUNDOFFS; + bc = BUFAC * u + ROUNDOFFS; + xphase = 0; + } + } + while (--count); + + if (dst == dst_last) break; + + dst--; + src_y++; + } +} + + + +void lcd_set_contrast(int val) { + (void) val; + // TODO: +} + +void lcd_set_invert_display(bool yesno) { + (void) yesno; + // TODO: +} + +void lcd_blit(const fb_data* data, int bx, int y, int bwidth, + int height, int stride) +{ + (void) data; + (void) bx; + (void) y; + (void) bwidth; + (void) height; + (void) stride; + //TODO: +} + +void lcd_set_flip(bool yesno) { + (void) yesno; + // TODO: +} + + + + + + + + + + + + + +#if 0 /* Performance function to blit a YUV bitmap directly to the LCD */ void lcd_yuv_blit(unsigned char * const src[3], int src_x, int src_y, int stride, @@ -129,3 +290,7 @@ void lcd_yuv_blit(unsigned char * const src[3], } while (dst < dst_end); } +#endif + + + diff --git a/firmware/target/arm/gigabeat/meg-fx/mmu-meg-fx.c b/firmware/target/arm/gigabeat/meg-fx/mmu-meg-fx.c new file mode 100644 index 0000000000..05b206c8ea --- /dev/null +++ b/firmware/target/arm/gigabeat/meg-fx/mmu-meg-fx.c @@ -0,0 +1,84 @@ +#include +#include "s3c2440.h" + +void map_memory(void); +static void enable_mmu(void); +static void set_ttb(void); +static void set_page_tables(void); +static void map_section(unsigned int pa, unsigned int va, int mb, int cache_flags); + +#define SECTION_ADDRESS_MASK (-1 << 20) +#define CACHE_ALL (1 << 3 | 1 << 2 ) +#define CACHE_NONE 0 +#define BUFFERED (1 << 2) +#define MB (1 << 20) + +void map_memory(void) { + set_ttb(); + set_page_tables(); + enable_mmu(); +} + +unsigned int* ttb_base; +const int ttb_size = 4096; + +void set_ttb() { + int i; + int* ttbPtr; + int domain_access; + + /* must be 16Kb (0x4000) aligned */ + ttb_base = (int*)0x31F00000; + for (i=0; i> 20; /* sections are 1Mb size */ + ttbPtr = ttb_base + section_no; + pa &= SECTION_ADDRESS_MASK; /* align to 1Mb */ + for(i=0; i ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Michael Sevakis + * + * 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. + * + ****************************************************************************/ +#include "system.h" +#include "kernel.h" +#include "logf.h" +#include "audio.h" +#include "wm8975.h" +#include "file.h" + +static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ + +#define FIFO_COUNT ((IISFCON >> 6) & 0x01F) + +/* number of bytes in FIFO */ +#define IIS_FIFO_SIZE 64 + +/* Setup for the DMA controller */ +#define DMA_CONTROL_SETUP ((1<<31) | (1<<29) | (1<<23) | (1<<22) | (1<<20)) + +unsigned short * p; +size_t p_size; + + + +/* DMA count has hit zero - no more data */ +/* Get more data from the callback and top off the FIFO */ +//void fiq(void) __attribute__ ((interrupt ("naked"))); +void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); +void fiq(void) +{ + /* clear any pending interrupt */ + SRCPND = (1<<19); + + /* Buffer empty. Try to get more. */ + if (pcm_callback_for_more) + { + pcm_callback_for_more((unsigned char**)&p, &p_size); + } + else + { + /* callback func is missing? */ + pcm_play_dma_stop(); + return; + } + + if (p_size) + { + /* set the new DMA values */ + DCON2 = DMA_CONTROL_SETUP | (p_size >> 1); + DISRC2 = (int)p + 0x30000000; + + /* Re-Activate the channel */ + DMASKTRIG2 = 0x2; + } + else + { + /* No more DMA to do */ + pcm_play_dma_stop(); + } + +} + + + +void pcm_init(void) +{ + pcm_playing = false; + pcm_paused = false; + pcm_callback_for_more = NULL; + + audiohw_init(); + audiohw_enable_output(true); + audiohw_mute(true); + + /* cannot use the WM8975 defaults since our clock is not the same */ + /* the input master clock is 16.9344MHz - we can divide exact for that */ + audiohw_set_sample_rate( (0<<6) | (0x11 << 1) | (0<<0)); + + /* init GPIO */ + GPCCON = (GPCCON & ~(3<<14)) | (1<<14); + GPCDAT |= 1<<7; + GPECON |= 0x2aa; + + /* Do no service DMA0 requests, yet */ + /* clear any pending int and mask it */ + INTMSK |= (1<<19); /* mask the interrupt */ + SRCPND = (1<<19); /* clear any pending interrupts */ + INTMOD |= (1<<19); /* connect to FIQ */ + +} + + + +void pcm_play_dma_start(const void *addr, size_t size) +{ + //FIXME + //return; + + int i; + + /* sanity check: bad pointer or too small file */ + if ((NULL == addr) || (size & ~1) <= IIS_FIFO_SIZE) return; + + p = (unsigned short *)addr; + p_size = size; + + + /* Enable the IIS clock */ + CLKCON |= (1<<17); + + /* IIS interface setup and set to idle */ + IISCON = (1<<5) | (1<<3); + + /* slave, transmit mode, 16 bit samples - 384fs - use 16.9344Mhz */ + IISMOD = (1<<9) | (1<<8) | (2<<6) | (1<<3) | (1<<2); + + /* connect DMA to the FIFO and enable the FIFO */ + IISFCON = (1<<15) | (1<<13); + + /* prefill the FIFO with half words */ + for (i=0; i < IIS_FIFO_SIZE; i+=2) + { + IISFIFO = *p++; + p_size -= 2; + } + + /* set DMA dest */ + DIDST2 = (int)&IISFIFO; + + /* IIS is on the APB bus, INT when TC reaches 0, fixed dest addr */ + DIDSTC2 = 0x03; + + /* How many transfers to make - we transfer half-word at a time = 2 bytes */ + /* DMA control: CURR_TC int, single service mode, I2SSDO int, HW trig */ + /* no auto-reload, half-word (16bit) */ + DCON2 = DMA_CONTROL_SETUP | (p_size / 2); + + /* set DMA source and options */ + DISRC2 = (int)p + 0x30000000; + DISRCC2 = 0x00; /* memory is on AHB bus, increment addresses */ + + /* clear pending DMA interrupt */ + SRCPND = 1<<19; + + enable_fiq(fiq); + + /* unmask the DMA interrupt */ + INTMSK &= ~(1<<19); + + /* Activate the channel */ + DMASKTRIG2 = 0x2; + + /* turn off the idle */ + IISCON &= ~(1<<3); + + pcm_playing = true; + + /* start the IIS */ + IISCON |= (1<<0); + +} + + + +/* Disconnect the DMA and wait for the FIFO to clear */ +void pcm_play_dma_stop(void) +{ + pcm_playing = false; + + /* mask the DMA interrupt */ + INTMSK |= (1<<19); + + /* De-Activate the channel */ + DMASKTRIG2 = 0x4; + + /* idle the IIS transmit */ + IISCON |= (1<<3); + + /* stop the IIS interface */ + IISCON &= ~(1<<0); + + /* Disconnect the IIS IIS clock */ + CLKCON &= ~(1<<17); + + + disable_fiq(); + +} + + + +void pcm_play_pause_pause(void) +{ + /* idle */ + IISCON |= (1<<3); +} + + + +void pcm_play_pause_unpause(void) +{ + /* no idle */ + IISCON &= ~(1<<3); +} + + + +void pcm_set_frequency(unsigned int frequency) +{ + int sr_ctrl; + + switch(frequency) + { + case SAMPR_11: + sr_ctrl = 0x19 << 1; + break; + case SAMPR_22: + sr_ctrl = 0x1B << 1; + break; + default: + case SAMPR_44: + sr_ctrl = 0x11 << 1; + break; + case SAMPR_88: + sr_ctrl = 0x1F << 1; + break; + } + audiohw_set_sample_rate(sr_ctrl); + pcm_freq = frequency; +} + + + +size_t pcm_get_bytes_waiting(void) +{ + return (DSTAT2 & 0xFFFFF) * 2; +} + + + +/* dummy functions for those not actually supporting all this yet */ +void pcm_apply_settings(bool reset) +{ + (void)reset; +} + +void pcm_set_monitor(int monitor) +{ + (void)monitor; +} +/** **/ + +void pcm_mute(bool mute) +{ + audiohw_mute(mute); + if (mute) + sleep(HZ/16); +} + +/* + * This function goes directly into the DMA buffer to calculate the left and + * right peak values. To avoid missing peaks it tries to look forward two full + * peek periods (2/HZ sec, 100% overlap), although it's always possible that + * the entire period will not be visible. To reduce CPU load it only looks at + * every third sample, and this can be reduced even further if needed (even + * every tenth sample would still be pretty accurate). + */ + +/* Check for a peak every PEAK_STRIDE samples */ +#define PEAK_STRIDE 3 +/* Up to 1/50th of a second of audio for peak calculation */ +/* This should use NATIVE_FREQUENCY, or eventually an adjustable freq. value */ +#define PEAK_SAMPLES (44100/50) +void pcm_calculate_peaks(int *left, int *right) +{ + short *addr; + short *end; + { + size_t samples = p_size / 4; + addr = p; + + if (samples > PEAK_SAMPLES) + samples = PEAK_SAMPLES - (PEAK_STRIDE - 1); + else + samples -= MIN(PEAK_STRIDE - 1, samples); + + end = &addr[samples * 2]; + } + + if (left && right) { + int left_peak = 0, right_peak = 0; + + while (addr < end) { + int value; + if ((value = addr [0]) > left_peak) + left_peak = value; + else if (-value > left_peak) + left_peak = -value; + + if ((value = addr [PEAK_STRIDE | 1]) > right_peak) + right_peak = value; + else if (-value > right_peak) + right_peak = -value; + + addr = &addr[PEAK_STRIDE * 2]; + } + + *left = left_peak; + *right = right_peak; + } + else if (left || right) { + int peak_value = 0, value; + + if (right) + addr += (PEAK_STRIDE | 1); + + while (addr < end) { + if ((value = addr [0]) > peak_value) + peak_value = value; + else if (-value > peak_value) + peak_value = -value; + + addr += PEAK_STRIDE * 2; + } + + if (left) + *left = peak_value; + else + *right = peak_value; + } +} diff --git a/firmware/target/arm/gigabeat/meg-fx/power-meg-fx.c b/firmware/target/arm/gigabeat/meg-fx/power-meg-fx.c index 688b44eaa6..eb2ffb5238 100644 --- a/firmware/target/arm/gigabeat/meg-fx/power-meg-fx.c +++ b/firmware/target/arm/gigabeat/meg-fx/power-meg-fx.c @@ -23,6 +23,8 @@ #include "system.h" #include "power.h" #include "pcf50606.h" +#include "backlight.h" +#include "backlight-target.h" #ifndef SIMULATOR @@ -33,21 +35,34 @@ void power_init(void) bool charger_inserted(void) { - return !(GPFDAT & (1 << 4)); + return (GPFDAT & (1 << 4)) ? false : true; +} + +/* Returns true if the unit is charging the batteries. */ +bool charging_state(void) { + return (GPGDAT & (1 << 8)) ? false : true; } void ide_power_enable(bool on) { - (void)on; + if (on) + GPGDAT |= (1 << 11); + else + GPGDAT &= ~(1 << 11); } bool ide_powered(void) { - return true; + return (GPGDAT & (1 << 11)) != 0; } void power_off(void) { + /* turn off backlight and wait for 1 second */ + __backlight_off(); + sleep(HZ/2); + /* set SLEEP bit to on in CLKCON to turn off */ + CLKCON |=(1<<3); } #else /* SIMULATOR */ diff --git a/firmware/target/arm/gigabeat/meg-fx/sc606-meg-fx.c b/firmware/target/arm/gigabeat/meg-fx/sc606-meg-fx.c index b0554a8260..39718a4ec6 100644 --- a/firmware/target/arm/gigabeat/meg-fx/sc606-meg-fx.c +++ b/firmware/target/arm/gigabeat/meg-fx/sc606-meg-fx.c @@ -24,10 +24,11 @@ #define SCL_SDA_HI GPHDAT |= (3 << 9) -/* arbitrary delay loop */ -#define DELAY do { int _x; for(_x=0;_x<2000;_x++);} while (0) +/* The SC606 can clock at 400KHz: 2.5uS period -> 1.25uS half period */ +/* At 300Mhz - if loop takes 6 cycles @ 3.3nS each -> 1.25uS / 20nS -> 63 */ +#define DELAY do { volatile int _x; for(_x=0;_x<63;_x++);} while (0) -void sc606_i2c_start(void) +static void sc606_i2c_start(void) { SCL_SDA_HI; DELAY; @@ -36,7 +37,7 @@ void sc606_i2c_start(void) SCL_LO; } -void sc606_i2c_restart(void) +static void sc606_i2c_restart(void) { SCL_SDA_HI; DELAY; @@ -45,7 +46,7 @@ void sc606_i2c_restart(void) SCL_LO; } -void sc606_i2c_stop(void) +static void sc606_i2c_stop(void) { SDA_LO; DELAY; @@ -55,7 +56,7 @@ void sc606_i2c_stop(void) DELAY; } -void sc606_i2c_ack(void) +static void sc606_i2c_ack(void) { SDA_LO; @@ -64,11 +65,11 @@ void sc606_i2c_ack(void) SCL_LO; } -int sc606_i2c_getack(void) +static int sc606_i2c_getack(void) { int ret = 0; - /* Don't need a delay since this follows a data bit with a delay on the end */ + /* Don't need a delay since follows a data bit with a delay on the end */ SDA_INPUT; /* And set to input */ SCL_HI; DELAY; @@ -83,7 +84,7 @@ int sc606_i2c_getack(void) return ret; } -int sc606_i2c_outb(unsigned char byte) +static int sc606_i2c_outb(unsigned char byte) { int i; @@ -106,7 +107,7 @@ int sc606_i2c_outb(unsigned char byte) return sc606_i2c_getack(); } -unsigned char sc606_i2c_inb(void) +static unsigned char sc606_i2c_inb(void) { int i; unsigned char byte = 0; @@ -128,6 +129,8 @@ unsigned char sc606_i2c_inb(void) return byte; } + + int sc606_write(unsigned char reg, unsigned char data) { int x = 0; diff --git a/firmware/target/arm/gigabeat/meg-fx/system-meg-fx.c b/firmware/target/arm/gigabeat/meg-fx/system-meg-fx.c new file mode 100644 index 0000000000..d1c736e91f --- /dev/null +++ b/firmware/target/arm/gigabeat/meg-fx/system-meg-fx.c @@ -0,0 +1,35 @@ +#include "kernel.h" +#include "system.h" +#include "panic.h" + +#include "lcd.h" +#include + +const int TIMER4_MASK = 1 << 14; + +int system_memory_guard(int newmode) +{ + (void)newmode; + return 0; +} + +extern void timer4(void); + +void irq(void) +{ + int intpending = INTPND; + + SRCPND = intpending; /* Clear this interrupt. */ + INTPND = intpending; /* Clear this interrupt. */ + + /* Timer 4 */ + if ((intpending & TIMER4_MASK) != 0) + { + timer4(); + } + else + { + /* unexpected interrupt */ + } +} + diff --git a/firmware/target/arm/gigabeat/meg-fx/usb-meg-fx.c b/firmware/target/arm/gigabeat/meg-fx/usb-meg-fx.c index 6e0f31e8c7..2415a099ba 100644 --- a/firmware/target/arm/gigabeat/meg-fx/usb-meg-fx.c +++ b/firmware/target/arm/gigabeat/meg-fx/usb-meg-fx.c @@ -20,33 +20,72 @@ #include #include "cpu.h" #include "system.h" +#include "kernel.h" + +#define USB_RST_ASSERT GPBDAT &= ~(1 << 4) +#define USB_RST_DEASSERT GPBDAT |= (1 << 4) + +#define USB_ATA_ENABLE GPBDAT |= (1 << 5) +#define USB_ATA_DISABLE GPBDAT &= ~(1 << 5) + +#define USB_VPLUS_PWR_ASSERT GPBDAT |= (1 << 6) +#define USB_VPLUS_PWR_DEASSERT GPBDAT &= ~(1 << 6) + +#define USB_IS_PRESENT (!(GPFDAT & 1)) + + + +/* The usb detect is one pin to the cpu active low */ +inline bool usb_detect(void) +{ + return USB_IS_PRESENT; +} + + void usb_init_device(void) { + USB_VPLUS_PWR_ASSERT; + sleep(HZ/20); + + /* Reset the usb port */ + /* Make sure the cpu pin for reset line is set to output */ + GPBCON = (GPBCON & ~0x300) | 0x100; + USB_RST_ASSERT; + sleep(HZ/25); + USB_RST_DEASSERT; + + /* needed to complete the reset */ + USB_ATA_ENABLE; + + sleep(HZ/15); /* 66ms */ + + USB_ATA_DISABLE; + + sleep(HZ/25); + + /* leave chip in low power mode */ + USB_VPLUS_PWR_DEASSERT; + + sleep(HZ/25); } -bool usb_detect(void) -{ - return (GPFDAT & 1) ? false : true; -} + void usb_enable(bool on) { - if(on) { - int i; - - GPBDAT &= 0x7EF; - GPBCON |= 1<<8; - - GPGDAT &= 0xE7FF; - GPGDAT |= 1<<11; - - for (i = 0; i < 10000000; i++) {continue;} - - GPBCON &= 0x2FFCFF; - GPBDAT |= 1<<5; - GPBDAT |= 1<<6; - } else { - /* TODO how turn USB mode back off again? */ + if (on) + { + /* make sure ata_en is high */ + USB_VPLUS_PWR_ASSERT; + USB_ATA_ENABLE; } + else + { + /* make sure ata_en is low */ + USB_ATA_DISABLE; + USB_VPLUS_PWR_DEASSERT; + } + + sleep(HZ/20); // > 50ms for detecting the enable state change } diff --git a/firmware/target/arm/gigabeat/meg-fx/wmcodec-meg-fx.c b/firmware/target/arm/gigabeat/meg-fx/wmcodec-meg-fx.c index 3835ce6c05..fd023e1be0 100644 --- a/firmware/target/arm/gigabeat/meg-fx/wmcodec-meg-fx.c +++ b/firmware/target/arm/gigabeat/meg-fx/wmcodec-meg-fx.c @@ -36,7 +36,6 @@ #include "file.h" #include "buffer.h" #include "audio.h" -#include "i2s.h" #include "i2c.h" #include "i2c-meg-fx.h" /* @@ -53,11 +52,16 @@ void i2s_reset(void) int audiohw_init(void) { /* reset I2C */ i2c_init(); + + /* GPC5 controls headphone output */ + GPCCON &= ~(0x3 << 10); + GPCCON |= (1 << 10); + GPCDAT |= (1 << 5); return 0; } void wmcodec_write(int reg, int data) { - i2c_send(0x34, (reg<<1) | ((data&0x100)>>8),data&0xff); + i2c_send(0x34, (reg<<1) | ((data&0x100)>>8), data&0xff); } diff --git a/tools/configure b/tools/configure index 4cb1f96291..53be8eee91 100755 --- a/tools/configure +++ b/tools/configure @@ -1031,7 +1031,7 @@ EOF target_id=20 archos="gigabeatf" target="-DGIGABEAT_F" - memory=32 # always + memory=30 # always arm9tdmicc tool="cp" bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"