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
This commit is contained in:
Marcoen Hirschberg 2007-04-18 12:22:27 +00:00
parent c3dcc87aa4
commit f44f961812
29 changed files with 18 additions and 18 deletions

View file

@ -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;
}
}

View file

@ -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

View file

@ -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 <stdbool.h>
#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)
{
}

View file

@ -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

View file

@ -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;
}
}
}
}

View file

@ -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

View file

@ -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 <stdlib.h>
#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;
}

View file

@ -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 <stdbool.h>
#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_ */

View file

@ -0,0 +1,8 @@
#include <sys/types.h>
void dma_start(const void* addr, size_t size) {
(void) addr;
(void) size;
//TODO:
}

View file

@ -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 <stdbool.h>
#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);
}

View file

@ -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);

View file

@ -0,0 +1,25 @@
#include "kernel.h"
#include "thread.h"
#include <stdio.h>
#include "lcd.h"
extern void (*tick_funcs[MAX_NUM_TICK_TASKS])(void);
void timer4(void) {
int i;
/* Run through the list of tick tasks */
for(i = 0; i < MAX_NUM_TICK_TASKS; i++)
{
if(tick_funcs[i])
{
tick_funcs[i]();
}
}
current_tick++;
/* following needs to be fixed. */
/*wake_up_thread();*/
}

View file

@ -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

View file

@ -0,0 +1,367 @@
#include "config.h"
#include <string.h>
#include "cpu.h"
#include "lcd.h"
#include "kernel.h"
#include "system.h"
#include "mmu-meg-fx.h"
#include <stdlib.h>
#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:
}

View file

@ -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);

View file

