From 295367686ec9855c4d90f68a6003e819fef8e7ab Mon Sep 17 00:00:00 2001 From: Marcoen Hirschberg Date: Fri, 29 Dec 2006 02:49:12 +0000 Subject: merge a big part of the unofficial gigabeat cvs back. Includes working bootloader and rockbox with audio. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11850 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/arm/gigabeat/meg-fx/adc-meg-fx.c | 122 ++++++-- firmware/target/arm/gigabeat/meg-fx/adc-target.h | 11 +- firmware/target/arm/gigabeat/meg-fx/ata-meg-fx.c | 9 +- firmware/target/arm/gigabeat/meg-fx/ata-target.h | 2 + .../target/arm/gigabeat/meg-fx/backlight-meg-fx.c | 7 +- .../target/arm/gigabeat/meg-fx/backlight-target.h | 1 + .../target/arm/gigabeat/meg-fx/button-meg-fx.c | 141 ++++++--- .../target/arm/gigabeat/meg-fx/button-target.h | 31 ++ firmware/target/arm/gigabeat/meg-fx/dma_start.c | 8 + .../target/arm/gigabeat/meg-fx/kernel-meg-fx.c | 25 ++ firmware/target/arm/gigabeat/meg-fx/lcd-meg-fx.c | 173 +++++++++- firmware/target/arm/gigabeat/meg-fx/mmu-meg-fx.c | 84 +++++ firmware/target/arm/gigabeat/meg-fx/pcm-meg-fx.c | 347 +++++++++++++++++++++ firmware/target/arm/gigabeat/meg-fx/power-meg-fx.c | 21 +- firmware/target/arm/gigabeat/meg-fx/sc606-meg-fx.c | 23 +- .../target/arm/gigabeat/meg-fx/system-meg-fx.c | 35 +++ firmware/target/arm/gigabeat/meg-fx/usb-meg-fx.c | 77 +++-- .../target/arm/gigabeat/meg-fx/wmcodec-meg-fx.c | 8 +- 18 files changed, 1019 insertions(+), 106 deletions(-) create mode 100644 firmware/target/arm/gigabeat/meg-fx/dma_start.c create mode 100644 firmware/target/arm/gigabeat/meg-fx/kernel-meg-fx.c create mode 100644 firmware/target/arm/gigabeat/meg-fx/mmu-meg-fx.c create mode 100644 firmware/target/arm/gigabeat/meg-fx/pcm-meg-fx.c create mode 100644 firmware/target/arm/gigabeat/meg-fx/system-meg-fx.c (limited to 'firmware/target/arm/gigabeat') 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 + +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" -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); } -- cgit v1.2.3