From f44f961812c059b69df19ac5bd828986ba10513f Mon Sep 17 00:00:00 2001 From: Marcoen Hirschberg Date: Wed, 18 Apr 2007 12:22:27 +0000 Subject: move the Gigabeat from gigabeat/meg-fx to s3c2440/gigabeat-fx to avoid problems with possible ports in the future: Gigabeat S/V (i.mx31 based) and Kenwood HD20GA7/HD20GA9 (s3c2440 based) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13200 a1c6a512-1295-4272-9138-f99709370657 --- .../target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c | 144 +++++ .../target/arm/s3c2440/gigabeat-fx/adc-target.h | 37 ++ .../target/arm/s3c2440/gigabeat-fx/ata-meg-fx.c | 143 +++++ .../target/arm/s3c2440/gigabeat-fx/ata-target.h | 70 +++ .../arm/s3c2440/gigabeat-fx/backlight-meg-fx.c | 692 +++++++++++++++++++++ .../arm/s3c2440/gigabeat-fx/backlight-target.h | 87 +++ .../target/arm/s3c2440/gigabeat-fx/button-meg-fx.c | 157 +++++ .../target/arm/s3c2440/gigabeat-fx/button-target.h | 89 +++ .../target/arm/s3c2440/gigabeat-fx/dma_start.c | 8 + .../target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c | 134 ++++ .../target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h | 22 + .../target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c | 25 + .../target/arm/s3c2440/gigabeat-fx/lcd-as-meg-fx.S | 222 +++++++ .../target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c | 367 +++++++++++ .../target/arm/s3c2440/gigabeat-fx/lcd-target.h | 21 + .../target/arm/s3c2440/gigabeat-fx/mmu-meg-fx.c | 222 +++++++ .../target/arm/s3c2440/gigabeat-fx/mmu-meg-fx.h | 35 ++ .../target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c | 376 +++++++++++ .../target/arm/s3c2440/gigabeat-fx/power-meg-fx.c | 90 +++ .../target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c | 225 +++++++ .../target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.h | 28 + .../target/arm/s3c2440/gigabeat-fx/system-meg-fx.c | 96 +++ .../target/arm/s3c2440/gigabeat-fx/system-target.h | 40 ++ .../target/arm/s3c2440/gigabeat-fx/usb-meg-fx.c | 94 +++ .../target/arm/s3c2440/gigabeat-fx/usb-target.h | 26 + .../arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c | 71 +++ 26 files changed, 3521 insertions(+) create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/adc-target.h create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/ata-meg-fx.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/ata-target.h create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/backlight-meg-fx.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/backlight-target.h create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/button-meg-fx.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/button-target.h create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/dma_start.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/lcd-as-meg-fx.S create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/lcd-target.h create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/mmu-meg-fx.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/mmu-meg-fx.h create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/power-meg-fx.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.h create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/system-meg-fx.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/system-target.h create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/usb-meg-fx.c create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/usb-target.h create mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c (limited to 'firmware/target/arm/s3c2440/gigabeat-fx') diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c new file mode 100644 index 0000000000..4c448c2e41 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c @@ -0,0 +1,144 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Wade Brown + * + * 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 "cpu.h" +#include "adc-target.h" +#include "kernel.h" + + + +static unsigned short adc_readings[NUM_ADC_CHANNELS]; + +/* prototypes */ +static unsigned short __adc_read(int channel); +static void adc_tick(void); + + + +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]; +} + + + +/** + * 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 */ + ADCCON = (ADCCON & ~(0x7<<3)) | (channel<<3); + + /* Start the conversion process */ + ADCCON |= 0x1; + + /* Wait for a low Enable_start */ + for (i = 20000;;) { + if(0 == (ADCCON & 0x1)) { + break; + } + else { + i--; + if (0 == i) { + /* Ran out of time */ + return ADC_READ_ERROR; + } + } + } + + /* Wait for high End_of_Conversion */ + for(i = 20000;;) { + if(ADCCON & (1<<15)) { + break; + } + else { + i--; + if(0 == i) { + /* Ran out of time */ + return ADC_READ_ERROR; + } + } + } + + 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/s3c2440/gigabeat-fx/adc-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/adc-target.h new file mode 100644 index 0000000000..8d2beaf320 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/adc-target.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Barry Wardell + * + * 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. + * + ****************************************************************************/ +#ifndef _ADC_TARGET_H_ +#define _ADC_TARGET_H_ + +/* only two channels used by the Gigabeat */ +#define NUM_ADC_CHANNELS 2 + +#define ADC_BATTERY 0 +#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/s3c2440/gigabeat-fx/ata-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/ata-meg-fx.c new file mode 100644 index 0000000000..bc2b53d776 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/ata-meg-fx.c @@ -0,0 +1,143 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id $ + * + * Copyright (C) 2006,2007 by Marcoen Hirschberg + * + * 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 "config.h" +#include "cpu.h" +#include +#include "kernel.h" +#include "system.h" +#include "power.h" +#include "panic.h" +#include "pcf50606.h" +#include "ata-target.h" +#include "mmu-meg-fx.h" +#include "backlight-target.h" + +/* ARESET on C7C68300 and RESET on ATA interface (Active Low) */ +#define ATA_RESET_ENABLE GPGDAT &= ~(1 << 10) +#define ATA_RESET_DISABLE GPGDAT |= (1 << 10) + +/* ATA_EN on C7C68300 */ +#define USB_ATA_ENABLE GPBDAT |= (1 << 5) +#define USB_ATA_DISABLE GPBDAT &= ~(1 << 5) + +void ata_reset(void) +{ + ATA_RESET_ENABLE; + sleep(1); /* > 25us */ + ATA_RESET_DISABLE; + sleep(1); /* > 2ms */ +} + +/* This function is called before enabling the USB bus */ +void ata_enable(bool on) +{ + if(on) + USB_ATA_DISABLE; + else + USB_ATA_ENABLE; + + GPBCON=( GPGCON&~(1<<11) ) | (1<<10); /* Make the pin an output */ +// GPBUP|=1<<5; /* Disable pullup in SOC as we are now driving */ +} + +bool ata_is_coldstart(void) +{ + /* Check the pin configuration - return true when pin is unconfigured */ + return (GPGCON & 0x00300000) == 0; +} + +void ata_device_init(void) +{ + /* ATA reset */ + ATA_RESET_DISABLE; /* Set the pin to disable an active low reset */ + GPGCON=( GPGCON&~(1<<21) ) | (1<<20); /* Make the pin an output */ + GPGUP |= 1<<10; /* Disable pullup in SOC as we are now driving */ +} + +#if !defined(BOOTLOADER) +void copy_read_sectors(unsigned char* buf, int wordcount) +{ + __buttonlight_trigger(); + + /* Unaligned transfer - slow copy */ + if ( (unsigned long)buf & 1) + { /* not 16-bit aligned, copy byte by byte */ + unsigned short tmp = 0; + unsigned char* bufend = buf + wordcount*2; + do + { + tmp = ATA_DATA; + *buf++ = tmp & 0xff; /* I assume big endian */ + *buf++ = tmp >> 8; /* and don't use the SWAB16 macro */ + } while (buf < bufend); /* tail loop is faster */ + return; + } + /* This should never happen, but worth watching for */ + if(wordcount > (1 << 18)) + panicf("atd-meg-fx.c: copy_read_sectors: too many sectors per read!"); + +//#define GIGABEAT_DEBUG_ATA +#ifdef GIGABEAT_DEBUG_ATA + static int line = 0; + static char str[256]; + snprintf(str, sizeof(str), "ODD DMA to %08x, %d", buf, wordcount); + lcd_puts(10, line, str); + line = (line+1) % 32; + lcd_update(); +#endif + /* Reset the channel */ + DMASKTRIG0 |= 4; + /* Wait for DMA controller to be ready */ + while(DMASKTRIG0 & 0x2) + ; + while(DSTAT0 & (1 << 20)) + ; + /* Source is ATA_DATA, on AHB Bus, Fixed */ + DISRC0 = (int) 0x18000000; + DISRCC0 = 0x1; + /* Dest mapped to physical address, on AHB bus, increment */ + DIDST0 = (int) buf; + if(DIDST0 < 0x30000000) + DIDST0 += 0x30000000; + DIDSTC0 = 0; + + /* DACK/DREQ Sync to AHB, Int on Transfer complete, Whole service, No reload, 16-bit transfers */ + DCON0 = ((1 << 30) | (1<< 29) | (1<<27) | (1<<22) | (1<<20)) | wordcount; + + /* Activate the channel */ + DMASKTRIG0 = 0x2; + + invalidate_dcache_range((void *)buf, wordcount*2); + + INTMSK &= ~(1<<17); /* unmask the interrupt */ + SRCPND = (1<<17); /* clear any pending interrupts */ + /* Start DMA */ + DMASKTRIG0 |= 0x1; + + /* Wait for transfer to complete */ + while((DSTAT0 & 0x000fffff)) + yield(); + /* Dump cache for the buffer */ +} +#endif +void dma0(void) +{ +} + + diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/ata-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/ata-target.h new file mode 100644 index 0000000000..95e3e110f2 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/ata-target.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Linus Nielsen Feltzing + * + * 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. + * + ****************************************************************************/ +#ifndef ATA_TARGET_H +#define ATA_TARGET_H + +/* Plain C read & write loops */ +#define PREFER_C_READING +#define PREFER_C_WRITING +#if !defined(BOOTLOADER) +#define ATA_OPTIMIZED_READING +void copy_read_sectors(unsigned char* buf, int wordcount); +#endif + +#define ATA_IOBASE 0x18000000 +#define ATA_DATA (*((volatile unsigned short*)(ATA_IOBASE))) +#define ATA_ERROR (*((volatile unsigned char*)(ATA_IOBASE + 0x02))) +#define ATA_NSECTOR (*((volatile unsigned char*)(ATA_IOBASE + 0x04))) +#define ATA_SECTOR (*((volatile unsigned char*)(ATA_IOBASE + 0x06))) +#define ATA_LCYL (*((volatile unsigned char*)(ATA_IOBASE + 0x08))) +#define ATA_HCYL (*((volatile unsigned char*)(ATA_IOBASE + 0x0A))) +#define ATA_SELECT (*((volatile unsigned char*)(ATA_IOBASE + 0x0C))) +#define ATA_COMMAND (*((volatile unsigned char*)(ATA_IOBASE + 0x0E))) +#define ATA_CONTROL (*((volatile unsigned char*)(0x20000000 + 0x1C))) + +#define STATUS_BSY 0x80 +#define STATUS_RDY 0x40 +#define STATUS_DF 0x20 +#define STATUS_DRQ 0x08 +#define STATUS_ERR 0x01 +#define ERROR_ABRT 0x04 + +#define WRITE_PATTERN1 0xa5 +#define WRITE_PATTERN2 0x5a +#define WRITE_PATTERN3 0xaa +#define WRITE_PATTERN4 0x55 + +#define READ_PATTERN1 0xa5 +#define READ_PATTERN2 0x5a +#define READ_PATTERN3 0xaa +#define READ_PATTERN4 0x55 + +#define READ_PATTERN1_MASK 0xff +#define READ_PATTERN2_MASK 0xff +#define READ_PATTERN3_MASK 0xff +#define READ_PATTERN4_MASK 0xff + +#define SET_REG(reg,val) reg = (val) +#define SET_16BITREG(reg,val) reg = (val) + +void ata_reset(void); +void ata_device_init(void); +bool ata_is_coldstart(void); + +#endif diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/backlight-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/backlight-meg-fx.c new file mode 100644 index 0000000000..a1b6a8a583 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/backlight-meg-fx.c @@ -0,0 +1,692 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Linus Nielsen Feltzing + * + * 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 "config.h" +#include "cpu.h" +#include "system.h" +#include "backlight-target.h" +#include "backlight.h" +#include "lcd.h" +#include "sc606-meg-fx.h" +#include "power.h" + + +#define FLICKER_PERIOD 15 +#define BUTTONLIGHT_MENU (SC606_LED_B1) +#define BUTTONLIGHT_ALL (SC606_LED_B1 | SC606_LED_B2 | SC606_LED_C1 | SC606_LED_C2) + +static void led_control_service(void); +static unsigned short backlight_brightness; +static unsigned short backlight_current; +static unsigned short backlight_target; +static unsigned short time_til_fade; +static unsigned short fade_interval; +static unsigned short initial_tick_delay; +static unsigned char backlight_leds; + +static enum backlight_states +{ + BACKLIGHT_CONTROL_IDLE, + BACKLIGHT_CONTROL_OFF, + BACKLIGHT_CONTROL_ON, + BACKLIGHT_CONTROL_SET, + BACKLIGHT_CONTROL_FADE_OFF, + BACKLIGHT_CONTROL_FADE_ON, + BACKLIGHT_CONTROL_FADE_ON_FROM_OFF +} backlight_control; + + + +enum buttonlight_states +{ + /* turn button lights off */ + BUTTONLIGHT_MODE_OFF_ENTRY, + BUTTONLIGHT_MODE_OFF, + + /* turns button lights on to setting */ + BUTTONLIGHT_MODE_ON_ENTRY, + BUTTONLIGHT_MODE_ON, + + /* turns button lights on to minimum */ + BUTTONLIGHT_MODE_FAINT_ENTRY, + BUTTONLIGHT_MODE_FAINT, + + /* allows button lights to flicker when triggered */ + BUTTONLIGHT_MODE_FLICKER_ENTRY, + BUTTONLIGHT_MODE_FLICKER, + BUTTONLIGHT_MODE_FLICKERING, + + /* button lights solid */ + BUTTONLIGHT_MODE_SOLID_ENTRY, + BUTTONLIGHT_MODE_SOLID, + + /* button light charing */ + BUTTONLIGHT_MODE_CHARGING_ENTRY, + BUTTONLIGHT_MODE_CHARGING, + BUTTONLIGHT_MODE_CHARGING_WAIT, + + /* internal use only */ + BUTTONLIGHT_HELPER_SET, + BUTTONLIGHT_HELPER_SET_FINAL, + BUTTONLIGHT_MODE_STOP, + + /* buttonlights follow the backlight settings */ + BUTTONLIGHT_MODE_FOLLOW_ENTRY, + BUTTONLIGHT_MODE_FOLLOW, +}; + + + +static char buttonlight_leds; +static unsigned short buttonlight_setting; +static unsigned short buttonlight_current; +static unsigned char buttonlight_selected; +static enum buttonlight_states buttonlight_state; +static enum buttonlight_states buttonlight_saved_state; +static unsigned short buttonlight_flickering; + +static unsigned short buttonlight_trigger_now; +static unsigned short buttonlight_trigger_brightness; + + + +static unsigned short charging_led_index; +static unsigned short buttonlight_charging_counter; + +#define CHARGING_LED_COUNT 60 +unsigned char charging_leds[] = { 0x00, 0x20, 0x38, 0x3C }; + + + +bool __backlight_init(void) +{ + backlight_control = BACKLIGHT_CONTROL_IDLE; + + backlight_current = DEFAULT_BRIGHTNESS_SETTING; + + buttonlight_state = BUTTONLIGHT_MODE_OFF; + + buttonlight_selected = 0x04; + + /* delay 4 seconds before any fading */ + initial_tick_delay = 400; + /* put the led control on the tick list */ + tick_add_task(led_control_service); + + return true; +} + + + +void __backlight_on(void) +{ + /* now go turn the backlight on */ + backlight_control = BACKLIGHT_CONTROL_ON; +} + + + +void __backlight_off(void) +{ + backlight_control = BACKLIGHT_CONTROL_OFF; +} + + + +/* Assumes that the backlight has been initialized */ +void __backlight_set_brightness(int brightness) +{ + /* stop the interrupt from messing us up */ + backlight_control = BACKLIGHT_CONTROL_IDLE; + + backlight_brightness = brightness + 1; + + /* only set the brightness if it is different from the current */ + if (backlight_brightness != backlight_current) + { + backlight_control = BACKLIGHT_CONTROL_SET; + } +} + + + +/* only works if the buttonlight mode is set to triggered mode */ +void __buttonlight_trigger(void) +{ + buttonlight_trigger_now = 1; +} + + + + +/* map the mode from the command into the state machine entries */ +void __buttonlight_mode(enum buttonlight_mode mode, + enum buttonlight_selection selection, + unsigned short brightness) +{ + /* choose stop to setup mode */ + buttonlight_state = BUTTONLIGHT_MODE_STOP; + + + /* clip brightness */ + if (brightness > MAX_BRIGHTNESS_SETTING) + { + brightness = MAX_BRIGHTNESS_SETTING; + } + + brightness++; + + /* Select which LEDs to use */ + switch (selection) + { + case BUTTONLIGHT_LED_ALL: + buttonlight_selected = BUTTONLIGHT_ALL; + break; + + case BUTTONLIGHT_LED_MENU: + buttonlight_selected = BUTTONLIGHT_MENU; + break; + } + + /* which mode to use */ + switch (mode) + { + case BUTTONLIGHT_OFF: + buttonlight_state = BUTTONLIGHT_MODE_OFF_ENTRY; + break; + + case BUTTONLIGHT_ON: + buttonlight_trigger_brightness = brightness; + buttonlight_state = BUTTONLIGHT_MODE_ON_ENTRY; + break; + + /* faint is just a quick way to set ON to 1 */ + case BUTTONLIGHT_FAINT: + buttonlight_trigger_brightness = 1; + buttonlight_state = BUTTONLIGHT_MODE_ON_ENTRY; + break; + + case BUTTONLIGHT_FLICKER: + buttonlight_trigger_brightness = brightness; + buttonlight_state = BUTTONLIGHT_MODE_FLICKER_ENTRY; + break; + + case BUTTONLIGHT_SIGNAL: + buttonlight_trigger_brightness = brightness; + buttonlight_state = BUTTONLIGHT_MODE_SOLID_ENTRY; + break; + + case BUTTONLIGHT_FOLLOW: + buttonlight_state = BUTTONLIGHT_MODE_FOLLOW_ENTRY; + break; + + case BUTTONLIGHT_CHARGING: + buttonlight_state = BUTTONLIGHT_MODE_CHARGING_ENTRY; + break; + + default: + return; /* unknown mode */ + } + + +} + + + +/* + * The button lights have 'modes' of operation. Each mode must setup and + * execute its own operation - taking care that this is all done in an ISR. + * + */ + + + +/* led_control_service runs in interrupt context - be brief! + * This service is called once per interrupt timer tick - 100 times a second. + * + * There should be at most only one i2c operation per call - if more are need + * the calls should be spread across calls. + * + * Putting all led servicing in one thread means that we wont step on any + * i2c operations - they are all serialized here in the ISR tick. It also + * insures that we get called at equal timing for good visual effect. + * + * The buttonlight service runs only after all backlight services have finished. + * Fading the buttonlights is possible, but not recommended because of the + * additional calls needed during the ISR + */ +static void led_control_service(void) +{ + if(initial_tick_delay) { + initial_tick_delay--; + return; + } + switch (backlight_control) + { + case BACKLIGHT_CONTROL_IDLE: + switch (buttonlight_state) + { + case BUTTONLIGHT_MODE_STOP: break; + + /* Buttonlight mode: OFF */ + case BUTTONLIGHT_MODE_OFF_ENTRY: + if (buttonlight_current) + { + buttonlight_leds = 0x00; + sc606_write(SC606_REG_CONF, backlight_leds); + buttonlight_current = 0; + } + buttonlight_state = BUTTONLIGHT_MODE_OFF; + break; + + case BUTTONLIGHT_MODE_OFF: + break; + + + /* button mode: CHARGING - show charging sequence */ + case BUTTONLIGHT_MODE_CHARGING_ENTRY: + /* start turned off */ + buttonlight_leds = 0x00; + sc606_write(SC606_REG_CONF, backlight_leds); + buttonlight_current = 0; + + /* temporary save for the next mode - then to do settings */ + buttonlight_setting = DEFAULT_BRIGHTNESS_SETTING; + buttonlight_saved_state = BUTTONLIGHT_MODE_CHARGING_WAIT; + buttonlight_state = BUTTONLIGHT_HELPER_SET; + break; + + + case BUTTONLIGHT_MODE_CHARGING: + if (--buttonlight_charging_counter == 0) + { + /* change led */ + if (charging_state()) + { + buttonlight_leds = charging_leds[charging_led_index]; + if (++charging_led_index >= sizeof(charging_leds)) + { + charging_led_index = 0; + } + sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); + buttonlight_charging_counter = CHARGING_LED_COUNT; + } + else + { + buttonlight_state = BUTTONLIGHT_MODE_CHARGING_ENTRY; + } + } + break; + + /* wait for the charget to be plugged in */ + case BUTTONLIGHT_MODE_CHARGING_WAIT: + if (charging_state()) + { + charging_led_index = 0; + buttonlight_charging_counter = CHARGING_LED_COUNT; + buttonlight_state = BUTTONLIGHT_MODE_CHARGING; + } + break; + + + /* Buttonlight mode: FOLLOW - try to stay current with backlight + * since this runs in the idle of the backlight it will not really + * follow in real time + */ + case BUTTONLIGHT_MODE_FOLLOW_ENTRY: + /* case 1 - backlight on, but buttonlight is off */ + if (backlight_current) + { + /* Turn the buttonlights on */ + buttonlight_leds = buttonlight_selected; + sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); + + /* temporary save for the next mode - then to do settings */ + buttonlight_setting = backlight_current; + buttonlight_saved_state = BUTTONLIGHT_MODE_FOLLOW; + buttonlight_state = BUTTONLIGHT_HELPER_SET; + } + /* case 2 - backlight off, but buttonlight is on */ + else + { + buttonlight_current = 0; + buttonlight_leds = 0x00; + sc606_write(SC606_REG_CONF, backlight_leds); + buttonlight_state = BUTTONLIGHT_MODE_FOLLOW; + } + break; + + case BUTTONLIGHT_MODE_FOLLOW: + if (buttonlight_current != backlight_current) + { + /* case 1 - backlight on, but buttonlight is off */ + if (backlight_current) + { + if (0 == buttonlight_current) + { + /* Turn the buttonlights on */ + buttonlight_leds = buttonlight_selected; + sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); + } + + /* temporary save for the next mode - then to do settings */ + buttonlight_setting = backlight_current; + buttonlight_saved_state = BUTTONLIGHT_MODE_FOLLOW; + buttonlight_state = BUTTONLIGHT_HELPER_SET; + } + + /* case 2 - backlight off, but buttonlight is on */ + else + { + buttonlight_current = 0; + buttonlight_leds = 0x00; + sc606_write(SC606_REG_CONF, backlight_leds); + } + + } + break; + + + + /* Buttonlight mode: ON - stays at the set brightness */ + case BUTTONLIGHT_MODE_ON_ENTRY: + buttonlight_leds = buttonlight_selected; + sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); + + /* temporary save for the next mode - then to do settings */ + buttonlight_setting = buttonlight_trigger_brightness; + buttonlight_saved_state = BUTTONLIGHT_MODE_ON; + buttonlight_state = BUTTONLIGHT_HELPER_SET; + break; + + case BUTTONLIGHT_MODE_ON: + break; + + + + /* Buttonlight mode: FLICKER */ + case BUTTONLIGHT_MODE_FLICKER_ENTRY: + /* already on? turn it off */ + if (buttonlight_current) + { + buttonlight_leds = 0x00; + sc606_write(SC606_REG_CONF, backlight_leds); + buttonlight_current = 0; + } + + /* set the brightness if not already set */ + if (buttonlight_current != buttonlight_trigger_brightness) + { + /* temporary save for the next mode - then to do settings */ + buttonlight_setting = buttonlight_trigger_brightness; + buttonlight_saved_state = BUTTONLIGHT_MODE_FLICKER; + buttonlight_state = BUTTONLIGHT_HELPER_SET; + } + else buttonlight_state = BUTTONLIGHT_MODE_FLICKER; + break; + + + case BUTTONLIGHT_MODE_FLICKER: + /* wait for the foreground to trigger flickering */ + if (buttonlight_trigger_now) + { + /* turn them on */ + buttonlight_leds = buttonlight_selected; + buttonlight_current = buttonlight_setting; + sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); + + /* reset the trigger and go flicker the LEDs */ + buttonlight_trigger_now = 0; + buttonlight_flickering = FLICKER_PERIOD; + buttonlight_state = BUTTONLIGHT_MODE_FLICKERING; + } + break; + + + case BUTTONLIGHT_MODE_FLICKERING: + /* flicker the LEDs for as long as we get triggered */ + if (buttonlight_flickering) + { + /* turn the leds off if they are on */ + if (buttonlight_current) + { + buttonlight_leds = 0x00; + sc606_write(SC606_REG_CONF, backlight_leds); + buttonlight_current = 0; + } + + buttonlight_flickering--; + } + else + { + /* is flickering triggered again? */ + if (!buttonlight_trigger_now) + { + /* completed a cycle - no new triggers - go back and wait */ + buttonlight_state = BUTTONLIGHT_MODE_FLICKER; + } + else + { + /* reset flickering */ + buttonlight_trigger_now = 0; + buttonlight_flickering = FLICKER_PERIOD; + + /* turn buttonlights on */ + buttonlight_leds = buttonlight_selected; + buttonlight_current = buttonlight_setting; + sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); + } + } + break; + + + /* Buttonlight mode: SIGNAL / SOLID */ + case BUTTONLIGHT_MODE_SOLID_ENTRY: + /* already on? turn it off */ + if (buttonlight_current) + { + buttonlight_leds = 0x00; + sc606_write(SC606_REG_CONF, backlight_leds); + buttonlight_current = 0; + } + + /* set the brightness if not already set */ + /* temporary save for the next mode - then to do settings */ + buttonlight_setting = buttonlight_trigger_brightness; + buttonlight_saved_state = BUTTONLIGHT_MODE_SOLID; + buttonlight_state = BUTTONLIGHT_HELPER_SET; + break; + + + case BUTTONLIGHT_MODE_SOLID: + /* wait for the foreground to trigger */ + if (buttonlight_trigger_now) + { + /* turn them on if not already on */ + if (0 == buttonlight_current) + { + buttonlight_leds = buttonlight_selected; + buttonlight_current = buttonlight_setting; + sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); + } + + /* reset the trigger */ + buttonlight_trigger_now = 0; + } + else + { + if (buttonlight_current) + { + buttonlight_leds = 0x00; + sc606_write(SC606_REG_CONF, backlight_leds); + buttonlight_current = 0; + } + } + break; + + + /* set the brightness for the buttonlights - takes 2 passes */ + case BUTTONLIGHT_HELPER_SET: + sc606_write(SC606_REG_B, buttonlight_setting-1); + buttonlight_state = BUTTONLIGHT_HELPER_SET_FINAL; + break; + + case BUTTONLIGHT_HELPER_SET_FINAL: + sc606_write(SC606_REG_C, buttonlight_setting-1); + buttonlight_current = buttonlight_setting; + buttonlight_state = buttonlight_saved_state; + break; + + default: + break; + + } + break; + + + case BACKLIGHT_CONTROL_FADE_ON_FROM_OFF: + backlight_leds = 0x03; + sc606_write(SC606_REG_CONF, 0x03 | buttonlight_leds); + backlight_control = BACKLIGHT_CONTROL_FADE_ON; + break; + + + case BACKLIGHT_CONTROL_OFF: + backlight_current = 0; + backlight_leds = 0x00; + sc606_write(SC606_REG_CONF, buttonlight_leds); + backlight_control = BACKLIGHT_CONTROL_IDLE; + + break; + + + case BACKLIGHT_CONTROL_ON: + backlight_leds = 0x03; + sc606_write(SC606_REG_CONF, 0x03 | buttonlight_leds); + backlight_current = backlight_brightness; + backlight_control = BACKLIGHT_CONTROL_IDLE; + break; + + + case BACKLIGHT_CONTROL_SET: + /* The SC606 LED driver can set the brightness in 64 steps */ + sc606_write(SC606_REG_A, backlight_brightness-1); + + /* if we were turned off - turn the backlight on */ + if (backlight_current) + { + backlight_current = backlight_brightness; + backlight_control = BACKLIGHT_CONTROL_IDLE; + } + else + { + backlight_control = BACKLIGHT_CONTROL_ON; + } + break; + + + case BACKLIGHT_CONTROL_FADE_ON: + if (--time_til_fade) return; + + /* The SC606 LED driver can set the brightness in 64 steps */ + sc606_write(SC606_REG_A, backlight_current++); + + /* have we hit the target? */ + if (backlight_current == backlight_target) + { + backlight_control = BACKLIGHT_CONTROL_IDLE; + } + else + { + time_til_fade = fade_interval; + } + break; + + + case BACKLIGHT_CONTROL_FADE_OFF: + if (--time_til_fade) return; + + /* The SC606 LED driver can set the brightness in 64 steps */ + sc606_write(SC606_REG_A, --backlight_current); + + /* have we hit the target? */ + if (backlight_current == backlight_target) + { + if (backlight_current) + { + backlight_control = BACKLIGHT_CONTROL_IDLE; + } + else + { + backlight_control = BACKLIGHT_CONTROL_OFF; + } + + } + else + { + time_til_fade = fade_interval; + } + break; + } + + if(backlight_current) + lcd_enable(true); + else + lcd_enable(false); +} + + + + + +void __backlight_dim(bool dim_now) +{ + unsigned short target; + + /* dont let the interrupt tick happen */ + backlight_control = BACKLIGHT_CONTROL_IDLE; + + target = (dim_now == true) ? 0 : backlight_brightness; + + /* only try and fade if the target is different */ + if (backlight_current != target) + { + backlight_target = target; + + if (backlight_current > backlight_target) + { + time_til_fade = fade_interval = 4; + backlight_control = BACKLIGHT_CONTROL_FADE_OFF; + } + else + { + time_til_fade = fade_interval = 1; + if (backlight_current) + { + backlight_control = BACKLIGHT_CONTROL_FADE_ON; + } + else + { + backlight_control = BACKLIGHT_CONTROL_FADE_ON_FROM_OFF; + } + } + } + +} + + diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/backlight-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/backlight-target.h new file mode 100644 index 0000000000..5f92cee935 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/backlight-target.h @@ -0,0 +1,87 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Linus Nielsen Feltzing + * + * 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. + * + ****************************************************************************/ +#ifndef BACKLIGHT_TARGET_H +#define BACKLIGHT_TARGET_H + + +/* select the led */ +enum buttonlight_selection +{ + /* all leds */ + BUTTONLIGHT_LED_ALL, + + /* only the menu/power led (two buttons for one LED) */ + BUTTONLIGHT_LED_MENU +}; + + +/* Use these to set the buttonlight mode */ +enum buttonlight_mode +{ + /* ON follows the setting */ + BUTTONLIGHT_ON, + + /* buttonlights always off */ + BUTTONLIGHT_OFF, + + /* buttonlights always on but set at lowest brightness */ + BUTTONLIGHT_FAINT, + + /* buttonlights flicker when triggered - continues to flicker + * even if the flicker is still asserted. + */ + BUTTONLIGHT_FLICKER, + + /* buttonlights solid for as long as triggered */ + BUTTONLIGHT_SIGNAL, + + /* buttonlights follow backlight */ + BUTTONLIGHT_FOLLOW, + + /* buttonlights show battery charging */ + BUTTONLIGHT_CHARGING, +}; + + +/* Call this to flicker or signal the button lights. Only is effective for + * modes that take a trigger input. + */ +void __buttonlight_trigger(void); + + +/* select which led to use on the button lights. Other combinations are + * possible, but don't look very good. + */ + +/* map the mode from the command into the state machine entries */ +/* See enum buttonlight_mode for available functions */ +void __buttonlight_mode(enum buttonlight_mode mode, + enum buttonlight_selection selection, + unsigned short brightness); + + +bool __backlight_init(void); +void __backlight_on(void); +void __backlight_off(void); +void __backlight_set_brightness(int val); + +/* true: backlight fades off - false: backlight fades on */ +void __backlight_dim(bool dim); + +#endif diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/button-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/button-meg-fx.c new file mode 100644 index 0000000000..71d45c385c --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/button-meg-fx.c @@ -0,0 +1,157 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Linus Nielsen Feltzing + * + * 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 +#include "config.h" +#include "cpu.h" +#include "system.h" +#include "button.h" +#include "kernel.h" +#include "backlight.h" +#include "adc.h" +#include "system.h" +#include "backlight-target.h" + +static bool headphones_detect; +static bool hold_button = false; + +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 */ +} + + + +inline bool button_hold(void) +{ + return (GPGDAT & (1 << 15)); +} + + + +int button_read_device(void) +{ + int touchpad; + int buttons; + static int lastbutton; + unsigned short remote_adc; + int btn = BUTTON_NONE; + bool hold_button_old; + + /* normal buttons */ + hold_button_old = hold_button; + hold_button = button_hold(); + +#ifndef BOOTLOADER + /* give BL notice if HB state chaged */ + if (hold_button != hold_button_old) + backlight_hold_changed(hold_button); +#endif + + /* 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; + } + + /* Check for hold first - exit if asserted with no button pressed */ + if (hold_button) + return btn; + + /* 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 */ + touchpad = GPJDAT & 0x10C9; + if (touchpad) + { + if (touchpad & (1 << 0)) + btn |= BUTTON_UP; + + if (touchpad & (1 << 12)) + btn |= BUTTON_RIGHT; + + if (touchpad & (1 << 6)) + btn |= BUTTON_DOWN; + + 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/s3c2440/gigabeat-fx/button-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/button-target.h new file mode 100644 index 0000000000..ab68e8050f --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/button-target.h @@ -0,0 +1,89 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Linus Nielsen Feltzing + * + * 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. + * + ****************************************************************************/ +#ifndef _BUTTON_TARGET_H_ +#define _BUTTON_TARGET_H_ + +#include +#include "config.h" + +#define HAS_BUTTON_HOLD + +bool button_hold(void); +void button_init_device(void); +int button_read_device(void); + +/* Toshiba Gigabeat specific button codes */ + +#define BUTTON_POWER 0x00000001 +#define BUTTON_MENU 0x00000002 + +#define BUTTON_LEFT 0x00000004 +#define BUTTON_RIGHT 0x00000008 +#define BUTTON_UP 0x00000010 +#define BUTTON_DOWN 0x00000020 + +#define BUTTON_VOL_UP 0x00000040 +#define BUTTON_VOL_DOWN 0x00000080 + +#define BUTTON_SELECT 0x00000100 +#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) + + +#define BUTTON_REMOTE 0 + +#define POWEROFF_BUTTON BUTTON_POWER +#define POWEROFF_COUNT 10 + +#endif /* _BUTTON_TARGET_H_ */ diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/dma_start.c b/firmware/target/arm/s3c2440/gigabeat-fx/dma_start.c new file mode 100644 index 0000000000..c1ab6c15cb --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-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/s3c2440/gigabeat-fx/i2c-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c new file mode 100644 index 0000000000..670d6cd04c --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c @@ -0,0 +1,134 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Linus Nielsen Feltzing + * + * 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 "config.h" +#include "cpu.h" +#include +#include "kernel.h" +#include "system.h" +#include "logf.h" +#include "debug.h" +#include "string.h" +#include "generic_i2c.h" + +static void i2c_sda_output(void) +{ + GPECON |= (1 << 30); +} + +static void i2c_sda_input(void) +{ + GPECON &= ~(3 << 30); +} + +static void i2c_sda_lo(void) +{ + GPEDAT &= ~(1 << 15); +} + +static void i2c_sda_hi(void) +{ + GPEDAT |= (1 << 15); +} + +static int i2c_sda(void) +{ + return GPEDAT & (1 << 15); +} + +static void i2c_scl_output(void) +{ + GPECON |= (1 << 28); +} + +static void i2c_scl_input(void) +{ + GPECON &= ~(3 << 28); +} + +static void i2c_scl_lo(void) +{ + GPEDAT &= ~(1 << 14); +} + +static int i2c_scl(void) +{ + return GPEDAT & (1 << 14); +} + +static void i2c_scl_hi(void) +{ + i2c_scl_input(); + while(!i2c_scl()); + GPEDAT |= (1 << 14); + i2c_scl_output(); +} + + + +static void i2c_delay(void) +{ + unsigned _x; + + /* The i2c can clock at 500KHz: 2uS period -> 1uS half period */ + /* about 30 cycles overhead + X * 7 */ + /* 300MHz: 1000nS @3.36nS/cyc = 297cyc: X = 38*/ + /* 100MHz: 1000nS @10nS/cyc = 100cyc : X = 10 */ + for (_x = 38; _x; _x--) + { + /* burn CPU cycles */ + /* gcc makes it an inc loop - check with objdump for asm timing */ + } +} + + + +struct i2c_interface s3c2440_i2c = { + 0x34, /* Address */ + + /* Bit-banged interface definitions */ + i2c_scl_hi, /* Drive SCL high, might sleep on clk stretch */ + i2c_scl_lo, /* Drive SCL low */ + i2c_sda_hi, /* Drive SDA high */ + i2c_sda_lo, /* Drive SDA low */ + i2c_sda_input, /* Set SDA as input */ + i2c_sda_output, /* Set SDA as output */ + i2c_scl_input, /* Set SCL as input */ + i2c_scl_output, /* Set SCL as output */ + i2c_scl, /* Read SCL, returns 0 or nonzero */ + i2c_sda, /* Read SDA, returns 0 or nonzero */ + + i2c_delay, /* START SDA hold time (tHD:SDA) */ + i2c_delay, /* SDA hold time (tHD:DAT) */ + i2c_delay, /* SDA setup time (tSU:DAT) */ + i2c_delay, /* STOP setup time (tSU:STO) */ + i2c_delay, /* Rep. START setup time (tSU:STA) */ + i2c_delay, /* SCL high period (tHIGH) */ +}; + +void i2c_init(void) +{ + /* Set GPE15 (SDA) and GPE14 (SCL) to 1 */ + GPECON = (GPECON & ~(0xF<<28)) | 5<<28; + i2c_add_node(&s3c2440_i2c); +} + +void i2c_send(int bus_address, int reg_address, const unsigned char buf) +{ + i2c_write_data(bus_address, reg_address, &buf, 1); +} diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h new file mode 100644 index 0000000000..cf69230487 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h @@ -0,0 +1,22 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Linus Nielsen Feltzing + * + * 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. + * + ****************************************************************************/ + +/* chip-specific i2c functions */ + +void i2c_send(int bus_address, int reg_address, const unsigned char buf); diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c new file mode 100644 index 0000000000..9df90a2344 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-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/s3c2440/gigabeat-fx/lcd-as-meg-fx.S b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-as-meg-fx.S new file mode 100644 index 0000000000..d431c95f29 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-as-meg-fx.S @@ -0,0 +1,222 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2007 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 "config.h" +#include "cpu.h" + +/**************************************************************************** + * void lcd_write_yuv_420_lines(fb_data *dst, + * unsigned char chroma_buf[LCD_HEIGHT/2*3], + unsigned char const * const src[3], + * int width, + * int stride); + * + * |R| |1.000000 -0.000001 1.402000| |Y'| + * |G| = |1.000000 -0.334136 -0.714136| |Pb| + * |B| |1.000000 1.772000 0.000000| |Pr| + * Scaled, normalized, rounded and tweaked to yield RGB 565: + * |R| |74 0 101| |Y' - 16| >> 9 + * |G| = |74 -24 -51| |Cb - 128| >> 8 + * |B| |74 128 0| |Cr - 128| >> 9 + */ + .section .icode, "ax", %progbits + .align 2 + .global lcd_write_yuv420_lines + .type lcd_write_yuv420_lines, %function +lcd_write_yuv420_lines: + @ r0 = dst + @ r1 = chroma_buf + @ r2 = yuv_src + @ r3 = width + @ [sp] = stride + stmdb sp!, { r4-r12, lr } @ save non-scratch + stmdb sp!, { r0, r3 } @ save dst and width + mov r14, #74 @ r14 = Y factor + ldmia r2, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p + @ r5 = yuv_src[1] = Cb_p + @ r6 = yuv_src[2] = Cr_p +10: @ loop line 1 @ + ldrb r2, [r4], #1 @ r2 = *Y'_p++; + ldrb r8, [r5], #1 @ r8 = *Cb_p++; + ldrb r11, [r6], #1 @ r11 = *Cr_p++; + @ + @ compute Y + sub r2, r2, #16 @ r7 = Y = (Y' - 16)*74 + mul r7, r2, r14 @ + @ + sub r8, r8, #128 @ Cb -= 128 + sub r11, r11, #128 @ Cr -= 128 + @ + mvn r2, #24 @ compute guv + mul r10, r2, r8 @ r10 = Cb*-24 + mvn r2, #51 @ + mla r10, r2, r11, r10 @ r10 = r10 + Cr*-51 + @ + mov r2, #101 @ compute rv + mul r9, r11, r2 @ r9 = rv = Cr*101 + @ + @ store chromas in line buffer + add r8, r8, #2 @ bu = (Cb + 2) >> 2 + mov r8, r8, asr #2 @ + strb r8, [r1], #1 @ + add r9, r9, #256 @ rv = (Cr + 256) >> 9 + mov r9, r9, asr #9 @ + strb r9, [r1], #1 @ + mov r10, r10, asr #8 @ guv >>= 8 + strb r10, [r1], #1 @ + @ compute R, G, and B + add r2, r8, r7, asr #9 @ r2 = b = (Y >> 9) + bu + add r11, r9, r7, asr #9 @ r11 = r = (Y >> 9) + rv + add r7, r10, r7, asr #8 @ r7 = g = (Y >> 8) + guv + @ + orr r12, r2, r11 @ check if clamping is needed... + orr r12, r12, r7, asr #1 @ ...at all + cmp r12, #31 @ + bls 15f @ no clamp @ + mov r12, #31 @ + cmp r12, r2 @ clamp b + andlo r2, r12, r2, asr #31 @ + eorlo r2, r2, r12 @ + cmp r12, r11 @ clamp r + andlo r11, r12, r11, asr #31 @ + eorlo r11, r11, r12 @ + cmp r12, r7, asr #1 @ clamp g + andlo r7, r12, r7, asr #31 @ + eorlo r7, r7, r12 @ + orrlo r7, r7, r7, asl #1 @ +15: @ no clamp @ + @ + orr r12, r2, r7, lsl #5 @ r4 |= (g << 5) + ldrb r2, [r4], #1 @ r2 = Y' = *Y'_p++ + orr r12, r12, r11, lsl #11 @ r4 = b | (r << 11) + strh r12, [r0], #240 @ store pixel + @ + sub r2, r2, #16 @ r7 = Y = (Y' - 16)*74 + mul r7, r2, r14 @ next Y + @ compute R, G, and B + add r2, r8, r7, asr #9 @ r2 = b = (Y >> 9) + bu + add r11, r9, r7, asr #9 @ r11 = r = (Y >> 9) + rv + add r7, r10, r7, asr #8 @ r7 = g = (Y >> 8) + guv + @ + orr r12, r2, r11 @ check if clamping is needed... + orr r12, r12, r7, asr #1 @ ...at all + cmp r12, #31 @ + bls 15f @ no clamp @ + mov r12, #31 @ + cmp r12, r2 @ clamp b + andlo r2, r12, r2, asr #31 @ + eorlo r2, r2, r12 @ + cmp r12, r11 @ clamp r + andlo r11, r12, r11, asr #31 @ + eorlo r11, r11, r12 @ + cmp r12, r7, asr #1 @ clamp g + andlo r7, r12, r7, asr #31 @ + eorlo r7, r7, r12 @ + orrlo r7, r7, r7, asl #1 @ +15: @ no clamp @ + @ + orr r12, r2, r11, lsl #11 @ r4 = b | (r << 11) + orr r12, r12, r7, lsl #5 @ r4 |= (g << 5) + strh r12, [r0, #240]! @ store pixel + add r0, r0, #2*240 @ + @ + subs r3, r3, #2 @ + bgt 10b @ loop line 1 @ + @ do second line + @ + ldmia sp!, { r0, r3 } @ pop dst and width + sub r0, r0, #2 @ set dst to start of next line + sub r1, r1, r3, asl #1 @ rewind chroma pointer... + ldr r2, [sp, #40] @ r2 = stride + add r1, r1, r3, asr #1 @ ... (r1 -= width/2*3) + @ move sources to start of next line + sub r2, r2, r3 @ r2 = skip = stride - width + add r4, r4, r2 @ r4 = Y'_p + skip + @ +20: @ loop line 2 @ + ldrb r2, [r4], #1 @ r7 = Y' = *Y'_p++ + ldrsb r8, [r1], #1 @ reload saved chromas + ldrsb r9, [r1], #1 @ + ldrsb r10, [r1], #1 @ + @ + sub r2, r2, #16 @ r2 = Y = (Y' - 16)*74 + mul r7, r2, r14 @ + @ compute R, G, and B + add r2, r8, r7, asr #9 @ r2 = b = (Y >> 9) + bu + add r11, r9, r7, asr #9 @ r11 = r = (Y >> 9) + rv + add r7, r10, r7, asr #8 @ r7 = g = (Y >> 8) + guv + @ + orr r12, r2, r11 @ check if clamping is needed... + orr r12, r12, r7, asr #1 @ ...at all + cmp r12, #31 @ + bls 25f @ no clamp @ + mov r12, #31 @ + cmp r12, r2 @ clamp b + andlo r2, r12, r2, asr #31 @ + eorlo r2, r2, r12 @ + cmp r12, r11 @ clamp r + andlo r11, r12, r11, asr #31 @ + eorlo r11, r11, r12 @ + cmp r12, r7, asr #1 @ clamp g + andlo r7, r12, r7, asr #31 @ + eorlo r7, r7, r12 @ + orrlo r7, r7, r7, asl #1 @ +25: @ no clamp @ + @ + orr r12, r2, r11, lsl #11 @ r4 = b | (r << 11) + ldrb r2, [r4], #1 @ r2 = Y' = *Y'_p++ + orr r12, r12, r7, lsl #5 @ r4 |= (g << 5) + strh r12, [r0], #240 @ store pixel + @ + @ do second pixel + @ + sub r2, r2, #16 @ r2 = Y = (Y' - 16)*74 + mul r7, r2, r14 @ + @ compute R, G, and B + add r2, r8, r7, asr #9 @ r2 = b = (Y >> 9) + bu + add r11, r9, r7, asr #9 @ r11 = r = (Y >> 9) + rv + add r7, r10, r7, asr #8 @ r7 = g = (Y >> 8) + guv + @ + orr r12, r2, r11 @ check if clamping is needed... + orr r12, r12, r7, asr #1 @ ...at all + cmp r12, #31 @ + bls 25f @ no clamp @ + mov r12, #31 @ + cmp r12, r2 @ clamp b + andlo r2, r12, r2, asr #31 @ + eorlo r2, r2, r12 @ + cmp r12, r11 @ clamp r + andlo r11, r12, r11, asr #31 @ + eorlo r11, r11, r12 @ + cmp r12, r7, asr #1 @ clamp g + andlo r7, r12, r7, asr #31 @ + eorlo r7, r7, r12 @ + orrlo r7, r7, r7, asl #1 @ +25: @ no clamp @ + @ + orr r12, r2, r11, lsl #11 @ r4 = b | (r << 11) + orr r12, r12, r7, lsl #5 @ r4 |= (g << 5) + strh r12, [r0, #240]! @ store pixel + add r0, r0, #2*240 @ + @ + subs r3, r3, #2 @ + bgt 20b @ loop line 2 @ + @ + ldmia sp!, { r4-r12, pc } @ restore registers and return + .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c new file mode 100644 index 0000000000..1bb68f9686 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c @@ -0,0 +1,367 @@ +#include "config.h" +#include +#include "cpu.h" +#include "lcd.h" +#include "kernel.h" +#include "system.h" +#include "mmu-meg-fx.h" +#include +#include "memory.h" +#include "lcd-target.h" +#include "font.h" +#include "rbunicode.h" +#include "bidi.h" + +#define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)]) +/* +** We prepare foreground and background fills ahead of time - DMA fills in 16 byte groups +*/ +unsigned long fg_pattern_blit[4]; +unsigned long bg_pattern_blit[4]; + +volatile bool use_dma_blit = false; +static volatile bool lcd_on = true; +volatile bool lcd_poweroff = false; +/* +** These are imported from lcd-16bit.c +*/ +extern unsigned fg_pattern; +extern unsigned bg_pattern; + +bool lcd_enabled() +{ + return lcd_on; +} + +unsigned int LCDBANK(unsigned int address) +{ + return ((address >> 22) & 0xff); +} + +unsigned int LCDBASEU(unsigned int address) +{ + return (address & ((1 << 22)-1)) >> 1; +} + +unsigned int LCDBASEL(unsigned int address) +{ + address += 320*240*2; + return (address & ((1 << 22)-1)) >> 1; +} + + +/* LCD init */ +void lcd_init_device(void) +{ + LCDSADDR1 = (LCDBANK((unsigned)FRAME) << 21) | (LCDBASEU((unsigned)FRAME)); + LCDSADDR2 = LCDBASEL((unsigned)FRAME); + LCDSADDR3 = 0x000000F0; + + LCDCON5 |= 1 << 11; /* Switch from 555I mode to 565 mode */ + +#if !defined(BOOTLOADER) + memset16(fg_pattern_blit, fg_pattern, sizeof(fg_pattern_blit)/2); + memset16(bg_pattern_blit, bg_pattern, sizeof(bg_pattern_blit)/2); + clean_dcache_range((void *)fg_pattern_blit, sizeof(fg_pattern_blit)); + clean_dcache_range((void *)bg_pattern_blit, sizeof(bg_pattern_blit)); + use_dma_blit = true; + lcd_poweroff = false; +#endif +} + +/* Update a fraction of the display. */ +void lcd_update_rect(int x, int y, int width, int height) +{ + (void)x; + (void)width; + (void)y; + (void)height; + + if(!lcd_on) + { + sleep(200); + return; + } + if (use_dma_blit) + { + /* Wait for this controller to stop pending transfer */ + while((DSTAT1 & 0x000fffff)) + CLKCON |= (1 << 2); /* set IDLE bit */ + + /* Flush DCache */ + invalidate_dcache_range((void *)(((int) &lcd_framebuffer[0][0])+(y * sizeof(fb_data) * LCD_WIDTH)), (height * sizeof(fb_data) * LCD_WIDTH)); + + /* set DMA dest */ + DIDST1 = ((int) FRAME) + (y * sizeof(fb_data) * LCD_WIDTH); + + /* FRAME on AHB buf, increment */ + DIDSTC1 = 0; + /* Handshake on AHB, Burst transfer, Whole service, Don't reload, transfer 32-bits */ + DCON1 = ((1<<30) | (1<<28) | (1<<27) | (1<<22) | (2<<20)) | ((height * sizeof(fb_data) * LCD_WIDTH) >> 4); + + /* set DMA source */ + DISRC1 = ((int) &lcd_framebuffer[0][0]) + (y * sizeof(fb_data) * LCD_WIDTH) + 0x30000000; + /* memory is on AHB bus, increment addresses */ + DISRCC1 = 0x00; + + /* Activate the channel */ + DMASKTRIG1 = 0x2; + + /* Start DMA */ + DMASKTRIG1 |= 0x1; + + /* Wait for transfer to complete */ + while((DSTAT1 & 0x000fffff)) + CLKCON |= (1 << 2); /* set IDLE bit */ + } + else + memcpy(((char*)FRAME) + (y * sizeof(fb_data) * LCD_WIDTH), ((char *)&lcd_framebuffer) + (y * sizeof(fb_data) * LCD_WIDTH), ((height * sizeof(fb_data) * LCD_WIDTH))); +} + + +void lcd_enable(bool state) +{ + if(!lcd_poweroff) + return; + if(state) { + if(!lcd_on) { + lcd_on = true; + memcpy(FRAME, lcd_framebuffer, LCD_WIDTH*LCD_HEIGHT*2); + LCDCON1 |= 1; + } + } + else { + if(lcd_on) { + lcd_on = false; + LCDCON1 &= ~1; + } + } +} + +void lcd_set_foreground(unsigned color) +{ + fg_pattern = color; + + memset16(fg_pattern_blit, fg_pattern, sizeof(fg_pattern_blit)/2); + invalidate_dcache_range((void *)fg_pattern_blit, sizeof(fg_pattern_blit)); +} + +void lcd_set_background(unsigned color) +{ + bg_pattern = color; + memset16(bg_pattern_blit, bg_pattern, sizeof(bg_pattern_blit)/2); + invalidate_dcache_range((void *)bg_pattern_blit, sizeof(bg_pattern_blit)); +} + +void lcd_device_prepare_backdrop(fb_data* backdrop) +{ + if(backdrop) + invalidate_dcache_range((void *)backdrop, (LCD_HEIGHT * sizeof(fb_data) * LCD_WIDTH)); +} + +void lcd_clear_display_dma(void) +{ + void *src; + bool inc = false; + + if(!lcd_on) { + sleep(200); + } + if (lcd_get_drawmode() & DRMODE_INVERSEVID) + src = fg_pattern_blit; + else + { + fb_data* lcd_backdrop = lcd_get_backdrop(); + + if (!lcd_backdrop) + src = bg_pattern_blit; + else + { + src = lcd_backdrop; + inc = true; + } + } + /* Wait for any pending transfer to complete */ + while((DSTAT3 & 0x000fffff)) + CLKCON |= (1 << 2); /* set IDLE bit */ + DMASKTRIG3 |= 0x4; /* Stop controller */ + DIDST3 = ((int) &lcd_framebuffer[0][0]) + 0x30000000; /* set DMA dest, physical address */ + DIDSTC3 = 0; /* Dest on AHB, increment */ + + DISRC3 = ((int) src) + 0x30000000; /* Set source, in physical space */ + DISRCC3 = inc ? 0x00 : 0x01; /* memory is on AHB bus, increment addresses based on backdrop */ + + /* Handshake on AHB, Burst mode, whole service mode, no reload, move 32-bits */ + DCON3 = ((1<<30) | (1<<28) | (1<<27) | (1<<22) | (2<<20)) | ((LCD_WIDTH*LCD_HEIGHT*sizeof(fb_data)) >> 4); + + /* Dump DCache for dest, we are about to overwrite it with DMA */ + invalidate_dcache_range((void *)lcd_framebuffer, sizeof(lcd_framebuffer)); + /* Activate the channel */ + DMASKTRIG3 = 2; + /* Start DMA */ + DMASKTRIG3 |= 1; + + /* Wait for transfer to complete */ + while((DSTAT3 & 0x000fffff)) + CLKCON |= (1 << 2); /* set IDLE bit */ +} + +void lcd_clear_display(void) +{ + lcd_stop_scroll(); + + if(use_dma_blit) + { + lcd_clear_display_dma(); + return; + } + + fb_data *dst = &lcd_framebuffer[0][0]; + + if (lcd_get_drawmode() & DRMODE_INVERSEVID) + { + memset16(dst, fg_pattern, LCD_WIDTH*LCD_HEIGHT); + } + else + { + fb_data* lcd_backdrop = lcd_get_backdrop(); + if (!lcd_backdrop) + memset16(dst, bg_pattern, LCD_WIDTH*LCD_HEIGHT); + else + memcpy(dst, lcd_backdrop, sizeof(lcd_framebuffer)); + } +} + + +/* Update the display. + This must be called after all other LCD functions that change the display. */ +void lcd_update(void) +{ + lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); +} + +void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y, + int stride, int x, int y, int width, + int height) +{ + fb_data *dst, *dst_end; + unsigned int transcolor; + + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) + || (x + width <= 0) || (y + height <= 0)) + return; + + /* clipping */ + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > LCD_WIDTH) + width = LCD_WIDTH - x; + if (y + height > LCD_HEIGHT) + height = LCD_HEIGHT - y; + + src += stride * src_y + src_x; /* move starting point */ + dst = &lcd_framebuffer[(y)][(x)]; + dst_end = dst + height * LCD_WIDTH; + width *= 2; + stride *= 2; + transcolor = TRANSPARENT_COLOR; + asm volatile( + "rowstart: \n" + "mov r0, #0 \n" + "nextpixel: \n" + "ldrh r1, [%0, r0] \n" /* Load word src+r0 */ + "cmp r1, %5 \n" /* Compare to transparent color */ + "strneh r1, [%1, r0] \n" /* Store dst+r0 if not transparent */ + "add r0, r0, #2 \n" + "cmp r0, %2 \n" /* r0 == width? */ + "bne nextpixel \n" /* More in this row? */ + "add %0, %0, %4 \n" /* src += stride */ + "add %1, %1, #480 \n" /* dst += LCD_WIDTH (x2) */ + "cmp %1, %3 \n" + "bne rowstart \n" /* if(dst != dst_end), keep going */ + : : "r" (src), "r" (dst), "r" (width), "r" (dst_end), "r" (stride), "r" (transcolor) : "r0", "r1" ); +} + +/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ +extern void lcd_write_yuv420_lines(fb_data *dst, + unsigned char chroma_buf[LCD_HEIGHT/2*3], + unsigned char const * const src[3], + int width, + int stride); +/* 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) +{ + /* Caches for chroma data so it only need be recaculated every other + line */ + unsigned char chroma_buf[LCD_HEIGHT/2*3]; /* 480 bytes */ + unsigned char const * yuv_src[3]; + off_t z; + + if (!lcd_on) + return; + + /* Sorry, but width and height must be >= 2 or else */ + width &= ~1; + height >>= 1; + + fb_data *dst = (fb_data*)FRAME + x * LCD_WIDTH + (LCD_WIDTH - y) - 1; + + z = stride*src_y; + yuv_src[0] = src[0] + z + src_x; + yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); + yuv_src[2] = src[2] + (yuv_src[1] - src[1]); + + do + { + lcd_write_yuv420_lines(dst, chroma_buf, yuv_src, width, + stride); + yuv_src[0] += stride << 1; /* Skip down two luma lines */ + yuv_src[1] += stride >> 1; /* Skip down one chroma line */ + yuv_src[2] += stride >> 1; + dst -= 2; + } + while (--height > 0); +} + +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: +} + diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/lcd-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-target.h new file mode 100644 index 0000000000..cb2a89f349 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-target.h @@ -0,0 +1,21 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id $ + * + * Copyright (C) 2007 by Greg White + * + * 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. + * + ****************************************************************************/ + +extern void lcd_enable(bool state); + diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/mmu-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/mmu-meg-fx.c new file mode 100644 index 0000000000..6142213f0c --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/mmu-meg-fx.c @@ -0,0 +1,222 @@ +#include +#include "s3c2440.h" +#include "mmu-meg-fx.h" +#include "panic.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 = (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*) TTB_BASE; + 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,2007 by Greg White + * + * 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. + * + ****************************************************************************/ + +/* Invalidate DCache for this range */ +/* Will do write back */ +void invalidate_dcache_range(const void *base, unsigned int size); + +/* clean DCache for this range */ +/* forces DCache writeback for the specified range */ +void clean_dcache_range(const void *base, unsigned int size); + +/* Dump DCache for this range */ +/* Will *NOT* do write back */ +void dump_dcache_range(const void *base, unsigned int size); + +/* Cleans entire DCache */ +void clean_dcache(void); + + diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c new file mode 100644 index 0000000000..0f22aa5c5c --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c @@ -0,0 +1,376 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "sound.h" +#include "file.h" +#include "mmu-meg-fx.h" + +static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ + +#define GIGABEAT_8000HZ 0x4d +#define GIGABEAT_11025HZ 0x32 +#define GIGABEAT_12000HZ 0x61 +#define GIGABEAT_16000HZ 0x55 +#define GIGABEAT_22050HZ 0x36 +#define GIGABEAT_24000HZ 0x79 +#define GIGABEAT_32000HZ 0x59 +#define GIGABEAT_44100HZ 0x22 +#define GIGABEAT_48000HZ 0x41 +#define GIGABEAT_88200HZ 0x3e +#define GIGABEAT_96000HZ 0x5d + +#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) + { + /* Flush any pending cache writes */ + clean_dcache_range(p, 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); + + /* 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 */ + pcm_set_frequency(SAMPR_44); + + /* init GPIO */ + GPCCON = (GPCCON & ~(3<<14)) | (1<<14); + GPCDAT |= 1<<7; + GPECON |= 0x2aa; + + /* Do not service DMA 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_postinit(void) +{ + audiohw_postinit(); +} + +void pcm_play_dma_start(const void *addr, size_t size) +{ + /* sanity check: bad pointer or too small file */ + if (NULL == addr || size <= 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); + + /* 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; + + set_fiq_handler(fiq); + enable_fiq(); + + /* unmask the DMA interrupt */ + INTMSK &= ~(1<<19); + + /* Flush any pending writes */ + clean_dcache_range(addr, size); + + /* 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) +{ + /* mask the DMA interrupt */ + INTMSK |= (1<<19); + + /* are we playing? wait for the chunk to finish */ + if (pcm_playing) + { + /* wait for the FIFO to empty before turning things off */ + while (IISCON & (1<<7)) ; + + pcm_playing = false; + } + + /* De-Activate the DMA channel */ + DMASKTRIG2 = 0x4; + + /* Disconnect the IIS clock */ + CLKCON &= ~(1<<17); + + disable_fiq(); + +} + + + +void pcm_play_pause_pause(void) +{ + /* stop servicing refills */ + INTMSK |= (1<<19); +} + + + +void pcm_play_pause_unpause(void) +{ + /* refill buffer and keep going */ + INTMSK &= ~(1<<19); +} + +void pcm_set_frequency(unsigned int frequency) +{ + int sr_ctrl; + + switch(frequency) + { + case SAMPR_8: + sr_ctrl = GIGABEAT_8000HZ; + break; + case SAMPR_11: + sr_ctrl = GIGABEAT_11025HZ; + break; + case SAMPR_12: + sr_ctrl = GIGABEAT_12000HZ; + break; + case SAMPR_16: + sr_ctrl = GIGABEAT_16000HZ; + break; + case SAMPR_22: + sr_ctrl = GIGABEAT_22050HZ; + break; + case SAMPR_24: + sr_ctrl = GIGABEAT_24000HZ; + break; + case SAMPR_32: + sr_ctrl = GIGABEAT_32000HZ; + break; + default: + frequency = SAMPR_44; + case SAMPR_44: + sr_ctrl = GIGABEAT_44100HZ; + break; + case SAMPR_48: + sr_ctrl = GIGABEAT_48000HZ; + break; + case SAMPR_88: + sr_ctrl = GIGABEAT_88200HZ; + break; + case SAMPR_96: + sr_ctrl = GIGABEAT_96000HZ; + 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(void) +{ +} + +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/s3c2440/gigabeat-fx/power-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/power-meg-fx.c new file mode 100644 index 0000000000..eb2ffb5238 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/power-meg-fx.c @@ -0,0 +1,90 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Linus Nielsen Feltzing + * + * 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 "config.h" +#include "cpu.h" +#include +#include "kernel.h" +#include "system.h" +#include "power.h" +#include "pcf50606.h" +#include "backlight.h" +#include "backlight-target.h" + +#ifndef SIMULATOR + +void power_init(void) +{ + /* Charger detect */ +} + +bool charger_inserted(void) +{ + 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) +{ + if (on) + GPGDAT |= (1 << 11); + else + GPGDAT &= ~(1 << 11); +} + +bool ide_powered(void) +{ + 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 */ + +bool charger_inserted(void) +{ + return false; +} + +void charger_enable(bool on) +{ + (void)on; +} + +void power_off(void) +{ +} + +void ide_power_enable(bool on) +{ + (void)on; +} + +#endif /* SIMULATOR */ + diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c new file mode 100644 index 0000000000..e69eab432a --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c @@ -0,0 +1,225 @@ +#include "config.h" +#include "cpu.h" +#include +#include "kernel.h" +#include "system.h" +#include "logf.h" +#include "debug.h" +#include "string.h" + +#define SLAVE_ADDRESS 0xCC + +#define SDA_LO (GPHDAT &= ~(1 << 9)) +#define SDA_HI (GPHDAT |= (1 << 9)) +#define SDA_INPUT (GPHCON &= ~(3 << 18)) +#define SDA_OUTPUT (GPHCON |= (1 << 18)) +#define SDA (GPHDAT & (1 << 9)) + +#define SCL_LO (GPHDAT &= ~(1 << 10)) +#define SCL_HI (GPHDAT |= (1 << 10)) +#define SCL_INPUT (GPHCON &= ~(3 << 20)) +#define SCL_OUTPUT (GPHCON |= (1 << 20)) +#define SCL (GPHDAT & (1 << 10)) + +#define SCL_SDA_HI (GPHDAT |= (3 << 9)) + +/* The SC606 can clock at 400KHz: */ +/* Clock period high is 600nS and low is 1300nS */ +/* The high and low times are different enough to need different timings */ +/* cycles delayed = 30 + 7 * loops */ +/* 100MHz = 10nS per cycle: LO:1300nS=130:14 HI:600nS=60:9 */ +/* 300MHz = 3.36nS per cycle: LO:1300nS=387:51 HI:600nS=179:21 */ +#define DELAY_LO do{int x;for(x=51;x;x--);} while (0) +#define DELAY do{int x;for(x=35;x;x--);} while (0) +#define DELAY_HI do{int x;for(x=21;x;x--);} while (0) + + + +static void sc606_i2c_start(void) +{ + SCL_SDA_HI; + DELAY; + SDA_LO; + DELAY; + SCL_LO; +} + +static void sc606_i2c_restart(void) +{ + SCL_SDA_HI; + DELAY; + SDA_LO; + DELAY; + SCL_LO; +} + +static void sc606_i2c_stop(void) +{ + SDA_LO; + SCL_HI; + DELAY_HI; + SDA_HI; +} + +static void sc606_i2c_ack(void) +{ + + SDA_LO; + SCL_HI; + DELAY_HI; + SCL_LO; +} + + + +static int sc606_i2c_getack(void) +{ + int ret; + + /* Don't need a delay since follows a data bit with a delay on the end */ + SDA_INPUT; /* And set to input */ + DELAY; + SCL_HI; + + ret = (SDA != 0); /* ack failed if SDA is not low */ + DELAY_HI; + + SCL_LO; + DELAY_LO; + + SDA_HI; + SDA_OUTPUT; + DELAY_LO; + + return ret; +} + + + +static void sc606_i2c_outb(unsigned char byte) +{ + int i; + + /* clock out each bit, MSB first */ + for (i = 0x80; i; i >>= 1) + { + if (i & byte) + { + SDA_HI; + } + else + { + SDA_LO; + } + DELAY; + + SCL_HI; + DELAY_HI; + + SCL_LO; + DELAY_LO; + } + + SDA_HI; + +} + + + +static unsigned char sc606_i2c_inb(void) +{ + int i; + unsigned char byte = 0; + + SDA_INPUT; /* And set to input */ + /* clock in each bit, MSB first */ + for (i = 0x80; i; i >>= 1) { + SCL_HI; + + if (SDA) + byte |= i; + + SCL_LO; + } + SDA_OUTPUT; + + sc606_i2c_ack(); + + return byte; +} + + + +/* returns number of acks that were bad */ +int sc606_write(unsigned char reg, unsigned char data) +{ + int x; + + sc606_i2c_start(); + + sc606_i2c_outb(SLAVE_ADDRESS); + x = sc606_i2c_getack(); + + sc606_i2c_outb(reg); + x += sc606_i2c_getack(); + + sc606_i2c_restart(); + + sc606_i2c_outb(SLAVE_ADDRESS); + x += sc606_i2c_getack(); + + sc606_i2c_outb(data); + x += sc606_i2c_getack(); + + sc606_i2c_stop(); + + return x; +} + + + +int sc606_read(unsigned char reg, unsigned char* data) +{ + int x; + + sc606_i2c_start(); + sc606_i2c_outb(SLAVE_ADDRESS); + x = sc606_i2c_getack(); + + sc606_i2c_outb(reg); + x += sc606_i2c_getack(); + + sc606_i2c_restart(); + sc606_i2c_outb(SLAVE_ADDRESS | 1); + x += sc606_i2c_getack(); + + *data = sc606_i2c_inb(); + sc606_i2c_stop(); + + return x; +} + + + +void sc606_init(void) +{ + volatile int i; + + /* Set GPB2 (EN) to 1 */ + GPBCON = (GPBCON & ~(3<<4)) | 1<<4; + + /* Turn enable line on */ + GPBDAT |= 1<<2; + /* OFF GPBDAT &= ~(1 << 2); */ + + /* About 400us - needs 350us */ + for (i = 200; i; i--) + { + DELAY_LO; + } + + /* Set GPH9 (SDA) and GPH10 (SCL) to 1 */ + GPHUP &= ~(3<<9); + GPHCON = (GPHCON & ~(0xF<<18)) | 5<<18; +} + diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.h b/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.h new file mode 100644 index 0000000000..3ea0917e86 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.h @@ -0,0 +1,28 @@ +#include "config.h" +#include "cpu.h" +#include +#include "kernel.h" +#include "system.h" +#include "logf.h" +#include "debug.h" +#include "string.h" + +#define SC606_REG_A 0 +#define SC606_REG_B 1 +#define SC606_REG_C 2 +#define SC606_REG_CONF 3 + +#define SC606_LED_A1 (1 << 0) +#define SC606_LED_A2 (1 << 1) +#define SC606_LED_B1 (1 << 2) +#define SC606_LED_B2 (1 << 3) +#define SC606_LED_C1 (1 << 4) +#define SC606_LED_C2 (1 << 5) + +#define SC606_LOW_FREQ (1 << 6) + +int sc606_write(unsigned char reg, unsigned char data); + +int sc606_read(unsigned char reg, unsigned char* data); + +void sc606_init(void); diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/system-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/system-meg-fx.c new file mode 100644 index 0000000000..b7e59e66ea --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/system-meg-fx.c @@ -0,0 +1,96 @@ +#include "kernel.h" +#include "system.h" +#include "panic.h" + +#include "lcd.h" +#include + +const int TIMER4_MASK = (1 << 14); +const int LCD_MASK = (1 << 16); +const int DMA0_MASK = (1 << 17); +const int DMA1_MASK = (1 << 18); +const int DMA2_MASK = (1 << 19); +const int DMA3_MASK = (1 << 20); + +int system_memory_guard(int newmode) +{ + (void)newmode; + return 0; +} + +extern void timer4(void); +extern void dma0(void); +extern void dma1(void); +extern void dma3(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 if ((intpending & DMA0_MASK) != 0) + dma0(); + else + { + /* unexpected interrupt */ + } +} + +void system_reboot(void) +{ + WTCON = 0; + WTCNT = WTDAT = 1 ; + WTCON = 0x21; + for(;;) + ; +} + +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) ); + + /* Turn off USB host */ + CLKCON &= ~(1 << 6); + + /* Turn off NAND flash controller */ + CLKCON &= ~(1 << 4); + +} + + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + +void set_cpu_frequency(long frequency) +{ + if (frequency == CPUFREQ_MAX) + { + asm volatile("mov r0, #0\n" + "mrc p15, 0, r0, c1, c0, 0\n" + "orr r0, r0, #3<<30\n" /* set to Asynchronous mode*/ + "mcr p15, 0, r0, c1, c0, 0" : : : "r0"); + + FREQ = CPUFREQ_MAX; + } + else + { + asm volatile("mov r0, #0\n" + "mrc p15, 0, r0, c1, c0, 0\n" + "bic r0, r0, #3<<30\n" /* set to FastBus mode*/ + "mcr p15, 0, r0, c1, c0, 0" : : : "r0"); + + FREQ = CPUFREQ_NORMAL; + } +} + +#endif diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/system-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/system-target.h new file mode 100644 index 0000000000..215b5a4daa --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/system-target.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2007 by Greg White + * + * 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. + * + ****************************************************************************/ +#ifndef SYSTEM_TARGET_H +#define SYSTEM_TARGET_H + +#include "mmu-meg-fx.h" +#include "system-arm.h" + +#define CPUFREQ_DEFAULT 98784000 +#define CPUFREQ_NORMAL 98784000 +#define CPUFREQ_MAX 296352000 + +#define HAVE_INVALIDATE_ICACHE +static inline void invalidate_icache(void) +{ + clean_dcache(); + asm volatile( + "mov r0, #0 \n" + "mcr p15, 0, r0, c7, c5, 0 \n" + : : : "r0" + ); +} + +#endif /* SYSTEM_TARGET_H */ diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/usb-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/usb-meg-fx.c new file mode 100644 index 0000000000..3aed8c3256 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/usb-meg-fx.c @@ -0,0 +1,94 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Linus Nielsen Feltzing + * + * 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 "config.h" +#include +#include "cpu.h" +#include "system.h" +#include "kernel.h" +#include "ata.h" + +#define USB_RST_ASSERT GPBDAT &= ~(1 << 4) +#define USB_RST_DEASSERT GPBDAT |= (1 << 4) + +#define USB_VPLUS_PWR_ASSERT GPBDAT |= (1 << 6) +#define USB_VPLUS_PWR_DEASSERT GPBDAT &= ~(1 << 6) + +#define USB_UNIT_IS_PRESENT !(GPFDAT & 0x01) +#define USB_CRADLE_IS_PRESENT ((GPFDAT &0x02)&&!(GPGDAT&1<<14)) + +#define USB_CRADLE_BUS_ENABLE GPHDAT |= (1 << 8) +#define USB_CRADLE_BUS_DISABLE GPHDAT &= ~(1 << 8) + +/* The usb detect is one pin to the cpu active low */ +inline bool usb_detect(void) +{ + return USB_UNIT_IS_PRESENT | USB_CRADLE_IS_PRESENT; +} + +void usb_init_device(void) +{ + /* Input is the default configuration, only pullups need to be disabled */ + GPFUP|=0x02; + + USB_VPLUS_PWR_ASSERT; + GPBCON=( GPBCON&~(1<<13) ) | (1 << 12); + + sleep(HZ/20); + + /* Reset the usb port */ + USB_RST_ASSERT; + GPBCON = (GPBCON & ~0x200) | 0x100; /* Make sure reset line is an output */ + + sleep(HZ/25); + USB_RST_DEASSERT; + + /* needed to complete the reset */ + ata_enable(false); + + sleep(HZ/15); /* 66ms */ + + ata_enable(true); + + sleep(HZ/25); + + /* leave chip in low power mode */ + USB_VPLUS_PWR_DEASSERT; + + sleep(HZ/25); +} + +void usb_enable(bool on) +{ + if (on) + { + USB_VPLUS_PWR_ASSERT; + if(USB_CRADLE_IS_PRESENT) USB_CRADLE_BUS_ENABLE; + } + else + { + if(USB_CRADLE_IS_PRESENT) USB_CRADLE_BUS_DISABLE; + USB_VPLUS_PWR_DEASSERT; + } + + /* Make sure USB_CRADLE_BUS pin is an output */ + GPHCON=( GPHCON&~(1<<17) ) | (1<<16); /* Make the pin an output */ + GPHUP|=1<<8; /* Disable pullup in SOC as we are now driving */ + + sleep(HZ/20); // > 50ms for detecting the enable state change +} diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/usb-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/usb-target.h new file mode 100644 index 0000000000..baeb539b38 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/usb-target.h @@ -0,0 +1,26 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Linus Nielsen Feltzing + * + * 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. + * + ****************************************************************************/ +#ifndef USB_TARGET_H +#define USB_TARGET_H + +bool usb_init_device(void); +bool usb_detect(void); +void usb_enable(bool on); + +#endif diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c new file mode 100644 index 0000000000..fe42b7527a --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c @@ -0,0 +1,71 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Gigabeat specific code for the Wolfson codec + * + * Based on code from the ipodlinux project - http://ipodlinux.org/ + * Adapted for Rockbox in December 2005 + * + * Original file: linux/arch/armnommu/mach-ipod/audio.c + * + * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org) + * + * 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 "lcd.h" +#include "cpu.h" +#include "kernel.h" +#include "thread.h" +#include "power.h" +#include "debug.h" +#include "system.h" +#include "sprintf.h" +#include "button.h" +#include "string.h" +#include "file.h" +#include "buffer.h" +#include "audio.h" +#include "i2c.h" +#include "i2c-meg-fx.h" +/* + * Reset the I2S BIT.FORMAT I2S, 16bit, FIFO.FORMAT 32bit + */ +void i2s_reset(void) +{ +} + +/* + * Initialise the WM8975 for playback via headphone and line out. + * Note, I'm using the WM8750 datasheet as its apparently close. + */ +int audiohw_init(void) { + /* reset I2C */ + i2c_init(); + + /* GPC5 controls headphone output */ + GPCCON &= ~(0x3 << 10); + GPCCON |= (1 << 10); + GPCDAT |= (1 << 5); + + return 0; +} + +void audiohw_postinit(void) +{ +} + +void wmcodec_write(int reg, int data) +{ + i2c_send(0x34, (reg<<1) | ((data&0x100)>>8), data&0xff); +} -- cgit v1.2.3