@ -0,0 +1,222 @@
#include <string.h>
#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<ttb_size; i++,ttbPtr++)
ttbPtr = 0;
asm volatile("mcr p15, 0, %0, c2, c0, 0" : : "r" (ttb_base));
/* set domain D0 to "client" permission access */
domain_access = 3;
asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (domain_access));
}
void set_page_tables() {
map_section(0, 0, 0x1000, CACHE_NONE); /* map every memory region to itself */
map_section(0x30000000, 0, 32, CACHE_ALL); /* map RAM to 0 and enable caching for it */
map_section((int)FRAME, (int)FRAME, 1, BUFFERED); /* enable buffered writing for the framebuffer */
}
void map_section(unsigned int pa, unsigned int va, int mb, int cache_flags) {
unsigned int* ttbPtr;
int i;
int section_no;
section_no = va >> 20; /* sections are 1Mb size */
ttbPtr = ttb_base + section_no;
pa &= SECTION_ADDRESS_MASK; /* align to 1Mb */
for(i=0; i<mb; i++, pa += MB) {
*(ttbPtr + i) =
pa |
1 << 10 | /* superuser - r/w, user - no access */
0 << 5 | /* domain 0th */
1 << 4 | /* should be "1" */
cache_flags |
1 << 1; /* Section signature */
}
}
static void enable_mmu(void) {
asm volatile("mov r0, #0\n"
"mcr p15, 0, r0, c8, c7, 0\n" /* invalidate TLB */
"mcr p15, 0, r0, c7, c7,0\n" /* invalidate both icache and dcache */
"mrc p15, 0, r0, c1, c0, 0\n"
"orr r0, r0, #1<<0\n" /* enable mmu bit, icache and dcache */
"orr r0, r0, #1<<2\n" /* enable dcache */
"orr r0, r0, #1<<12\n" /* enable icache */
"mcr p15, 0, r0, c1, c0, 0" : : : "r0");
asm volatile("nop \n nop \n nop \n nop");
}
/* Invalidate DCache for this range */
/* Will do write back */
void invalidate_dcache_range(const void *base, unsigned int size) {
unsigned int addr = (((int) base) & ~31); /* Align start to cache line*/
unsigned int end = ((addr+size) & ~31)+64; /* Align end to cache line, pad */
asm volatile(
"inv_start: \n"
"mcr p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */
"add %0, %0, #32 \n"
"cmp %0, %1 \n"
"mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */
"addne %0, %0, #32 \n"
"cmpne %0, %1 \n"
"mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */
"addne %0, %0, #32 \n"
"cmpne %0, %1 \n"
"mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */
"addne %0, %0, #32 \n"
"cmpne %0, %1 \n"
"mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */
"addne %0, %0, #32 \n"
"cmpne %0, %1 \n"
"mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */
"addne %0, %0, #32 \n"
"cmpne %0, %1 \n"
"mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */
"addne %0, %0, #32 \n"
"cmpne %0, %1 \n"
"mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */
"addne %0, %0, #32 \n"
"cmpne %0, %1 \n"
"bne inv_start \n"
"mov %0, #0\n"
"mcr p15,0,%0,c7,c10,4\n" /* Drain write buffer */
: : "r" (addr), "r" (end));
}
/* clean DCache for this range */
/* forces DCache writeback for the specified range */
void clean_dcache_range(const void *base, unsigned int size) {
unsigned int addr = (int) base;
unsigned int end = addr+size+32;
asm volatile(
"bic %0, %0, #31 \n"
"clean_start: \n"
"mcr p15, 0, %0, c7, c10, 1 \n" /* Clean this line */
"add %0, %0, #32 \n"
"cmp %0, %1 \n"
"mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */
"addlo %0, %0, #32 \n"
"cmplo %0, %1 \n"
"mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */
"addlo %0, %0, #32 \n"
"cmplo %0, %1 \n"
"mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */
"addlo %0, %0, #32 \n"
"cmplo %0, %1 \n"
"mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */
"addlo %0, %0, #32 \n"
"cmplo %0, %1 \n"
"mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */
"addlo %0, %0, #32 \n"
"cmplo %0, %1 \n"
"mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */
"addlo %0, %0, #32 \n"
"cmplo %0, %1 \n"
"mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */
"addlo %0, %0, #32 \n"
"cmplo %0, %1 \n"
"blo clean_start \n"
"mov %0, #0\n"
"mcr p15,0,%0,c7,c10,4 \n" /* Drain write buffer */
: : "r" (addr), "r" (end));
}
/* Dump DCache for this range */
/* Will *NOT* do write back */
void dump_dcache_range(const void *base, unsigned int size) {
unsigned int addr = (int) base;
unsigned int end = addr+size;
asm volatile(
"tst %0, #31 \n" /* Check to see if low five bits are set */
"bic %0, %0, #31 \n" /* Clear them */
"mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line, if those bits were set */
"add %0, %0, #32 \n" /* Move to the next cache line */
"tst %1, #31 \n" /* Check last line for bits set */
"bic %1, %1, #31 \n" /* Clear those bits */
"mcrne p15, 0, %1, c7, c14, 1 \n" /* Clean and invalidate this line, if not cache aligned */
"dump_start: \n"
"mcr p15, 0, %0, c7, c6, 1 \n" /* Invalidate this line */
"add %0, %0, #32 \n" /* Next cache line */
"cmp %0, %1 \n"
"bne dump_start \n"
"dump_end: \n"
"mcr p15,0,%0,c7,c10,4 \n" /* Drain write buffer */
: : "r" (addr), "r" (end));
}
/* Cleans entire DCache */
void clean_dcache(void)
{
unsigned int index, addr;
for(index = 0; index <= 63; index++) {
addr = (0 << 5) | (index << 26);
asm volatile(
"mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */
: : "r" (addr));
addr = (1 << 5) | (index << 26);
asm volatile(
"mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */
: : "r" (addr));
addr = (2 << 5) | (index << 26);
asm volatile(
"mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */
: : "r" (addr));
addr = (3 << 5) | (index << 26);
asm volatile(
"mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */
: : "r" (addr));
addr = (4 << 5) | (index << 26);
asm volatile(
"mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */
: : "r" (addr));
addr = (5 << 5) | (index << 26);
asm volatile(
"mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */
: : "r" (addr));
addr = (6 << 5) | (index << 26);
asm volatile(
"mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */
: : "r" (addr));
addr = (7 << 5) | (index << 26);
asm volatile(
"mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */
: : "r" (addr));
}
}

View file

@ -0,0 +1,35 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* 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);

View file

@ -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;
}
}

View file

@ -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 <stdbool.h>
#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 */

View file

@ -0,0 +1,225 @@
#include "config.h"
#include "cpu.h"
#include <stdbool.h>
#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;
}

View file

@ -0,0 +1,28 @@
#include "config.h"
#include "cpu.h"
#include <stdbool.h>
#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);

View file

@ -0,0 +1,96 @@
#include "kernel.h"
#include "system.h"
#include "panic.h"
#include "lcd.h"
#include <stdio.h>
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

View file

@ -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 */

View file

@ -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 <stdbool.h>
#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
}

View file

@ -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

View file

@ -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);
}