summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/plugins/plugin.lds7
-rw-r--r--bootloader/gigabeat.c367
-rw-r--r--firmware/SOURCES8
-rw-r--r--firmware/app.lds11
-rw-r--r--firmware/boot.lds2
-rw-r--r--firmware/export/config-gigabeat.h52
-rw-r--r--firmware/export/config.h1
-rw-r--r--firmware/kernel.c41
-rw-r--r--firmware/pcm_playback.c41
-rw-r--r--firmware/powermgmt.c11
-rw-r--r--firmware/system.c10
-rw-r--r--firmware/target/arm/crt0.S30
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/adc-meg-fx.c122
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/adc-target.h11
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/ata-meg-fx.c9
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/ata-target.h2
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/backlight-meg-fx.c7
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/backlight-target.h1
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/button-meg-fx.c141
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/button-target.h31
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/dma_start.c8
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/kernel-meg-fx.c25
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/lcd-meg-fx.c173
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/mmu-meg-fx.c84
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/pcm-meg-fx.c347
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/power-meg-fx.c21
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/sc606-meg-fx.c23
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/system-meg-fx.c35
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/usb-meg-fx.c77
-rw-r--r--firmware/target/arm/gigabeat/meg-fx/wmcodec-meg-fx.c8
-rwxr-xr-xtools/configure2
31 files changed, 1509 insertions, 199 deletions
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);
+ 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;
+ }
- testfile = open("/boottest.txt", O_WRONLY|O_CREAT|O_TRUNC);
- write(testfile, "It works!", 9);
- close(testfile);
+ 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);
+
+
+}
+
+
+
+/* Called to get the recent ADC reading */
+inline unsigned short adc_read(int channel)
+{
+ return adc_readings[channel];
}
-unsigned short adc_read(int 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--;
+ for (i = 20000;;) {
+ if(0 == (ADCCON & 0x1)) {
+ break;
}
else {
- break;
+ i--;
+ if (0 == i) {
+ /* Ran out of time */
+ return ADC_READ_ERROR;
+ }
}
}
- if(i == 0) {
- /* Ran out of time */
- return(0);
- }
/* 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;
-
- /* Check for hold first */
- if (buttons & (1 << 15))
- return btn;
- /* the side buttons */
- if (buttons & (1 << 0))
- btn |= BUTTON_POWER;
-
- if (buttons & (1 << 1))
- btn |= BUTTON_MENU;
-
- if (buttons & (1 << 2))
- btn |= BUTTON_VOL_UP;
-
- if (buttons & (1 << 3))
- btn |= BUTTON_VOL_DOWN;
-
- if (buttons & (1 << 4))
- btn |= BUTTON_A;
+int button_read_device(void)
+{
+ int btn;
+ int touchpad;
+ int buttons;
+ static int lastbutton;
+ unsigned short remote_adc;
+
+ /* Check for hold first - exit if asserted with no button pressed */
+ if (button_hold())
+ return BUTTON_NONE;
+
+ /* 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.
+ */
+
+
+ /* 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 << 1))
+ btn |= BUTTON_MENU;
+
+ if (buttons & (1 << 2))
+ btn |= BUTTON_VOL_UP;
+
+ 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 <sys/types.h>
+
+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 <stdio.h>
+#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 <string.h>
#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.
@@ -45,6 +74,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,
int x, int y, int width, int height)
@@ -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 <string.h>
+#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<ttb_size; i++,ttbPtr++)
+ ttbPtr = 0;
+ asm volatile("mcr p15, 0, %0, c2, c0, 0" : : "r" (ttb_base));
+
+ /* set domain D0 to "client" permission access */
+
+ domain_access = 3;
+ asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (domain_access));
+
+}
+
+void set_page_tables() {
+
+ map_section(0, 0, 0x1000, CACHE_NONE);
+
+ map_section(0x30000000, 0, 32, CACHE_NONE); /* map RAM to 0 */
+
+ map_section(0x30000000, 0, 30, CACHE_ALL); /* cache the first 30 MB or RAM */
+ map_section(0x31E00000, 0x31E00000, 1, BUFFERED); /* enable buffered writing for the framebuffer */
+}
+
+void map_section(unsigned int pa, unsigned int va, int mb, int cache_flags) {
+ unsigned int* ttbPtr;
+ int i;
+ int section_no;
+
+ section_no = va >> 20; /* sections are 1Mb size */
+ ttbPtr = ttb_base + section_no;
+ pa &= SECTION_ADDRESS_MASK; /* align to 1Mb */
+ for(i=0; i<mb; i++, pa += MB) {
+ *(ttbPtr + i) =
+ pa |
+ 1 << 10 | /* superuser - r/w, user - no access */
+ 0 << 5 | /* domain 0th */
+ 1 << 4 | /* should be "1" */
+ cache_flags |
+ 1 << 1; /* Section signature */
+ }
+}
+
+static void enable_mmu(void) {
+ asm volatile("mov r0, #0\n"
+ "mcr p15, 0, r0, c8, c7, 0\n" /* invalidate TLB */
+
+ "mcr p15, 0, r0, c7, c7,0\n" /* invalidate both icache and dcache */
+
+ "mrc p15, 0, r0, c1, c0, 0\n"
+ "orr r0, r0, #1<<0\n" /* enable mmu bit, icache and dcache */
+ "orr r0, r0, #1<<2\n" /* enable dcache */
+ "orr r0, r0, #1<<12\n" /* enable icache */
+ "mcr p15, 0, r0, c1, c0, 0" : : : "r0");
+ asm volatile("nop \n nop \n nop \n nop");
+}
diff --git a/firmware/target/arm/gigabeat/meg-fx/pcm-meg-fx.c b/firmware/target/arm/gigabeat/meg-fx/pcm-meg-fx.c
new file mode 100644
index 0000000000..a3c09c5c64
--- /dev/null
+++ b/firmware/target/arm/gigabeat/meg-fx/pcm-meg-fx.c
@@ -0,0 +1,347 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * 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 <stdio.h>
+
+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 <stdbool.h>
#include "cpu.h"
#include "system.h"
+#include "kernel.h"
-void usb_init_device(void)
-{
-}
+#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)
-bool usb_detect(void)
+#define USB_IS_PRESENT (!(GPFDAT & 1))
+
+
+
+/* The usb detect is one pin to the cpu active low */
+inline bool usb_detect(void)
{
- return (GPFDAT & 1) ? false : true;
+ return USB_IS_PRESENT;
}
-void usb_enable(bool on)
-{
- if(on) {
- int i;
- GPBDAT &= 0x7EF;
- GPBCON |= 1<<8;
- GPGDAT &= 0xE7FF;
- GPGDAT |= 1<<11;
+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);
+}
+
- for (i = 0; i < 10000000; i++) {continue;}
- GPBCON &= 0x2FFCFF;
- GPBDAT |= 1<<5;
- GPBDAT |= 1<<6;
- } else {
- /* TODO how turn USB mode back off again? */
+void usb_enable(bool on)
+{
+ 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"