From 5cf79723ecb9a22de432d169ce65eb19aa651e8a Mon Sep 17 00:00:00 2001 From: Rafaël Carré Date: Tue, 3 Jan 2012 04:39:56 +0000 Subject: move PP specific files to pp/ git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31533 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 40 +- firmware/target/arm/adc-pp5020.c | 179 ---- firmware/target/arm/ascodec-pp.c | 82 -- firmware/target/arm/ata-pp5002.c | 53 - firmware/target/arm/ata-pp5020.c | 248 ----- firmware/target/arm/ata-sd-pp.c | 1387 ------------------------- firmware/target/arm/audio-pp.c | 135 --- firmware/target/arm/boot-pp502x-bl-usb.lds | 133 --- firmware/target/arm/crt0-pp-bl.S | 217 ---- firmware/target/arm/crt0-pp.S | 430 -------- firmware/target/arm/crt0-pp502x-bl-usb.S | 367 ------- firmware/target/arm/debug-pp.c | 232 ----- firmware/target/arm/i2c-pp.c | 314 ------ firmware/target/arm/i2s-pp.c | 95 -- firmware/target/arm/iriver/boot.lds | 2 +- firmware/target/arm/kernel-pp.c | 64 -- firmware/target/arm/pcm-pp.c | 734 ------------- firmware/target/arm/philips/boot.lds | 2 +- firmware/target/arm/pp/adc-pp5020.c | 179 ++++ firmware/target/arm/pp/ascodec-pp.c | 82 ++ firmware/target/arm/pp/ata-pp5002.c | 53 + firmware/target/arm/pp/ata-pp5020.c | 248 +++++ firmware/target/arm/pp/ata-sd-pp.c | 1387 +++++++++++++++++++++++++ firmware/target/arm/pp/audio-pp.c | 135 +++ firmware/target/arm/pp/boot-pp502x-bl-usb.lds | 133 +++ firmware/target/arm/pp/crt0-pp-bl.S | 217 ++++ firmware/target/arm/pp/crt0-pp.S | 430 ++++++++ firmware/target/arm/pp/crt0-pp502x-bl-usb.S | 367 +++++++ firmware/target/arm/pp/debug-pp.c | 232 +++++ firmware/target/arm/pp/i2c-pp.c | 314 ++++++ firmware/target/arm/pp/i2s-pp.c | 95 ++ firmware/target/arm/pp/kernel-pp.c | 64 ++ firmware/target/arm/pp/pcm-pp.c | 734 +++++++++++++ firmware/target/arm/pp/system-pp5002.c | 227 ++++ firmware/target/arm/pp/system-pp502x.c | 607 +++++++++++ firmware/target/arm/pp/thread-pp.c | 554 ++++++++++ firmware/target/arm/pp/timer-pp.c | 86 ++ firmware/target/arm/pp/usb-fw-pp5002.c | 75 ++ firmware/target/arm/pp/usb-fw-pp502x.c | 308 ++++++ firmware/target/arm/pp/wmcodec-pp.c | 112 ++ firmware/target/arm/sandisk/boot.lds | 2 +- firmware/target/arm/system-pp5002.c | 227 ---- firmware/target/arm/system-pp502x.c | 607 ----------- firmware/target/arm/thread-pp.c | 554 ---------- firmware/target/arm/timer-pp.c | 86 -- firmware/target/arm/usb-fw-pp5002.c | 75 -- firmware/target/arm/usb-fw-pp502x.c | 308 ------ firmware/target/arm/wmcodec-pp.c | 112 -- 48 files changed, 6662 insertions(+), 6662 deletions(-) delete mode 100644 firmware/target/arm/adc-pp5020.c delete mode 100644 firmware/target/arm/ascodec-pp.c delete mode 100644 firmware/target/arm/ata-pp5002.c delete mode 100644 firmware/target/arm/ata-pp5020.c delete mode 100644 firmware/target/arm/ata-sd-pp.c delete mode 100644 firmware/target/arm/audio-pp.c delete mode 100644 firmware/target/arm/boot-pp502x-bl-usb.lds delete mode 100644 firmware/target/arm/crt0-pp-bl.S delete mode 100644 firmware/target/arm/crt0-pp.S delete mode 100644 firmware/target/arm/crt0-pp502x-bl-usb.S delete mode 100644 firmware/target/arm/debug-pp.c delete mode 100644 firmware/target/arm/i2c-pp.c delete mode 100644 firmware/target/arm/i2s-pp.c delete mode 100644 firmware/target/arm/kernel-pp.c delete mode 100644 firmware/target/arm/pcm-pp.c create mode 100644 firmware/target/arm/pp/adc-pp5020.c create mode 100644 firmware/target/arm/pp/ascodec-pp.c create mode 100644 firmware/target/arm/pp/ata-pp5002.c create mode 100644 firmware/target/arm/pp/ata-pp5020.c create mode 100644 firmware/target/arm/pp/ata-sd-pp.c create mode 100644 firmware/target/arm/pp/audio-pp.c create mode 100644 firmware/target/arm/pp/boot-pp502x-bl-usb.lds create mode 100644 firmware/target/arm/pp/crt0-pp-bl.S create mode 100644 firmware/target/arm/pp/crt0-pp.S create mode 100644 firmware/target/arm/pp/crt0-pp502x-bl-usb.S create mode 100644 firmware/target/arm/pp/debug-pp.c create mode 100644 firmware/target/arm/pp/i2c-pp.c create mode 100644 firmware/target/arm/pp/i2s-pp.c create mode 100644 firmware/target/arm/pp/kernel-pp.c create mode 100644 firmware/target/arm/pp/pcm-pp.c create mode 100644 firmware/target/arm/pp/system-pp5002.c create mode 100644 firmware/target/arm/pp/system-pp502x.c create mode 100644 firmware/target/arm/pp/thread-pp.c create mode 100644 firmware/target/arm/pp/timer-pp.c create mode 100644 firmware/target/arm/pp/usb-fw-pp5002.c create mode 100644 firmware/target/arm/pp/usb-fw-pp502x.c create mode 100644 firmware/target/arm/pp/wmcodec-pp.c delete mode 100644 firmware/target/arm/system-pp5002.c delete mode 100644 firmware/target/arm/system-pp502x.c delete mode 100644 firmware/target/arm/thread-pp.c delete mode 100644 firmware/target/arm/timer-pp.c delete mode 100644 firmware/target/arm/usb-fw-pp5002.c delete mode 100644 firmware/target/arm/usb-fw-pp502x.c delete mode 100644 firmware/target/arm/wmcodec-pp.c diff --git a/firmware/SOURCES b/firmware/SOURCES index 1eab0d5de8..a52f01494d 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -480,7 +480,7 @@ target/arm/system-arm.c #if CONFIG_STORAGE & STORAGE_ATA # ifdef CPU_PP502x -target/arm/ata-pp5020.c +target/arm/pp/ata-pp5020.c # endif # if CONFIG_CPU == DM320 || defined(CPU_PP502x) target/arm/ata-as-arm.S @@ -502,7 +502,7 @@ target/arm/ipod/powermgmt-ipod-pcf.c #endif /* CPU_PP && IPOD_ARCH */ #if CONFIG_I2C == I2C_PP5024 || CONFIG_I2C == I2C_PP5020 || CONFIG_I2C == I2C_PP5002 -target/arm/i2c-pp.c +target/arm/pp/i2c-pp.c #elif CONFIG_I2C == I2C_PNX0101 target/arm/pnx0101/i2c-pnx0101.c #elif CONFIG_I2C == I2C_TCC780X || CONFIG_I2C == I2C_TCC77X @@ -589,36 +589,36 @@ target/arm/as3525/pcm-as3525.c #endif /* CONFIG_CPU == AS3525 */ #if defined(CPU_PP) -target/arm/i2s-pp.c -target/arm/kernel-pp.c -target/arm/timer-pp.c +target/arm/pp/i2s-pp.c +target/arm/pp/kernel-pp.c +target/arm/pp/timer-pp.c # if CONFIG_STORAGE & STORAGE_SD -target/arm/ata-sd-pp.c +target/arm/pp/ata-sd-pp.c # endif # if !defined(HAVE_AS3514) && !defined(HAVE_AK4537) -target/arm/wmcodec-pp.c +target/arm/pp/wmcodec-pp.c # endif #if CONFIG_CPU == PP5002 -target/arm/system-pp5002.c -target/arm/usb-fw-pp5002.c -target/arm/ata-pp5002.c +target/arm/pp/system-pp5002.c +target/arm/pp/usb-fw-pp5002.c +target/arm/pp/ata-pp5002.c #elif defined CPU_PP502x -target/arm/usb-fw-pp502x.c -target/arm/system-pp502x.c +target/arm/pp/usb-fw-pp502x.c +target/arm/pp/system-pp502x.c #endif #ifdef BOOTLOADER #ifdef HAVE_BOOTLOADER_USB_MODE -target/arm/crt0-pp502x-bl-usb.S +target/arm/pp/crt0-pp502x-bl-usb.S #else -target/arm/crt0-pp-bl.S +target/arm/pp/crt0-pp-bl.S #endif /* HAVE_BOOTLOADER_USB_MODE */ #else /* !BOOTLOADER */ -target/arm/pcm-pp.c -target/arm/debug-pp.c +target/arm/pp/pcm-pp.c +target/arm/pp/debug-pp.c #if !defined(SANSA_E200) && !defined(SANSA_C200) -target/arm/audio-pp.c +target/arm/pp/audio-pp.c #endif /* SANSA_E200 */ -target/arm/crt0-pp.S +target/arm/pp/crt0-pp.S #endif #elif CONFIG_CPU == PNX0101 target/arm/pnx0101/crt0-pnx0101.S @@ -744,7 +744,7 @@ drivers/audio/tsc2100.c #ifdef HAVE_AS3514 # ifdef CPU_PP -target/arm/ascodec-pp.c +target/arm/pp/ascodec-pp.c # endif # if !defined(BOOTLOADER) || defined(CPU_PP) target/arm/adc-as3514.c @@ -758,7 +758,7 @@ target/arm/powermgmt-ascodec.c # ifdef IPOD_ARCH target/arm/ipod/adc-ipod-pcf.c # else -target/arm/adc-pp5020.c +target/arm/pp/adc-pp5020.c # endif /* IPOD_ARCH */ #elif CONFIG_I2C == I2C_PP5002 diff --git a/firmware/target/arm/adc-pp5020.c b/firmware/target/arm/adc-pp5020.c deleted file mode 100644 index 2d75a7e25f..0000000000 --- a/firmware/target/arm/adc-pp5020.c +++ /dev/null @@ -1,179 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2006 by Barry Wardell - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * 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 "kernel.h" -#include "thread.h" -#include "adc.h" - -#define ADC_ADDR (*(volatile unsigned long*)(0x7000ad00)) -#define ADC_STATUS (*(volatile unsigned long*)(0x7000ad04)) -#define ADC_DATA_1 (*(volatile unsigned long*)(0x7000ad20)) -#define ADC_DATA_2 (*(volatile unsigned long*)(0x7000ad24)) -#define ADC_INIT (*(volatile unsigned long*)(0x7000ad2c)) - -#if defined(PBELL_VIBE500) -#define ADC_UNK (*(volatile unsigned long*)(0x7000002c)) -#endif - -static unsigned short adcdata[NUM_ADC_CHANNELS]; - -/* Scan ADC so that adcdata[channel] gets updated. */ -unsigned short adc_scan(int channel) -{ - unsigned int adc_data_1; - unsigned int adc_data_2; - - if (channel >= NUM_ADC_CHANNELS) - return 0; - - /* Start conversion */ - ADC_ADDR |= 0x80000000; - - /* Wait for conversion to complete */ - while((ADC_STATUS & (0x40<<8*channel))==0); - - /* Stop conversion */ - ADC_ADDR &=~ 0x80000000; - - /* ADC_DATA_1 and ADC_DATA_2 are both four bytes, one byte per channel. - For each channel, ADC_DATA_1 stores the 8-bit msb, ADC_DATA_2 stores the - 2-bit lsb (in bits 0 and 1). Each channel is 10 bits total. */ - adc_data_1 = ((ADC_DATA_1 >> (8*channel)) & 0xff); - adc_data_2 = ((ADC_DATA_2 >> (8*channel+6)) & 0x3); - - adcdata[channel] = (adc_data_1<<2 | adc_data_2); - -#if !(defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330)) - /* ADC values read low if PLL is enabled */ - if(PLL_CONTROL & 0x80000000){ - adcdata[channel] += 0x14; - if(adcdata[channel] > 0x400) - adcdata[channel] = 0x400; - } -#endif - - return adcdata[channel]; -} - -/* Read 10-bit channel data */ -unsigned short adc_read(int channel) -{ - return adcdata[channel]; -} - -static int adc_counter; - -static void adc_tick(void) -{ - if(++adc_counter == HZ) - { - adc_counter = 0; - adc_scan(0); - adc_scan(1); - adc_scan(2); - adc_scan(3); - } -} - -/* Figured out from how the OF does things */ -void adc_init(void) -{ -#if defined(PBELL_VIBE500) - ADC_UNK |= 0x1000; -#endif - -#if defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) - ADC_INIT = 0; -#else - ADC_INIT |= 1; - ADC_INIT |= 0x40000000; -#endif - udelay(100); - - /* Reset ADC */ - DEV_RS2 |= 0x20; - udelay(100); - - DEV_RS2 &=~ 0x20; - udelay(100); - - /* Enable ADC */ - DEV_EN2 |= 0x20; - udelay(100); - - ADC_CLOCK_SRC |= 0x3; - udelay(100); - - ADC_ADDR = 0; - ADC_ADDR |= 0x40; - -#if !(defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330)) - ADC_ADDR |= 0x20000000; - udelay(100); - - ADC_INIT; - ADC_INIT = 0; - udelay(100); -#endif - - ADC_STATUS = 0; - - /* Enable channel 0 (battery) */ - DEV_INIT1 &=~0x3; - ADC_ADDR |= 0x1000000; - ADC_STATUS |= 0x20; - - /* Enable channel 1 (unknown) */ - DEV_INIT1 &=~30; - ADC_ADDR |= 0x2000000; - ADC_STATUS |= 0x2000; - -#if defined (IRIVER_H10) || defined(IRIVER_H10_5GB) || \ - defined(MROBE_100) - /* Enable channel 2 (H10:remote) */ - DEV_INIT1 &=~0x300; - DEV_INIT1 |= 0x100; - ADC_ADDR |= 0x4000000; - ADC_STATUS |= 0x200000; - - /* Enable channel 3 (H10:scroll pad) */ - DEV_INIT1 &=~0x3000; - DEV_INIT1 |= 0x1000; - ADC_ADDR |= 0x8000000; - ADC_STATUS |= 0x20000000; -#endif - -#if defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) - ADC_INIT |= 0x80000000; - udelay(100); - ADC_INIT = 0; -#endif - - /* Force a scan of all channels to get initial values */ - adc_scan(0); - adc_scan(1); - adc_scan(2); - adc_scan(3); - - tick_add_task(adc_tick); -} diff --git a/firmware/target/arm/ascodec-pp.c b/firmware/target/arm/ascodec-pp.c deleted file mode 100644 index 49a69d1a11..0000000000 --- a/firmware/target/arm/ascodec-pp.c +++ /dev/null @@ -1,82 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Driver for AS3514 audio codec - * - * Copyright (c) 2007 Daniel Ankers - * Copyright (c) 2007 Christian Gmeiner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "cpu.h" -#include "system.h" - -#include "audiohw.h" -#include "i2s.h" -#include "ascodec-target.h" - -/* - * Initialise the PP I2C and I2S. - */ -void audiohw_init(void) -{ - /* normal outputs for CDI and I2S pin groups */ - DEV_INIT2 &= ~0x300; - - /*mini2?*/ - DEV_INIT1 &=~0x3000000; - /*mini2?*/ - - /* I2S device reset */ - DEV_RS |= DEV_I2S; - DEV_RS &=~DEV_I2S; - - /* I2S device enable */ - DEV_EN |= DEV_I2S; - - /* enable external dev clock clocks */ - DEV_EN |= DEV_EXTCLOCKS; - - /* external dev clock to 24MHz */ - outl(inl(0x70000018) & ~0xc, 0x70000018); - -#ifdef SANSA_E200 - /* Prevent pops on startup */ - GPIOG_ENABLE |= 0x08; - GPIO_SET_BITWISE(GPIOG_OUTPUT_VAL, 0x08); - GPIOG_OUTPUT_EN |= 0x08; -#endif - - i2s_reset(); - - audiohw_preinit(); -} - -void ascodec_suppressor_on(bool on) -{ - /* CHECK: Good for c200 too? */ -#ifdef SANSA_E200 - if (on) { - /* Set pop prevention */ - GPIO_SET_BITWISE(GPIOG_OUTPUT_VAL, 0x08); - } else { - /* Release pop prevention */ - GPIO_CLEAR_BITWISE(GPIOG_OUTPUT_VAL, 0x08); - } -#else - (void)on; -#endif -} diff --git a/firmware/target/arm/ata-pp5002.c b/firmware/target/arm/ata-pp5002.c deleted file mode 100644 index 5ab0e9ddc7..0000000000 --- a/firmware/target/arm/ata-pp5002.c +++ /dev/null @@ -1,53 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2006 by Barry Wardell - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -/* ATA stuff was taken from the iPod code */ - -#include -#include "system.h" -#include "ata-driver.h" - -void ata_reset() -{ - -} - -void ata_enable(bool on) -{ - /* TODO: Implement ata_enable() */ - (void)on; -} - -bool ata_is_coldstart() -{ - return false; - /* TODO: Implement coldstart variable */ -} - -void ata_device_init() -{ - /* From ipod-ide.c:ipod_ide_register() */ - outl(inl(0xc0003024) | (1 << 7), 0xc0003024); - outl(inl(0xc0003024) & ~(1<<2), 0xc0003024); - - outl(0x10, 0xc0003000); - outl(0x80002150, 0xc0003004); -} diff --git a/firmware/target/arm/ata-pp5020.c b/firmware/target/arm/ata-pp5020.c deleted file mode 100644 index 50a38cb23d..0000000000 --- a/firmware/target/arm/ata-pp5020.c +++ /dev/null @@ -1,248 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2006 by Barry Wardell - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -/* ATA stuff was taken from the iPod code */ - -#include -#include "system.h" -#include "ata-driver.h" - -void ata_reset() -{ - -} - -void ata_enable(bool on) -{ - /* TODO: Implement ata_enable() */ - (void)on; -} - -bool ata_is_coldstart() -{ - return false; - /* TODO: Implement coldstart variable */ -} - -void ata_device_init() -{ -#ifdef SAMSUNG_YH920 - CPU_INT_DIS = (1< 65MHz */ -#else - IDE0_CFG &=~(0x10000000); /* cpu < 65MHz */ -#endif -#endif - - IDE0_PRI_TIMING0 = 0x10; - IDE0_PRI_TIMING1 = 0x80002150; -} - -/* These are PIO timings for 80 Mhz. At 24 Mhz, - the first value is 0 but the rest are the same. - They go in IDE0_PRI_TIMING0. - - Rockbox used 0x10, and test_disk shows that leads to faster PIO. - If 0x10 is incorrect, these timings may be needed with some devices. -static const unsigned long pio80mhz[] = { - 0xC293, 0x43A2, 0x11A1, 0x7232, 0x3131 -}; -*/ - -#ifdef HAVE_ATA_DMA -/* Timings for multi-word and ultra DMA modes. - These go in IDE0_PRI_TIMING1 - */ -static const unsigned long tm_mwdma[] = { - 0xF9F92, 0x56562, 0x45451 -}; - -static const unsigned long tm_udma[] = { - 0x800037C1, 0x80003491, 0x80003371, -#if ATA_MAX_UDMA > 2 - 0x80003271, 0x80003071 -#endif -}; - -#if ATA_MAX_UDMA > 2 -static bool dma_boosted = false; -static bool dma_needs_boost; -#endif - -/* This function sets up registers for 80 Mhz. - Ultra DMA mode 2 works at 30 Mhz. - */ -void ata_dma_set_mode(unsigned char mode) { - int modeidx; - - (*(volatile unsigned long *)(0x600060C4)) = 0xC0000000; /* 80 Mhz */ -#if !defined(IPOD_NANO) - IDE0_CFG &= ~0x10000000; -#endif - - modeidx = mode & 7; - mode &= 0xF8; - if (mode == 0x40 && modeidx <= ATA_MAX_UDMA) { - IDE0_PRI_TIMING1 = tm_udma[modeidx]; -#if ATA_MAX_UDMA > 2 - if (modeidx > 2) - dma_needs_boost = true; - else - dma_needs_boost = false; -#endif - } else if (mode == 0x20 && modeidx <= ATA_MAX_MWDMA) - IDE0_PRI_TIMING1 = tm_mwdma[modeidx]; - -#if !defined(IPOD_NANO) - IDE0_CFG |= 0x20000000; /* >= 50 Mhz */ -#endif -} - -#define IDE_CFG_INTRQ 8 -#define IDE_DMA_CONTROL_READ 8 - -/* This waits for an ATA interrupt using polling. - In ATA_CONTROL, CONTROL_nIEN must be cleared. - */ -STATICIRAM ICODE_ATTR int ata_wait_intrq(void) -{ - long timeout = current_tick + HZ*10; - - do - { - if (IDE0_CFG & IDE_CFG_INTRQ) - return 1; - ata_keep_active(); - yield(); - } while (TIME_BEFORE(current_tick, timeout)); - - return 0; /* timeout */ -} - -/* This function checks if parameters are appropriate for DMA, - and if they are, it sets up for DMA. - - If return value is false, caller may use PIO for this transfer. - - If return value is true, caller must issue a DMA ATA command - and then call ata_dma_finish(). - */ -bool ata_dma_setup(void *addr, unsigned long bytes, bool write) { - /* Require cacheline alignment for reads to prevent interference. */ - if (!write && ((unsigned long)addr & 15)) - return false; - - /* Writes only need to be word-aligned, but by default DMA - * is not used for writing as it appears to be slower. - */ -#ifdef ATA_DMA_WRITES - if (write && ((unsigned long)addr & 3)) - return false; -#else - if (write) - return false; -#endif - -#if ATA_MAX_UDMA > 2 - if (dma_needs_boost && !dma_boosted) { - cpu_boost(true); - dma_boosted = true; - } -#endif - - if (write) { - /* If unflushed, old data may be written to disk */ - commit_dcache(); - } - else { - /* Invalidate cache because new data may be present in RAM */ - commit_discard_dcache(); - } - - /* Clear pending interrupts so ata_dma_finish() can wait for an - interrupt from this transfer - */ - IDE0_CFG |= IDE_CFG_INTRQ; - - IDE_DMA_CONTROL |= 2; - IDE_DMA_LENGTH = bytes - 4; - -#if !defined(BOOTLOADER) || defined (HAVE_BOOTLOADER_USB_MODE) - if ((unsigned long)addr < DRAM_START) - /* Rockbox remaps DRAM to start at 0 */ - IDE_DMA_ADDR = (unsigned long)addr + DRAM_START; - else -#endif - IDE_DMA_ADDR = (unsigned long)addr; - - if (write) - IDE_DMA_CONTROL &= ~IDE_DMA_CONTROL_READ; - else - IDE_DMA_CONTROL |= IDE_DMA_CONTROL_READ; - - IDE0_CFG |= 0x8000; - - return true; -} - -/* This function waits for a DMA transfer to end. - It must be called to finish what ata_dma_setup started. - - Return value is true if DMA completed before the timeout, and false - if a timeout happened. - */ -bool ata_dma_finish(void) { - bool res; - - /* It may be okay to put this at the end of setup */ - IDE_DMA_CONTROL |= 1; - - /* Wait for end of transfer. - Reading standard ATA status while DMA is in progress causes - failures and hangs. Because of that, another wait is used. - */ - res = ata_wait_intrq(); - - IDE0_CFG &= ~0x8000; - IDE_DMA_CONTROL &= ~0x80000001; - -#if ATA_MAX_UDMA > 2 - if (dma_boosted) { - cpu_boost(false); - dma_boosted = false; - } -#endif - - return res; -} - -#endif /* HAVE_ATA_DMA */ diff --git a/firmware/target/arm/ata-sd-pp.c b/firmware/target/arm/ata-sd-pp.c deleted file mode 100644 index f83bb60566..0000000000 --- a/firmware/target/arm/ata-sd-pp.c +++ /dev/null @@ -1,1387 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2006 Daniel Ankers - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "config.h" /* for HAVE_MULTIDRIVE */ -#include "fat.h" -#include "sdmmc.h" -#include "gcc_extensions.h" -#ifdef HAVE_HOTSWAP -#include "sd-pp-target.h" -#endif -#include "ata_idle_notify.h" -#include "system.h" -#include -#include "thread.h" -#include "led.h" -#include "disk.h" -#include "cpu.h" -#include "panic.h" -#include "usb.h" -#include "sd.h" -#include "storage.h" - -#define SECTOR_SIZE 512 -#define BLOCKS_PER_BANK 0x7a7800 - -/* Comparing documentations of various MMC/SD controllers revealed, */ -/* that this controller seems to be a mix of PXA27x, PXA255 and */ -/* some PP specific stuff. The register and bit definitions are */ -/* taken from the 'PXA27x Developers Manual', as it appears to be */ -/* the closest match. Known differences and obscurities are commented.*/ - -#define MMC_STRPCL (*(volatile unsigned int *)(0x70008200)) -#define MMC_STAT (*(volatile unsigned int *)(0x70008204)) -#define MMC_CLKRT (*(volatile unsigned int *)(0x70008208)) -#define MMC_SPI (*(volatile unsigned int *)(0x7000820c)) -#define MMC_CMDAT (*(volatile unsigned int *)(0x70008210)) -#define MMC_RESTO (*(volatile unsigned int *)(0x70008214)) -#define MMC_RDTO (*(volatile unsigned int *)(0x70008218)) -#define MMC_BLKLEN (*(volatile unsigned int *)(0x7000821c)) -#define MMC_NUMBLK (*(volatile unsigned int *)(0x70008220)) -#define MMC_I_MASK (*(volatile unsigned int *)(0x70008224)) -#define MMC_CMD (*(volatile unsigned int *)(0x70008228)) -#define MMC_ARGH (*(volatile unsigned int *)(0x7000822c)) -#define MMC_ARGL (*(volatile unsigned int *)(0x70008230)) -#define MMC_RES (*(volatile unsigned int *)(0x70008234)) - -/* PXA255/27x have separate RX/TX FIFOs with 32x8 bit */ -/* PP502x has a combined Data FIFO with 16x16 bit */ -#define MMC_DATA_FIFO (*(volatile unsigned int *)(0x70008280)) - -/* PP specific registers, no other controller seem to have such. */ -#define MMC_SD_STATE (*(volatile unsigned int *)(0x70008238)) -#define MMC_INIT_1 (*(volatile unsigned int *)(0x70008240)) -#define MMC_INIT_2 (*(volatile unsigned int *)(0x70008244)) - -/* MMC_STAT bits */ -#define STAT_SDIO_SUSPEND_ACK (1 << 16) -#define STAT_SDIO_INT (1 << 15) -#define STAT_RD_STALLED (1 << 14) -#define STAT_END_CMD_RES (1 << 13) -#define STAT_PRG_DONE (1 << 12) -#define STAT_DATA_TRAN_DONE (1 << 11) -#define STAT_SPI_WR_ERR (1 << 10) -#define STAT_FLASH_ERR (1 << 9) -#define STAT_CLK_EN (1 << 8) -#define STAT_RECV_FIFO_FULL (1 << 7) /* taken from PXA255 */ -#define STAT_XMIT_FIFO_EMPTY (1 << 6) /* taken from PXA255 */ -#define STAT_RES_CRC_ERR (1 << 5) -#define STAT_DAT_ERR_TOKEN (1 << 4) -#define STAT_CRC_RD_ERR (1 << 3) -#define STAT_CRC_WR_ERR (1 << 2) -#define STAT_TIME_OUT_RES (1 << 1) -#define STAT_TIME_OUT_READ (1) -#define STAT_ERROR_BITS (0x3f) - -/* MMC_CMDAT bits */ -/* Some of the bits used by the OF don't make much sense with these */ -/* definitions. So they're probably different between PXA and PP502x */ -/* Bits 0-5 appear to match though. */ -#define CMDAT_SDIO_RESUME (1 << 13) -#define CMDAT_SDIO_SUSPEND (1 << 12) -#define CMDAT_SDIO_INT_EN (1 << 11) -#define CMDAT_STOP_TRAN (1 << 10) -#define CMDAT_SD_4DAT (1 << 8) -#define CMDAT_DMA_EN (1 << 7) -#define CMDAT_INIT (1 << 6) -#define CMDAT_BUSY (1 << 5) -#define CMDAT_STRM_BLK (1 << 4) -#define CMDAT_WR_RD (1 << 3) -#define CMDAT_DATA_EN (1 << 2) -#define CMDAT_RES_TYPE3 (3) -#define CMDAT_RES_TYPE2 (2) -#define CMDAT_RES_TYPE1 (1) - -/* MMC_I_MASK bits */ -/* PP502x apparently only has bits 0-3 */ -#define I_MASK_SDIO_SUSPEND_ACK (1 << 12) -#define I_MASK_SDIO_INT (1 << 11) -#define I_MASK_RD_STALLED (1 << 10) -#define I_MASK_RES_ERR (1 << 9) -#define I_MASK_DAT_ERR (1 << 8) -#define I_MASK_TINT (1 << 7) -#define I_MASK_TXFIFO_WR_REQ (1 << 6) -#define I_MASK_RXFIFO_RD_REQ (1 << 5) -#define I_MASK_CLK_IS_OFF (1 << 4) -#define I_MASK_STOP_CMD (1 << 3) -#define I_MASK_END_CMD_RES (1 << 2) -#define I_MASK_PRG_DONE (1 << 1) -#define I_MASK_DATA_TRAN_DONE (1 << 0) - -#define FIFO_LEN 16 /* FIFO is 16 words deep */ - -#define EC_OK 0 -#define EC_FAILED 1 -#define EC_NOCARD 2 -#define EC_WAIT_STATE_FAILED 3 -#define EC_CHECK_TIMEOUT_FAILED 4 -#define EC_POWER_UP 5 -#define EC_READ_TIMEOUT 6 -#define EC_WRITE_TIMEOUT 7 -#define EC_TRAN_SEL_BANK 8 -#define EC_TRAN_READ_ENTRY 9 -#define EC_TRAN_READ_EXIT 10 -#define EC_TRAN_WRITE_ENTRY 11 -#define EC_TRAN_WRITE_EXIT 12 -#define EC_FIFO_SEL_BANK_EMPTY 13 -#define EC_FIFO_SEL_BANK_DONE 14 -#define EC_FIFO_ENA_BANK_EMPTY 15 -#define EC_FIFO_READ_FULL 16 -#define EC_FIFO_WR_EMPTY 17 -#define EC_FIFO_WR_DONE 18 -#define EC_COMMAND 19 -#define NUM_EC 20 - -/* for compatibility */ -static long last_disk_activity = -1; - -/** static, private data **/ -static bool initialized = false; -static unsigned int sd_thread_id = 0; - -#define Q_CLOSE 1 - -static long next_yield = 0; -#define MIN_YIELD_PERIOD 1000 - -static tCardInfo card_info[2]; -static tCardInfo *currcard = NULL; /* current active card */ - -struct sd_card_status -{ - int retry; - int retry_max; -}; - -static struct sd_card_status sd_status[NUM_DRIVES] = -{ - { 0, 1 }, -#ifdef HAVE_MULTIDRIVE - { 0, 10 } -#endif -}; - -/* Shoot for around 75% usage */ -static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x1c0)/sizeof(long)]; -static const char sd_thread_name[] = "ata/sd"; -static struct mutex sd_mtx SHAREDBSS_ATTR; -static struct event_queue sd_queue SHAREDBSS_ATTR; - -#ifdef HAVE_HOTSWAP -static int sd_first_drive = 0; -#endif - -/* Posted when card plugged status has changed */ -#define SD_HOTSWAP 1 -/* Actions taken by sd_thread when card status has changed */ -enum sd_thread_actions -{ - SDA_NONE = 0x0, - SDA_UNMOUNTED = 0x1, - SDA_MOUNTED = 0x2 -}; - -/* Private Functions */ - -static unsigned int check_time[NUM_EC]; - -static inline bool sd_check_timeout(long timeout, int id) -{ - return !TIME_AFTER(USEC_TIMER, check_time[id] + timeout); -} - -static bool sd_poll_status(unsigned int trigger, long timeout) -{ - long t = USEC_TIMER; - - while ((MMC_STAT & trigger) == 0) - { - long time = USEC_TIMER; - - if (TIME_AFTER(time, next_yield)) - { - long ty = USEC_TIMER; - yield(); - timeout += USEC_TIMER - ty; - next_yield = ty + MIN_YIELD_PERIOD; - } - - if (TIME_AFTER(time, t + timeout)) - return false; - } - - return true; -} - -static int sd_command(unsigned int cmd, unsigned long arg1, - unsigned long *response, unsigned int cmdat) -{ - int i, words; /* Number of 16 bit words to read from MMC_RES */ - unsigned int data[9]; - - MMC_CMD = cmd; - MMC_ARGH = (unsigned int)((arg1 & 0xffff0000) >> 16); - MMC_ARGL = (unsigned int)((arg1 & 0xffff)); - MMC_CMDAT = cmdat; - - if (!sd_poll_status(STAT_END_CMD_RES, 100000)) - return -EC_COMMAND; - - if ((MMC_STAT & STAT_ERROR_BITS) != 0) - /* Error sending command */ - return -EC_COMMAND - (MMC_STAT & STAT_ERROR_BITS)*100; - - if (cmd == SD_GO_IDLE_STATE) - return 0; /* no response here */ - - words = (cmdat == CMDAT_RES_TYPE2) ? 9 : 3; - - for (i = 0; i < words; i++) /* MMC_RES is read MSB first */ - data[i] = MMC_RES; /* Read most significant 16-bit word */ - - if (response == NULL) - { - /* response discarded */ - } - else if (cmdat == CMDAT_RES_TYPE2) - { - /* Response type 2 has the following structure: - * [135:135] Start Bit - '0' - * [134:134] Transmission bit - '0' - * [133:128] Reserved - '111111' - * [127:001] CID or CSD register including internal CRC7 - * [000:000] End Bit - '1' - */ - response[3] = (data[0]<<24) + (data[1]<<8) + (data[2]>>8); - response[2] = (data[2]<<24) + (data[3]<<8) + (data[4]>>8); - response[1] = (data[4]<<24) + (data[5]<<8) + (data[6]>>8); - response[0] = (data[6]<<24) + (data[7]<<8) + (data[8]>>8); - } - else - { - /* Response types 1, 1b, 3, 6, 7 have the following structure: - * Types 4 and 5 are not supported. - * - * [47] Start bit - '0' - * [46] Transmission bit - '0' - * [45:40] R1, R1b, R6, R7: Command index - * R3: Reserved - '111111' - * [39:8] R1, R1b: Card Status - * R3: OCR Register - * R6: [31:16] RCA - * [15: 0] Card Status Bits 23, 22, 19, 12:0 - * [23] COM_CRC_ERROR - * [22] ILLEGAL_COMMAND - * [19] ERROR - * [12:9] CURRENT_STATE - * [8] READY_FOR_DATA - * [7:6] - * [5] SD_APP_CMD - * [4] - * [3] AKE_SEQ_ERROR - * [2] Reserved - * [1:0] Reserved for test mode - * R7: [19:16] Voltage accepted - * [15:8] echo-back of check pattern - * [7:1] R1, R1b: CRC7 - * R3: Reserved - '1111111' - * [0] End Bit - '1' - */ - response[0] = (data[0]<<24) + (data[1]<<8) + (data[2]>>8); - } - - return 0; -} - -static int sd_wait_for_state(unsigned int state, int id) -{ - unsigned long response = 0; - unsigned int timeout = 0x80000; - - check_time[id] = USEC_TIMER; - - while (1) - { - int ret = sd_command(SD_SEND_STATUS, currcard->rca, &response, CMDAT_RES_TYPE1); - long us; - - if (ret < 0) - return ret*100 - id; - - if (((response >> 9) & 0xf) == state) - { - MMC_SD_STATE = state; - return 0; - } - - if (!sd_check_timeout(timeout, id)) - return -EC_WAIT_STATE_FAILED*100 - id; - - us = USEC_TIMER; - if (TIME_AFTER(us, next_yield)) - { - yield(); - timeout += USEC_TIMER - us; - next_yield = us + MIN_YIELD_PERIOD; - } - } -} - - -static inline bool card_detect_target(void) -{ -#ifdef HAVE_HOTSWAP -#ifdef SANSA_E200 - return (GPIOA_INPUT_VAL & 0x80) == 0; /* low active */ -#elif defined SANSA_C200 - return (GPIOL_INPUT_VAL & 0x08) != 0; /* high active */ -#endif -#else - return false; -#endif -} - - -static inline void copy_read_sectors_fast(unsigned char **buf) -{ - /* Copy one chunk of 16 words using best method for start alignment */ - switch ( (intptr_t)*buf & 3 ) - { - case 0: - asm volatile ( - "ldmia %[data], { r2-r9 } \r\n" - "orr r2, r2, r3, lsl #16 \r\n" - "orr r4, r4, r5, lsl #16 \r\n" - "orr r6, r6, r7, lsl #16 \r\n" - "orr r8, r8, r9, lsl #16 \r\n" - "stmia %[buf]!, { r2, r4, r6, r8 } \r\n" - "ldmia %[data], { r2-r9 } \r\n" - "orr r2, r2, r3, lsl #16 \r\n" - "orr r4, r4, r5, lsl #16 \r\n" - "orr r6, r6, r7, lsl #16 \r\n" - "orr r8, r8, r9, lsl #16 \r\n" - "stmia %[buf]!, { r2, r4, r6, r8 } \r\n" - : [buf]"+&r"(*buf) - : [data]"r"(&MMC_DATA_FIFO) - : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9" - ); - break; - case 1: - asm volatile ( - "ldmia %[data], { r2-r9 } \r\n" - "orr r3, r2, r3, lsl #16 \r\n" - "strb r3, [%[buf]], #1 \r\n" - "mov r3, r3, lsr #8 \r\n" - "strh r3, [%[buf]], #2 \r\n" - "mov r3, r3, lsr #16 \r\n" - "orr r3, r3, r4, lsl #8 \r\n" - "orr r3, r3, r5, lsl #24 \r\n" - "mov r5, r5, lsr #8 \r\n" - "orr r5, r5, r6, lsl #8 \r\n" - "orr r5, r5, r7, lsl #24 \r\n" - "mov r7, r7, lsr #8 \r\n" - "orr r7, r7, r8, lsl #8 \r\n" - "orr r7, r7, r9, lsl #24 \r\n" - "mov r2, r9, lsr #8 \r\n" - "stmia %[buf]!, { r3, r5, r7 } \r\n" - "ldmia %[data], { r3-r10 } \r\n" - "orr r2, r2, r3, lsl #8 \r\n" - "orr r2, r2, r4, lsl #24 \r\n" - "mov r4, r4, lsr #8 \r\n" - "orr r4, r4, r5, lsl #8 \r\n" - "orr r4, r4, r6, lsl #24 \r\n" - "mov r6, r6, lsr #8 \r\n" - "orr r6, r6, r7, lsl #8 \r\n" - "orr r6, r6, r8, lsl #24 \r\n" - "mov r8, r8, lsr #8 \r\n" - "orr r8, r8, r9, lsl #8 \r\n" - "orr r8, r8, r10, lsl #24 \r\n" - "mov r10, r10, lsr #8 \r\n" - "stmia %[buf]!, { r2, r4, r6, r8 } \r\n" - "strb r10, [%[buf]], #1 \r\n" - : [buf]"+&r"(*buf) - : [data]"r"(&MMC_DATA_FIFO) - : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10" - ); - break; - case 2: - asm volatile ( - "ldmia %[data], { r2-r9 } \r\n" - "strh r2, [%[buf]], #2 \r\n" - "orr r3, r3, r4, lsl #16 \r\n" - "orr r5, r5, r6, lsl #16 \r\n" - "orr r7, r7, r8, lsl #16 \r\n" - "stmia %[buf]!, { r3, r5, r7 } \r\n" - "ldmia %[data], { r2-r8, r10 } \r\n" - "orr r2, r9, r2, lsl #16 \r\n" - "orr r3, r3, r4, lsl #16 \r\n" - "orr r5, r5, r6, lsl #16 \r\n" - "orr r7, r7, r8, lsl #16 \r\n" - "stmia %[buf]!, { r2, r3, r5, r7 } \r\n" - "strh r10, [%[buf]], #2 \r\n" - : [buf]"+&r"(*buf) - : [data]"r"(&MMC_DATA_FIFO) - : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10" - ); - break; - case 3: - asm volatile ( - "ldmia %[data], { r2-r9 } \r\n" - "orr r3, r2, r3, lsl #16 \r\n" - "strb r3, [%[buf]], #1 \r\n" - "mov r3, r3, lsr #8 \r\n" - "orr r3, r3, r4, lsl #24 \r\n" - "mov r4, r4, lsr #8 \r\n" - "orr r5, r4, r5, lsl #8 \r\n" - "orr r5, r5, r6, lsl #24 \r\n" - "mov r6, r6, lsr #8 \r\n" - "orr r7, r6, r7, lsl #8 \r\n" - "orr r7, r7, r8, lsl #24 \r\n" - "mov r8, r8, lsr #8 \r\n" - "orr r2, r8, r9, lsl #8 \r\n" - "stmia %[buf]!, { r3, r5, r7 } \r\n" - "ldmia %[data], { r3-r10 } \r\n" - "orr r2, r2, r3, lsl #24 \r\n" - "mov r3, r3, lsr #8 \r\n" - "orr r4, r3, r4, lsl #8 \r\n" - "orr r4, r4, r5, lsl #24 \r\n" - "mov r5, r5, lsr #8 \r\n" - "orr r6, r5, r6, lsl #8 \r\n" - "orr r6, r6, r7, lsl #24 \r\n" - "mov r7, r7, lsr #8 \r\n" - "orr r8, r7, r8, lsl #8 \r\n" - "orr r8, r8, r9, lsl #24 \r\n" - "mov r9, r9, lsr #8 \r\n" - "orr r10, r9, r10, lsl #8 \r\n" - "stmia %[buf]!, { r2, r4, r6, r8 } \r\n" - "strh r10, [%[buf]], #2 \r\n" - "mov r10, r10, lsr #16 \r\n" - "strb r10, [%[buf]], #1 \r\n" - : [buf]"+&r"(*buf) - : [data]"r"(&MMC_DATA_FIFO) - : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10" - ); - break; - } -} - -static inline void copy_read_sectors_slow(unsigned char** buf) -{ - int cnt = FIFO_LEN; - int t; - - /* Copy one chunk of 16 words */ - asm volatile ( - "1: \r\n" - "ldrh %[t], [%[data]] \r\n" - "strb %[t], [%[buf]], #1 \r\n" - "mov %[t], %[t], lsr #8 \r\n" - "strb %[t], [%[buf]], #1 \r\n" - "subs %[cnt], %[cnt], #1 \r\n" - "bgt 1b \r\n" - : [cnt]"+&r"(cnt), [buf]"+&r"(*buf), - [t]"=&r"(t) - : [data]"r"(&MMC_DATA_FIFO) - ); -} - -/* Writes have to be kept slow for now */ -static inline void copy_write_sectors(const unsigned char** buf) -{ - int cnt = FIFO_LEN - 1; - unsigned t; - long time; - - time = USEC_TIMER + 3; - if (((intptr_t)*buf & 3) == 0) - { - asm volatile ( - "ldmia %[buf]!, { r3, r5, r7, r9 } \r\n" - "mov r4, r3, lsr #16 \r\n" - "mov r6, r5, lsr #16 \r\n" - "mov r8, r7, lsr #16 \r\n" - "mov r10, r9, lsr #16 \r\n" - "stmia %[data], { r3-r10 } \r\n" - "ldmia %[buf]!, { r3, r5, r7, r9 } \r\n" - "mov r4, r3, lsr #16 \r\n" - "mov r6, r5, lsr #16 \r\n" - "mov r8, r7, lsr #16 \r\n" - "mov %[t], r9, lsr #16 \r\n" - "stmia %[data], { r3-r9 } \r\n" - : [buf]"+&r"(*buf), [t]"=&r"(t) - : [data]"r"(&MMC_DATA_FIFO) - : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10" - ); - } - else - { - do - { - t = *(*buf)++; - t |= *(*buf)++ << 8; - MMC_DATA_FIFO = t; - } while (--cnt > 0); /* tail loop is faster */ - t = *(*buf)++; - t |= *(*buf)++ << 8; - } - /* Don't write the last word before at least 3 usec have elapsed since FIFO_EMPTY */ - /* This prevents the 'two bytes inserted' bug. */ - - while (!TIME_AFTER(USEC_TIMER, time)); - MMC_DATA_FIFO = t; -} - -static int sd_select_bank(unsigned char bank) -{ - unsigned char card_data[FIFO_LEN*2];// FIFO_LEN words=FIFO_LEN*2 bytes - const unsigned char* write_buf; - int i, ret; - - memset(card_data, 0, sizeof card_data); - - ret = sd_wait_for_state(SD_TRAN, EC_TRAN_SEL_BANK); - if (ret < 0) - return ret; - - MMC_BLKLEN = 512; - MMC_NUMBLK = 1; - - ret = sd_command(35, 0, NULL, /* CMD35 is vendor specific */ - 0x1c00 | CMDAT_WR_RD | CMDAT_DATA_EN | CMDAT_RES_TYPE1); - if (ret < 0) - return ret; - - MMC_SD_STATE = SD_PRG; - - card_data[0] = bank; - - /* Write the card data */ - for (i = 0; i < SD_BLOCK_SIZE/2; i += FIFO_LEN) - { - write_buf = card_data; - /* Wait for the FIFO to empty */ - if (sd_poll_status(STAT_XMIT_FIFO_EMPTY, 10000)) - { - copy_write_sectors(&write_buf); /* Copy one chunk of 16 words */ - /* clear buffer: only the first chunk contains interesting data (bank), the remaining is zero filling */ - memset(card_data, 0, sizeof card_data); - continue; - } - - return -EC_FIFO_SEL_BANK_EMPTY; - } - - if (!sd_poll_status(STAT_PRG_DONE, 10000)) - return -EC_FIFO_SEL_BANK_DONE; - - currcard->current_bank = bank; - - return 0; -} - -static void sd_card_mux(int card_no) -{ -/* Set the current card mux */ -#if defined(SANSA_E200) - if (card_no == 0) - { - GPO32_VAL |= 0x4; - - GPIO_CLEAR_BITWISE(GPIOA_ENABLE, 0x7a); - GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_EN, 0x7a); - GPIO_SET_BITWISE(GPIOD_ENABLE, 0x1f); - GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL, 0x1f); - GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x1f); - - outl((inl(0x70000014) & ~(0x3ffff)) | 0x255aa, 0x70000014); - } - else - { - GPO32_VAL &= ~0x4; - - GPIO_CLEAR_BITWISE(GPIOD_ENABLE, 0x1f); - GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN, 0x1f); - GPIO_SET_BITWISE(GPIOA_ENABLE, 0x7a); - GPIO_SET_BITWISE(GPIOA_OUTPUT_VAL, 0x7a); - GPIO_SET_BITWISE( GPIOA_OUTPUT_EN, 0x7a); - - outl(inl(0x70000014) & ~(0x3ffff), 0x70000014); - } -#elif defined(SANSA_C200) - if (card_no == 0) - { - GPO32_VAL |= 0x4; - - GPIO_CLEAR_BITWISE(GPIOD_ENABLE, 0x1f); - GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN, 0x1f); - GPIO_SET_BITWISE(GPIOA_ENABLE, 0x7a); - GPIO_SET_BITWISE(GPIOA_OUTPUT_VAL, 0x7a); - GPIO_SET_BITWISE( GPIOA_OUTPUT_EN, 0x7a); - - outl(inl(0x70000014) & ~(0x3ffff), 0x70000014); - } - else - { - GPO32_VAL &= ~0x4; - - GPIO_CLEAR_BITWISE(GPIOA_ENABLE, 0x7a); - GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_EN, 0x7a); - GPIO_SET_BITWISE(GPIOD_ENABLE, 0x1f); - GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL, 0x1f); - GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x1f); - - outl((inl(0x70000014) & ~(0x3ffff)) | 0x255aa, 0x70000014); - } -#elif defined(PHILIPS_SA9200) - /* only 1 "card" (no external memory card) */ - (void)card_no; - - GPIO_SET_BITWISE(GPIOH_ENABLE, 0x80); - GPIO_SET_BITWISE(GPIOH_OUTPUT_EN, 0x80); - - outl(0x255aa, 0x70000014); - - GPIO_CLEAR_BITWISE(GPIOA_ENABLE, 0x04); - GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_EN, 0x04); - - GPIO_CLEAR_BITWISE(GPIOA_ENABLE, 0x7a); - GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_EN, 0x7a); - - GPIO_SET_BITWISE(GPIOH_OUTPUT_VAL, 0x80); - GPIO_SET_BITWISE(GPIOH_OUTPUT_EN, 0x80); -#endif -} - -static void sd_init_device(int card_no) -{ -/* SD Protocol registers */ -#ifdef HAVE_HOTSWAP - unsigned long response = 0; -#endif - unsigned int i; - unsigned char carddata[512]; - unsigned char *dataptr; - unsigned long temp_reg[4]; - int ret; - -/* Enable and initialise controller */ - MMC_CLKRT = 6; /* switch to lowest clock rate */ - -/* Initialise card data as blank */ - memset(currcard, 0, sizeof(*currcard)); - -/* Switch card mux to card to initialize */ - sd_card_mux(card_no); - -/* Init NAND */ - MMC_INIT_1 |= (1 << 15); - MMC_INIT_2 |= (1 << 15); - MMC_INIT_2 &= ~(3 << 12); - MMC_INIT_2 |= (1 << 13); - MMC_INIT_1 &= ~(3 << 12); - MMC_INIT_1 |= (1 << 13); - - DEV_EN |= DEV_ATA; /* Enable controller */ - DEV_RS |= DEV_ATA; /* Reset controller */ - DEV_RS &=~DEV_ATA; /* Clear Reset */ - - MMC_SD_STATE = SD_TRAN; - - MMC_I_MASK = 0xf; /* disable interrupts */ - - ret = sd_command(SD_GO_IDLE_STATE, 0, NULL, 0x100); - if (ret < 0) - goto card_init_error; - - check_time[EC_POWER_UP] = USEC_TIMER; - -#ifdef HAVE_HOTSWAP - /* Check for SDHC: - - non-SDHC cards simply ignore SD_SEND_IF_COND (CMD8) and we get error -219, - which we can just ignore and assume we're dealing with standard SD. - - SDHC cards echo back the argument into the response. This is how we - tell if the card is SDHC. - */ - ret = sd_command(SD_SEND_IF_COND,0x1aa, &response, - CMDAT_DATA_EN | CMDAT_RES_TYPE3); - if ( (ret < 0) && (ret!=-219) ) - goto card_init_error; -#endif - - while ((currcard->ocr & (1 << 31)) == 0) /* until card is powered up */ - { - ret = sd_command(SD_APP_CMD, currcard->rca, NULL, CMDAT_RES_TYPE1); - if (ret < 0) - goto card_init_error; - -#ifdef HAVE_HOTSWAP - if(response == 0x1aa) - { - /* SDHC */ - ret = sd_command(SD_APP_OP_COND, (1<<30)|0x100000, - &currcard->ocr, CMDAT_RES_TYPE3); - } - else -#endif /* HAVE_HOTSWAP */ - { - /* SD Standard */ - ret = sd_command(SD_APP_OP_COND, 0x100000, &currcard->ocr, - CMDAT_RES_TYPE3); - } - - if (ret < 0) - goto card_init_error; - - if (!sd_check_timeout(5000000, EC_POWER_UP)) - { - ret = -EC_POWER_UP; - goto card_init_error; - } - } - - ret = sd_command(SD_ALL_SEND_CID, 0, temp_reg, CMDAT_RES_TYPE2); - if (ret < 0) - goto card_init_error; - - for(i=0; i<4; i++) - currcard->cid[i] = temp_reg[3-i]; - - ret = sd_command(SD_SEND_RELATIVE_ADDR, 0, &currcard->rca, CMDAT_RES_TYPE1); - if (ret < 0) - goto card_init_error; - - ret = sd_command(SD_SEND_CSD, currcard->rca, temp_reg, CMDAT_RES_TYPE2); - if (ret < 0) - goto card_init_error; - - for(i=0; i<4; i++) - currcard->csd[i] = temp_reg[3-i]; - - sd_parse_csd(currcard); - - MMC_CLKRT = 0; /* switch to highest clock rate */ - - ret = sd_command(SD_SELECT_CARD, currcard->rca, NULL, - 0x80 | CMDAT_RES_TYPE1); - if (ret < 0) - goto card_init_error; - - ret = sd_command(SD_APP_CMD, currcard->rca, NULL, CMDAT_RES_TYPE1); - if (ret < 0) - goto card_init_error; - - ret = sd_command(SD_SET_BUS_WIDTH, currcard->rca | 2, NULL, - CMDAT_RES_TYPE1); /* 4 bit */ - if (ret < 0) - goto card_init_error; - - ret = sd_command(SD_SET_BLOCKLEN, currcard->blocksize, NULL, - CMDAT_RES_TYPE1); - if (ret < 0) - goto card_init_error; - - MMC_BLKLEN = currcard->blocksize; - - /* If this card is >4GB & not SDHC, then we need to enable bank switching */ - if( (currcard->numblocks >= BLOCKS_PER_BANK) && - ((currcard->ocr & (1<<30)) == 0) ) - { - MMC_SD_STATE = SD_TRAN; - MMC_NUMBLK = 1; - - ret = sd_command(SD_SWITCH_FUNC, 0x80ffffef, NULL, - 0x1c00 | CMDAT_DATA_EN | CMDAT_RES_TYPE1); - if (ret < 0) - goto card_init_error; - - /* Read 512 bytes from the card. - The first 512 bits contain the status information - TODO: Do something useful with this! */ - dataptr = carddata; - for (i = 0; i < SD_BLOCK_SIZE/2; i += FIFO_LEN) - { - /* Wait for the FIFO to be full */ - if (sd_poll_status(STAT_RECV_FIFO_FULL, 100000)) - { - copy_read_sectors_slow(&dataptr); - continue; - } - - ret = -EC_FIFO_ENA_BANK_EMPTY; - goto card_init_error; - } - } - - currcard->initialized = 1; - return; - - /* Card failed to initialize so disable it */ -card_init_error: - currcard->initialized = ret; -} - -/* lock must already be aquired */ -static void sd_select_device(int card_no) -{ - currcard = &card_info[card_no]; - - if (card_no == 0) - { - /* Main card always gets a chance */ - sd_status[0].retry = 0; - } - - if (currcard->initialized > 0) - { - /* This card is already initialized - switch to it */ - sd_card_mux(card_no); - return; - } - - if (currcard->initialized == 0) - { - /* Card needs (re)init */ - sd_init_device(card_no); - } -} - -/* API Functions */ - -int sd_read_sectors(IF_MD2(int drive,) unsigned long start, int incount, - void* inbuf) -{ -#ifndef HAVE_MULTIDRIVE - const int drive = 0; -#endif - int ret; - unsigned char *buf, *buf_end; - unsigned int bank; - - /* TODO: Add DMA support. */ - - mutex_lock(&sd_mtx); - sd_enable(true); - led(true); - -sd_read_retry: - if (drive != 0 && !card_detect_target()) - { - /* no external sd-card inserted */ - ret = -EC_NOCARD; - goto sd_read_error; - } - - sd_select_device(drive); - - if (currcard->initialized < 0) - { - ret = currcard->initialized; - goto sd_read_error; - } - - last_disk_activity = current_tick; - - /* Only switch banks with non-SDHC cards */ - if((currcard->ocr & (1<<30))==0) - { - bank = start / BLOCKS_PER_BANK; - - if (currcard->current_bank != bank) - { - ret = sd_select_bank(bank); - if (ret < 0) - goto sd_read_error; - } - - start -= bank * BLOCKS_PER_BANK; - } - - ret = sd_wait_for_state(SD_TRAN, EC_TRAN_READ_ENTRY); - if (ret < 0) - goto sd_read_error; - - MMC_NUMBLK = incount; - -#ifdef HAVE_HOTSWAP - if(currcard->ocr & (1<<30) ) - { - /* SDHC */ - ret = sd_command(SD_READ_MULTIPLE_BLOCK, start, NULL, - 0x1c00 | CMDAT_BUSY | CMDAT_DATA_EN | CMDAT_RES_TYPE1); - } - else -#endif - { - ret = sd_command(SD_READ_MULTIPLE_BLOCK, start * SD_BLOCK_SIZE, NULL, - 0x1c00 | CMDAT_BUSY | CMDAT_DATA_EN | CMDAT_RES_TYPE1); - } - if (ret < 0) - goto sd_read_error; - - /* TODO: Don't assume SD_BLOCK_SIZE == SECTOR_SIZE */ - - buf_end = (unsigned char *)inbuf + incount * currcard->blocksize; - for (buf = inbuf; buf < buf_end;) - { - /* Wait for the FIFO to be full */ - if (sd_poll_status(STAT_RECV_FIFO_FULL, 0x80000)) - { - copy_read_sectors_fast(&buf); /* Copy one chunk of 16 words */ - /* TODO: Switch bank if necessary */ - continue; - } - - ret = -EC_FIFO_READ_FULL; - goto sd_read_error; - } - - last_disk_activity = current_tick; - - ret = sd_command(SD_STOP_TRANSMISSION, 0, NULL, CMDAT_RES_TYPE1); - if (ret < 0) - goto sd_read_error; - - ret = sd_wait_for_state(SD_TRAN, EC_TRAN_READ_EXIT); - if (ret < 0) - goto sd_read_error; - - while (1) - { - led(false); - sd_enable(false); - mutex_unlock(&sd_mtx); - - return ret; - -sd_read_error: - if (sd_status[drive].retry < sd_status[drive].retry_max - && ret != -EC_NOCARD) - { - sd_status[drive].retry++; - currcard->initialized = 0; - goto sd_read_retry; - } - } -} - -int sd_write_sectors(IF_MD2(int drive,) unsigned long start, int count, - const void* outbuf) -{ -/* Write support is not finished yet */ -/* TODO: The standard suggests using ACMD23 prior to writing multiple blocks - to improve performance */ -#ifndef HAVE_MULTIDRIVE - const int drive = 0; -#endif - int ret; - const unsigned char *buf, *buf_end; - unsigned int bank; - - mutex_lock(&sd_mtx); - sd_enable(true); - led(true); - -sd_write_retry: - if (drive != 0 && !card_detect_target()) - { - /* no external sd-card inserted */ - ret = -EC_NOCARD; - goto sd_write_error; - } - - sd_select_device(drive); - - if (currcard->initialized < 0) - { - ret = currcard->initialized; - goto sd_write_error; - } - - /* Only switch banks with non-SDHC cards */ - if((currcard->ocr & (1<<30))==0) - { - bank = start / BLOCKS_PER_BANK; - - if (currcard->current_bank != bank) - { - ret = sd_select_bank(bank); - if (ret < 0) - goto sd_write_error; - } - - start -= bank * BLOCKS_PER_BANK; - } - - check_time[EC_WRITE_TIMEOUT] = USEC_TIMER; - - ret = sd_wait_for_state(SD_TRAN, EC_TRAN_WRITE_ENTRY); - if (ret < 0) - goto sd_write_error; - - MMC_NUMBLK = count; - -#ifdef HAVE_HOTSWAP - if(currcard->ocr & (1<<30) ) - { - /* SDHC */ - ret = sd_command(SD_WRITE_MULTIPLE_BLOCK, start, NULL, - CMDAT_WR_RD | CMDAT_DATA_EN | CMDAT_RES_TYPE1); - } - else -#endif - { - ret = sd_command(SD_WRITE_MULTIPLE_BLOCK, start*SD_BLOCK_SIZE, NULL, - CMDAT_WR_RD | CMDAT_DATA_EN | CMDAT_RES_TYPE1); - } - if (ret < 0) - goto sd_write_error; - - buf_end = outbuf + count * currcard->blocksize - 2*FIFO_LEN; - - for (buf = outbuf; buf <= buf_end;) - { - if (buf == buf_end) - { - /* Set MMC_SD_STATE to SD_PRG for the last buffer fill */ - MMC_SD_STATE = SD_PRG; - } - - copy_write_sectors(&buf); /* Copy one chunk of 16 words */ - /* TODO: Switch bank if necessary */ - - /* Wait for the FIFO to empty */ - if (!sd_poll_status(STAT_XMIT_FIFO_EMPTY, 0x80000)) - { - ret = -EC_FIFO_WR_EMPTY; - goto sd_write_error; - } - } - - last_disk_activity = current_tick; - - if (!sd_poll_status(STAT_PRG_DONE, 0x80000)) - { - ret = -EC_FIFO_WR_DONE; - goto sd_write_error; - } - - ret = sd_command(SD_STOP_TRANSMISSION, 0, NULL, CMDAT_RES_TYPE1); - if (ret < 0) - goto sd_write_error; - - ret = sd_wait_for_state(SD_TRAN, EC_TRAN_WRITE_EXIT); - if (ret < 0) - goto sd_write_error; - - while (1) - { - led(false); - sd_enable(false); - mutex_unlock(&sd_mtx); - - return ret; - -sd_write_error: - if (sd_status[drive].retry < sd_status[drive].retry_max - && ret != -EC_NOCARD) - { - sd_status[drive].retry++; - currcard->initialized = 0; - goto sd_write_retry; - } - } -} - -#ifndef SD_DRIVER_CLOSE -static void sd_thread(void) NORETURN_ATTR; -#endif -static void sd_thread(void) -{ - struct queue_event ev; - bool idle_notified = false; - - while (1) - { - queue_wait_w_tmo(&sd_queue, &ev, HZ); - - switch ( ev.id ) - { -#ifdef HAVE_HOTSWAP - case SYS_HOTSWAP_INSERTED: - case SYS_HOTSWAP_EXTRACTED: - fat_lock(); /* lock-out FAT activity first - - prevent deadlocking via disk_mount that - would cause a reverse-order attempt with - another thread */ - mutex_lock(&sd_mtx); /* lock-out card activity - direct calls - into driver that bypass the fat cache */ - - /* We now have exclusive control of fat cache and ata */ - - disk_unmount(sd_first_drive+1); /* release "by force", ensure file - descriptors aren't leaked and any busy - ones are invalid if mounting */ - - /* Force card init for new card, re-init for re-inserted one or - * clear if the last attempt to init failed with an error. */ - card_info[1].initialized = 0; - sd_status[1].retry = 0; - - if (ev.id == SYS_HOTSWAP_INSERTED) - disk_mount(sd_first_drive+1); - - queue_broadcast(SYS_FS_CHANGED, 0); - - /* Access is now safe */ - mutex_unlock(&sd_mtx); - fat_unlock(); - break; -#endif - case SYS_TIMEOUT: - if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) - { - idle_notified = false; - } - else - { - /* never let a timer wrap confuse us */ - next_yield = USEC_TIMER; - - if (!idle_notified) - { - call_storage_idle_notifys(false); - idle_notified = true; - } - } - break; - case SYS_USB_CONNECTED: - usb_acknowledge(SYS_USB_CONNECTED_ACK); - /* Wait until the USB cable is extracted again */ - usb_wait_for_disconnect(&sd_queue); - break; - -#ifdef SD_DRIVER_CLOSE - case Q_CLOSE: - return; -#endif - } - } -} - -#ifdef SD_DRIVER_CLOSE -void sd_close(void) -{ - unsigned int thread_id = sd_thread_id; - - if (thread_id == 0) - return; - - sd_thread_id = 0; - - queue_post(&sd_queue, Q_CLOSE, 0); - thread_wait(thread_id); -} -#endif /* SD_DRIVER_CLOSE */ - -void sd_enable(bool on) -{ - if(on) - { - DEV_EN |= DEV_ATA; /* Enable controller */ - } - else - { - DEV_EN &= ~DEV_ATA; /* Disable controller */ - } -} - - -int sd_init(void) -{ - int ret = 0; - - if (!initialized) - mutex_init(&sd_mtx); - - mutex_lock(&sd_mtx); - - led(false); - - if (!initialized) - { - initialized = true; - - /* init controller */ -#if defined(PHILIPS_SA9200) - GPIOA_ENABLE = 0x00; - GPIO_SET_BITWISE(GPIOD_ENABLE, 0x01); -#else - outl(inl(0x70000088) & ~(0x4), 0x70000088); - outl(inl(0x7000008c) & ~(0x4), 0x7000008c); - GPO32_ENABLE |= 0x4; - - GPIO_SET_BITWISE(GPIOG_ENABLE, (0x3 << 5)); - GPIO_SET_BITWISE(GPIOG_OUTPUT_EN, (0x3 << 5)); - GPIO_SET_BITWISE(GPIOG_OUTPUT_VAL, (0x3 << 5)); -#endif - -#ifdef HAVE_HOTSWAP - /* enable card detection port - mask interrupt first */ -#ifdef SANSA_E200 - GPIO_CLEAR_BITWISE(GPIOA_INT_EN, 0x80); - - GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_EN, 0x80); - GPIO_SET_BITWISE(GPIOA_ENABLE, 0x80); -#elif defined SANSA_C200 - GPIO_CLEAR_BITWISE(GPIOL_INT_EN, 0x08); - - GPIO_CLEAR_BITWISE(GPIOL_OUTPUT_EN, 0x08); - GPIO_SET_BITWISE(GPIOL_ENABLE, 0x08); -#endif -#endif - sd_select_device(0); - - if (currcard->initialized < 0) - ret = currcard->initialized; - - queue_init(&sd_queue, true); - sd_thread_id = create_thread(sd_thread, sd_stack, sizeof(sd_stack), - 0, sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) - IF_COP(, CPU)); - - /* enable interupt for the mSD card */ - sleep(HZ/10); -#ifdef HAVE_HOTSWAP -#ifdef SANSA_E200 - CPU_INT_EN = HI_MASK; - CPU_HI_INT_EN = GPIO0_MASK; - - GPIOA_INT_LEV = (0x80 << 8) | (~GPIOA_INPUT_VAL & 0x80); - - GPIOA_INT_CLR = 0x80; - - /* enable the card detect interrupt */ - GPIO_SET_BITWISE(GPIOA_INT_EN, 0x80); -#elif defined SANSA_C200 - CPU_INT_EN = HI_MASK; - CPU_HI_INT_EN = GPIO2_MASK; - - GPIOL_INT_LEV = (0x08 << 8) | (~GPIOL_INPUT_VAL & 0x08); - - GPIOL_INT_CLR = 0x08; - - /* enable the card detect interrupt */ - GPIO_SET_BITWISE(GPIOL_INT_EN, 0x08); -#endif -#endif - } - - mutex_unlock(&sd_mtx); - - return ret; -} - -tCardInfo *card_get_info_target(int card_no) -{ - return &card_info[card_no]; -} -#ifdef HAVE_HOTSWAP -static int sd1_oneshot_callback(struct timeout *tmo) -{ - (void)tmo; - - /* This is called only if the state was stable for 300ms - check state - * and post appropriate event. */ - if (card_detect_target()) - queue_broadcast(SYS_HOTSWAP_INSERTED, 0); - else - queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0); - - return 0; -} - -/* called on insertion/removal interrupt */ -void microsd_int(void) -{ - static struct timeout sd1_oneshot; - -#ifdef SANSA_E200 - GPIO_CLEAR_BITWISE(GPIOA_INT_EN, 0x80); - GPIOA_INT_LEV = (0x80 << 8) | (~GPIOA_INPUT_VAL & 0x80); - GPIOA_INT_CLR = 0x80; - GPIO_SET_BITWISE(GPIOA_INT_EN, 0x80); - -#elif defined SANSA_C200 - GPIO_CLEAR_BITWISE(GPIOL_INT_EN, 0x08); - GPIOL_INT_LEV = (0x08 << 8) | (~GPIOL_INPUT_VAL & 0x08); - GPIOL_INT_CLR = 0x08; - GPIO_SET_BITWISE(GPIOL_INT_EN, 0x08); -#endif - timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0); -} -#endif /* HAVE_HOTSWAP */ - -long sd_last_disk_activity(void) -{ - return last_disk_activity; -} - -#ifdef HAVE_HOTSWAP -bool sd_removable(IF_MD_NONVOID(int drive)) -{ -#ifndef HAVE_MULTIDRIVE - const int drive=0; -#endif - return (drive==1); -} - -bool sd_present(IF_MD_NONVOID(int drive)) -{ -#ifndef HAVE_MULTIDRIVE - const int drive=0; -#endif - if(drive==0) - { - return true; - } - else - { - return card_detect_target(); - } -} -#endif - -#ifdef CONFIG_STORAGE_MULTI -int sd_num_drives(int first_drive) -{ -#ifdef HAVE_HOTSWAP - /* Store which logical drive number(s) we have been assigned */ - sd_first_drive = first_drive; -#else - (void)first_drive; -#endif - -#ifdef HAVE_MULTIDRIVE - return 2; -#else - return 1; -#endif -} -#endif diff --git a/firmware/target/arm/audio-pp.c b/firmware/target/arm/audio-pp.c deleted file mode 100644 index 6b5b082cc7..0000000000 --- a/firmware/target/arm/audio-pp.c +++ /dev/null @@ -1,135 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2006 by Michael Sevakis - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "system.h" -#include "cpu.h" -#include "audio.h" -#include "sound.h" - -#if INPUT_SRC_CAPS != 0 -void audio_set_output_source(int source) -{ - if ((unsigned)source >= AUDIO_NUM_SOURCES) - source = AUDIO_SRC_PLAYBACK; -} /* audio_set_output_source */ - -void audio_input_mux(int source, unsigned flags) -{ - (void)flags; - /* Prevent pops from unneeded switching */ - static int last_source = AUDIO_SRC_PLAYBACK; -#ifdef HAVE_FMRADIO_REC - bool recording = flags & SRCF_RECORDING; - static bool last_recording = false; -#endif - -#if defined(IPOD_COLOR) || defined (IPOD_4G) - /* The usual magic from IPL - I'm guessing this configures the headphone - socket to be input or output. */ - if ((flags & SRCF_RECORDING) && source != AUDIO_SRC_PLAYBACK) - { - /* input */ - GPIO_CLEAR_BITWISE(GPIOI_OUTPUT_VAL, 0x40); - GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_VAL, 0x04); - } - else - { - /* output */ - GPIO_SET_BITWISE(GPIOI_OUTPUT_VAL, 0x40); - GPIO_SET_BITWISE(GPIOA_OUTPUT_VAL, 0x04); - } -#endif /* IPOD_COLOR || IPOD_4G */ - - switch (source) - { - default: /* playback - no recording */ - source = AUDIO_SRC_PLAYBACK; - case AUDIO_SRC_PLAYBACK: -#ifdef HAVE_RECORDING - if (source != last_source) - { - audiohw_set_monitor(false); - audiohw_disable_recording(); - } -#endif - break; -#ifdef HAVE_MIC_REC - case AUDIO_SRC_MIC: /* recording only */ - if (source != last_source) - { - audiohw_set_monitor(false); - audiohw_enable_recording(true); /* source mic */ - } - break; -#endif -#ifdef HAVE_LINE_REC - case AUDIO_SRC_LINEIN: /* recording only */ -#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) - /* Switch line in source to line-in */ - GPIO_SET_BITWISE(GPIOB_OUTPUT_VAL, 0x04); -#endif - if (source != last_source) - { - audiohw_set_monitor(false); - audiohw_enable_recording(false); /* source line */ - } - break; -#endif -#ifdef HAVE_FMRADIO_REC - case AUDIO_SRC_FMRADIO: /* recording and playback */ -#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) - /* Switch line in source to tuner */ - GPIO_CLEAR_BITWISE(GPIOB_OUTPUT_VAL, 0x04); - /* Set line-in vol to +12dB, which is proper for H10's */ - if (!recording) - audiohw_set_recvol(0x1f, 0x1f, AUDIO_GAIN_LINEIN); -#else /* Set line-in vol to 0dB*/ - if (!recording) - audiohw_set_recvol(0x17, 0x17, AUDIO_GAIN_LINEIN); -#endif - - if (source == last_source && recording == last_recording) - break; - - last_recording = recording; - -#if CONFIG_TUNER & IPOD_REMOTE_TUNER - /* Ipod FM tuner is in the remote connected to line-in */ - audiohw_enable_recording(false); /* source line */ - audiohw_set_monitor(true); /* enable bypass mode */ -#else - if (recording) - { - audiohw_set_monitor(false); /* disable bypass mode */ - audiohw_enable_recording(false); /* select line-in source */ - } - else - { - audiohw_disable_recording(); - audiohw_set_monitor(true); /* enable bypass mode */ - } -#endif - break; -#endif - } /* end switch */ - - last_source = source; -} /* audio_input_mux */ -#endif /* INPUT_SRC_CAPS != 0 */ diff --git a/firmware/target/arm/boot-pp502x-bl-usb.lds b/firmware/target/arm/boot-pp502x-bl-usb.lds deleted file mode 100644 index e721991c5a..0000000000 --- a/firmware/target/arm/boot-pp502x-bl-usb.lds +++ /dev/null @@ -1,133 +0,0 @@ -/* Will have been included from boot.lds */ -ENTRY(start) -OUTPUT_FORMAT(elf32-littlearm) -OUTPUT_ARCH(arm) -STARTUP(target/arm/crt0-pp502x-bl-usb.o) - -#define DRAMORIG 0x01000000 /* Load at 16 MB */ -#define DRAMSIZE 0x00100000 /* 1MB for bootloader */ -#define MEMEND (MEMORYSIZE*0x100000) /* From virtual mapping at 0 */ -#define NOCACHE_BASE 0x10000000 -#ifndef IRAMORIG -#define IRAMORIG 0x40000000 -#endif -#define IRAMSIZE 0x20000 -#define FLASHORIG 0x001f0000 -#define FLASHSIZE 2M - -#define CACHEALIGN_SIZE 16 - -MEMORY -{ - DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE - IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE -} - -SECTIONS -{ - . = DRAMORIG; - _loadaddress = . + NOCACHE_BASE; - - .text : - { - *(.init.text) - *(.text*) - *(.glue_7) - *(.glue_7t) - . = ALIGN(0x4); - } > DRAM - - .rodata : - { - *(.rodata*) - . = ALIGN(0x4); - } > DRAM - - .data : - { - *(.data*) - . = ALIGN(0x4); - } > DRAM - - /* .ncdata section is placed at uncached physical alias address and is - * loaded at the proper cached virtual address - no copying is - * performed in the init code */ - .ncdata . + NOCACHE_BASE : - { - . = ALIGN(CACHEALIGN_SIZE); - *(.ncdata*) - . = ALIGN(CACHEALIGN_SIZE); - } AT> DRAM - - /DISCARD/ . - NOCACHE_BASE : - { - *(.eh_frame) - } > DRAM - - _noloaddram = .; - - .ibss IRAMORIG (NOLOAD) : - { - _iedata = .; - *(.qharray) - *(.ibss*) - . = ALIGN(0x4); - _iend = .; - } > IRAM - - .iram _iend : - { - _iramstart = .; - *(.icode*) - *(.irodata*) - *(.idata*) - _iramend = .; - } > IRAM AT> DRAM - - _iramcopy = LOADADDR(.iram); - - .loadaddressend : - { - _loadaddressend = . + NOCACHE_BASE; - } AT> DRAM - - .stack (NOLOAD) : - { - . = ALIGN(8); - *(.stack) - stackbegin = .; - . += 0x2000; - stackend = .; - } > IRAM - - /* .bss and .ncbss are treated as a single section to use one init loop - * to zero them - note "_edata" and "_end" */ - .bss _noloaddram (NOLOAD) : - { - _edata = .; - *(.bss*) - *(COMMON) - } > DRAM - - .ncbss . + NOCACHE_BASE (NOLOAD) : - { - . = ALIGN(CACHEALIGN_SIZE); - *(.ncbss*) - . = ALIGN(CACHEALIGN_SIZE); - } AT> DRAM - - /* This will be aligned by preceding alignments */ - .endaddr . - NOCACHE_BASE (NOLOAD) : - { - _end = .; - } > DRAM - - /* Reference to all DRAM after loaded bootloader image */ - .freebuffer _end (NOLOAD) : - { - . = ALIGN(4); - freebuffer = .; - . = MEMEND-1; - freebufferend = .; - } -} diff --git a/firmware/target/arm/crt0-pp-bl.S b/firmware/target/arm/crt0-pp-bl.S deleted file mode 100644 index 01681288f9..0000000000 --- a/firmware/target/arm/crt0-pp-bl.S +++ /dev/null @@ -1,217 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 by Linus Nielsen Feltzing - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "config.h" -#include "cpu.h" - - .section .init.text,"ax",%progbits - - .global start -start: - -/* PortalPlayer bootloader and startup code based on startup.s from the iPodLinux - * loader - * - * Copyright (c) 2003, Daniel Palffy (dpalffy (at) rainstorm.org) - * Copyright (c) 2005, Bernard Leach - * - */ -#if CONFIG_CPU == PP5002 - .equ PROC_ID, 0xc4000000 - .equ CPU_CTRL, 0xcf004054 - .equ CPU_STATUS, 0xcf004050 - .equ COP_CTRL, 0xcf004058 - .equ COP_STATUS, 0xcf004050 - .equ IIS_CONFIG, 0xc0002500 - .equ SLEEP, 0xca - .equ WAKE, 0xce - .equ CPUSLEEPING, 0x8000 - .equ COPSLEEPING, 0x4000 - .equ CACHE_CTRL, 0xcf004024 - .equ CACHE_ENAB, 0x2 /* Actually the CACHE_CTL_INIT flag */ -#else - .equ PROC_ID, 0x60000000 - .equ CPU_CTRL, 0x60007000 - .equ CPU_STATUS, 0x60007000 - .equ COP_CTRL, 0x60007004 - .equ COP_STATUS, 0x60007004 - .equ IIS_CONFIG, 0x70002800 - .equ SLEEP, 0x80000000 - .equ WAKE, 0x0 - .equ CPUSLEEPING, 0x80000000 - .equ COPSLEEPING, 0x80000000 - .equ CACHE_CTRL, 0x6000c000 - .equ CACHE_ENAB, 0x1 -#endif - - msr cpsr_c, #0xdf /* enter sys mode, disable IRQ */ -#ifndef E200R_INSTALLER -/* 1 - Copy the bootloader to IRAM */ - /* get the high part of our execute address */ - bic r0, pc, #0xff /* r4 = pc & 0xffffff00 */ - - /* Copy bootloader to safe area - 0x40000000 (IRAM) */ - mov r1, #0x40000000 - ldr r2, =_dataend -1: - cmp r2, r1 - ldrhi r3, [r0], #4 - strhi r3, [r1], #4 - bhi 1b - -#ifndef IPOD_ARCH - /* For builds on targets with mi4 firmware, scramble writes data to - 0xe0-0xeb, so jump past that. pad_skip must then exist at an - address >= 0xec */ - b pad_skip - -.space 60*4 - -pad_skip: -#endif /* IPOD_ARCH */ - - -/* 2 - Jump both CPU and COP there */ - ldr pc, =start_loc /* jump to the relocated start_loc: */ -#endif /* E200R_INSTALLER */ - -start_loc: - /* Find out which processor we are */ - ldr r0, =PROC_ID - ldrb r0, [r0] - cmp r0, #0x55 - beq cpu - -cop: - /* put us (co-processor) to sleep */ - ldr r0, =COP_CTRL - mov r1, #SLEEP - str r1, [r0] - nop - nop - - /* Invalidate cache */ - mov r0, #1 - bl cache_op - - ldr r0, =startup_loc - ldr pc, [r0] - -cpu: - /* Wait for COP to be sleeping */ - ldr r0, =COP_STATUS -1: - ldr r1, [r0] - tst r1, #COPSLEEPING - beq 1b - - /* Initialise bss section to zero */ - ldr r0, =_edata - ldr r1, =_end - mov r2, #0 -1: - cmp r1, r0 - strhi r2, [r0], #4 - bhi 1b - - /* Set up some stack and munge it with 0xdeadbeef */ - ldr sp, =stackend - ldr r0, =stackbegin - ldr r1, =0xdeadbeef -1: - cmp sp, r0 - strhi r1, [r0], #4 - bhi 1b - - /* execute the loader - this will load an image to 0x10000000 */ - bl main - - /* store actual startup location returned by main() */ - ldr r1, =startup_loc - str r0, [r1] - - /* flush cache */ - mov r0, #0 - bl cache_op - - /* Wake up the coprocessor before executing the firmware */ - ldr r0, =COP_CTRL - mov r1, #WAKE - str r1, [r0] - -#if defined(SANSA_C200) || defined(PHILIPS_HDD1630) - /* Magic for loading the c200 OF */ - ldr r0, =0xb00d10ad - mov r1, #0x700 - ldr r2, =0xfff0 - mov r3, #0x7 -#endif - -#if defined(PHILIPS_HDD6330) - /* Magic for loading the HDD6XX0 OF */ - ldr r0, =0xb00d10ad - mov r1, #0x800 - ldr r2, =0xfff0 - mov r3, #0x7 -#endif - - ldr r4, =startup_loc - ldr pc, [r4] - -startup_loc: - .word 0x0 - -#ifdef IPOD_ARCH -.align 8 /* starts at 0x100 */ -.global boot_table -boot_table: - /* here comes the boot table, don't move its offset - preceding - code+data must stay <= 256 bytes */ - .space 400 -#endif - -cache_op: - ldr r2, =CACHE_CTRL - ldr r1, [r2] - tst r1, #CACHE_ENAB - bxeq lr - cmp r0, #0 -#ifdef CPU_PP502x - ldr r0, =0xf000f044 - ldr r1, [r0] - orrne r1, r1, #0x6 - orreq r1, r1, #0x2 - str r1, [r0] -1: - ldr r1, [r2] - tst r1, #0x8000 - bne 1b -#elif CONFIG_CPU == PP5002 - ldrne r0, =0xf0004000 - ldreq r0, =0xf000c000 - add r1, r0, #0x2000 - mov r2, #0 -1: - cmp r1, r0 - strhi r2, [r0], #16 - bhi 1b -#endif /* CPU type */ - bx lr - diff --git a/firmware/target/arm/crt0-pp.S b/firmware/target/arm/crt0-pp.S deleted file mode 100644 index 5a9835a71f..0000000000 --- a/firmware/target/arm/crt0-pp.S +++ /dev/null @@ -1,430 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 by Linus Nielsen Feltzing - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "config.h" -#include "cpu.h" - - .section .init.text,"ax",%progbits - - .global start -start: - -/* PortalPlayer bootloader and startup code based on startup.s from the iPodLinux - * loader - * - * Copyright (c) 2003, Daniel Palffy (dpalffy (at) rainstorm.org) - * Copyright (c) 2005, Bernard Leach - * - */ -#if CONFIG_CPU == PP5002 - .equ PROC_ID, 0xc4000000 - .equ CPU_ICLR, 0xcf001028 - .equ CPU_CTRL, 0xcf004054 - .equ COP_ICLR, 0xcf001038 - .equ COP_CTRL, 0xcf004058 - .equ CPU_STATUS, 0xcf004050 - .equ COP_STATUS, 0xcf004050 - .equ SLEEP, 0x000000ca - .equ WAKE, 0x000000ce - .equ CPUSLEEPING, 0x00008000 - .equ COPSLEEPING, 0x00004000 - .equ CACHE_CTRL, 0xcf004024 - .equ MMAP_LOG, 0xf000f000 /* MMAP0 */ - .equ MMAP_PHYS, 0xf000f004 -#if MEMORYSIZE > 32 - .equ MMAP_MASK, 0x00003c00 -#else - .equ MMAP_MASK, 0x00003e00 -#endif - .equ MMAP_FLAGS, 0x00003f84 -#else - .equ PROC_ID, 0x60000000 - .equ CPU_ICLR, 0x60004028 - .equ CPU_CTRL, 0x60007000 - .equ CPU_STATUS, 0x60007000 - .equ COP_ICLR, 0x60004038 - .equ COP_CTRL, 0x60007004 - .equ COP_STATUS, 0x60007004 - .equ SLEEP, 0x80000000 - .equ WAKE, 0x00000000 - .equ CPUSLEEPING, 0x80000000 - .equ COPSLEEPING, 0x80000000 - .equ CACHE_CTRL, 0x6000c000 - .equ MMAP_LOG, 0xf000f000 /* MMAP0 */ - .equ MMAP_PHYS, 0xf000f004 -#if MEMORYSIZE > 32 - .equ MMAP_MASK, 0x00003c00 -#else - .equ MMAP_MASK, 0x00003e00 -#endif - .equ MMAP_FLAGS, 0x00000f84 -#endif - - msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */ - b pad_skip - -.space 6*4 /* pad to offset 0x20 */ - - .ascii "Rockbox" /* signature for bootloader checking osos */ - .byte 1 /* osos boot version, only 1 exists for now */ - -.space 56*4 /* (more than enough) space for exception vectors and mi4 magic */ - -pad_skip: - /* Find out which processor we are - r0 should be preserved for the - * duration of the init to avoid constant reloading of the processor ID. - * For each stage, CPU proceeds first, then COP. - */ - ldr r0, =PROC_ID - ldrb r0, [r0] - - /* We need to remap memory from wherever SDRAM is mapped natively, to - base address 0, so we can put our exception vectors there. We don't - want to do this remapping while executing from SDRAM, so we copy the - remapping code to IRAM, then execute from there. Hence, the following - code is compiled for address 0, but is currently executing at either - 0x28000000 or 0x10000000, depending on chipset version. Do not use any - absolute addresses until remapping has been done. */ - - /* Cores are stepped though the init in turn: CPU then COP. The the remap - stage is completed by each core in turn and then the COP waits for the - CPU to finish initializing its kernel where the CPU will wake the COP - and wait for the COP to finish. This ensures no threading activity - starts until it is safe. */ - cmp r0, #0x55 - - /* mask all interrupt sources before setting anything up */ - ldreq r2, =CPU_ICLR - ldrne r2, =COP_ICLR - mvn r1, #0 - str r1, [r2] - - /* put us (co-processor) to sleep and wait for CPU to remap */ - ldrne r2, =COP_CTRL - movne r1, #SLEEP - strne r1, [r2] - nop - nop - nop - - /* wait for co-processor to sleep then CPU can begin its remapping */ - ldreq r2, =COP_STATUS -1: - ldreq r1, [r2] - tsteq r1, #COPSLEEPING - beq 1b - - /* disable cache and local interrupt vectors - it is really not desireable - to have them enabled here */ - ldr r2, =CACHE_CTRL - mov r1, #0 - str r1, [r2] - -#if defined(IPOD_VIDEO) - /* detect 32mb vs 64mb model */ - /* we do this here because after SDRAM is remapped, we already assumed */ - /* its size to be whatever we were compiled for. */ - - mov r2, #0x12000000 - mov r3, #64 - strb r3, [r2, #-1] /* first write 64 to last byte of first 32MB bank */ - - mov r2, #0x14000000 - mov r3, #32 - strb r3, [r2, #-1] /* now write 32 to last byte of second 32MB bank */ - - /* now the last word of the first 32MB bank tells you the RAM size */ - /* since on a 32MB model both writes will touch the same actual location */ - /* this is read later on in boot */ -#endif - - mov r2, #0x40000000 - ldr r3, =remap_start - ldr r4, =remap_end - - and r6, pc, #0xff000000 /* adjust for execute address */ - orr r3, r3, r6 - orr r4, r4, r6 - - /* copy the code to 0x40000000 */ -1: - ldr r5, [r3], #4 - str r5, [r2], #4 - cmp r3, r4 - blo 1b - - ldr r4, =MMAP_FLAGS - orr r4, r4, r6 /* adjust for execute address */ - ldr r3, =MMAP_PHYS - ldr r2, =MMAP_MASK /* ldr is more flexible */ - ldr r1, =MMAP_LOG - mov pc, #0x40000000 - -remap_start: - str r2, [r1] - str r4, [r3] - ldr r1, L_post_remap - bx r1 -L_post_remap: - .word remap_end -remap_end: - - cmp r0, #0x55 - ldr r4, =COP_CTRL - /* Wakeup co-processor to let it do remappings */ - moveq r3, #WAKE - /* Sleep us (co-processor) and wait for CPU to do kernel initialization */ - movne r3, #SLEEP - str r3, [r4] - nop - nop - nop - - /* Jump to co-processor init */ - ldrne pc, =cop_init - -cpu_init: - /* Wait for COP to go to sleep before proceeding */ - ldr r4, =COP_STATUS -1: - ldr r3, [r4] - tst r3, #COPSLEEPING - beq 1b - - /* Vectors and IRAM copy is done first since they are reclaimed for - * other uninitialized sections */ - - /* Copy exception handler code to address 0 */ - ldr r2, =_vectorsstart - ldr r3, =_vectorsend - ldr r4, =_vectorscopy -1: - cmp r3, r2 - ldrhi r5, [r4], #4 - strhi r5, [r2], #4 - bhi 1b - - /* Copy the IRAM */ - ldr r2, =_iramcopy - ldr r3, =_iramstart - ldr r4, =_iramend -1: - cmp r4, r3 - ldrhi r5, [r2], #4 - strhi r5, [r3], #4 - bhi 1b - -#ifdef HAVE_INIT_ATTR - /* copy init code to codec buffer */ - ldr r2, =_initstart - ldr r3, =_initend - ldr r4, =_initcopy - -1: - cmp r3, r2 - ldrhi r5, [r4], #4 - strhi r5, [r2], #4 - bhi 1b -#endif - - /* Zero out IBSS */ - ldr r2, =_iedata - ldr r3, =_iend - mov r4, #0 -1: - cmp r3, r2 - strhi r4, [r2], #4 - bhi 1b - - /* Initialise bss section to zero */ - ldr r2, =_edata - ldr r3, =_end - mov r4, #0 -1: - cmp r3, r2 - strhi r4, [r2], #4 - bhi 1b - - /* Load stack munge value */ - ldr r4, =0xdeadbeef - -#if NUM_CORES > 1 - /* Set up idle stack and munge it with 0xdeadbeef */ - ldr r2, =cpu_idlestackbegin - ldr r3, =cpu_idlestackend -1: - cmp r3, r2 - strhi r4, [r2], #4 - bhi 1b -#endif - - /* Set up stack for IRQ mode */ - msr cpsr_c, #0x92 /* IRQ disabled, FIQ enabled */ - ldr sp, =irq_stack - /* Set up stack for FIQ mode */ - msr cpsr_c, #0xd1 /* IRQ/FIQ disabled */ - ldr sp, =fiq_stack - - /* Let svc, abort and undefined modes use irq stack */ - msr cpsr_c, #0xd3 /* IRQ/FIQ disabled */ - ldr sp, =irq_stack - msr cpsr_c, #0xd7 /* IRQ/FIQ disabled */ - ldr sp, =irq_stack - msr cpsr_c, #0xdb /* IRQ/FIQ disabled */ - ldr sp, =irq_stack - - /* Switch to sys mode */ - msr cpsr_c, #0xdf - - /* Set up some stack and munge it with 0xdeadbeef */ - ldr r2, =stackbegin - ldr sp, =stackend -1: - cmp sp, r2 - strhi r4, [r2], #4 - bhi 1b - - /* Delay waking the COP until thread initialization is complete unless dual-core - support is not enabled in which case the cop_main function does not perform - any kernel or thread initialization. It's just a trivial sleep loop. */ -#if NUM_CORES == 1 - ldr r4, =COP_CTRL - mov r3, #WAKE - str r3, [r4] -#endif - - ldr pc, =main - /* main() should never return */ - -cop_init: -#if NUM_CORES > 1 - /* Wait for CPU to go to sleep at the end of its kernel init */ - ldr r4, =CPU_STATUS -1: - ldr r3, [r4] - tst r3, #CPUSLEEPING - beq 1b -#endif - - /* Set up stack for IRQ mode */ - msr cpsr_c, #0x92 /* IRQ disabled, FIQ enabled */ - ldr sp, =cop_irq_stack - /* Set up stack for FIQ mode */ - msr cpsr_c, #0xd1 /* IRQ/FIQ disabled */ - ldr sp, =cop_fiq_stack - - /* Let svc, abort and undefined modes use irq stack */ - msr cpsr_c, #0xd3 /* IRQ/FIQ disabled */ - ldr sp, =cop_irq_stack - msr cpsr_c, #0xd7 /* IRQ/FIQ disabled */ - ldr sp, =cop_irq_stack - msr cpsr_c, #0xdb /* IRQ/FIQ disabled */ - ldr sp, =cop_irq_stack - - /* Switch to sys mode */ - msr cpsr_c, #0xdf - - /* Set up idle stack for COP and munge it with 0xdeadbeef */ - ldr sp, =cop_idlestackend - ldr r2, =cop_idlestackbegin - ldr r4, =0xdeadbeef -2: - cmp sp, r2 - strhi r4, [r2], #4 - bhi 2b - - /* Run cop_main() in apps/main.c */ - ldr pc, =cop_main - -/* Exception handlers. Will be copied to address 0 after memory remapping */ - .section .vectors,"aw" - ldr pc, [pc, #24] - ldr pc, [pc, #24] - ldr pc, [pc, #24] - ldr pc, [pc, #24] - ldr pc, [pc, #24] - ldr pc, [pc, #24] - ldr pc, [pc, #24] - ldr pc, [pc, #24] - - /* Exception vectors */ - .global vectors -vectors: - .word start - .word undef_instr_handler - .word software_int_handler - .word prefetch_abort_handler - .word data_abort_handler - .word reserved_handler - .word irq_handler - .word fiq_handler - - .text - -/* All illegal exceptions call into UIE with exception address as first - parameter. This is calculated differently depending on which exception - we're in. Second parameter is exception number, used for a string lookup - in UIE. - */ -undef_instr_handler: - sub r0, lr, #4 - mov r1, #0 - b UIE - -/* We run sys mode most of the time, and should never see a software - exception being thrown. Make it illegal and call UIE. - */ -software_int_handler: -reserved_handler: - sub r0, lr, #4 - mov r1, #4 - b UIE - -prefetch_abort_handler: - sub r0, lr, #4 - mov r1, #1 - b UIE - -data_abort_handler: - sub r0, lr, #8 - mov r1, #2 - b UIE - -/* Align stacks to cache line boundary */ - .balign 32 - -/* 256 words of IRQ stack */ - .space 256*4 -irq_stack: - -/* 256 words of COP IRQ stack */ - .space 256*4 -cop_irq_stack: - -/* 256 words of FIQ stack */ - .space 256*4 -fiq_stack: - -/* We'll need this soon - just reserve the symbol */ -#if 0 -/* 256 words of COP FIQ stack */ - .space 256*4 -#endif -cop_fiq_stack: diff --git a/firmware/target/arm/crt0-pp502x-bl-usb.S b/firmware/target/arm/crt0-pp502x-bl-usb.S deleted file mode 100644 index 7b0489b2a8..0000000000 --- a/firmware/target/arm/crt0-pp502x-bl-usb.S +++ /dev/null @@ -1,367 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 by Linus Nielsen Feltzing - * Copyright (C) 2010 by Michael Sevakis - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "config.h" -#include "cpu.h" - -/* PortalPlayer bootloader and startup code based on startup.s from the iPodLinux - * loader - * - * Copyright (c) 2003, Daniel Palffy (dpalffy (at) rainstorm.org) - * Copyright (c) 2005, Bernard Leach - * - */ - .equ PROC_ID, 0x60000000 - .equ CPU_IDIS, 0x60004028 - .equ CPU_CTRL, 0x60007000 - .equ CPU_STATUS, 0x60007000 - .equ COP_IDIS, 0x60004038 - .equ COP_CTRL, 0x60007004 - .equ COP_STATUS, 0x60007004 - .equ CPU_SLEEPING,0x80000000 - .equ COP_SLEEPING,0x80000000 - .equ SLEEP, 0x80000000 - .equ WAKE, 0x00000000 - .equ MMAP_LOG, 0xf000f000 /* MMAP0 */ - .equ MMAP_PHYS, 0xf000f004 - .equ INT_VECT_TBL,0x6000f100 - .equ CACHE_CTRL, 0x6000c000 - .equ CACHE_ENAB, 0x1 - .equ CACHE_OP_COMMIT_DISCARD, 0x1 - .equ CACHE_OP_COMMIT , 0x0 -#if MEMORYSIZE > 32 - .equ MMAP_MASK, 0x00003c00 -#else - .equ MMAP_MASK, 0x00003e00 -#endif - .equ MMAP_FLAGS, 0x00000f84 - -/* - * Entry point - */ - .section .init.text,"ax",%progbits - .global start -start: - b newstart - -#ifdef IPOD_ARCH -.align 8 /* starts at 0x100 */ -.global boot_table -boot_table: - /* here comes the boot table, don't move its offset - preceding - code+data must stay <= 256 bytes */ - .space 400 -#else /* !IPOD_ARCH */ - /* (more than enough) space for exception vectors and mi4 magic */ - .space 68*4 -#endif /* IPOD_ARCH */ - -newstart: - msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */ - adr r4, start /* cache initial load address */ - - /* Copy startup stub to IRAM since we need to both move the bootloader's - * location, which could overlap itself, and setup the memory mapper. */ - adr r0, start_stub_begin - mov r1, #0x40000000 - adr r2, start_stub_end -1: - ldr r3, [r0], #4 - str r3, [r1], #4 - cmp r0, r2 - blo 1b - mov pc, #0x40000000 - -start_stub_begin: - ldr r0, =PROC_ID - ldrb r0, [r0] - cmp r0, #0x55 - beq cpu - -cop: - mov r0, #CACHE_OP_COMMIT_DISCARD - bl cache_operation - - ldr r1, =COP_CTRL - mov r0, #SLEEP - - /* sleep us (co-processor) while bootloader is copied */ - str r0, [r1] - nop - nop - nop - - /* branch to final physical load address */ - ldr r2, =1f - and r4, r4, #0xfc000000 - add pc, r2, r4 -1: - /* wait for bootloader to finish */ - str r0, [r1] - nop - nop - nop - - /* branch to the address returned by main() */ - adr r0, startup_loc - ldr pc, [r0] - -cpu: - /* wait for COP to sleep */ - ldr r1, =COP_STATUS -1: - ldr r0, [r1] - tst r0, #COP_SLEEPING - beq 1b - - mov r0, #CACHE_OP_COMMIT_DISCARD - bl cache_operation - - /* move bootloader to the correct load address if needed */ - ldr r1, =_loadaddress - cmp r4, r1 - ldrne r2, =_loadaddressend - movne r0, r4 - sublo r3, r2, r1 /* size */ - addlo r0, r0, r3 /* initial load end addr */ -1: /* lower to higher move - copy up */ - cmphi r2, r1 - ldrhi r3, [r0], #4 - strhi r3, [r1], #4 - bhi 1b -1: /* higher to lower move - copy down */ - cmplo r1, r2 - ldrlo r3, [r0, #-4]! - strlo r3, [r2, #-4]! - blo 1b - - mov r0, #CACHE_OP_COMMIT - bl cache_operation - - and r4, r4, #0xfc000000 - - ldr r0, =MMAP_FLAGS - orr r0, r0, r4 /* adjust for execute address */ - ldr r1, =MMAP_MASK - ldr r2, =MMAP_LOG - ldr r3, =MMAP_PHYS - str r1, [r2] /* MMAP_LOG = MMAP_MASK */ - str r0, [r3] /* MMAP_PHYS = MMAP_FLAGS | SDRAM base addr */ - - /* wake the COP to jump it to the correct place */ - ldr r1, =COP_CTRL - mov r0, #WAKE - str r0, [r1] - - /* wait for COP to halt then loading may proceed */ - ldr r1, =COP_STATUS -1: - ldr r0, [r1] - tst r0, #COP_SLEEPING - beq 1b - - ldr r0, =start_stub_end - add pc, r0, r4 - -cache_operation: /* (bool commit_discard) */ - ldr r2, =CACHE_CTRL - ldr r1, [r2] - tst r1, #CACHE_ENAB - bxeq lr - cmp r0, #CACHE_OP_COMMIT - ldr r0, =0xf000f044 - ldr r1, [r0] - orrne r1, r1, #0x6 - orreq r1, r1, #0x2 - str r1, [r0] -1: - ldr r1, [r2] - tst r1, #0x8000 - bne 1b - bx lr - .ltorg /* constants used in stub come with us to IRAM */ -start_stub_end: - /* now executing from final physical address */ - - /* copy the vector addresses to the table */ - ldr r0, =INT_VECT_TBL - adr r1, vectorsstart - adr r2, vectorsend -1: - cmp r2, r1 - ldrhi r3, [r1], #4 - strhi r3, [r0], #4 - bhi 1b - - /* Copy the IRAM */ - ldr r0, =_iramcopy - ldr r1, =_iramstart - ldr r2, =_iramend -1: - cmp r2, r1 - ldrhi r3, [r0], #4 - strhi r3, [r1], #4 - bhi 1b - - mov r0, #0 - - /* Zero out IBSS */ - ldr r1, =_iedata - ldr r2, =_iend -1: - cmp r2, r1 - strhi r0, [r1], #4 - bhi 1b - - /* Initialise bss/ncbss sections to zero */ - ldr r1, =_edata - ldr r2, =_end -1: - cmp r2, r1 - strhi r0, [r1], #4 - bhi 1b - - /* Set up stack for IRQ mode */ - msr cpsr_c, #0xd2 /* IRQ/FIQ disabled */ - ldr sp, =irq_stack - /* Let svc, abort and undefined modes use irq stack */ - msr cpsr_c, #0xd3 - ldr sp, =irq_stack - msr cpsr_c, #0xd7 /* IRQ/FIQ disabled */ - ldr sp, =irq_stack - msr cpsr_c, #0xdb /* IRQ/FIQ disabled */ - ldr sp, =irq_stack - - /* Switch back to sys mode */ - msr cpsr_c, #0xdf - - /* Set up some stack and munge it with 0xdeadbeef */ - ldr r0, =0xdeadbeef - ldr r1, =stackbegin - ldr sp, =stackend -1: - cmp sp, r1 - strhi r0, [r1], #4 - bhi 1b - - /* execute the loader - this will load an image to 0x10000000 */ - ldr r0, =main - mov lr, pc - bx r0 - - /* store actual startup location returned by main() */ - ldr r1, =startup_loc - str r0, [r1] - - /* write back anything loaded + startup_loc */ - mov r0, #CACHE_OP_COMMIT - bl cache_operation - - mov r0, #0 - - /* disable memory mapper */ - ldr r1, =MMAP_LOG - ldr r2, =MMAP_PHYS - str r0, [r1] - str r0, [r2] - - /* bring COP back to life */ - ldr r1, =COP_CTRL - mov r0, #WAKE - str r0, [r1] - - /* after this point, r0-r3 are reserved for OF magic */ - -#if defined(SANSA_C200) || defined(PHILIPS_HDD1630) - /* Magic for loading the c200 OF */ - ldr r0, =0xb00d10ad - mov r1, #0x700 - ldr r2, =0xfff0 - mov r3, #0x7 -#endif - -#if defined(PHILIPS_HDD6330) - /* Magic for loading the HDD6XX0 OF */ - ldr r0, =0xb00d10ad - mov r1, #0x800 - ldr r2, =0xfff0 - mov r3, #0x7 -#endif - - /* branch to the address returned by main() */ - adr r4, startup_loc - ldr pc, [r4] - -startup_loc: - .word 0x00000000 - -/* exception handlers: will be copied to local vector table */ -vectorsstart: - .word newstart - .word undef_instr_handler - .word software_int_handler - .word prefetch_abort_handler - .word data_abort_handler - .word reserved_handler - .word irq_handler - .word fiq_handler -vectorsend: - - .text - -/* All illegal exceptions call into UIE with exception address as first - parameter. This is calculated differently depending on which exception - we're in. Second parameter is exception number, used for a string lookup - in UIE. - */ -undef_instr_handler: - sub r0, lr, #4 - mov r1, #0 - b UIE - -/* We run sys mode most of the time, and should never see a software - exception being thrown. Make it illegal and call UIE. - */ -software_int_handler: -reserved_handler: - sub r0, lr, #4 - mov r1, #4 - b UIE - -prefetch_abort_handler: - sub r0, lr, #4 - mov r1, #1 - b UIE - -data_abort_handler: - sub r0, lr, #8 - mov r1, #2 - b UIE - -/* should never happen in the bootloader */ -fiq_handler: - subs pc, lr, #4 - -/* 256 words of IRQ stack */ - .section .bss - .balign 16 - .space 256*4 -irq_stack: diff --git a/firmware/target/arm/debug-pp.c b/firmware/target/arm/debug-pp.c deleted file mode 100644 index 5f252db417..0000000000 --- a/firmware/target/arm/debug-pp.c +++ /dev/null @@ -1,232 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2006 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "config.h" -#include "system.h" -#include -#include "font.h" -#include "lcd.h" -#include "button.h" -#include "powermgmt.h" -#include "adc.h" -#include "iap.h" -#include "hwcompat.h" -#include "debug-target.h" - -static int perfcheck(void) -{ - int result; - - asm ( - "mrs r2, CPSR \n" - "orr r0, r2, #0xc0 \n" /* disable IRQ and FIQ */ - "msr CPSR_c, r0 \n" - "mov %[res], #0 \n" - "ldr r0, [%[timr]] \n" - "add r0, r0, %[tmo] \n" - "1: \n" - "add %[res], %[res], #1 \n" - "ldr r1, [%[timr]] \n" - "cmp r1, r0 \n" - "bmi 1b \n" - "msr CPSR_c, r2 \n" /* reset IRQ and FIQ state */ - : - [res]"=&r"(result) - : - [timr]"r"(&USEC_TIMER), - [tmo]"r"( -#if CONFIG_CPU == PP5002 - 16000 -#else /* PP5020/5022/5024 */ - 10226 -#endif - ) - : - "r0", "r1", "r2" - ); - return result; -} - -bool dbg_ports(void) -{ - int line; - - lcd_clear_display(); - lcd_setfont(FONT_SYSFIXED); - - while(1) - { - line = 0; -#if defined(CPU_PP502x) -#if (LCD_HEIGHT >= 176) /* Only for displays with appropriate height. */ - lcd_puts(0, line++, "GPIO ENABLE:"); - lcd_putsf(0, line++, "A: %02x E: %02x I: %02x", - (unsigned int)GPIOA_ENABLE, - (unsigned int)GPIOE_ENABLE, - (unsigned int)GPIOI_ENABLE); - lcd_putsf(0, line++, "B: %02x F: %02x J: %02x", - (unsigned int)GPIOB_ENABLE, - (unsigned int)GPIOF_ENABLE, - (unsigned int)GPIOJ_ENABLE); - lcd_putsf(0, line++, "C: %02x G: %02x K: %02x", - (unsigned int)GPIOC_ENABLE, - (unsigned int)GPIOG_ENABLE, - (unsigned int)GPIOK_ENABLE); - lcd_putsf(0, line++, "D: %02x H: %02x L: %02x", - (unsigned int)GPIOD_ENABLE, - (unsigned int)GPIOH_ENABLE, - (unsigned int)GPIOL_ENABLE); - line++; -#endif - lcd_puts(0, line++, "GPIO INPUT VAL:"); - lcd_putsf(0, line++, "A: %02x E: %02x I: %02x", - (unsigned int)GPIOA_INPUT_VAL, - (unsigned int)GPIOE_INPUT_VAL, - (unsigned int)GPIOI_INPUT_VAL); - lcd_putsf(0, line++, "B: %02x F: %02x J: %02x", - (unsigned int)GPIOB_INPUT_VAL, - (unsigned int)GPIOF_INPUT_VAL, - (unsigned int)GPIOJ_INPUT_VAL); - lcd_putsf(0, line++, "C: %02x G: %02x K: %02x", - (unsigned int)GPIOC_INPUT_VAL, - (unsigned int)GPIOG_INPUT_VAL, - (unsigned int)GPIOK_INPUT_VAL); - lcd_putsf(0, line++, "D: %02x H: %02x L: %02x", - (unsigned int)GPIOD_INPUT_VAL, - (unsigned int)GPIOH_INPUT_VAL, - (unsigned int)GPIOL_INPUT_VAL); - line++; - lcd_putsf(0, line++, "GPO32_VAL: %08lx", GPO32_VAL); - lcd_putsf(0, line++, "GPO32_EN: %08lx", GPO32_ENABLE); - lcd_putsf(0, line++, "DEV_EN: %08lx", DEV_EN); - lcd_putsf(0, line++, "DEV_EN2: %08lx", DEV_EN2); - lcd_putsf(0, line++, "DEV_EN3: %08lx", inl(0x60006044)); /* to be verified */ - lcd_putsf(0, line++, "DEV_INIT1: %08lx", DEV_INIT1); - lcd_putsf(0, line++, "DEV_INIT2: %08lx", DEV_INIT2); -#ifdef ADC_ACCESSORY - lcd_putsf(0, line++, "ACCESSORY: %d", adc_read(ADC_ACCESSORY)); -#endif -#if defined(IPOD_VIDEO) || defined(IPOD_NANO) - lcd_putsf(0, line++, "4066_ISTAT: %d", adc_read(ADC_4066_ISTAT)); -#endif - -#if defined(IPOD_ACCESSORY_PROTOCOL) - const unsigned char *serbuf = iap_get_serbuf(); - lcd_putsf(0, line++, "IAP: %02x %02x %02x %02x %02x %02x %02x %02x", - serbuf[0], serbuf[1], serbuf[2], serbuf[3], serbuf[4], serbuf[5], - serbuf[6], serbuf[7]); -#endif - -#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) - line++; - lcd_putsf(0, line++, "BATT: %03x UNK1: %03x", - adc_read(ADC_BATTERY), adc_read(ADC_UNKNOWN_1)); - lcd_putsf(0, line++, "REM: %03x PAD: %03x", - adc_read(ADC_REMOTE), adc_read(ADC_SCROLLPAD)); -#elif defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) - line++; - lcd_putsf(0, line++, "BATT: %03x UNK1: %03x", - adc_read(ADC_BATTERY), adc_read(ADC_UNKNOWN_1)); -#elif defined(SANSA_E200) || defined(PHILIPS_SA9200) - lcd_putsf(0, line++, "ADC_BVDD: %4d", adc_read(ADC_BVDD)); - lcd_putsf(0, line++, "ADC_RTCSUP: %4d", adc_read(ADC_RTCSUP)); - lcd_putsf(0, line++, "ADC_UVDD: %4d", adc_read(ADC_UVDD)); - lcd_putsf(0, line++, "ADC_CHG_IN: %4d", adc_read(ADC_CHG_IN)); - lcd_putsf(0, line++, "ADC_CVDD: %4d", adc_read(ADC_CVDD)); - lcd_putsf(0, line++, "ADC_BATTEMP: %4d", adc_read(ADC_BATTEMP)); - lcd_putsf(0, line++, "ADC_MICSUP1: %4d", adc_read(ADC_MICSUP1)); - lcd_putsf(0, line++, "ADC_MICSUP2: %4d", adc_read(ADC_MICSUP2)); - lcd_putsf(0, line++, "ADC_VBE1: %4d", adc_read(ADC_VBE1)); - lcd_putsf(0, line++, "ADC_VBE2: %4d", adc_read(ADC_VBE2)); - lcd_putsf(0, line++, "ADC_I_MICSUP1:%4d", adc_read(ADC_I_MICSUP1)); -#if !defined(PHILIPS_SA9200) - lcd_putsf(0, line++, "ADC_I_MICSUP2:%4d", adc_read(ADC_I_MICSUP2)); - lcd_putsf(0, line++, "ADC_VBAT: %4d", adc_read(ADC_VBAT)); -#endif -#endif - -#elif CONFIG_CPU == PP5002 - lcd_putsf(0, line++, "GPIO_A: %02x GPIO_B: %02x", - (unsigned int)GPIOA_INPUT_VAL, (unsigned int)GPIOB_INPUT_VAL); - lcd_putsf(0, line++, "GPIO_C: %02x GPIO_D: %02x", - (unsigned int)GPIOC_INPUT_VAL, (unsigned int)GPIOD_INPUT_VAL); - - lcd_putsf(0, line++, "DEV_EN: %08lx", DEV_EN); - lcd_putsf(0, line++, "CLOCK_ENABLE: %08lx", CLOCK_ENABLE); - lcd_putsf(0, line++, "CLOCK_SOURCE: %08lx", CLOCK_SOURCE); - lcd_putsf(0, line++, "PLL_CONTROL: %08lx", PLL_CONTROL); - lcd_putsf(0, line++, "PLL_DIV: %08lx", PLL_DIV); - lcd_putsf(0, line++, "PLL_MULT: %08lx", PLL_MULT); - lcd_putsf(0, line++, "TIMING1_CTL: %08lx", TIMING1_CTL); - lcd_putsf(0, line++, "TIMING2_CTL: %08lx", TIMING2_CTL); -#endif - lcd_update(); - if (button_get_w_tmo(HZ/10) == (DEBUG_CANCEL|BUTTON_REL)) - { - lcd_setfont(FONT_UI); - return false; - } - } - return false; -} - -bool dbg_hw_info(void) -{ - int line = 0; -#if defined(CPU_PP502x) - char pp_version[] = { (PP_VER2 >> 24) & 0xff, (PP_VER2 >> 16) & 0xff, - (PP_VER2 >> 8) & 0xff, (PP_VER2) & 0xff, - (PP_VER1 >> 24) & 0xff, (PP_VER1 >> 16) & 0xff, - (PP_VER1 >> 8) & 0xff, (PP_VER1) & 0xff, '\0' }; -#elif CONFIG_CPU == PP5002 - char pp_version[] = { (PP_VER4 >> 8) & 0xff, PP_VER4 & 0xff, - (PP_VER3 >> 8) & 0xff, PP_VER3 & 0xff, - (PP_VER2 >> 8) & 0xff, PP_VER2 & 0xff, - (PP_VER1 >> 8) & 0xff, PP_VER1 & 0xff, '\0' }; -#endif - - lcd_setfont(FONT_SYSFIXED); - lcd_clear_display(); - - lcd_puts(0, line++, "[Hardware info]"); - -#ifdef IPOD_ARCH - lcd_putsf(0, line++, "HW rev: 0x%08lx", IPOD_HW_REVISION); -#endif - -#if defined(IPOD_COLOR) || defined(IPOD_NANO) - extern int lcd_type; /* Defined in lcd-colornano.c */ - - lcd_putsf(0, line++, "LCD type: %d", lcd_type); -#endif - - lcd_putsf(0, line++, "PP version: %s", pp_version); - - lcd_putsf(0, line++, "Est. clock (kHz): %d", perfcheck()); - - lcd_update(); - - /* wait for exit */ - while (button_get_w_tmo(HZ/10) != (DEBUG_CANCEL|BUTTON_REL)); - - lcd_setfont(FONT_UI); - return false; -} diff --git a/firmware/target/arm/i2c-pp.c b/firmware/target/arm/i2c-pp.c deleted file mode 100644 index 58740b5c66..0000000000 --- a/firmware/target/arm/i2c-pp.c +++ /dev/null @@ -1,314 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * PP502X and PP5002 I2C driver - * - * Based on code from the ipodlinux project - http://ipodlinux.org/ - * Adapted for Rockbox in November 2005 - * - * Original file: linux/arch/armnommu/mach-ipod/hardware.c - * - * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "cpu.h" -#include "kernel.h" -#include "thread.h" -#include "logf.h" -#include "system.h" -#include "i2c.h" -#include "i2c-pp.h" -#include "ascodec.h" -#include "as3514.h" - -#define I2C_CTRL (*(volatile unsigned char*)(I2C_BASE+0x00)) -#define I2C_ADDR (*(volatile unsigned char*)(I2C_BASE+0x04)) -#define I2C_DATA(X) (*(volatile unsigned char*)(I2C_BASE+0xc+(4*X))) -#define I2C_STATUS (*(volatile unsigned char*)(I2C_BASE+0x1c)) - -/* I2C_CTRL bit definitions */ -#define I2C_SEND 0x80 - -/* I2C_STATUS bit definitions */ -#define I2C_BUSY (1<<6) - -/* Local functions definitions */ -static struct mutex i2c_mtx SHAREDBSS_ATTR; - -#define POLL_TIMEOUT (HZ) - -static int pp_i2c_wait_not_busy(void) -{ - unsigned long timeout; - timeout = current_tick + POLL_TIMEOUT; - while (TIME_BEFORE(current_tick, timeout)) { - if (!(I2C_STATUS & I2C_BUSY)) { - return 0; - } - yield(); - } - - return -1; -} - -static int pp_i2c_read_bytes(unsigned int addr, int len, unsigned char *data) -{ - int i; - - if (len < 1 || len > 4) - { - return -1; - } - - if (pp_i2c_wait_not_busy() < 0) - { - return -2; - } - - { - int old_irq_level = disable_irq_save(); - - /* clear top 15 bits, left shift 1, or in 0x1 for a read */ - I2C_ADDR = ((addr << 17) >> 16) | 0x1; - - I2C_CTRL |= 0x20; - - I2C_CTRL = (I2C_CTRL & ~0x6) | ((len-1) << 1); - - I2C_CTRL |= I2C_SEND; - - restore_irq(old_irq_level); - - if (pp_i2c_wait_not_busy() < 0) - { - return -2; - } - - old_irq_level = disable_irq_save(); - - if (data) - { - for ( i = 0; i < len; i++ ) - *data++ = I2C_DATA(i); - } - - restore_irq(old_irq_level); - } - - return 0; -} - -static int pp_i2c_send_bytes(unsigned int addr, int len, unsigned char *data) -{ - int i; - - if (len < 1 || len > 4) - { - return -1; - } - - if (pp_i2c_wait_not_busy() < 0) - { - return -2; - } - - { - int old_irq_level = disable_irq_save(); - - /* clear top 15 bits, left shift 1 */ - I2C_ADDR = (addr << 17) >> 16; - - I2C_CTRL &= ~0x20; - - for ( i = 0; i < len; i++ ) - { - I2C_DATA(i) = *data++; - } - - I2C_CTRL = (I2C_CTRL & ~0x6) | ((len-1) << 1); - - I2C_CTRL |= I2C_SEND; - - restore_irq(old_irq_level); - } - - return 0; -} - -static int pp_i2c_send_byte(unsigned int addr, int data0) -{ - unsigned char data[1]; - - data[0] = data0; - - return pp_i2c_send_bytes(addr, 1, data); -} - -/* Public functions */ -void i2c_lock(void) -{ - mutex_lock(&i2c_mtx); -} - -void i2c_unlock(void) -{ - mutex_unlock(&i2c_mtx); -} - -int i2c_readbytes(unsigned int dev_addr, int addr, int len, unsigned char *data) -{ - int i, n; - - mutex_lock(&i2c_mtx); - - if (addr >= 0) - pp_i2c_send_byte(dev_addr, addr); - - i = 0; - while (len > 0) - { - n = (len < 4) ? len : 4; - - if (pp_i2c_read_bytes(dev_addr, n, data + i) < 0) - break; - - len -= n; - i += n; - } - - mutex_unlock(&i2c_mtx); - - return i; -} - -int i2c_readbyte(unsigned int dev_addr, int addr) -{ - unsigned char data; - - mutex_lock(&i2c_mtx); - pp_i2c_send_byte(dev_addr, addr); - pp_i2c_read_bytes(dev_addr, 1, &data); - mutex_unlock(&i2c_mtx); - - return (int)data; -} - -int i2c_sendbytes(unsigned int addr, int len, const unsigned char *data) -{ - int i, n; - - mutex_lock(&i2c_mtx); - - i = 0; - while (len > 0) - { - n = (len < 4) ? len : 4; - - if (pp_i2c_send_bytes(addr, n, (unsigned char *)(data + i)) < 0) - break; - - len -= n; - i += n; - } - - mutex_unlock(&i2c_mtx); - - return i; -} - -int pp_i2c_send(unsigned int addr, int data0, int data1) -{ - int retval; - unsigned char data[2]; - - data[0] = data0; - data[1] = data1; - - mutex_lock(&i2c_mtx); - retval = pp_i2c_send_bytes(addr, 2, data); - mutex_unlock(&i2c_mtx); - - return retval; -} - -void i2c_init(void) -{ - /* From ipodlinux */ - mutex_init(&i2c_mtx); - -#ifdef IPOD_MINI - /* GPIO port C disable port 0x10 */ - GPIOC_ENABLE &= ~0x10; - - /* GPIO port C disable port 0x20 */ - GPIOC_ENABLE &= ~0x20; -#endif - -#if CONFIG_I2C == I2C_PP5002 - DEV_EN |= 0x2; -#else - DEV_EN |= DEV_I2C; /* Enable I2C */ -#endif - DEV_RS |= DEV_I2C; /* Start I2C Reset */ - DEV_RS &=~DEV_I2C; /* End I2C Reset */ - -#if CONFIG_I2C == I2C_PP5020 - outl(0x0, 0x600060a4); -#if defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) || \ - defined(SAMSUNG_YH820) || defined(SAMSUNG_YH920) || \ - defined(SAMSUNG_YH925) || defined(PBELL_VIBE500) - outl(inl(0x600060a4) | 0x20, 0x600060a4); - outl(inl(0x7000c020) | 0x3, 0x7000c020); - outl(0x55, 0x7000c02c); - outl(0x54, 0x7000c030); -#else - outl(0x80 | (0 << 8), 0x600060a4); -#endif -#elif CONFIG_I2C == I2C_PP5024 -#if defined(SANSA_E200) || defined(PHILIPS_SA9200) - /* Sansa OF sets this to 0x20 first, communicates with the AS3514 - then sets it to 0x23 - this still works fine though */ - outl(0x0, 0x600060a4); - outl(0x23, 0x600060a4); -#elif defined(SANSA_C200) - /* This is the init sequence from the Sansa c200 bootloader. - I'm not sure what's really necessary. */ - pp_i2c_wait_not_busy(); - - outl(0, 0x600060a4); - outl(0x64, 0x600060a4); - - outl(0x55, 0x7000c02c); - outl(0x54, 0x7000c030); - - outl(0, 0x600060a4); - outl(0x1e, 0x600060a4); - - ascodec_write(AS3514_SUPERVISOR, 5); -#elif defined(PHILIPS_SA9200) - outl(0x0, 0x600060a4); - outl(inl(0x600060a4) | 0x20, 0x600060a4); - - outl(inl(0x7000c020) | 0x3, 0x7000c020); - outl(0x55, 0x7000c02c); - outl(0x54, 0x7000c030); -#endif -#endif - - i2c_readbyte(0x8, 0); -} diff --git a/firmware/target/arm/i2s-pp.c b/firmware/target/arm/i2s-pp.c deleted file mode 100644 index 83f39515c4..0000000000 --- a/firmware/target/arm/i2s-pp.c +++ /dev/null @@ -1,95 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Portalplayer specific code for I2S - * - * 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) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "system.h" -#include "cpu.h" -#include "i2s.h" -#if defined (SANSA_E200) || defined (SANSA_C200) -#include "audiohw.h" -#include "pcm_sampr.h" -#endif - -#if CONFIG_CPU == PP5002 -void i2s_reset(void) -{ - /* I2S device reset */ - DEV_RS |= DEV_I2S; - DEV_RS &= ~DEV_I2S; - - /* I2S controller enable */ - IISCONFIG |= IIS_ENABLE; - - /* reset DAC and ADC fifo */ - IISFIFO_CFG |= IIS_RXCLR | IIS_TXCLR; -} -#else /* PP502X */ - -/* - * Reset the I2S BIT.FORMAT I2S, 16bit, FIFO.FORMAT 32bit - */ -void i2s_reset(void) -{ - /* I2S soft reset */ - IISCONFIG |= IIS_RESET; - IISCONFIG &= ~IIS_RESET; - - /* BIT.FORMAT */ - IISCONFIG = ((IISCONFIG & ~IIS_FORMAT_MASK) | IIS_FORMAT_IIS); - /* BIT.SIZE */ - IISCONFIG = ((IISCONFIG & ~IIS_SIZE_MASK) | IIS_SIZE_16BIT); - - /* FIFO.FORMAT */ - /* If BIT.SIZE < FIFO.FORMAT low bits will be 0 */ -#ifdef HAVE_AS3514 - /* AS3514 can only operate as I2S Slave */ - IISCONFIG |= IIS_MASTER; - - /* Set I2S to 44.1kHz */ -#ifdef PHILIPS_SA9200 - /* values taken from the SA9200 OF */ - IISCLK = (IISCLK & ~0x1ff) | 31; - IISDIV = (IISDIV & ~0xc0000000) | (2 << 30); - IISDIV = (IISDIV & ~0x3f) | 16; -#elif defined (SANSA_E200) || defined (SANSA_C200) - audiohw_set_sampr_dividers(HW_FREQ_DEFAULT); -#else - IISCLK = (IISCLK & ~0x1ff) | 33; - IISDIV = 7; -#endif -#endif /* HAVE_AS3514 */ - - IISCONFIG = ((IISCONFIG & ~IIS_FIFO_FORMAT_MASK) | IIS_FIFO_FORMAT_LE16_2); - - /* RX_ATN_LVL = when 12 slots full */ - /* TX_ATN_LVL = DMA request when 4 slots empty */ - IISFIFO_CFG |= IIS_RX_FULL_LVL_12 | IIS_TX_EMPTY_LVL_4; - - /* Rx.CLR = 1, TX.CLR = 1 */ - IISFIFO_CFG |= IIS_RXCLR | IIS_TXCLR; -} - -#endif /* CONFIG_CPU == */ diff --git a/firmware/target/arm/iriver/boot.lds b/firmware/target/arm/iriver/boot.lds index ed4fc351fe..6065b50310 100644 --- a/firmware/target/arm/iriver/boot.lds +++ b/firmware/target/arm/iriver/boot.lds @@ -1,2 +1,2 @@ #include "config.h" -#include "../boot-pp502x-bl-usb.lds" +#include "../pp/boot-pp502x-bl-usb.lds" diff --git a/firmware/target/arm/kernel-pp.c b/firmware/target/arm/kernel-pp.c deleted file mode 100644 index 2a00254173..0000000000 --- a/firmware/target/arm/kernel-pp.c +++ /dev/null @@ -1,64 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 by Björn Stenberg - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "config.h" -#include "system.h" -#include "kernel.h" - -#if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE) -void TIMER1(void) -{ - /* Run through the list of tick tasks (using main core) */ - TIMER1_VAL; /* Read value to ack IRQ */ - - /* Run through the list of tick tasks using main CPU core - - wake up the COP through its control interface to provide pulse */ - call_tick_tasks(); - -#if NUM_CORES > 1 - /* Pulse the COP */ - core_wake(COP); -#endif /* NUM_CORES */ -} -#endif - -/* Must be last function called init kernel/thread initialization */ -void tick_start(unsigned int interval_in_ms) -{ -#if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE) - TIMER1_CFG = 0x0; - TIMER1_VAL; - /* enable timer */ - TIMER1_CFG = 0xc0000000 | (interval_in_ms*1000 - 1); - /* unmask interrupt source */ - CPU_INT_EN = TIMER1_MASK; -#else - /* We don't enable interrupts in the bootloader */ - (void)interval_in_ms; -#endif -} - -#ifdef HAVE_BOOTLOADER_USB_MODE -void tick_stop(void) -{ - CPU_INT_DIS = TIMER1_MASK; - TIMER1_CFG = 0; -} -#endif diff --git a/firmware/target/arm/pcm-pp.c b/firmware/target/arm/pcm-pp.c deleted file mode 100644 index 3854206ae8..0000000000 --- a/firmware/target/arm/pcm-pp.c +++ /dev/null @@ -1,734 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2006 by Michael Sevakis - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include -#include "system.h" -#include "kernel.h" -#include "logf.h" -#include "audio.h" -#include "sound.h" -#include "pcm.h" -#include "pcm_sampr.h" -#include "pcm-internal.h" - -/** DMA **/ - -#ifdef CPU_PP502x -/* 16-bit, L-R packed into 32 bits with left in the least significant halfword */ -#define SAMPLE_SIZE 16 -/* DMA Requests from IIS, Memory to peripheral, single transfer, - wait for DMA request, interrupt on complete */ -#define DMA_PLAY_CONFIG ((DMA_REQ_IIS << DMA_CMD_REQ_ID_POS) | \ - DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \ - DMA_CMD_WAIT_REQ | DMA_CMD_INTR) -/* DMA status cannot be viewed from outside code in control because that can - * clear the interrupt from outside the handler and prevent the handler from - * from being called. Split up transfers to a reasonable size that is good as - * a timer, obtaining a keyclick position and peaking yet still keeps the - * FIQ count low. - */ -#define MAX_DMA_CHUNK_SIZE (pcm_curr_sampr >> 6) /* ~1/256 seconds */ -#else -/* 32-bit, one left 32-bit sample followed by one right 32-bit sample */ -#define SAMPLE_SIZE 32 -#endif - -struct dma_data -{ -/* NOTE: The order of size and p is important if you use assembler - optimised fiq handler, so don't change it. */ - union - { - unsigned long addr; - uint32_t *p16; /* For packed 16-16 stereo pairs */ - uint16_t *p32; /* For individual samples converted to 32-bit */ - }; - size_t size; -#if NUM_CORES > 1 - unsigned core; -#endif - int locked; - int state; -}; - -extern void *fiq_function; - -/* Dispatch to the proper handler and leave the main vector table alone */ -void fiq_handler(void) ICODE_ATTR __attribute__((naked)); -void fiq_handler(void) -{ - asm volatile ( - "ldr pc, [pc, #-4] \n" - "fiq_function: \n" - ".word 0 \n" - ); -} - -#ifdef HAVE_PCM_DMA_ADDRESS -void * pcm_dma_addr(void *addr) -{ - if (addr != NULL && (unsigned long)addr < UNCACHED_BASE_ADDR) - addr = UNCACHED_ADDR(addr); - return addr; -} -#endif - -/* TODO: Get simultaneous recording and playback to work. Just needs some tweaking */ - -/**************************************************************************** - ** Playback DMA transfer - **/ -static struct dma_data dma_play_data IBSS_ATTR = -{ - /* Initialize to a locked, stopped state */ - { .addr = 0 }, - .size = 0, -#if NUM_CORES > 1 - .core = 0x00, -#endif - .locked = 0, - .state = 0 -}; - -void pcm_dma_apply_settings(void) -{ - audiohw_set_frequency(pcm_fsel); -} - -#if defined(CPU_PP502x) -/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ -void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void) -{ - bool new_buffer = false; - register size_t size; - - DMA0_STATUS; /* Clear any pending interrupt */ - - size = (DMA0_CMD & 0xffff) + 4; /* Get size of trasfer that caused this - interrupt */ - dma_play_data.addr += size; - dma_play_data.size -= size; - - while (1) - { - if (dma_play_data.size > 0) { - size = MAX_DMA_CHUNK_SIZE; - /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less - * than a FIFO's worth of data after this transfer? */ - if (size + 16*4 > dma_play_data.size) - size = dma_play_data.size; - - /* Set the new DMA values and activate channel */ - DMA0_RAM_ADDR = dma_play_data.addr; - DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START; - - if (new_buffer) - pcm_play_dma_started_callback(); - return; - } - - new_buffer = true; - - /* Buffer empty. Try to get more. */ - pcm_play_get_more_callback((void **)&dma_play_data.addr, - &dma_play_data.size); - - if (dma_play_data.size == 0) { - /* No more data */ - return; - } - - if (dma_play_data.addr < UNCACHED_BASE_ADDR) { - /* Flush any pending cache writes */ - dma_play_data.addr = UNCACHED_ADDR(dma_play_data.addr); - commit_discard_idcache(); - } - } -} -#else -/* ASM optimised FIQ handler. Checks for the minimum allowed loop cycles by - * evalutation of free IISFIFO-slots against available source buffer words. - * Through this it is possible to move the check for IIS_TX_FREE_COUNT outside - * the loop and do some further optimization. Right after the loops (source - * buffer -> IISFIFO) are done we need to check whether we have to exit FIQ - * handler (this must be done, if all free FIFO slots were filled) or we will - * have to get some new source data. Important information kept from former - * ASM implementation (not used anymore): GCC fails to make use of the fact - * that FIQ mode has registers r8-r14 banked, and so does not need to be saved. - * This routine uses only these registers, and so will never touch the stack - * unless it actually needs to do so when calling pcm_callback_for_more. - * C version is still included below for reference and testing. - */ -#if 1 -void fiq_playback(void) ICODE_ATTR __attribute__((naked)); -void fiq_playback(void) -{ - /* r10 contains IISCONFIG address (set in crt0.S to minimise code in actual - * FIQ handler. r11 contains address of p (also set in crt0.S). Most other - * addresses we need are generated by using offsets with these two. - * r10 + 0x40 is IISFIFO_WR, and r10 + 0x0c is IISFIFO_CFG. - * r8 and r9 contains local copies of p and size respectively. - * r0-r3 and r12 is a working register. - */ - asm volatile ( - "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */ - - "mov r4, #0 \n" /* Was the callback called? */ -#if CONFIG_CPU == PP5002 - "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */ - "ldr r12, [r12] \n" -#endif - "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */ - "cmp r9, #0 \n" /* is size 0? */ - "beq .more_data \n" /* if so, ask pcmbuf for more data */ - -#if SAMPLE_SIZE == 16 - ".check_fifo: \n" - "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */ - "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 16 (PP502x) */ - - "mov r1, r0, lsr #16 \n" /* number of free FIFO slots */ - "cmp r1, r9, lsr #2 \n" /* number of words from source */ - "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */ - "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */ - - "subs r1, r1, #2 \n" - ".fifo_loop_2: \n" - "ldmgeia r8!, {r2, r12} \n" /* load four samples */ - "strge r2 , [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */ - "strge r12, [r10, %[wr]] \n" /* write sample 2-3 to IISFIFO_WR */ - "subges r1, r1, #2 \n" /* one more loop? */ - "bge .fifo_loop_2 \n" /* yes, continue */ - - "tst r1, #1 \n" /* two samples (one word) left? */ - "ldrne r12, [r8], #4 \n" /* load two samples */ - "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */ -#elif SAMPLE_SIZE == 32 - ".check_fifo: \n" - "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */ - "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */ - - "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */ - "beq .fifo_fill_complete \n" /* no complete pair? -> exit */ - "cmp r1, r9, lsr #2 \n" /* number of words from source */ - "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */ - "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */ - - ".fifo_loop: \n" - "ldr r12, [r8], #4 \n" /* load two samples */ - "mov r2 , r12, lsl #16 \n" /* put left sample at the top bits */ - "str r2 , [r10, %[wr]] \n" /* write top sample to IISFIFO_WR */ - "str r12, [r10, %[wr]] \n" /* write low sample to IISFIFO_WR*/ - "subs r1, r1, #1 \n" /* one more loop? */ - "bgt .fifo_loop \n" /* yes, continue */ - - ".fifo_fill_complete: \n" -#endif - "cmp r4, #0 \n" /* If fill came after get_more... */ - "beq .still_old_buffer \n" - "mov r4, #0 \n" - "ldr r2, =pcm_play_dma_started \n" - "ldrne r2, [r2] \n" - "cmp r2, #0 \n" - "movne lr, pc \n" - "bxne r2 \n" - - ".still_old_buffer: \n" - "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */ - "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */ - - ".more_data: \n" - "mov r4, #1 \n" /* Remember we did this */ - "ldr r2, =pcm_play_get_more_callback \n" - "mov r0, r11 \n" /* r0 = &p */ - "add r1, r11, #4 \n" /* r1 = &size */ - "mov lr, pc \n" /* call pcm_play_get_more_callback */ - "bx r2 \n" - "ldmia r11, { r8-r9 } \n" /* load new p and size */ - "cmp r9, #0 \n" - "bne .check_fifo \n" /* size != 0? refill */ - - ".exit: \n" /* (r9=0 if stopping, look above) */ - "stmia r11, { r8-r9 } \n" /* save p and size */ - "ldmfd sp!, { r0-r4, lr } \n" - "subs pc, lr, #4 \n" /* FIQ specific return sequence */ - ".ltorg \n" - : /* These must only be integers! No regs */ - : [mask]"i"(IIS_TX_FREE_MASK), - [cfg]"i"((int)&IISFIFO_CFG - (int)&IISCONFIG), - [wr]"i"((int)&IISFIFO_WR - (int)&IISCONFIG) - ); -} -#else /* C version for reference */ -void fiq_playback(void) __attribute__((interrupt ("FIQ"))) ICODE_ATTR; -/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ -void fiq_playback(void) -{ - bool new_buffer = false; - -#if CONFIG_CPU == PP5002 - inl(0xcf001040); -#endif - - do { - while (dma_play_data.size > 0) { - if (IIS_TX_FREE_COUNT < 2) { - if (new_buffer) { - new_buffer = false; - pcm_play_dma_started_callback(); - } - return; - } -#if SAMPLE_SIZE == 16 - IISFIFO_WR = *dma_play_data.p16++; -#elif SAMPLE_SIZE == 32 - IISFIFO_WR = *dma_play_data.p32++ << 16; - IISFIFO_WR = *dma_play_data.p32++ << 16; -#endif - dma_play_data.size -= 4; - } - - if (new_buffer) { - new_buffer = false; - pcm_play_dma_started_callback(); - } - - /* p is empty, get some more data */ - pcm_play_get_more_callback((void **)&dma_play_data.addr, - &dma_play_data.size); - new_buffer = true; - } while (dma_play_data.size); - - /* No more data */ -} -#endif /* ASM / C selection */ -#endif /* CPU_PP502x */ - -/* For the locks, FIQ must be disabled because the handler manipulates - IISCONFIG and the operation is not atomic - dual core support - will require other measures */ -void pcm_play_lock(void) -{ - int status = disable_fiq_save(); - - if (++dma_play_data.locked == 1) { -#ifdef CPU_PP502x - CPU_INT_DIS = DMA_MASK; -#else - IIS_IRQTX_REG &= ~IIS_IRQTX; -#endif - } - - restore_fiq(status); -} - -void pcm_play_unlock(void) -{ - int status = disable_fiq_save(); - - if (--dma_play_data.locked == 0 && dma_play_data.state != 0) { -#ifdef CPU_PP502x - CPU_INT_EN = DMA_MASK; -#else - IIS_IRQTX_REG |= IIS_IRQTX; -#endif - } - - restore_fiq(status); -} - -static void play_start_pcm(void) -{ - fiq_function = fiq_playback; - -#ifdef CPU_PP502x - /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less than a - * FIFO's worth of data after this transfer? */ - size_t size = MAX_DMA_CHUNK_SIZE; - if (size + 16*4 > dma_play_data.size) - size = dma_play_data.size; - - DMA0_RAM_ADDR = dma_play_data.addr; - DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START; - dma_play_data.state = 1; -#else - IISCONFIG &= ~IIS_TXFIFOEN; /* Stop transmitting */ - - /* Fill the FIFO or start when data is used up */ - while (1) { - if (IIS_TX_FREE_COUNT < 2 || dma_play_data.size == 0) { - IISCONFIG |= IIS_TXFIFOEN; /* Start transmitting */ - dma_play_data.state = 1; - return; - } - -#if SAMPLE_SIZE == 16 - IISFIFO_WR = *dma_play_data.p16++; -#elif SAMPLE_SIZE == 32 - IISFIFO_WR = *dma_play_data.p32++ << 16; - IISFIFO_WR = *dma_play_data.p32++ << 16; -#endif - dma_play_data.size -= 4; - } -#endif -} - -static void play_stop_pcm(void) -{ -#ifdef CPU_PP502x - unsigned long status = DMA0_STATUS; /* Snapshot- resume from this point */ - unsigned long cmd = DMA0_CMD; - size_t size = 0; - - /* Stop transfer */ - DMA0_CMD = cmd & ~(DMA_CMD_START | DMA_CMD_INTR); - - /* Wait for not busy + clear int */ - while (DMA0_STATUS & (DMA_STATUS_BUSY | DMA_STATUS_INTR)); - - if (status & DMA_STATUS_BUSY) { - /* Transfer was interrupted - leave what's left */ - size = (cmd & 0xfffc) - (status & 0xfffc); - } - else if (status & DMA_STATUS_INTR) { - /* Transfer was finished - DMA0_STATUS will have been reloaded - * automatically with size in DMA0_CMD. Setup to restart on next - * segment. */ - size = (cmd & 0xfffc) + 4; - } - /* else not an active state - size = 0 */ - - dma_play_data.addr += size; - dma_play_data.size -= size; - - if (dma_play_data.size == 0) - dma_play_data.addr = 0; /* Entire buffer has completed. */ -#else - /* Disable TX interrupt */ - IIS_IRQTX_REG &= ~IIS_IRQTX; -#endif - - /* Wait for FIFO to empty */ - while (!IIS_TX_IS_EMPTY); - - dma_play_data.state = 0; -} - -void pcm_play_dma_start(const void *addr, size_t size) -{ -#if NUM_CORES > 1 - /* This will become more important later - and different ! */ - dma_play_data.core = processor_id(); /* save initiating core */ -#endif - - pcm_play_dma_stop(); - -#ifdef CPU_PP502x - if ((unsigned long)addr < UNCACHED_BASE_ADDR) { - /* Flush any pending cache writes */ - addr = UNCACHED_ADDR(addr); - commit_discard_idcache(); - } - - dma_play_data.addr = (unsigned long)addr; - dma_play_data.size = size; - DMA0_PER_ADDR = (unsigned long)&IISFIFO_WR; - DMA0_FLAGS = DMA_FLAGS_UNK26; - DMA0_INCR = DMA_INCR_RANGE_FIXED | DMA_INCR_WIDTH_32BIT; -#else - dma_play_data.addr = (unsigned long)addr; - dma_play_data.size = size; -#endif - - play_start_pcm(); -} - -/* Stops the DMA transfer and interrupt */ -void pcm_play_dma_stop(void) -{ - play_stop_pcm(); - dma_play_data.addr = 0; - dma_play_data.size = 0; -#if NUM_CORES > 1 - dma_play_data.core = 0; /* no core in control */ -#endif -} - -void pcm_play_dma_pause(bool pause) -{ - if (pause) { - play_stop_pcm(); - } else { - play_start_pcm(); - } -} - -size_t pcm_get_bytes_waiting(void) -{ - return dma_play_data.size & ~3; -} - -void pcm_play_dma_init(void) -{ - /* Initialize default register values. */ - audiohw_init(); - -#ifdef CPU_PP502x - /* Enable DMA controller */ - DMA_MASTER_CONTROL |= DMA_MASTER_CONTROL_EN; - /* FIQ priority for DMA */ - CPU_INT_PRIORITY |= DMA_MASK; - /* Enable request?? Not setting or clearing everything doesn't seem to - * prevent it operating. Perhaps important for reliability (how requests - * are handled). */ - DMA_REQ_STATUS |= 1ul << DMA_REQ_IIS; - DMA0_STATUS; -#else - /* Set up banked registers for FIQ mode */ - - /* Use non-banked registers for scratch. */ - register volatile void *iiscfg asm("r0") = &IISCONFIG; - register volatile void *dmapd asm("r1") = &dma_play_data; - - asm volatile ( - "mrs r2, cpsr \n" /* Save mode and interrupt status */ - "msr cpsr_c, #0xd1 \n" /* Switch to FIQ mode */ - "mov r8, #0 \n" - "mov r9, #0 \n" - "mov r10, %[iiscfg] \n" - "mov r11, %[dmapd] \n" - "msr cpsr_c, r2 \n" - : - : [iiscfg]"r"(iiscfg), [dmapd]"r"(dmapd) - : "r2"); - - /* FIQ priority for I2S */ - CPU_INT_PRIORITY |= IIS_MASK; - CPU_INT_EN = IIS_MASK; -#endif - - IISCONFIG |= IIS_TXFIFOEN; -} - -void pcm_play_dma_postinit(void) -{ - audiohw_postinit(); -} - -const void * pcm_play_dma_get_peak_buffer(int *count) -{ - unsigned long addr, size; - - int status = disable_fiq_save(); - addr = dma_play_data.addr; - size = dma_play_data.size; - restore_fiq(status); - - *count = size >> 2; - return (void *)((addr + 2) & ~3); -} - -/**************************************************************************** - ** Recording DMA transfer - **/ -#ifdef HAVE_RECORDING -/* PCM recording interrupt routine lockout */ -static struct dma_data dma_rec_data IBSS_ATTR = -{ - /* Initialize to a locked, stopped state */ - { .addr = 0 }, - .size = 0, -#if NUM_CORES > 1 - .core = 0x00, -#endif - .locked = 0, - .state = 0 -}; - -/* For the locks, FIQ must be disabled because the handler manipulates - IISCONFIG and the operation is not atomic - dual core support - will require other measures */ -void pcm_rec_lock(void) -{ - int status = disable_fiq_save(); - - if (++dma_rec_data.locked == 1) - IIS_IRQRX_REG &= ~IIS_IRQRX; - - restore_fiq(status); -} - -void pcm_rec_unlock(void) -{ - int status = disable_fiq_save(); - - if (--dma_rec_data.locked == 0 && dma_rec_data.state != 0) - IIS_IRQRX_REG |= IIS_IRQRX; - - restore_fiq(status); -} - -/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ -void fiq_record(void) ICODE_ATTR __attribute__((interrupt ("FIQ"))); - -#if defined(SANSA_C200) || defined(SANSA_E200) -void fiq_record(void) -{ - register int32_t value; - - if (audio_channels == 2) { - /* RX is stereo */ - while (dma_rec_data.size > 0) { - if (IIS_RX_FULL_COUNT < 2) { - return; - } - - /* Discard every other sample since ADC clock is 1/2 LRCK */ - value = IISFIFO_RD; - IISFIFO_RD; - - *dma_rec_data.p16++ = value; - dma_rec_data.size -= 4; - - /* TODO: Figure out how to do IIS loopback */ - if (audio_output_source != AUDIO_SRC_PLAYBACK) { - if (IIS_TX_FREE_COUNT >= 16) { - /* Resync the output FIFO - it ran dry */ - IISFIFO_WR = 0; - IISFIFO_WR = 0; - } - IISFIFO_WR = value; - IISFIFO_WR = value; - } - } - } - else { - /* RX is left channel mono */ - while (dma_rec_data.size > 0) { - if (IIS_RX_FULL_COUNT < 2) { - return; - } - - /* Discard every other sample since ADC clock is 1/2 LRCK */ - value = IISFIFO_RD; - IISFIFO_RD; - - value = (uint16_t)value | (value << 16); - - *dma_rec_data.p16++ = value; - dma_rec_data.size -= 4; - - if (audio_output_source != AUDIO_SRC_PLAYBACK) { - if (IIS_TX_FREE_COUNT >= 16) { - /* Resync the output FIFO - it ran dry */ - IISFIFO_WR = 0; - IISFIFO_WR = 0; - } - - value = *((int32_t *)dma_rec_data.p16 - 1); - IISFIFO_WR = value; - IISFIFO_WR = value; - } - } - } - - pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr, - &dma_rec_data.size); -} - -#else -void fiq_record(void) -{ - while (dma_rec_data.size > 0) { - if (IIS_RX_FULL_COUNT < 2) { - return; - } - -#if SAMPLE_SIZE == 16 - *dma_rec_data.p16++ = IISFIFO_RD; -#elif SAMPLE_SIZE == 32 - *dma_rec_data.p32++ = IISFIFO_RD >> 16; - *dma_rec_data.p32++ = IISFIFO_RD >> 16; -#endif - dma_rec_data.size -= 4; - } - - pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr, - &dma_rec_data.size); -} - -#endif /* SANSA_E200 */ - -void pcm_rec_dma_stop(void) -{ - /* disable interrupt */ - IIS_IRQRX_REG &= ~IIS_IRQRX; - - dma_rec_data.state = 0; - dma_rec_data.size = 0; -#if NUM_CORES > 1 - dma_rec_data.core = 0x00; -#endif - - /* disable fifo */ - IISCONFIG &= ~IIS_RXFIFOEN; - IISFIFO_CFG |= IIS_RXCLR; -} - -void pcm_rec_dma_start(void *addr, size_t size) -{ - pcm_rec_dma_stop(); - - dma_rec_data.addr = (unsigned long)addr; - dma_rec_data.size = size; -#if NUM_CORES > 1 - /* This will become more important later - and different ! */ - dma_rec_data.core = processor_id(); /* save initiating core */ -#endif - /* setup FIQ handler */ - fiq_function = fiq_record; - - /* interrupt on full fifo, enable record fifo interrupt */ - dma_rec_data.state = 1; - - /* enable RX FIFO */ - IISCONFIG |= IIS_RXFIFOEN; - - /* enable IIS interrupt as FIQ */ - CPU_INT_PRIORITY |= IIS_MASK; - CPU_INT_EN = IIS_MASK; -} - -void pcm_rec_dma_close(void) -{ - pcm_rec_dma_stop(); -} /* pcm_close_recording */ - -void pcm_rec_dma_init(void) -{ - pcm_rec_dma_stop(); -} /* pcm_init */ - -const void * pcm_rec_dma_get_peak_buffer(void) -{ - return (void *)((unsigned long)dma_rec_data.addr & ~3); -} /* pcm_rec_dma_get_peak_buffer */ - -#endif /* HAVE_RECORDING */ diff --git a/firmware/target/arm/philips/boot.lds b/firmware/target/arm/philips/boot.lds index 5d63caddb0..46a2bfdfd2 100644 --- a/firmware/target/arm/philips/boot.lds +++ b/firmware/target/arm/philips/boot.lds @@ -2,7 +2,7 @@ /* Can't link all Philips ARM devices the same way at this time */ #ifdef HAVE_BOOTLOADER_USB_MODE -#include "../boot-pp502x-bl-usb.lds" +#include "../pp/boot-pp502x-bl-usb.lds" #else /* !HAVE_BOOTLOADER_USB_MODE */ ENTRY(start) OUTPUT_FORMAT(elf32-littlearm) diff --git a/firmware/target/arm/pp/adc-pp5020.c b/firmware/target/arm/pp/adc-pp5020.c new file mode 100644 index 0000000000..2d75a7e25f --- /dev/null +++ b/firmware/target/arm/pp/adc-pp5020.c @@ -0,0 +1,179 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Barry Wardell + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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 "kernel.h" +#include "thread.h" +#include "adc.h" + +#define ADC_ADDR (*(volatile unsigned long*)(0x7000ad00)) +#define ADC_STATUS (*(volatile unsigned long*)(0x7000ad04)) +#define ADC_DATA_1 (*(volatile unsigned long*)(0x7000ad20)) +#define ADC_DATA_2 (*(volatile unsigned long*)(0x7000ad24)) +#define ADC_INIT (*(volatile unsigned long*)(0x7000ad2c)) + +#if defined(PBELL_VIBE500) +#define ADC_UNK (*(volatile unsigned long*)(0x7000002c)) +#endif + +static unsigned short adcdata[NUM_ADC_CHANNELS]; + +/* Scan ADC so that adcdata[channel] gets updated. */ +unsigned short adc_scan(int channel) +{ + unsigned int adc_data_1; + unsigned int adc_data_2; + + if (channel >= NUM_ADC_CHANNELS) + return 0; + + /* Start conversion */ + ADC_ADDR |= 0x80000000; + + /* Wait for conversion to complete */ + while((ADC_STATUS & (0x40<<8*channel))==0); + + /* Stop conversion */ + ADC_ADDR &=~ 0x80000000; + + /* ADC_DATA_1 and ADC_DATA_2 are both four bytes, one byte per channel. + For each channel, ADC_DATA_1 stores the 8-bit msb, ADC_DATA_2 stores the + 2-bit lsb (in bits 0 and 1). Each channel is 10 bits total. */ + adc_data_1 = ((ADC_DATA_1 >> (8*channel)) & 0xff); + adc_data_2 = ((ADC_DATA_2 >> (8*channel+6)) & 0x3); + + adcdata[channel] = (adc_data_1<<2 | adc_data_2); + +#if !(defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330)) + /* ADC values read low if PLL is enabled */ + if(PLL_CONTROL & 0x80000000){ + adcdata[channel] += 0x14; + if(adcdata[channel] > 0x400) + adcdata[channel] = 0x400; + } +#endif + + return adcdata[channel]; +} + +/* Read 10-bit channel data */ +unsigned short adc_read(int channel) +{ + return adcdata[channel]; +} + +static int adc_counter; + +static void adc_tick(void) +{ + if(++adc_counter == HZ) + { + adc_counter = 0; + adc_scan(0); + adc_scan(1); + adc_scan(2); + adc_scan(3); + } +} + +/* Figured out from how the OF does things */ +void adc_init(void) +{ +#if defined(PBELL_VIBE500) + ADC_UNK |= 0x1000; +#endif + +#if defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) + ADC_INIT = 0; +#else + ADC_INIT |= 1; + ADC_INIT |= 0x40000000; +#endif + udelay(100); + + /* Reset ADC */ + DEV_RS2 |= 0x20; + udelay(100); + + DEV_RS2 &=~ 0x20; + udelay(100); + + /* Enable ADC */ + DEV_EN2 |= 0x20; + udelay(100); + + ADC_CLOCK_SRC |= 0x3; + udelay(100); + + ADC_ADDR = 0; + ADC_ADDR |= 0x40; + +#if !(defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330)) + ADC_ADDR |= 0x20000000; + udelay(100); + + ADC_INIT; + ADC_INIT = 0; + udelay(100); +#endif + + ADC_STATUS = 0; + + /* Enable channel 0 (battery) */ + DEV_INIT1 &=~0x3; + ADC_ADDR |= 0x1000000; + ADC_STATUS |= 0x20; + + /* Enable channel 1 (unknown) */ + DEV_INIT1 &=~30; + ADC_ADDR |= 0x2000000; + ADC_STATUS |= 0x2000; + +#if defined (IRIVER_H10) || defined(IRIVER_H10_5GB) || \ + defined(MROBE_100) + /* Enable channel 2 (H10:remote) */ + DEV_INIT1 &=~0x300; + DEV_INIT1 |= 0x100; + ADC_ADDR |= 0x4000000; + ADC_STATUS |= 0x200000; + + /* Enable channel 3 (H10:scroll pad) */ + DEV_INIT1 &=~0x3000; + DEV_INIT1 |= 0x1000; + ADC_ADDR |= 0x8000000; + ADC_STATUS |= 0x20000000; +#endif + +#if defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) + ADC_INIT |= 0x80000000; + udelay(100); + ADC_INIT = 0; +#endif + + /* Force a scan of all channels to get initial values */ + adc_scan(0); + adc_scan(1); + adc_scan(2); + adc_scan(3); + + tick_add_task(adc_tick); +} diff --git a/firmware/target/arm/pp/ascodec-pp.c b/firmware/target/arm/pp/ascodec-pp.c new file mode 100644 index 0000000000..49a69d1a11 --- /dev/null +++ b/firmware/target/arm/pp/ascodec-pp.c @@ -0,0 +1,82 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Driver for AS3514 audio codec + * + * Copyright (c) 2007 Daniel Ankers + * Copyright (c) 2007 Christian Gmeiner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "cpu.h" +#include "system.h" + +#include "audiohw.h" +#include "i2s.h" +#include "ascodec-target.h" + +/* + * Initialise the PP I2C and I2S. + */ +void audiohw_init(void) +{ + /* normal outputs for CDI and I2S pin groups */ + DEV_INIT2 &= ~0x300; + + /*mini2?*/ + DEV_INIT1 &=~0x3000000; + /*mini2?*/ + + /* I2S device reset */ + DEV_RS |= DEV_I2S; + DEV_RS &=~DEV_I2S; + + /* I2S device enable */ + DEV_EN |= DEV_I2S; + + /* enable external dev clock clocks */ + DEV_EN |= DEV_EXTCLOCKS; + + /* external dev clock to 24MHz */ + outl(inl(0x70000018) & ~0xc, 0x70000018); + +#ifdef SANSA_E200 + /* Prevent pops on startup */ + GPIOG_ENABLE |= 0x08; + GPIO_SET_BITWISE(GPIOG_OUTPUT_VAL, 0x08); + GPIOG_OUTPUT_EN |= 0x08; +#endif + + i2s_reset(); + + audiohw_preinit(); +} + +void ascodec_suppressor_on(bool on) +{ + /* CHECK: Good for c200 too? */ +#ifdef SANSA_E200 + if (on) { + /* Set pop prevention */ + GPIO_SET_BITWISE(GPIOG_OUTPUT_VAL, 0x08); + } else { + /* Release pop prevention */ + GPIO_CLEAR_BITWISE(GPIOG_OUTPUT_VAL, 0x08); + } +#else + (void)on; +#endif +} diff --git a/firmware/target/arm/pp/ata-pp5002.c b/firmware/target/arm/pp/ata-pp5002.c new file mode 100644 index 0000000000..5ab0e9ddc7 --- /dev/null +++ b/firmware/target/arm/pp/ata-pp5002.c @@ -0,0 +1,53 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Barry Wardell + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* ATA stuff was taken from the iPod code */ + +#include +#include "system.h" +#include "ata-driver.h" + +void ata_reset() +{ + +} + +void ata_enable(bool on) +{ + /* TODO: Implement ata_enable() */ + (void)on; +} + +bool ata_is_coldstart() +{ + return false; + /* TODO: Implement coldstart variable */ +} + +void ata_device_init() +{ + /* From ipod-ide.c:ipod_ide_register() */ + outl(inl(0xc0003024) | (1 << 7), 0xc0003024); + outl(inl(0xc0003024) & ~(1<<2), 0xc0003024); + + outl(0x10, 0xc0003000); + outl(0x80002150, 0xc0003004); +} diff --git a/firmware/target/arm/pp/ata-pp5020.c b/firmware/target/arm/pp/ata-pp5020.c new file mode 100644 index 0000000000..50a38cb23d --- /dev/null +++ b/firmware/target/arm/pp/ata-pp5020.c @@ -0,0 +1,248 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Barry Wardell + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* ATA stuff was taken from the iPod code */ + +#include +#include "system.h" +#include "ata-driver.h" + +void ata_reset() +{ + +} + +void ata_enable(bool on) +{ + /* TODO: Implement ata_enable() */ + (void)on; +} + +bool ata_is_coldstart() +{ + return false; + /* TODO: Implement coldstart variable */ +} + +void ata_device_init() +{ +#ifdef SAMSUNG_YH920 + CPU_INT_DIS = (1< 65MHz */ +#else + IDE0_CFG &=~(0x10000000); /* cpu < 65MHz */ +#endif +#endif + + IDE0_PRI_TIMING0 = 0x10; + IDE0_PRI_TIMING1 = 0x80002150; +} + +/* These are PIO timings for 80 Mhz. At 24 Mhz, + the first value is 0 but the rest are the same. + They go in IDE0_PRI_TIMING0. + + Rockbox used 0x10, and test_disk shows that leads to faster PIO. + If 0x10 is incorrect, these timings may be needed with some devices. +static const unsigned long pio80mhz[] = { + 0xC293, 0x43A2, 0x11A1, 0x7232, 0x3131 +}; +*/ + +#ifdef HAVE_ATA_DMA +/* Timings for multi-word and ultra DMA modes. + These go in IDE0_PRI_TIMING1 + */ +static const unsigned long tm_mwdma[] = { + 0xF9F92, 0x56562, 0x45451 +}; + +static const unsigned long tm_udma[] = { + 0x800037C1, 0x80003491, 0x80003371, +#if ATA_MAX_UDMA > 2 + 0x80003271, 0x80003071 +#endif +}; + +#if ATA_MAX_UDMA > 2 +static bool dma_boosted = false; +static bool dma_needs_boost; +#endif + +/* This function sets up registers for 80 Mhz. + Ultra DMA mode 2 works at 30 Mhz. + */ +void ata_dma_set_mode(unsigned char mode) { + int modeidx; + + (*(volatile unsigned long *)(0x600060C4)) = 0xC0000000; /* 80 Mhz */ +#if !defined(IPOD_NANO) + IDE0_CFG &= ~0x10000000; +#endif + + modeidx = mode & 7; + mode &= 0xF8; + if (mode == 0x40 && modeidx <= ATA_MAX_UDMA) { + IDE0_PRI_TIMING1 = tm_udma[modeidx]; +#if ATA_MAX_UDMA > 2 + if (modeidx > 2) + dma_needs_boost = true; + else + dma_needs_boost = false; +#endif + } else if (mode == 0x20 && modeidx <= ATA_MAX_MWDMA) + IDE0_PRI_TIMING1 = tm_mwdma[modeidx]; + +#if !defined(IPOD_NANO) + IDE0_CFG |= 0x20000000; /* >= 50 Mhz */ +#endif +} + +#define IDE_CFG_INTRQ 8 +#define IDE_DMA_CONTROL_READ 8 + +/* This waits for an ATA interrupt using polling. + In ATA_CONTROL, CONTROL_nIEN must be cleared. + */ +STATICIRAM ICODE_ATTR int ata_wait_intrq(void) +{ + long timeout = current_tick + HZ*10; + + do + { + if (IDE0_CFG & IDE_CFG_INTRQ) + return 1; + ata_keep_active(); + yield(); + } while (TIME_BEFORE(current_tick, timeout)); + + return 0; /* timeout */ +} + +/* This function checks if parameters are appropriate for DMA, + and if they are, it sets up for DMA. + + If return value is false, caller may use PIO for this transfer. + + If return value is true, caller must issue a DMA ATA command + and then call ata_dma_finish(). + */ +bool ata_dma_setup(void *addr, unsigned long bytes, bool write) { + /* Require cacheline alignment for reads to prevent interference. */ + if (!write && ((unsigned long)addr & 15)) + return false; + + /* Writes only need to be word-aligned, but by default DMA + * is not used for writing as it appears to be slower. + */ +#ifdef ATA_DMA_WRITES + if (write && ((unsigned long)addr & 3)) + return false; +#else + if (write) + return false; +#endif + +#if ATA_MAX_UDMA > 2 + if (dma_needs_boost && !dma_boosted) { + cpu_boost(true); + dma_boosted = true; + } +#endif + + if (write) { + /* If unflushed, old data may be written to disk */ + commit_dcache(); + } + else { + /* Invalidate cache because new data may be present in RAM */ + commit_discard_dcache(); + } + + /* Clear pending interrupts so ata_dma_finish() can wait for an + interrupt from this transfer + */ + IDE0_CFG |= IDE_CFG_INTRQ; + + IDE_DMA_CONTROL |= 2; + IDE_DMA_LENGTH = bytes - 4; + +#if !defined(BOOTLOADER) || defined (HAVE_BOOTLOADER_USB_MODE) + if ((unsigned long)addr < DRAM_START) + /* Rockbox remaps DRAM to start at 0 */ + IDE_DMA_ADDR = (unsigned long)addr + DRAM_START; + else +#endif + IDE_DMA_ADDR = (unsigned long)addr; + + if (write) + IDE_DMA_CONTROL &= ~IDE_DMA_CONTROL_READ; + else + IDE_DMA_CONTROL |= IDE_DMA_CONTROL_READ; + + IDE0_CFG |= 0x8000; + + return true; +} + +/* This function waits for a DMA transfer to end. + It must be called to finish what ata_dma_setup started. + + Return value is true if DMA completed before the timeout, and false + if a timeout happened. + */ +bool ata_dma_finish(void) { + bool res; + + /* It may be okay to put this at the end of setup */ + IDE_DMA_CONTROL |= 1; + + /* Wait for end of transfer. + Reading standard ATA status while DMA is in progress causes + failures and hangs. Because of that, another wait is used. + */ + res = ata_wait_intrq(); + + IDE0_CFG &= ~0x8000; + IDE_DMA_CONTROL &= ~0x80000001; + +#if ATA_MAX_UDMA > 2 + if (dma_boosted) { + cpu_boost(false); + dma_boosted = false; + } +#endif + + return res; +} + +#endif /* HAVE_ATA_DMA */ diff --git a/firmware/target/arm/pp/ata-sd-pp.c b/firmware/target/arm/pp/ata-sd-pp.c new file mode 100644 index 0000000000..f83bb60566 --- /dev/null +++ b/firmware/target/arm/pp/ata-sd-pp.c @@ -0,0 +1,1387 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Daniel Ankers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" /* for HAVE_MULTIDRIVE */ +#include "fat.h" +#include "sdmmc.h" +#include "gcc_extensions.h" +#ifdef HAVE_HOTSWAP +#include "sd-pp-target.h" +#endif +#include "ata_idle_notify.h" +#include "system.h" +#include +#include "thread.h" +#include "led.h" +#include "disk.h" +#include "cpu.h" +#include "panic.h" +#include "usb.h" +#include "sd.h" +#include "storage.h" + +#define SECTOR_SIZE 512 +#define BLOCKS_PER_BANK 0x7a7800 + +/* Comparing documentations of various MMC/SD controllers revealed, */ +/* that this controller seems to be a mix of PXA27x, PXA255 and */ +/* some PP specific stuff. The register and bit definitions are */ +/* taken from the 'PXA27x Developers Manual', as it appears to be */ +/* the closest match. Known differences and obscurities are commented.*/ + +#define MMC_STRPCL (*(volatile unsigned int *)(0x70008200)) +#define MMC_STAT (*(volatile unsigned int *)(0x70008204)) +#define MMC_CLKRT (*(volatile unsigned int *)(0x70008208)) +#define MMC_SPI (*(volatile unsigned int *)(0x7000820c)) +#define MMC_CMDAT (*(volatile unsigned int *)(0x70008210)) +#define MMC_RESTO (*(volatile unsigned int *)(0x70008214)) +#define MMC_RDTO (*(volatile unsigned int *)(0x70008218)) +#define MMC_BLKLEN (*(volatile unsigned int *)(0x7000821c)) +#define MMC_NUMBLK (*(volatile unsigned int *)(0x70008220)) +#define MMC_I_MASK (*(volatile unsigned int *)(0x70008224)) +#define MMC_CMD (*(volatile unsigned int *)(0x70008228)) +#define MMC_ARGH (*(volatile unsigned int *)(0x7000822c)) +#define MMC_ARGL (*(volatile unsigned int *)(0x70008230)) +#define MMC_RES (*(volatile unsigned int *)(0x70008234)) + +/* PXA255/27x have separate RX/TX FIFOs with 32x8 bit */ +/* PP502x has a combined Data FIFO with 16x16 bit */ +#define MMC_DATA_FIFO (*(volatile unsigned int *)(0x70008280)) + +/* PP specific registers, no other controller seem to have such. */ +#define MMC_SD_STATE (*(volatile unsigned int *)(0x70008238)) +#define MMC_INIT_1 (*(volatile unsigned int *)(0x70008240)) +#define MMC_INIT_2 (*(volatile unsigned int *)(0x70008244)) + +/* MMC_STAT bits */ +#define STAT_SDIO_SUSPEND_ACK (1 << 16) +#define STAT_SDIO_INT (1 << 15) +#define STAT_RD_STALLED (1 << 14) +#define STAT_END_CMD_RES (1 << 13) +#define STAT_PRG_DONE (1 << 12) +#define STAT_DATA_TRAN_DONE (1 << 11) +#define STAT_SPI_WR_ERR (1 << 10) +#define STAT_FLASH_ERR (1 << 9) +#define STAT_CLK_EN (1 << 8) +#define STAT_RECV_FIFO_FULL (1 << 7) /* taken from PXA255 */ +#define STAT_XMIT_FIFO_EMPTY (1 << 6) /* taken from PXA255 */ +#define STAT_RES_CRC_ERR (1 << 5) +#define STAT_DAT_ERR_TOKEN (1 << 4) +#define STAT_CRC_RD_ERR (1 << 3) +#define STAT_CRC_WR_ERR (1 << 2) +#define STAT_TIME_OUT_RES (1 << 1) +#define STAT_TIME_OUT_READ (1) +#define STAT_ERROR_BITS (0x3f) + +/* MMC_CMDAT bits */ +/* Some of the bits used by the OF don't make much sense with these */ +/* definitions. So they're probably different between PXA and PP502x */ +/* Bits 0-5 appear to match though. */ +#define CMDAT_SDIO_RESUME (1 << 13) +#define CMDAT_SDIO_SUSPEND (1 << 12) +#define CMDAT_SDIO_INT_EN (1 << 11) +#define CMDAT_STOP_TRAN (1 << 10) +#define CMDAT_SD_4DAT (1 << 8) +#define CMDAT_DMA_EN (1 << 7) +#define CMDAT_INIT (1 << 6) +#define CMDAT_BUSY (1 << 5) +#define CMDAT_STRM_BLK (1 << 4) +#define CMDAT_WR_RD (1 << 3) +#define CMDAT_DATA_EN (1 << 2) +#define CMDAT_RES_TYPE3 (3) +#define CMDAT_RES_TYPE2 (2) +#define CMDAT_RES_TYPE1 (1) + +/* MMC_I_MASK bits */ +/* PP502x apparently only has bits 0-3 */ +#define I_MASK_SDIO_SUSPEND_ACK (1 << 12) +#define I_MASK_SDIO_INT (1 << 11) +#define I_MASK_RD_STALLED (1 << 10) +#define I_MASK_RES_ERR (1 << 9) +#define I_MASK_DAT_ERR (1 << 8) +#define I_MASK_TINT (1 << 7) +#define I_MASK_TXFIFO_WR_REQ (1 << 6) +#define I_MASK_RXFIFO_RD_REQ (1 << 5) +#define I_MASK_CLK_IS_OFF (1 << 4) +#define I_MASK_STOP_CMD (1 << 3) +#define I_MASK_END_CMD_RES (1 << 2) +#define I_MASK_PRG_DONE (1 << 1) +#define I_MASK_DATA_TRAN_DONE (1 << 0) + +#define FIFO_LEN 16 /* FIFO is 16 words deep */ + +#define EC_OK 0 +#define EC_FAILED 1 +#define EC_NOCARD 2 +#define EC_WAIT_STATE_FAILED 3 +#define EC_CHECK_TIMEOUT_FAILED 4 +#define EC_POWER_UP 5 +#define EC_READ_TIMEOUT 6 +#define EC_WRITE_TIMEOUT 7 +#define EC_TRAN_SEL_BANK 8 +#define EC_TRAN_READ_ENTRY 9 +#define EC_TRAN_READ_EXIT 10 +#define EC_TRAN_WRITE_ENTRY 11 +#define EC_TRAN_WRITE_EXIT 12 +#define EC_FIFO_SEL_BANK_EMPTY 13 +#define EC_FIFO_SEL_BANK_DONE 14 +#define EC_FIFO_ENA_BANK_EMPTY 15 +#define EC_FIFO_READ_FULL 16 +#define EC_FIFO_WR_EMPTY 17 +#define EC_FIFO_WR_DONE 18 +#define EC_COMMAND 19 +#define NUM_EC 20 + +/* for compatibility */ +static long last_disk_activity = -1; + +/** static, private data **/ +static bool initialized = false; +static unsigned int sd_thread_id = 0; + +#define Q_CLOSE 1 + +static long next_yield = 0; +#define MIN_YIELD_PERIOD 1000 + +static tCardInfo card_info[2]; +static tCardInfo *currcard = NULL; /* current active card */ + +struct sd_card_status +{ + int retry; + int retry_max; +}; + +static struct sd_card_status sd_status[NUM_DRIVES] = +{ + { 0, 1 }, +#ifdef HAVE_MULTIDRIVE + { 0, 10 } +#endif +}; + +/* Shoot for around 75% usage */ +static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x1c0)/sizeof(long)]; +static const char sd_thread_name[] = "ata/sd"; +static struct mutex sd_mtx SHAREDBSS_ATTR; +static struct event_queue sd_queue SHAREDBSS_ATTR; + +#ifdef HAVE_HOTSWAP +static int sd_first_drive = 0; +#endif + +/* Posted when card plugged status has changed */ +#define SD_HOTSWAP 1 +/* Actions taken by sd_thread when card status has changed */ +enum sd_thread_actions +{ + SDA_NONE = 0x0, + SDA_UNMOUNTED = 0x1, + SDA_MOUNTED = 0x2 +}; + +/* Private Functions */ + +static unsigned int check_time[NUM_EC]; + +static inline bool sd_check_timeout(long timeout, int id) +{ + return !TIME_AFTER(USEC_TIMER, check_time[id] + timeout); +} + +static bool sd_poll_status(unsigned int trigger, long timeout) +{ + long t = USEC_TIMER; + + while ((MMC_STAT & trigger) == 0) + { + long time = USEC_TIMER; + + if (TIME_AFTER(time, next_yield)) + { + long ty = USEC_TIMER; + yield(); + timeout += USEC_TIMER - ty; + next_yield = ty + MIN_YIELD_PERIOD; + } + + if (TIME_AFTER(time, t + timeout)) + return false; + } + + return true; +} + +static int sd_command(unsigned int cmd, unsigned long arg1, + unsigned long *response, unsigned int cmdat) +{ + int i, words; /* Number of 16 bit words to read from MMC_RES */ + unsigned int data[9]; + + MMC_CMD = cmd; + MMC_ARGH = (unsigned int)((arg1 & 0xffff0000) >> 16); + MMC_ARGL = (unsigned int)((arg1 & 0xffff)); + MMC_CMDAT = cmdat; + + if (!sd_poll_status(STAT_END_CMD_RES, 100000)) + return -EC_COMMAND; + + if ((MMC_STAT & STAT_ERROR_BITS) != 0) + /* Error sending command */ + return -EC_COMMAND - (MMC_STAT & STAT_ERROR_BITS)*100; + + if (cmd == SD_GO_IDLE_STATE) + return 0; /* no response here */ + + words = (cmdat == CMDAT_RES_TYPE2) ? 9 : 3; + + for (i = 0; i < words; i++) /* MMC_RES is read MSB first */ + data[i] = MMC_RES; /* Read most significant 16-bit word */ + + if (response == NULL) + { + /* response discarded */ + } + else if (cmdat == CMDAT_RES_TYPE2) + { + /* Response type 2 has the following structure: + * [135:135] Start Bit - '0' + * [134:134] Transmission bit - '0' + * [133:128] Reserved - '111111' + * [127:001] CID or CSD register including internal CRC7 + * [000:000] End Bit - '1' + */ + response[3] = (data[0]<<24) + (data[1]<<8) + (data[2]>>8); + response[2] = (data[2]<<24) + (data[3]<<8) + (data[4]>>8); + response[1] = (data[4]<<24) + (data[5]<<8) + (data[6]>>8); + response[0] = (data[6]<<24) + (data[7]<<8) + (data[8]>>8); + } + else + { + /* Response types 1, 1b, 3, 6, 7 have the following structure: + * Types 4 and 5 are not supported. + * + * [47] Start bit - '0' + * [46] Transmission bit - '0' + * [45:40] R1, R1b, R6, R7: Command index + * R3: Reserved - '111111' + * [39:8] R1, R1b: Card Status + * R3: OCR Register + * R6: [31:16] RCA + * [15: 0] Card Status Bits 23, 22, 19, 12:0 + * [23] COM_CRC_ERROR + * [22] ILLEGAL_COMMAND + * [19] ERROR + * [12:9] CURRENT_STATE + * [8] READY_FOR_DATA + * [7:6] + * [5] SD_APP_CMD + * [4] + * [3] AKE_SEQ_ERROR + * [2] Reserved + * [1:0] Reserved for test mode + * R7: [19:16] Voltage accepted + * [15:8] echo-back of check pattern + * [7:1] R1, R1b: CRC7 + * R3: Reserved - '1111111' + * [0] End Bit - '1' + */ + response[0] = (data[0]<<24) + (data[1]<<8) + (data[2]>>8); + } + + return 0; +} + +static int sd_wait_for_state(unsigned int state, int id) +{ + unsigned long response = 0; + unsigned int timeout = 0x80000; + + check_time[id] = USEC_TIMER; + + while (1) + { + int ret = sd_command(SD_SEND_STATUS, currcard->rca, &response, CMDAT_RES_TYPE1); + long us; + + if (ret < 0) + return ret*100 - id; + + if (((response >> 9) & 0xf) == state) + { + MMC_SD_STATE = state; + return 0; + } + + if (!sd_check_timeout(timeout, id)) + return -EC_WAIT_STATE_FAILED*100 - id; + + us = USEC_TIMER; + if (TIME_AFTER(us, next_yield)) + { + yield(); + timeout += USEC_TIMER - us; + next_yield = us + MIN_YIELD_PERIOD; + } + } +} + + +static inline bool card_detect_target(void) +{ +#ifdef HAVE_HOTSWAP +#ifdef SANSA_E200 + return (GPIOA_INPUT_VAL & 0x80) == 0; /* low active */ +#elif defined SANSA_C200 + return (GPIOL_INPUT_VAL & 0x08) != 0; /* high active */ +#endif +#else + return false; +#endif +} + + +static inline void copy_read_sectors_fast(unsigned char **buf) +{ + /* Copy one chunk of 16 words using best method for start alignment */ + switch ( (intptr_t)*buf & 3 ) + { + case 0: + asm volatile ( + "ldmia %[data], { r2-r9 } \r\n" + "orr r2, r2, r3, lsl #16 \r\n" + "orr r4, r4, r5, lsl #16 \r\n" + "orr r6, r6, r7, lsl #16 \r\n" + "orr r8, r8, r9, lsl #16 \r\n" + "stmia %[buf]!, { r2, r4, r6, r8 } \r\n" + "ldmia %[data], { r2-r9 } \r\n" + "orr r2, r2, r3, lsl #16 \r\n" + "orr r4, r4, r5, lsl #16 \r\n" + "orr r6, r6, r7, lsl #16 \r\n" + "orr r8, r8, r9, lsl #16 \r\n" + "stmia %[buf]!, { r2, r4, r6, r8 } \r\n" + : [buf]"+&r"(*buf) + : [data]"r"(&MMC_DATA_FIFO) + : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9" + ); + break; + case 1: + asm volatile ( + "ldmia %[data], { r2-r9 } \r\n" + "orr r3, r2, r3, lsl #16 \r\n" + "strb r3, [%[buf]], #1 \r\n" + "mov r3, r3, lsr #8 \r\n" + "strh r3, [%[buf]], #2 \r\n" + "mov r3, r3, lsr #16 \r\n" + "orr r3, r3, r4, lsl #8 \r\n" + "orr r3, r3, r5, lsl #24 \r\n" + "mov r5, r5, lsr #8 \r\n" + "orr r5, r5, r6, lsl #8 \r\n" + "orr r5, r5, r7, lsl #24 \r\n" + "mov r7, r7, lsr #8 \r\n" + "orr r7, r7, r8, lsl #8 \r\n" + "orr r7, r7, r9, lsl #24 \r\n" + "mov r2, r9, lsr #8 \r\n" + "stmia %[buf]!, { r3, r5, r7 } \r\n" + "ldmia %[data], { r3-r10 } \r\n" + "orr r2, r2, r3, lsl #8 \r\n" + "orr r2, r2, r4, lsl #24 \r\n" + "mov r4, r4, lsr #8 \r\n" + "orr r4, r4, r5, lsl #8 \r\n" + "orr r4, r4, r6, lsl #24 \r\n" + "mov r6, r6, lsr #8 \r\n" + "orr r6, r6, r7, lsl #8 \r\n" + "orr r6, r6, r8, lsl #24 \r\n" + "mov r8, r8, lsr #8 \r\n" + "orr r8, r8, r9, lsl #8 \r\n" + "orr r8, r8, r10, lsl #24 \r\n" + "mov r10, r10, lsr #8 \r\n" + "stmia %[buf]!, { r2, r4, r6, r8 } \r\n" + "strb r10, [%[buf]], #1 \r\n" + : [buf]"+&r"(*buf) + : [data]"r"(&MMC_DATA_FIFO) + : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10" + ); + break; + case 2: + asm volatile ( + "ldmia %[data], { r2-r9 } \r\n" + "strh r2, [%[buf]], #2 \r\n" + "orr r3, r3, r4, lsl #16 \r\n" + "orr r5, r5, r6, lsl #16 \r\n" + "orr r7, r7, r8, lsl #16 \r\n" + "stmia %[buf]!, { r3, r5, r7 } \r\n" + "ldmia %[data], { r2-r8, r10 } \r\n" + "orr r2, r9, r2, lsl #16 \r\n" + "orr r3, r3, r4, lsl #16 \r\n" + "orr r5, r5, r6, lsl #16 \r\n" + "orr r7, r7, r8, lsl #16 \r\n" + "stmia %[buf]!, { r2, r3, r5, r7 } \r\n" + "strh r10, [%[buf]], #2 \r\n" + : [buf]"+&r"(*buf) + : [data]"r"(&MMC_DATA_FIFO) + : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10" + ); + break; + case 3: + asm volatile ( + "ldmia %[data], { r2-r9 } \r\n" + "orr r3, r2, r3, lsl #16 \r\n" + "strb r3, [%[buf]], #1 \r\n" + "mov r3, r3, lsr #8 \r\n" + "orr r3, r3, r4, lsl #24 \r\n" + "mov r4, r4, lsr #8 \r\n" + "orr r5, r4, r5, lsl #8 \r\n" + "orr r5, r5, r6, lsl #24 \r\n" + "mov r6, r6, lsr #8 \r\n" + "orr r7, r6, r7, lsl #8 \r\n" + "orr r7, r7, r8, lsl #24 \r\n" + "mov r8, r8, lsr #8 \r\n" + "orr r2, r8, r9, lsl #8 \r\n" + "stmia %[buf]!, { r3, r5, r7 } \r\n" + "ldmia %[data], { r3-r10 } \r\n" + "orr r2, r2, r3, lsl #24 \r\n" + "mov r3, r3, lsr #8 \r\n" + "orr r4, r3, r4, lsl #8 \r\n" + "orr r4, r4, r5, lsl #24 \r\n" + "mov r5, r5, lsr #8 \r\n" + "orr r6, r5, r6, lsl #8 \r\n" + "orr r6, r6, r7, lsl #24 \r\n" + "mov r7, r7, lsr #8 \r\n" + "orr r8, r7, r8, lsl #8 \r\n" + "orr r8, r8, r9, lsl #24 \r\n" + "mov r9, r9, lsr #8 \r\n" + "orr r10, r9, r10, lsl #8 \r\n" + "stmia %[buf]!, { r2, r4, r6, r8 } \r\n" + "strh r10, [%[buf]], #2 \r\n" + "mov r10, r10, lsr #16 \r\n" + "strb r10, [%[buf]], #1 \r\n" + : [buf]"+&r"(*buf) + : [data]"r"(&MMC_DATA_FIFO) + : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10" + ); + break; + } +} + +static inline void copy_read_sectors_slow(unsigned char** buf) +{ + int cnt = FIFO_LEN; + int t; + + /* Copy one chunk of 16 words */ + asm volatile ( + "1: \r\n" + "ldrh %[t], [%[data]] \r\n" + "strb %[t], [%[buf]], #1 \r\n" + "mov %[t], %[t], lsr #8 \r\n" + "strb %[t], [%[buf]], #1 \r\n" + "subs %[cnt], %[cnt], #1 \r\n" + "bgt 1b \r\n" + : [cnt]"+&r"(cnt), [buf]"+&r"(*buf), + [t]"=&r"(t) + : [data]"r"(&MMC_DATA_FIFO) + ); +} + +/* Writes have to be kept slow for now */ +static inline void copy_write_sectors(const unsigned char** buf) +{ + int cnt = FIFO_LEN - 1; + unsigned t; + long time; + + time = USEC_TIMER + 3; + if (((intptr_t)*buf & 3) == 0) + { + asm volatile ( + "ldmia %[buf]!, { r3, r5, r7, r9 } \r\n" + "mov r4, r3, lsr #16 \r\n" + "mov r6, r5, lsr #16 \r\n" + "mov r8, r7, lsr #16 \r\n" + "mov r10, r9, lsr #16 \r\n" + "stmia %[data], { r3-r10 } \r\n" + "ldmia %[buf]!, { r3, r5, r7, r9 } \r\n" + "mov r4, r3, lsr #16 \r\n" + "mov r6, r5, lsr #16 \r\n" + "mov r8, r7, lsr #16 \r\n" + "mov %[t], r9, lsr #16 \r\n" + "stmia %[data], { r3-r9 } \r\n" + : [buf]"+&r"(*buf), [t]"=&r"(t) + : [data]"r"(&MMC_DATA_FIFO) + : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10" + ); + } + else + { + do + { + t = *(*buf)++; + t |= *(*buf)++ << 8; + MMC_DATA_FIFO = t; + } while (--cnt > 0); /* tail loop is faster */ + t = *(*buf)++; + t |= *(*buf)++ << 8; + } + /* Don't write the last word before at least 3 usec have elapsed since FIFO_EMPTY */ + /* This prevents the 'two bytes inserted' bug. */ + + while (!TIME_AFTER(USEC_TIMER, time)); + MMC_DATA_FIFO = t; +} + +static int sd_select_bank(unsigned char bank) +{ + unsigned char card_data[FIFO_LEN*2];// FIFO_LEN words=FIFO_LEN*2 bytes + const unsigned char* write_buf; + int i, ret; + + memset(card_data, 0, sizeof card_data); + + ret = sd_wait_for_state(SD_TRAN, EC_TRAN_SEL_BANK); + if (ret < 0) + return ret; + + MMC_BLKLEN = 512; + MMC_NUMBLK = 1; + + ret = sd_command(35, 0, NULL, /* CMD35 is vendor specific */ + 0x1c00 | CMDAT_WR_RD | CMDAT_DATA_EN | CMDAT_RES_TYPE1); + if (ret < 0) + return ret; + + MMC_SD_STATE = SD_PRG; + + card_data[0] = bank; + + /* Write the card data */ + for (i = 0; i < SD_BLOCK_SIZE/2; i += FIFO_LEN) + { + write_buf = card_data; + /* Wait for the FIFO to empty */ + if (sd_poll_status(STAT_XMIT_FIFO_EMPTY, 10000)) + { + copy_write_sectors(&write_buf); /* Copy one chunk of 16 words */ + /* clear buffer: only the first chunk contains interesting data (bank), the remaining is zero filling */ + memset(card_data, 0, sizeof card_data); + continue; + } + + return -EC_FIFO_SEL_BANK_EMPTY; + } + + if (!sd_poll_status(STAT_PRG_DONE, 10000)) + return -EC_FIFO_SEL_BANK_DONE; + + currcard->current_bank = bank; + + return 0; +} + +static void sd_card_mux(int card_no) +{ +/* Set the current card mux */ +#if defined(SANSA_E200) + if (card_no == 0) + { + GPO32_VAL |= 0x4; + + GPIO_CLEAR_BITWISE(GPIOA_ENABLE, 0x7a); + GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_EN, 0x7a); + GPIO_SET_BITWISE(GPIOD_ENABLE, 0x1f); + GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL, 0x1f); + GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x1f); + + outl((inl(0x70000014) & ~(0x3ffff)) | 0x255aa, 0x70000014); + } + else + { + GPO32_VAL &= ~0x4; + + GPIO_CLEAR_BITWISE(GPIOD_ENABLE, 0x1f); + GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN, 0x1f); + GPIO_SET_BITWISE(GPIOA_ENABLE, 0x7a); + GPIO_SET_BITWISE(GPIOA_OUTPUT_VAL, 0x7a); + GPIO_SET_BITWISE( GPIOA_OUTPUT_EN, 0x7a); + + outl(inl(0x70000014) & ~(0x3ffff), 0x70000014); + } +#elif defined(SANSA_C200) + if (card_no == 0) + { + GPO32_VAL |= 0x4; + + GPIO_CLEAR_BITWISE(GPIOD_ENABLE, 0x1f); + GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_EN, 0x1f); + GPIO_SET_BITWISE(GPIOA_ENABLE, 0x7a); + GPIO_SET_BITWISE(GPIOA_OUTPUT_VAL, 0x7a); + GPIO_SET_BITWISE( GPIOA_OUTPUT_EN, 0x7a); + + outl(inl(0x70000014) & ~(0x3ffff), 0x70000014); + } + else + { + GPO32_VAL &= ~0x4; + + GPIO_CLEAR_BITWISE(GPIOA_ENABLE, 0x7a); + GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_EN, 0x7a); + GPIO_SET_BITWISE(GPIOD_ENABLE, 0x1f); + GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL, 0x1f); + GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x1f); + + outl((inl(0x70000014) & ~(0x3ffff)) | 0x255aa, 0x70000014); + } +#elif defined(PHILIPS_SA9200) + /* only 1 "card" (no external memory card) */ + (void)card_no; + + GPIO_SET_BITWISE(GPIOH_ENABLE, 0x80); + GPIO_SET_BITWISE(GPIOH_OUTPUT_EN, 0x80); + + outl(0x255aa, 0x70000014); + + GPIO_CLEAR_BITWISE(GPIOA_ENABLE, 0x04); + GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_EN, 0x04); + + GPIO_CLEAR_BITWISE(GPIOA_ENABLE, 0x7a); + GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_EN, 0x7a); + + GPIO_SET_BITWISE(GPIOH_OUTPUT_VAL, 0x80); + GPIO_SET_BITWISE(GPIOH_OUTPUT_EN, 0x80); +#endif +} + +static void sd_init_device(int card_no) +{ +/* SD Protocol registers */ +#ifdef HAVE_HOTSWAP + unsigned long response = 0; +#endif + unsigned int i; + unsigned char carddata[512]; + unsigned char *dataptr; + unsigned long temp_reg[4]; + int ret; + +/* Enable and initialise controller */ + MMC_CLKRT = 6; /* switch to lowest clock rate */ + +/* Initialise card data as blank */ + memset(currcard, 0, sizeof(*currcard)); + +/* Switch card mux to card to initialize */ + sd_card_mux(card_no); + +/* Init NAND */ + MMC_INIT_1 |= (1 << 15); + MMC_INIT_2 |= (1 << 15); + MMC_INIT_2 &= ~(3 << 12); + MMC_INIT_2 |= (1 << 13); + MMC_INIT_1 &= ~(3 << 12); + MMC_INIT_1 |= (1 << 13); + + DEV_EN |= DEV_ATA; /* Enable controller */ + DEV_RS |= DEV_ATA; /* Reset controller */ + DEV_RS &=~DEV_ATA; /* Clear Reset */ + + MMC_SD_STATE = SD_TRAN; + + MMC_I_MASK = 0xf; /* disable interrupts */ + + ret = sd_command(SD_GO_IDLE_STATE, 0, NULL, 0x100); + if (ret < 0) + goto card_init_error; + + check_time[EC_POWER_UP] = USEC_TIMER; + +#ifdef HAVE_HOTSWAP + /* Check for SDHC: + - non-SDHC cards simply ignore SD_SEND_IF_COND (CMD8) and we get error -219, + which we can just ignore and assume we're dealing with standard SD. + - SDHC cards echo back the argument into the response. This is how we + tell if the card is SDHC. + */ + ret = sd_command(SD_SEND_IF_COND,0x1aa, &response, + CMDAT_DATA_EN | CMDAT_RES_TYPE3); + if ( (ret < 0) && (ret!=-219) ) + goto card_init_error; +#endif + + while ((currcard->ocr & (1 << 31)) == 0) /* until card is powered up */ + { + ret = sd_command(SD_APP_CMD, currcard->rca, NULL, CMDAT_RES_TYPE1); + if (ret < 0) + goto card_init_error; + +#ifdef HAVE_HOTSWAP + if(response == 0x1aa) + { + /* SDHC */ + ret = sd_command(SD_APP_OP_COND, (1<<30)|0x100000, + &currcard->ocr, CMDAT_RES_TYPE3); + } + else +#endif /* HAVE_HOTSWAP */ + { + /* SD Standard */ + ret = sd_command(SD_APP_OP_COND, 0x100000, &currcard->ocr, + CMDAT_RES_TYPE3); + } + + if (ret < 0) + goto card_init_error; + + if (!sd_check_timeout(5000000, EC_POWER_UP)) + { + ret = -EC_POWER_UP; + goto card_init_error; + } + } + + ret = sd_command(SD_ALL_SEND_CID, 0, temp_reg, CMDAT_RES_TYPE2); + if (ret < 0) + goto card_init_error; + + for(i=0; i<4; i++) + currcard->cid[i] = temp_reg[3-i]; + + ret = sd_command(SD_SEND_RELATIVE_ADDR, 0, &currcard->rca, CMDAT_RES_TYPE1); + if (ret < 0) + goto card_init_error; + + ret = sd_command(SD_SEND_CSD, currcard->rca, temp_reg, CMDAT_RES_TYPE2); + if (ret < 0) + goto card_init_error; + + for(i=0; i<4; i++) + currcard->csd[i] = temp_reg[3-i]; + + sd_parse_csd(currcard); + + MMC_CLKRT = 0; /* switch to highest clock rate */ + + ret = sd_command(SD_SELECT_CARD, currcard->rca, NULL, + 0x80 | CMDAT_RES_TYPE1); + if (ret < 0) + goto card_init_error; + + ret = sd_command(SD_APP_CMD, currcard->rca, NULL, CMDAT_RES_TYPE1); + if (ret < 0) + goto card_init_error; + + ret = sd_command(SD_SET_BUS_WIDTH, currcard->rca | 2, NULL, + CMDAT_RES_TYPE1); /* 4 bit */ + if (ret < 0) + goto card_init_error; + + ret = sd_command(SD_SET_BLOCKLEN, currcard->blocksize, NULL, + CMDAT_RES_TYPE1); + if (ret < 0) + goto card_init_error; + + MMC_BLKLEN = currcard->blocksize; + + /* If this card is >4GB & not SDHC, then we need to enable bank switching */ + if( (currcard->numblocks >= BLOCKS_PER_BANK) && + ((currcard->ocr & (1<<30)) == 0) ) + { + MMC_SD_STATE = SD_TRAN; + MMC_NUMBLK = 1; + + ret = sd_command(SD_SWITCH_FUNC, 0x80ffffef, NULL, + 0x1c00 | CMDAT_DATA_EN | CMDAT_RES_TYPE1); + if (ret < 0) + goto card_init_error; + + /* Read 512 bytes from the card. + The first 512 bits contain the status information + TODO: Do something useful with this! */ + dataptr = carddata; + for (i = 0; i < SD_BLOCK_SIZE/2; i += FIFO_LEN) + { + /* Wait for the FIFO to be full */ + if (sd_poll_status(STAT_RECV_FIFO_FULL, 100000)) + { + copy_read_sectors_slow(&dataptr); + continue; + } + + ret = -EC_FIFO_ENA_BANK_EMPTY; + goto card_init_error; + } + } + + currcard->initialized = 1; + return; + + /* Card failed to initialize so disable it */ +card_init_error: + currcard->initialized = ret; +} + +/* lock must already be aquired */ +static void sd_select_device(int card_no) +{ + currcard = &card_info[card_no]; + + if (card_no == 0) + { + /* Main card always gets a chance */ + sd_status[0].retry = 0; + } + + if (currcard->initialized > 0) + { + /* This card is already initialized - switch to it */ + sd_card_mux(card_no); + return; + } + + if (currcard->initialized == 0) + { + /* Card needs (re)init */ + sd_init_device(card_no); + } +} + +/* API Functions */ + +int sd_read_sectors(IF_MD2(int drive,) unsigned long start, int incount, + void* inbuf) +{ +#ifndef HAVE_MULTIDRIVE + const int drive = 0; +#endif + int ret; + unsigned char *buf, *buf_end; + unsigned int bank; + + /* TODO: Add DMA support. */ + + mutex_lock(&sd_mtx); + sd_enable(true); + led(true); + +sd_read_retry: + if (drive != 0 && !card_detect_target()) + { + /* no external sd-card inserted */ + ret = -EC_NOCARD; + goto sd_read_error; + } + + sd_select_device(drive); + + if (currcard->initialized < 0) + { + ret = currcard->initialized; + goto sd_read_error; + } + + last_disk_activity = current_tick; + + /* Only switch banks with non-SDHC cards */ + if((currcard->ocr & (1<<30))==0) + { + bank = start / BLOCKS_PER_BANK; + + if (currcard->current_bank != bank) + { + ret = sd_select_bank(bank); + if (ret < 0) + goto sd_read_error; + } + + start -= bank * BLOCKS_PER_BANK; + } + + ret = sd_wait_for_state(SD_TRAN, EC_TRAN_READ_ENTRY); + if (ret < 0) + goto sd_read_error; + + MMC_NUMBLK = incount; + +#ifdef HAVE_HOTSWAP + if(currcard->ocr & (1<<30) ) + { + /* SDHC */ + ret = sd_command(SD_READ_MULTIPLE_BLOCK, start, NULL, + 0x1c00 | CMDAT_BUSY | CMDAT_DATA_EN | CMDAT_RES_TYPE1); + } + else +#endif + { + ret = sd_command(SD_READ_MULTIPLE_BLOCK, start * SD_BLOCK_SIZE, NULL, + 0x1c00 | CMDAT_BUSY | CMDAT_DATA_EN | CMDAT_RES_TYPE1); + } + if (ret < 0) + goto sd_read_error; + + /* TODO: Don't assume SD_BLOCK_SIZE == SECTOR_SIZE */ + + buf_end = (unsigned char *)inbuf + incount * currcard->blocksize; + for (buf = inbuf; buf < buf_end;) + { + /* Wait for the FIFO to be full */ + if (sd_poll_status(STAT_RECV_FIFO_FULL, 0x80000)) + { + copy_read_sectors_fast(&buf); /* Copy one chunk of 16 words */ + /* TODO: Switch bank if necessary */ + continue; + } + + ret = -EC_FIFO_READ_FULL; + goto sd_read_error; + } + + last_disk_activity = current_tick; + + ret = sd_command(SD_STOP_TRANSMISSION, 0, NULL, CMDAT_RES_TYPE1); + if (ret < 0) + goto sd_read_error; + + ret = sd_wait_for_state(SD_TRAN, EC_TRAN_READ_EXIT); + if (ret < 0) + goto sd_read_error; + + while (1) + { + led(false); + sd_enable(false); + mutex_unlock(&sd_mtx); + + return ret; + +sd_read_error: + if (sd_status[drive].retry < sd_status[drive].retry_max + && ret != -EC_NOCARD) + { + sd_status[drive].retry++; + currcard->initialized = 0; + goto sd_read_retry; + } + } +} + +int sd_write_sectors(IF_MD2(int drive,) unsigned long start, int count, + const void* outbuf) +{ +/* Write support is not finished yet */ +/* TODO: The standard suggests using ACMD23 prior to writing multiple blocks + to improve performance */ +#ifndef HAVE_MULTIDRIVE + const int drive = 0; +#endif + int ret; + const unsigned char *buf, *buf_end; + unsigned int bank; + + mutex_lock(&sd_mtx); + sd_enable(true); + led(true); + +sd_write_retry: + if (drive != 0 && !card_detect_target()) + { + /* no external sd-card inserted */ + ret = -EC_NOCARD; + goto sd_write_error; + } + + sd_select_device(drive); + + if (currcard->initialized < 0) + { + ret = currcard->initialized; + goto sd_write_error; + } + + /* Only switch banks with non-SDHC cards */ + if((currcard->ocr & (1<<30))==0) + { + bank = start / BLOCKS_PER_BANK; + + if (currcard->current_bank != bank) + { + ret = sd_select_bank(bank); + if (ret < 0) + goto sd_write_error; + } + + start -= bank * BLOCKS_PER_BANK; + } + + check_time[EC_WRITE_TIMEOUT] = USEC_TIMER; + + ret = sd_wait_for_state(SD_TRAN, EC_TRAN_WRITE_ENTRY); + if (ret < 0) + goto sd_write_error; + + MMC_NUMBLK = count; + +#ifdef HAVE_HOTSWAP + if(currcard->ocr & (1<<30) ) + { + /* SDHC */ + ret = sd_command(SD_WRITE_MULTIPLE_BLOCK, start, NULL, + CMDAT_WR_RD | CMDAT_DATA_EN | CMDAT_RES_TYPE1); + } + else +#endif + { + ret = sd_command(SD_WRITE_MULTIPLE_BLOCK, start*SD_BLOCK_SIZE, NULL, + CMDAT_WR_RD | CMDAT_DATA_EN | CMDAT_RES_TYPE1); + } + if (ret < 0) + goto sd_write_error; + + buf_end = outbuf + count * currcard->blocksize - 2*FIFO_LEN; + + for (buf = outbuf; buf <= buf_end;) + { + if (buf == buf_end) + { + /* Set MMC_SD_STATE to SD_PRG for the last buffer fill */ + MMC_SD_STATE = SD_PRG; + } + + copy_write_sectors(&buf); /* Copy one chunk of 16 words */ + /* TODO: Switch bank if necessary */ + + /* Wait for the FIFO to empty */ + if (!sd_poll_status(STAT_XMIT_FIFO_EMPTY, 0x80000)) + { + ret = -EC_FIFO_WR_EMPTY; + goto sd_write_error; + } + } + + last_disk_activity = current_tick; + + if (!sd_poll_status(STAT_PRG_DONE, 0x80000)) + { + ret = -EC_FIFO_WR_DONE; + goto sd_write_error; + } + + ret = sd_command(SD_STOP_TRANSMISSION, 0, NULL, CMDAT_RES_TYPE1); + if (ret < 0) + goto sd_write_error; + + ret = sd_wait_for_state(SD_TRAN, EC_TRAN_WRITE_EXIT); + if (ret < 0) + goto sd_write_error; + + while (1) + { + led(false); + sd_enable(false); + mutex_unlock(&sd_mtx); + + return ret; + +sd_write_error: + if (sd_status[drive].retry < sd_status[drive].retry_max + && ret != -EC_NOCARD) + { + sd_status[drive].retry++; + currcard->initialized = 0; + goto sd_write_retry; + } + } +} + +#ifndef SD_DRIVER_CLOSE +static void sd_thread(void) NORETURN_ATTR; +#endif +static void sd_thread(void) +{ + struct queue_event ev; + bool idle_notified = false; + + while (1) + { + queue_wait_w_tmo(&sd_queue, &ev, HZ); + + switch ( ev.id ) + { +#ifdef HAVE_HOTSWAP + case SYS_HOTSWAP_INSERTED: + case SYS_HOTSWAP_EXTRACTED: + fat_lock(); /* lock-out FAT activity first - + prevent deadlocking via disk_mount that + would cause a reverse-order attempt with + another thread */ + mutex_lock(&sd_mtx); /* lock-out card activity - direct calls + into driver that bypass the fat cache */ + + /* We now have exclusive control of fat cache and ata */ + + disk_unmount(sd_first_drive+1); /* release "by force", ensure file + descriptors aren't leaked and any busy + ones are invalid if mounting */ + + /* Force card init for new card, re-init for re-inserted one or + * clear if the last attempt to init failed with an error. */ + card_info[1].initialized = 0; + sd_status[1].retry = 0; + + if (ev.id == SYS_HOTSWAP_INSERTED) + disk_mount(sd_first_drive+1); + + queue_broadcast(SYS_FS_CHANGED, 0); + + /* Access is now safe */ + mutex_unlock(&sd_mtx); + fat_unlock(); + break; +#endif + case SYS_TIMEOUT: + if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) + { + idle_notified = false; + } + else + { + /* never let a timer wrap confuse us */ + next_yield = USEC_TIMER; + + if (!idle_notified) + { + call_storage_idle_notifys(false); + idle_notified = true; + } + } + break; + case SYS_USB_CONNECTED: + usb_acknowledge(SYS_USB_CONNECTED_ACK); + /* Wait until the USB cable is extracted again */ + usb_wait_for_disconnect(&sd_queue); + break; + +#ifdef SD_DRIVER_CLOSE + case Q_CLOSE: + return; +#endif + } + } +} + +#ifdef SD_DRIVER_CLOSE +void sd_close(void) +{ + unsigned int thread_id = sd_thread_id; + + if (thread_id == 0) + return; + + sd_thread_id = 0; + + queue_post(&sd_queue, Q_CLOSE, 0); + thread_wait(thread_id); +} +#endif /* SD_DRIVER_CLOSE */ + +void sd_enable(bool on) +{ + if(on) + { + DEV_EN |= DEV_ATA; /* Enable controller */ + } + else + { + DEV_EN &= ~DEV_ATA; /* Disable controller */ + } +} + + +int sd_init(void) +{ + int ret = 0; + + if (!initialized) + mutex_init(&sd_mtx); + + mutex_lock(&sd_mtx); + + led(false); + + if (!initialized) + { + initialized = true; + + /* init controller */ +#if defined(PHILIPS_SA9200) + GPIOA_ENABLE = 0x00; + GPIO_SET_BITWISE(GPIOD_ENABLE, 0x01); +#else + outl(inl(0x70000088) & ~(0x4), 0x70000088); + outl(inl(0x7000008c) & ~(0x4), 0x7000008c); + GPO32_ENABLE |= 0x4; + + GPIO_SET_BITWISE(GPIOG_ENABLE, (0x3 << 5)); + GPIO_SET_BITWISE(GPIOG_OUTPUT_EN, (0x3 << 5)); + GPIO_SET_BITWISE(GPIOG_OUTPUT_VAL, (0x3 << 5)); +#endif + +#ifdef HAVE_HOTSWAP + /* enable card detection port - mask interrupt first */ +#ifdef SANSA_E200 + GPIO_CLEAR_BITWISE(GPIOA_INT_EN, 0x80); + + GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_EN, 0x80); + GPIO_SET_BITWISE(GPIOA_ENABLE, 0x80); +#elif defined SANSA_C200 + GPIO_CLEAR_BITWISE(GPIOL_INT_EN, 0x08); + + GPIO_CLEAR_BITWISE(GPIOL_OUTPUT_EN, 0x08); + GPIO_SET_BITWISE(GPIOL_ENABLE, 0x08); +#endif +#endif + sd_select_device(0); + + if (currcard->initialized < 0) + ret = currcard->initialized; + + queue_init(&sd_queue, true); + sd_thread_id = create_thread(sd_thread, sd_stack, sizeof(sd_stack), + 0, sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) + IF_COP(, CPU)); + + /* enable interupt for the mSD card */ + sleep(HZ/10); +#ifdef HAVE_HOTSWAP +#ifdef SANSA_E200 + CPU_INT_EN = HI_MASK; + CPU_HI_INT_EN = GPIO0_MASK; + + GPIOA_INT_LEV = (0x80 << 8) | (~GPIOA_INPUT_VAL & 0x80); + + GPIOA_INT_CLR = 0x80; + + /* enable the card detect interrupt */ + GPIO_SET_BITWISE(GPIOA_INT_EN, 0x80); +#elif defined SANSA_C200 + CPU_INT_EN = HI_MASK; + CPU_HI_INT_EN = GPIO2_MASK; + + GPIOL_INT_LEV = (0x08 << 8) | (~GPIOL_INPUT_VAL & 0x08); + + GPIOL_INT_CLR = 0x08; + + /* enable the card detect interrupt */ + GPIO_SET_BITWISE(GPIOL_INT_EN, 0x08); +#endif +#endif + } + + mutex_unlock(&sd_mtx); + + return ret; +} + +tCardInfo *card_get_info_target(int card_no) +{ + return &card_info[card_no]; +} +#ifdef HAVE_HOTSWAP +static int sd1_oneshot_callback(struct timeout *tmo) +{ + (void)tmo; + + /* This is called only if the state was stable for 300ms - check state + * and post appropriate event. */ + if (card_detect_target()) + queue_broadcast(SYS_HOTSWAP_INSERTED, 0); + else + queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0); + + return 0; +} + +/* called on insertion/removal interrupt */ +void microsd_int(void) +{ + static struct timeout sd1_oneshot; + +#ifdef SANSA_E200 + GPIO_CLEAR_BITWISE(GPIOA_INT_EN, 0x80); + GPIOA_INT_LEV = (0x80 << 8) | (~GPIOA_INPUT_VAL & 0x80); + GPIOA_INT_CLR = 0x80; + GPIO_SET_BITWISE(GPIOA_INT_EN, 0x80); + +#elif defined SANSA_C200 + GPIO_CLEAR_BITWISE(GPIOL_INT_EN, 0x08); + GPIOL_INT_LEV = (0x08 << 8) | (~GPIOL_INPUT_VAL & 0x08); + GPIOL_INT_CLR = 0x08; + GPIO_SET_BITWISE(GPIOL_INT_EN, 0x08); +#endif + timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0); +} +#endif /* HAVE_HOTSWAP */ + +long sd_last_disk_activity(void) +{ + return last_disk_activity; +} + +#ifdef HAVE_HOTSWAP +bool sd_removable(IF_MD_NONVOID(int drive)) +{ +#ifndef HAVE_MULTIDRIVE + const int drive=0; +#endif + return (drive==1); +} + +bool sd_present(IF_MD_NONVOID(int drive)) +{ +#ifndef HAVE_MULTIDRIVE + const int drive=0; +#endif + if(drive==0) + { + return true; + } + else + { + return card_detect_target(); + } +} +#endif + +#ifdef CONFIG_STORAGE_MULTI +int sd_num_drives(int first_drive) +{ +#ifdef HAVE_HOTSWAP + /* Store which logical drive number(s) we have been assigned */ + sd_first_drive = first_drive; +#else + (void)first_drive; +#endif + +#ifdef HAVE_MULTIDRIVE + return 2; +#else + return 1; +#endif +} +#endif diff --git a/firmware/target/arm/pp/audio-pp.c b/firmware/target/arm/pp/audio-pp.c new file mode 100644 index 0000000000..6b5b082cc7 --- /dev/null +++ b/firmware/target/arm/pp/audio-pp.c @@ -0,0 +1,135 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Michael Sevakis + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "cpu.h" +#include "audio.h" +#include "sound.h" + +#if INPUT_SRC_CAPS != 0 +void audio_set_output_source(int source) +{ + if ((unsigned)source >= AUDIO_NUM_SOURCES) + source = AUDIO_SRC_PLAYBACK; +} /* audio_set_output_source */ + +void audio_input_mux(int source, unsigned flags) +{ + (void)flags; + /* Prevent pops from unneeded switching */ + static int last_source = AUDIO_SRC_PLAYBACK; +#ifdef HAVE_FMRADIO_REC + bool recording = flags & SRCF_RECORDING; + static bool last_recording = false; +#endif + +#if defined(IPOD_COLOR) || defined (IPOD_4G) + /* The usual magic from IPL - I'm guessing this configures the headphone + socket to be input or output. */ + if ((flags & SRCF_RECORDING) && source != AUDIO_SRC_PLAYBACK) + { + /* input */ + GPIO_CLEAR_BITWISE(GPIOI_OUTPUT_VAL, 0x40); + GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_VAL, 0x04); + } + else + { + /* output */ + GPIO_SET_BITWISE(GPIOI_OUTPUT_VAL, 0x40); + GPIO_SET_BITWISE(GPIOA_OUTPUT_VAL, 0x04); + } +#endif /* IPOD_COLOR || IPOD_4G */ + + switch (source) + { + default: /* playback - no recording */ + source = AUDIO_SRC_PLAYBACK; + case AUDIO_SRC_PLAYBACK: +#ifdef HAVE_RECORDING + if (source != last_source) + { + audiohw_set_monitor(false); + audiohw_disable_recording(); + } +#endif + break; +#ifdef HAVE_MIC_REC + case AUDIO_SRC_MIC: /* recording only */ + if (source != last_source) + { + audiohw_set_monitor(false); + audiohw_enable_recording(true); /* source mic */ + } + break; +#endif +#ifdef HAVE_LINE_REC + case AUDIO_SRC_LINEIN: /* recording only */ +#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) + /* Switch line in source to line-in */ + GPIO_SET_BITWISE(GPIOB_OUTPUT_VAL, 0x04); +#endif + if (source != last_source) + { + audiohw_set_monitor(false); + audiohw_enable_recording(false); /* source line */ + } + break; +#endif +#ifdef HAVE_FMRADIO_REC + case AUDIO_SRC_FMRADIO: /* recording and playback */ +#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) + /* Switch line in source to tuner */ + GPIO_CLEAR_BITWISE(GPIOB_OUTPUT_VAL, 0x04); + /* Set line-in vol to +12dB, which is proper for H10's */ + if (!recording) + audiohw_set_recvol(0x1f, 0x1f, AUDIO_GAIN_LINEIN); +#else /* Set line-in vol to 0dB*/ + if (!recording) + audiohw_set_recvol(0x17, 0x17, AUDIO_GAIN_LINEIN); +#endif + + if (source == last_source && recording == last_recording) + break; + + last_recording = recording; + +#if CONFIG_TUNER & IPOD_REMOTE_TUNER + /* Ipod FM tuner is in the remote connected to line-in */ + audiohw_enable_recording(false); /* source line */ + audiohw_set_monitor(true); /* enable bypass mode */ +#else + if (recording) + { + audiohw_set_monitor(false); /* disable bypass mode */ + audiohw_enable_recording(false); /* select line-in source */ + } + else + { + audiohw_disable_recording(); + audiohw_set_monitor(true); /* enable bypass mode */ + } +#endif + break; +#endif + } /* end switch */ + + last_source = source; +} /* audio_input_mux */ +#endif /* INPUT_SRC_CAPS != 0 */ diff --git a/firmware/target/arm/pp/boot-pp502x-bl-usb.lds b/firmware/target/arm/pp/boot-pp502x-bl-usb.lds new file mode 100644 index 0000000000..e721991c5a --- /dev/null +++ b/firmware/target/arm/pp/boot-pp502x-bl-usb.lds @@ -0,0 +1,133 @@ +/* Will have been included from boot.lds */ +ENTRY(start) +OUTPUT_FORMAT(elf32-littlearm) +OUTPUT_ARCH(arm) +STARTUP(target/arm/crt0-pp502x-bl-usb.o) + +#define DRAMORIG 0x01000000 /* Load at 16 MB */ +#define DRAMSIZE 0x00100000 /* 1MB for bootloader */ +#define MEMEND (MEMORYSIZE*0x100000) /* From virtual mapping at 0 */ +#define NOCACHE_BASE 0x10000000 +#ifndef IRAMORIG +#define IRAMORIG 0x40000000 +#endif +#define IRAMSIZE 0x20000 +#define FLASHORIG 0x001f0000 +#define FLASHSIZE 2M + +#define CACHEALIGN_SIZE 16 + +MEMORY +{ + DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE + IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE +} + +SECTIONS +{ + . = DRAMORIG; + _loadaddress = . + NOCACHE_BASE; + + .text : + { + *(.init.text) + *(.text*) + *(.glue_7) + *(.glue_7t) + . = ALIGN(0x4); + } > DRAM + + .rodata : + { + *(.rodata*) + . = ALIGN(0x4); + } > DRAM + + .data : + { + *(.data*) + . = ALIGN(0x4); + } > DRAM + + /* .ncdata section is placed at uncached physical alias address and is + * loaded at the proper cached virtual address - no copying is + * performed in the init code */ + .ncdata . + NOCACHE_BASE : + { + . = ALIGN(CACHEALIGN_SIZE); + *(.ncdata*) + . = ALIGN(CACHEALIGN_SIZE); + } AT> DRAM + + /DISCARD/ . - NOCACHE_BASE : + { + *(.eh_frame) + } > DRAM + + _noloaddram = .; + + .ibss IRAMORIG (NOLOAD) : + { + _iedata = .; + *(.qharray) + *(.ibss*) + . = ALIGN(0x4); + _iend = .; + } > IRAM + + .iram _iend : + { + _iramstart = .; + *(.icode*) + *(.irodata*) + *(.idata*) + _iramend = .; + } > IRAM AT> DRAM + + _iramcopy = LOADADDR(.iram); + + .loadaddressend : + { + _loadaddressend = . + NOCACHE_BASE; + } AT> DRAM + + .stack (NOLOAD) : + { + . = ALIGN(8); + *(.stack) + stackbegin = .; + . += 0x2000; + stackend = .; + } > IRAM + + /* .bss and .ncbss are treated as a single section to use one init loop + * to zero them - note "_edata" and "_end" */ + .bss _noloaddram (NOLOAD) : + { + _edata = .; + *(.bss*) + *(COMMON) + } > DRAM + + .ncbss . + NOCACHE_BASE (NOLOAD) : + { + . = ALIGN(CACHEALIGN_SIZE); + *(.ncbss*) + . = ALIGN(CACHEALIGN_SIZE); + } AT> DRAM + + /* This will be aligned by preceding alignments */ + .endaddr . - NOCACHE_BASE (NOLOAD) : + { + _end = .; + } > DRAM + + /* Reference to all DRAM after loaded bootloader image */ + .freebuffer _end (NOLOAD) : + { + . = ALIGN(4); + freebuffer = .; + . = MEMEND-1; + freebufferend = .; + } +} diff --git a/firmware/target/arm/pp/crt0-pp-bl.S b/firmware/target/arm/pp/crt0-pp-bl.S new file mode 100644 index 0000000000..01681288f9 --- /dev/null +++ b/firmware/target/arm/pp/crt0-pp-bl.S @@ -0,0 +1,217 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" +#include "cpu.h" + + .section .init.text,"ax",%progbits + + .global start +start: + +/* PortalPlayer bootloader and startup code based on startup.s from the iPodLinux + * loader + * + * Copyright (c) 2003, Daniel Palffy (dpalffy (at) rainstorm.org) + * Copyright (c) 2005, Bernard Leach + * + */ +#if CONFIG_CPU == PP5002 + .equ PROC_ID, 0xc4000000 + .equ CPU_CTRL, 0xcf004054 + .equ CPU_STATUS, 0xcf004050 + .equ COP_CTRL, 0xcf004058 + .equ COP_STATUS, 0xcf004050 + .equ IIS_CONFIG, 0xc0002500 + .equ SLEEP, 0xca + .equ WAKE, 0xce + .equ CPUSLEEPING, 0x8000 + .equ COPSLEEPING, 0x4000 + .equ CACHE_CTRL, 0xcf004024 + .equ CACHE_ENAB, 0x2 /* Actually the CACHE_CTL_INIT flag */ +#else + .equ PROC_ID, 0x60000000 + .equ CPU_CTRL, 0x60007000 + .equ CPU_STATUS, 0x60007000 + .equ COP_CTRL, 0x60007004 + .equ COP_STATUS, 0x60007004 + .equ IIS_CONFIG, 0x70002800 + .equ SLEEP, 0x80000000 + .equ WAKE, 0x0 + .equ CPUSLEEPING, 0x80000000 + .equ COPSLEEPING, 0x80000000 + .equ CACHE_CTRL, 0x6000c000 + .equ CACHE_ENAB, 0x1 +#endif + + msr cpsr_c, #0xdf /* enter sys mode, disable IRQ */ +#ifndef E200R_INSTALLER +/* 1 - Copy the bootloader to IRAM */ + /* get the high part of our execute address */ + bic r0, pc, #0xff /* r4 = pc & 0xffffff00 */ + + /* Copy bootloader to safe area - 0x40000000 (IRAM) */ + mov r1, #0x40000000 + ldr r2, =_dataend +1: + cmp r2, r1 + ldrhi r3, [r0], #4 + strhi r3, [r1], #4 + bhi 1b + +#ifndef IPOD_ARCH + /* For builds on targets with mi4 firmware, scramble writes data to + 0xe0-0xeb, so jump past that. pad_skip must then exist at an + address >= 0xec */ + b pad_skip + +.space 60*4 + +pad_skip: +#endif /* IPOD_ARCH */ + + +/* 2 - Jump both CPU and COP there */ + ldr pc, =start_loc /* jump to the relocated start_loc: */ +#endif /* E200R_INSTALLER */ + +start_loc: + /* Find out which processor we are */ + ldr r0, =PROC_ID + ldrb r0, [r0] + cmp r0, #0x55 + beq cpu + +cop: + /* put us (co-processor) to sleep */ + ldr r0, =COP_CTRL + mov r1, #SLEEP + str r1, [r0] + nop + nop + + /* Invalidate cache */ + mov r0, #1 + bl cache_op + + ldr r0, =startup_loc + ldr pc, [r0] + +cpu: + /* Wait for COP to be sleeping */ + ldr r0, =COP_STATUS +1: + ldr r1, [r0] + tst r1, #COPSLEEPING + beq 1b + + /* Initialise bss section to zero */ + ldr r0, =_edata + ldr r1, =_end + mov r2, #0 +1: + cmp r1, r0 + strhi r2, [r0], #4 + bhi 1b + + /* Set up some stack and munge it with 0xdeadbeef */ + ldr sp, =stackend + ldr r0, =stackbegin + ldr r1, =0xdeadbeef +1: + cmp sp, r0 + strhi r1, [r0], #4 + bhi 1b + + /* execute the loader - this will load an image to 0x10000000 */ + bl main + + /* store actual startup location returned by main() */ + ldr r1, =startup_loc + str r0, [r1] + + /* flush cache */ + mov r0, #0 + bl cache_op + + /* Wake up the coprocessor before executing the firmware */ + ldr r0, =COP_CTRL + mov r1, #WAKE + str r1, [r0] + +#if defined(SANSA_C200) || defined(PHILIPS_HDD1630) + /* Magic for loading the c200 OF */ + ldr r0, =0xb00d10ad + mov r1, #0x700 + ldr r2, =0xfff0 + mov r3, #0x7 +#endif + +#if defined(PHILIPS_HDD6330) + /* Magic for loading the HDD6XX0 OF */ + ldr r0, =0xb00d10ad + mov r1, #0x800 + ldr r2, =0xfff0 + mov r3, #0x7 +#endif + + ldr r4, =startup_loc + ldr pc, [r4] + +startup_loc: + .word 0x0 + +#ifdef IPOD_ARCH +.align 8 /* starts at 0x100 */ +.global boot_table +boot_table: + /* here comes the boot table, don't move its offset - preceding + code+data must stay <= 256 bytes */ + .space 400 +#endif + +cache_op: + ldr r2, =CACHE_CTRL + ldr r1, [r2] + tst r1, #CACHE_ENAB + bxeq lr + cmp r0, #0 +#ifdef CPU_PP502x + ldr r0, =0xf000f044 + ldr r1, [r0] + orrne r1, r1, #0x6 + orreq r1, r1, #0x2 + str r1, [r0] +1: + ldr r1, [r2] + tst r1, #0x8000 + bne 1b +#elif CONFIG_CPU == PP5002 + ldrne r0, =0xf0004000 + ldreq r0, =0xf000c000 + add r1, r0, #0x2000 + mov r2, #0 +1: + cmp r1, r0 + strhi r2, [r0], #16 + bhi 1b +#endif /* CPU type */ + bx lr + diff --git a/firmware/target/arm/pp/crt0-pp.S b/firmware/target/arm/pp/crt0-pp.S new file mode 100644 index 0000000000..5a9835a71f --- /dev/null +++ b/firmware/target/arm/pp/crt0-pp.S @@ -0,0 +1,430 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" +#include "cpu.h" + + .section .init.text,"ax",%progbits + + .global start +start: + +/* PortalPlayer bootloader and startup code based on startup.s from the iPodLinux + * loader + * + * Copyright (c) 2003, Daniel Palffy (dpalffy (at) rainstorm.org) + * Copyright (c) 2005, Bernard Leach + * + */ +#if CONFIG_CPU == PP5002 + .equ PROC_ID, 0xc4000000 + .equ CPU_ICLR, 0xcf001028 + .equ CPU_CTRL, 0xcf004054 + .equ COP_ICLR, 0xcf001038 + .equ COP_CTRL, 0xcf004058 + .equ CPU_STATUS, 0xcf004050 + .equ COP_STATUS, 0xcf004050 + .equ SLEEP, 0x000000ca + .equ WAKE, 0x000000ce + .equ CPUSLEEPING, 0x00008000 + .equ COPSLEEPING, 0x00004000 + .equ CACHE_CTRL, 0xcf004024 + .equ MMAP_LOG, 0xf000f000 /* MMAP0 */ + .equ MMAP_PHYS, 0xf000f004 +#if MEMORYSIZE > 32 + .equ MMAP_MASK, 0x00003c00 +#else + .equ MMAP_MASK, 0x00003e00 +#endif + .equ MMAP_FLAGS, 0x00003f84 +#else + .equ PROC_ID, 0x60000000 + .equ CPU_ICLR, 0x60004028 + .equ CPU_CTRL, 0x60007000 + .equ CPU_STATUS, 0x60007000 + .equ COP_ICLR, 0x60004038 + .equ COP_CTRL, 0x60007004 + .equ COP_STATUS, 0x60007004 + .equ SLEEP, 0x80000000 + .equ WAKE, 0x00000000 + .equ CPUSLEEPING, 0x80000000 + .equ COPSLEEPING, 0x80000000 + .equ CACHE_CTRL, 0x6000c000 + .equ MMAP_LOG, 0xf000f000 /* MMAP0 */ + .equ MMAP_PHYS, 0xf000f004 +#if MEMORYSIZE > 32 + .equ MMAP_MASK, 0x00003c00 +#else + .equ MMAP_MASK, 0x00003e00 +#endif + .equ MMAP_FLAGS, 0x00000f84 +#endif + + msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */ + b pad_skip + +.space 6*4 /* pad to offset 0x20 */ + + .ascii "Rockbox" /* signature for bootloader checking osos */ + .byte 1 /* osos boot version, only 1 exists for now */ + +.space 56*4 /* (more than enough) space for exception vectors and mi4 magic */ + +pad_skip: + /* Find out which processor we are - r0 should be preserved for the + * duration of the init to avoid constant reloading of the processor ID. + * For each stage, CPU proceeds first, then COP. + */ + ldr r0, =PROC_ID + ldrb r0, [r0] + + /* We need to remap memory from wherever SDRAM is mapped natively, to + base address 0, so we can put our exception vectors there. We don't + want to do this remapping while executing from SDRAM, so we copy the + remapping code to IRAM, then execute from there. Hence, the following + code is compiled for address 0, but is currently executing at either + 0x28000000 or 0x10000000, depending on chipset version. Do not use any + absolute addresses until remapping has been done. */ + + /* Cores are stepped though the init in turn: CPU then COP. The the remap + stage is completed by each core in turn and then the COP waits for the + CPU to finish initializing its kernel where the CPU will wake the COP + and wait for the COP to finish. This ensures no threading activity + starts until it is safe. */ + cmp r0, #0x55 + + /* mask all interrupt sources before setting anything up */ + ldreq r2, =CPU_ICLR + ldrne r2, =COP_ICLR + mvn r1, #0 + str r1, [r2] + + /* put us (co-processor) to sleep and wait for CPU to remap */ + ldrne r2, =COP_CTRL + movne r1, #SLEEP + strne r1, [r2] + nop + nop + nop + + /* wait for co-processor to sleep then CPU can begin its remapping */ + ldreq r2, =COP_STATUS +1: + ldreq r1, [r2] + tsteq r1, #COPSLEEPING + beq 1b + + /* disable cache and local interrupt vectors - it is really not desireable + to have them enabled here */ + ldr r2, =CACHE_CTRL + mov r1, #0 + str r1, [r2] + +#if defined(IPOD_VIDEO) + /* detect 32mb vs 64mb model */ + /* we do this here because after SDRAM is remapped, we already assumed */ + /* its size to be whatever we were compiled for. */ + + mov r2, #0x12000000 + mov r3, #64 + strb r3, [r2, #-1] /* first write 64 to last byte of first 32MB bank */ + + mov r2, #0x14000000 + mov r3, #32 + strb r3, [r2, #-1] /* now write 32 to last byte of second 32MB bank */ + + /* now the last word of the first 32MB bank tells you the RAM size */ + /* since on a 32MB model both writes will touch the same actual location */ + /* this is read later on in boot */ +#endif + + mov r2, #0x40000000 + ldr r3, =remap_start + ldr r4, =remap_end + + and r6, pc, #0xff000000 /* adjust for execute address */ + orr r3, r3, r6 + orr r4, r4, r6 + + /* copy the code to 0x40000000 */ +1: + ldr r5, [r3], #4 + str r5, [r2], #4 + cmp r3, r4 + blo 1b + + ldr r4, =MMAP_FLAGS + orr r4, r4, r6 /* adjust for execute address */ + ldr r3, =MMAP_PHYS + ldr r2, =MMAP_MASK /* ldr is more flexible */ + ldr r1, =MMAP_LOG + mov pc, #0x40000000 + +remap_start: + str r2, [r1] + str r4, [r3] + ldr r1, L_post_remap + bx r1 +L_post_remap: + .word remap_end +remap_end: + + cmp r0, #0x55 + ldr r4, =COP_CTRL + /* Wakeup co-processor to let it do remappings */ + moveq r3, #WAKE + /* Sleep us (co-processor) and wait for CPU to do kernel initialization */ + movne r3, #SLEEP + str r3, [r4] + nop + nop + nop + + /* Jump to co-processor init */ + ldrne pc, =cop_init + +cpu_init: + /* Wait for COP to go to sleep before proceeding */ + ldr r4, =COP_STATUS +1: + ldr r3, [r4] + tst r3, #COPSLEEPING + beq 1b + + /* Vectors and IRAM copy is done first since they are reclaimed for + * other uninitialized sections */ + + /* Copy exception handler code to address 0 */ + ldr r2, =_vectorsstart + ldr r3, =_vectorsend + ldr r4, =_vectorscopy +1: + cmp r3, r2 + ldrhi r5, [r4], #4 + strhi r5, [r2], #4 + bhi 1b + + /* Copy the IRAM */ + ldr r2, =_iramcopy + ldr r3, =_iramstart + ldr r4, =_iramend +1: + cmp r4, r3 + ldrhi r5, [r2], #4 + strhi r5, [r3], #4 + bhi 1b + +#ifdef HAVE_INIT_ATTR + /* copy init code to codec buffer */ + ldr r2, =_initstart + ldr r3, =_initend + ldr r4, =_initcopy + +1: + cmp r3, r2 + ldrhi r5, [r4], #4 + strhi r5, [r2], #4 + bhi 1b +#endif + + /* Zero out IBSS */ + ldr r2, =_iedata + ldr r3, =_iend + mov r4, #0 +1: + cmp r3, r2 + strhi r4, [r2], #4 + bhi 1b + + /* Initialise bss section to zero */ + ldr r2, =_edata + ldr r3, =_end + mov r4, #0 +1: + cmp r3, r2 + strhi r4, [r2], #4 + bhi 1b + + /* Load stack munge value */ + ldr r4, =0xdeadbeef + +#if NUM_CORES > 1 + /* Set up idle stack and munge it with 0xdeadbeef */ + ldr r2, =cpu_idlestackbegin + ldr r3, =cpu_idlestackend +1: + cmp r3, r2 + strhi r4, [r2], #4 + bhi 1b +#endif + + /* Set up stack for IRQ mode */ + msr cpsr_c, #0x92 /* IRQ disabled, FIQ enabled */ + ldr sp, =irq_stack + /* Set up stack for FIQ mode */ + msr cpsr_c, #0xd1 /* IRQ/FIQ disabled */ + ldr sp, =fiq_stack + + /* Let svc, abort and undefined modes use irq stack */ + msr cpsr_c, #0xd3 /* IRQ/FIQ disabled */ + ldr sp, =irq_stack + msr cpsr_c, #0xd7 /* IRQ/FIQ disabled */ + ldr sp, =irq_stack + msr cpsr_c, #0xdb /* IRQ/FIQ disabled */ + ldr sp, =irq_stack + + /* Switch to sys mode */ + msr cpsr_c, #0xdf + + /* Set up some stack and munge it with 0xdeadbeef */ + ldr r2, =stackbegin + ldr sp, =stackend +1: + cmp sp, r2 + strhi r4, [r2], #4 + bhi 1b + + /* Delay waking the COP until thread initialization is complete unless dual-core + support is not enabled in which case the cop_main function does not perform + any kernel or thread initialization. It's just a trivial sleep loop. */ +#if NUM_CORES == 1 + ldr r4, =COP_CTRL + mov r3, #WAKE + str r3, [r4] +#endif + + ldr pc, =main + /* main() should never return */ + +cop_init: +#if NUM_CORES > 1 + /* Wait for CPU to go to sleep at the end of its kernel init */ + ldr r4, =CPU_STATUS +1: + ldr r3, [r4] + tst r3, #CPUSLEEPING + beq 1b +#endif + + /* Set up stack for IRQ mode */ + msr cpsr_c, #0x92 /* IRQ disabled, FIQ enabled */ + ldr sp, =cop_irq_stack + /* Set up stack for FIQ mode */ + msr cpsr_c, #0xd1 /* IRQ/FIQ disabled */ + ldr sp, =cop_fiq_stack + + /* Let svc, abort and undefined modes use irq stack */ + msr cpsr_c, #0xd3 /* IRQ/FIQ disabled */ + ldr sp, =cop_irq_stack + msr cpsr_c, #0xd7 /* IRQ/FIQ disabled */ + ldr sp, =cop_irq_stack + msr cpsr_c, #0xdb /* IRQ/FIQ disabled */ + ldr sp, =cop_irq_stack + + /* Switch to sys mode */ + msr cpsr_c, #0xdf + + /* Set up idle stack for COP and munge it with 0xdeadbeef */ + ldr sp, =cop_idlestackend + ldr r2, =cop_idlestackbegin + ldr r4, =0xdeadbeef +2: + cmp sp, r2 + strhi r4, [r2], #4 + bhi 2b + + /* Run cop_main() in apps/main.c */ + ldr pc, =cop_main + +/* Exception handlers. Will be copied to address 0 after memory remapping */ + .section .vectors,"aw" + ldr pc, [pc, #24] + ldr pc, [pc, #24] + ldr pc, [pc, #24] + ldr pc, [pc, #24] + ldr pc, [pc, #24] + ldr pc, [pc, #24] + ldr pc, [pc, #24] + ldr pc, [pc, #24] + + /* Exception vectors */ + .global vectors +vectors: + .word start + .word undef_instr_handler + .word software_int_handler + .word prefetch_abort_handler + .word data_abort_handler + .word reserved_handler + .word irq_handler + .word fiq_handler + + .text + +/* All illegal exceptions call into UIE with exception address as first + parameter. This is calculated differently depending on which exception + we're in. Second parameter is exception number, used for a string lookup + in UIE. + */ +undef_instr_handler: + sub r0, lr, #4 + mov r1, #0 + b UIE + +/* We run sys mode most of the time, and should never see a software + exception being thrown. Make it illegal and call UIE. + */ +software_int_handler: +reserved_handler: + sub r0, lr, #4 + mov r1, #4 + b UIE + +prefetch_abort_handler: + sub r0, lr, #4 + mov r1, #1 + b UIE + +data_abort_handler: + sub r0, lr, #8 + mov r1, #2 + b UIE + +/* Align stacks to cache line boundary */ + .balign 32 + +/* 256 words of IRQ stack */ + .space 256*4 +irq_stack: + +/* 256 words of COP IRQ stack */ + .space 256*4 +cop_irq_stack: + +/* 256 words of FIQ stack */ + .space 256*4 +fiq_stack: + +/* We'll need this soon - just reserve the symbol */ +#if 0 +/* 256 words of COP FIQ stack */ + .space 256*4 +#endif +cop_fiq_stack: diff --git a/firmware/target/arm/pp/crt0-pp502x-bl-usb.S b/firmware/target/arm/pp/crt0-pp502x-bl-usb.S new file mode 100644 index 0000000000..7b0489b2a8 --- /dev/null +++ b/firmware/target/arm/pp/crt0-pp502x-bl-usb.S @@ -0,0 +1,367 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * Copyright (C) 2010 by Michael Sevakis + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" +#include "cpu.h" + +/* PortalPlayer bootloader and startup code based on startup.s from the iPodLinux + * loader + * + * Copyright (c) 2003, Daniel Palffy (dpalffy (at) rainstorm.org) + * Copyright (c) 2005, Bernard Leach + * + */ + .equ PROC_ID, 0x60000000 + .equ CPU_IDIS, 0x60004028 + .equ CPU_CTRL, 0x60007000 + .equ CPU_STATUS, 0x60007000 + .equ COP_IDIS, 0x60004038 + .equ COP_CTRL, 0x60007004 + .equ COP_STATUS, 0x60007004 + .equ CPU_SLEEPING,0x80000000 + .equ COP_SLEEPING,0x80000000 + .equ SLEEP, 0x80000000 + .equ WAKE, 0x00000000 + .equ MMAP_LOG, 0xf000f000 /* MMAP0 */ + .equ MMAP_PHYS, 0xf000f004 + .equ INT_VECT_TBL,0x6000f100 + .equ CACHE_CTRL, 0x6000c000 + .equ CACHE_ENAB, 0x1 + .equ CACHE_OP_COMMIT_DISCARD, 0x1 + .equ CACHE_OP_COMMIT , 0x0 +#if MEMORYSIZE > 32 + .equ MMAP_MASK, 0x00003c00 +#else + .equ MMAP_MASK, 0x00003e00 +#endif + .equ MMAP_FLAGS, 0x00000f84 + +/* + * Entry point + */ + .section .init.text,"ax",%progbits + .global start +start: + b newstart + +#ifdef IPOD_ARCH +.align 8 /* starts at 0x100 */ +.global boot_table +boot_table: + /* here comes the boot table, don't move its offset - preceding + code+data must stay <= 256 bytes */ + .space 400 +#else /* !IPOD_ARCH */ + /* (more than enough) space for exception vectors and mi4 magic */ + .space 68*4 +#endif /* IPOD_ARCH */ + +newstart: + msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */ + adr r4, start /* cache initial load address */ + + /* Copy startup stub to IRAM since we need to both move the bootloader's + * location, which could overlap itself, and setup the memory mapper. */ + adr r0, start_stub_begin + mov r1, #0x40000000 + adr r2, start_stub_end +1: + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r0, r2 + blo 1b + mov pc, #0x40000000 + +start_stub_begin: + ldr r0, =PROC_ID + ldrb r0, [r0] + cmp r0, #0x55 + beq cpu + +cop: + mov r0, #CACHE_OP_COMMIT_DISCARD + bl cache_operation + + ldr r1, =COP_CTRL + mov r0, #SLEEP + + /* sleep us (co-processor) while bootloader is copied */ + str r0, [r1] + nop + nop + nop + + /* branch to final physical load address */ + ldr r2, =1f + and r4, r4, #0xfc000000 + add pc, r2, r4 +1: + /* wait for bootloader to finish */ + str r0, [r1] + nop + nop + nop + + /* branch to the address returned by main() */ + adr r0, startup_loc + ldr pc, [r0] + +cpu: + /* wait for COP to sleep */ + ldr r1, =COP_STATUS +1: + ldr r0, [r1] + tst r0, #COP_SLEEPING + beq 1b + + mov r0, #CACHE_OP_COMMIT_DISCARD + bl cache_operation + + /* move bootloader to the correct load address if needed */ + ldr r1, =_loadaddress + cmp r4, r1 + ldrne r2, =_loadaddressend + movne r0, r4 + sublo r3, r2, r1 /* size */ + addlo r0, r0, r3 /* initial load end addr */ +1: /* lower to higher move - copy up */ + cmphi r2, r1 + ldrhi r3, [r0], #4 + strhi r3, [r1], #4 + bhi 1b +1: /* higher to lower move - copy down */ + cmplo r1, r2 + ldrlo r3, [r0, #-4]! + strlo r3, [r2, #-4]! + blo 1b + + mov r0, #CACHE_OP_COMMIT + bl cache_operation + + and r4, r4, #0xfc000000 + + ldr r0, =MMAP_FLAGS + orr r0, r0, r4 /* adjust for execute address */ + ldr r1, =MMAP_MASK + ldr r2, =MMAP_LOG + ldr r3, =MMAP_PHYS + str r1, [r2] /* MMAP_LOG = MMAP_MASK */ + str r0, [r3] /* MMAP_PHYS = MMAP_FLAGS | SDRAM base addr */ + + /* wake the COP to jump it to the correct place */ + ldr r1, =COP_CTRL + mov r0, #WAKE + str r0, [r1] + + /* wait for COP to halt then loading may proceed */ + ldr r1, =COP_STATUS +1: + ldr r0, [r1] + tst r0, #COP_SLEEPING + beq 1b + + ldr r0, =start_stub_end + add pc, r0, r4 + +cache_operation: /* (bool commit_discard) */ + ldr r2, =CACHE_CTRL + ldr r1, [r2] + tst r1, #CACHE_ENAB + bxeq lr + cmp r0, #CACHE_OP_COMMIT + ldr r0, =0xf000f044 + ldr r1, [r0] + orrne r1, r1, #0x6 + orreq r1, r1, #0x2 + str r1, [r0] +1: + ldr r1, [r2] + tst r1, #0x8000 + bne 1b + bx lr + .ltorg /* constants used in stub come with us to IRAM */ +start_stub_end: + /* now executing from final physical address */ + + /* copy the vector addresses to the table */ + ldr r0, =INT_VECT_TBL + adr r1, vectorsstart + adr r2, vectorsend +1: + cmp r2, r1 + ldrhi r3, [r1], #4 + strhi r3, [r0], #4 + bhi 1b + + /* Copy the IRAM */ + ldr r0, =_iramcopy + ldr r1, =_iramstart + ldr r2, =_iramend +1: + cmp r2, r1 + ldrhi r3, [r0], #4 + strhi r3, [r1], #4 + bhi 1b + + mov r0, #0 + + /* Zero out IBSS */ + ldr r1, =_iedata + ldr r2, =_iend +1: + cmp r2, r1 + strhi r0, [r1], #4 + bhi 1b + + /* Initialise bss/ncbss sections to zero */ + ldr r1, =_edata + ldr r2, =_end +1: + cmp r2, r1 + strhi r0, [r1], #4 + bhi 1b + + /* Set up stack for IRQ mode */ + msr cpsr_c, #0xd2 /* IRQ/FIQ disabled */ + ldr sp, =irq_stack + /* Let svc, abort and undefined modes use irq stack */ + msr cpsr_c, #0xd3 + ldr sp, =irq_stack + msr cpsr_c, #0xd7 /* IRQ/FIQ disabled */ + ldr sp, =irq_stack + msr cpsr_c, #0xdb /* IRQ/FIQ disabled */ + ldr sp, =irq_stack + + /* Switch back to sys mode */ + msr cpsr_c, #0xdf + + /* Set up some stack and munge it with 0xdeadbeef */ + ldr r0, =0xdeadbeef + ldr r1, =stackbegin + ldr sp, =stackend +1: + cmp sp, r1 + strhi r0, [r1], #4 + bhi 1b + + /* execute the loader - this will load an image to 0x10000000 */ + ldr r0, =main + mov lr, pc + bx r0 + + /* store actual startup location returned by main() */ + ldr r1, =startup_loc + str r0, [r1] + + /* write back anything loaded + startup_loc */ + mov r0, #CACHE_OP_COMMIT + bl cache_operation + + mov r0, #0 + + /* disable memory mapper */ + ldr r1, =MMAP_LOG + ldr r2, =MMAP_PHYS + str r0, [r1] + str r0, [r2] + + /* bring COP back to life */ + ldr r1, =COP_CTRL + mov r0, #WAKE + str r0, [r1] + + /* after this point, r0-r3 are reserved for OF magic */ + +#if defined(SANSA_C200) || defined(PHILIPS_HDD1630) + /* Magic for loading the c200 OF */ + ldr r0, =0xb00d10ad + mov r1, #0x700 + ldr r2, =0xfff0 + mov r3, #0x7 +#endif + +#if defined(PHILIPS_HDD6330) + /* Magic for loading the HDD6XX0 OF */ + ldr r0, =0xb00d10ad + mov r1, #0x800 + ldr r2, =0xfff0 + mov r3, #0x7 +#endif + + /* branch to the address returned by main() */ + adr r4, startup_loc + ldr pc, [r4] + +startup_loc: + .word 0x00000000 + +/* exception handlers: will be copied to local vector table */ +vectorsstart: + .word newstart + .word undef_instr_handler + .word software_int_handler + .word prefetch_abort_handler + .word data_abort_handler + .word reserved_handler + .word irq_handler + .word fiq_handler +vectorsend: + + .text + +/* All illegal exceptions call into UIE with exception address as first + parameter. This is calculated differently depending on which exception + we're in. Second parameter is exception number, used for a string lookup + in UIE. + */ +undef_instr_handler: + sub r0, lr, #4 + mov r1, #0 + b UIE + +/* We run sys mode most of the time, and should never see a software + exception being thrown. Make it illegal and call UIE. + */ +software_int_handler: +reserved_handler: + sub r0, lr, #4 + mov r1, #4 + b UIE + +prefetch_abort_handler: + sub r0, lr, #4 + mov r1, #1 + b UIE + +data_abort_handler: + sub r0, lr, #8 + mov r1, #2 + b UIE + +/* should never happen in the bootloader */ +fiq_handler: + subs pc, lr, #4 + +/* 256 words of IRQ stack */ + .section .bss + .balign 16 + .space 256*4 +irq_stack: diff --git a/firmware/target/arm/pp/debug-pp.c b/firmware/target/arm/pp/debug-pp.c new file mode 100644 index 0000000000..5f252db417 --- /dev/null +++ b/firmware/target/arm/pp/debug-pp.c @@ -0,0 +1,232 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Dave Chapman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "system.h" +#include +#include "font.h" +#include "lcd.h" +#include "button.h" +#include "powermgmt.h" +#include "adc.h" +#include "iap.h" +#include "hwcompat.h" +#include "debug-target.h" + +static int perfcheck(void) +{ + int result; + + asm ( + "mrs r2, CPSR \n" + "orr r0, r2, #0xc0 \n" /* disable IRQ and FIQ */ + "msr CPSR_c, r0 \n" + "mov %[res], #0 \n" + "ldr r0, [%[timr]] \n" + "add r0, r0, %[tmo] \n" + "1: \n" + "add %[res], %[res], #1 \n" + "ldr r1, [%[timr]] \n" + "cmp r1, r0 \n" + "bmi 1b \n" + "msr CPSR_c, r2 \n" /* reset IRQ and FIQ state */ + : + [res]"=&r"(result) + : + [timr]"r"(&USEC_TIMER), + [tmo]"r"( +#if CONFIG_CPU == PP5002 + 16000 +#else /* PP5020/5022/5024 */ + 10226 +#endif + ) + : + "r0", "r1", "r2" + ); + return result; +} + +bool dbg_ports(void) +{ + int line; + + lcd_clear_display(); + lcd_setfont(FONT_SYSFIXED); + + while(1) + { + line = 0; +#if defined(CPU_PP502x) +#if (LCD_HEIGHT >= 176) /* Only for displays with appropriate height. */ + lcd_puts(0, line++, "GPIO ENABLE:"); + lcd_putsf(0, line++, "A: %02x E: %02x I: %02x", + (unsigned int)GPIOA_ENABLE, + (unsigned int)GPIOE_ENABLE, + (unsigned int)GPIOI_ENABLE); + lcd_putsf(0, line++, "B: %02x F: %02x J: %02x", + (unsigned int)GPIOB_ENABLE, + (unsigned int)GPIOF_ENABLE, + (unsigned int)GPIOJ_ENABLE); + lcd_putsf(0, line++, "C: %02x G: %02x K: %02x", + (unsigned int)GPIOC_ENABLE, + (unsigned int)GPIOG_ENABLE, + (unsigned int)GPIOK_ENABLE); + lcd_putsf(0, line++, "D: %02x H: %02x L: %02x", + (unsigned int)GPIOD_ENABLE, + (unsigned int)GPIOH_ENABLE, + (unsigned int)GPIOL_ENABLE); + line++; +#endif + lcd_puts(0, line++, "GPIO INPUT VAL:"); + lcd_putsf(0, line++, "A: %02x E: %02x I: %02x", + (unsigned int)GPIOA_INPUT_VAL, + (unsigned int)GPIOE_INPUT_VAL, + (unsigned int)GPIOI_INPUT_VAL); + lcd_putsf(0, line++, "B: %02x F: %02x J: %02x", + (unsigned int)GPIOB_INPUT_VAL, + (unsigned int)GPIOF_INPUT_VAL, + (unsigned int)GPIOJ_INPUT_VAL); + lcd_putsf(0, line++, "C: %02x G: %02x K: %02x", + (unsigned int)GPIOC_INPUT_VAL, + (unsigned int)GPIOG_INPUT_VAL, + (unsigned int)GPIOK_INPUT_VAL); + lcd_putsf(0, line++, "D: %02x H: %02x L: %02x", + (unsigned int)GPIOD_INPUT_VAL, + (unsigned int)GPIOH_INPUT_VAL, + (unsigned int)GPIOL_INPUT_VAL); + line++; + lcd_putsf(0, line++, "GPO32_VAL: %08lx", GPO32_VAL); + lcd_putsf(0, line++, "GPO32_EN: %08lx", GPO32_ENABLE); + lcd_putsf(0, line++, "DEV_EN: %08lx", DEV_EN); + lcd_putsf(0, line++, "DEV_EN2: %08lx", DEV_EN2); + lcd_putsf(0, line++, "DEV_EN3: %08lx", inl(0x60006044)); /* to be verified */ + lcd_putsf(0, line++, "DEV_INIT1: %08lx", DEV_INIT1); + lcd_putsf(0, line++, "DEV_INIT2: %08lx", DEV_INIT2); +#ifdef ADC_ACCESSORY + lcd_putsf(0, line++, "ACCESSORY: %d", adc_read(ADC_ACCESSORY)); +#endif +#if defined(IPOD_VIDEO) || defined(IPOD_NANO) + lcd_putsf(0, line++, "4066_ISTAT: %d", adc_read(ADC_4066_ISTAT)); +#endif + +#if defined(IPOD_ACCESSORY_PROTOCOL) + const unsigned char *serbuf = iap_get_serbuf(); + lcd_putsf(0, line++, "IAP: %02x %02x %02x %02x %02x %02x %02x %02x", + serbuf[0], serbuf[1], serbuf[2], serbuf[3], serbuf[4], serbuf[5], + serbuf[6], serbuf[7]); +#endif + +#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) + line++; + lcd_putsf(0, line++, "BATT: %03x UNK1: %03x", + adc_read(ADC_BATTERY), adc_read(ADC_UNKNOWN_1)); + lcd_putsf(0, line++, "REM: %03x PAD: %03x", + adc_read(ADC_REMOTE), adc_read(ADC_SCROLLPAD)); +#elif defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) + line++; + lcd_putsf(0, line++, "BATT: %03x UNK1: %03x", + adc_read(ADC_BATTERY), adc_read(ADC_UNKNOWN_1)); +#elif defined(SANSA_E200) || defined(PHILIPS_SA9200) + lcd_putsf(0, line++, "ADC_BVDD: %4d", adc_read(ADC_BVDD)); + lcd_putsf(0, line++, "ADC_RTCSUP: %4d", adc_read(ADC_RTCSUP)); + lcd_putsf(0, line++, "ADC_UVDD: %4d", adc_read(ADC_UVDD)); + lcd_putsf(0, line++, "ADC_CHG_IN: %4d", adc_read(ADC_CHG_IN)); + lcd_putsf(0, line++, "ADC_CVDD: %4d", adc_read(ADC_CVDD)); + lcd_putsf(0, line++, "ADC_BATTEMP: %4d", adc_read(ADC_BATTEMP)); + lcd_putsf(0, line++, "ADC_MICSUP1: %4d", adc_read(ADC_MICSUP1)); + lcd_putsf(0, line++, "ADC_MICSUP2: %4d", adc_read(ADC_MICSUP2)); + lcd_putsf(0, line++, "ADC_VBE1: %4d", adc_read(ADC_VBE1)); + lcd_putsf(0, line++, "ADC_VBE2: %4d", adc_read(ADC_VBE2)); + lcd_putsf(0, line++, "ADC_I_MICSUP1:%4d", adc_read(ADC_I_MICSUP1)); +#if !defined(PHILIPS_SA9200) + lcd_putsf(0, line++, "ADC_I_MICSUP2:%4d", adc_read(ADC_I_MICSUP2)); + lcd_putsf(0, line++, "ADC_VBAT: %4d", adc_read(ADC_VBAT)); +#endif +#endif + +#elif CONFIG_CPU == PP5002 + lcd_putsf(0, line++, "GPIO_A: %02x GPIO_B: %02x", + (unsigned int)GPIOA_INPUT_VAL, (unsigned int)GPIOB_INPUT_VAL); + lcd_putsf(0, line++, "GPIO_C: %02x GPIO_D: %02x", + (unsigned int)GPIOC_INPUT_VAL, (unsigned int)GPIOD_INPUT_VAL); + + lcd_putsf(0, line++, "DEV_EN: %08lx", DEV_EN); + lcd_putsf(0, line++, "CLOCK_ENABLE: %08lx", CLOCK_ENABLE); + lcd_putsf(0, line++, "CLOCK_SOURCE: %08lx", CLOCK_SOURCE); + lcd_putsf(0, line++, "PLL_CONTROL: %08lx", PLL_CONTROL); + lcd_putsf(0, line++, "PLL_DIV: %08lx", PLL_DIV); + lcd_putsf(0, line++, "PLL_MULT: %08lx", PLL_MULT); + lcd_putsf(0, line++, "TIMING1_CTL: %08lx", TIMING1_CTL); + lcd_putsf(0, line++, "TIMING2_CTL: %08lx", TIMING2_CTL); +#endif + lcd_update(); + if (button_get_w_tmo(HZ/10) == (DEBUG_CANCEL|BUTTON_REL)) + { + lcd_setfont(FONT_UI); + return false; + } + } + return false; +} + +bool dbg_hw_info(void) +{ + int line = 0; +#if defined(CPU_PP502x) + char pp_version[] = { (PP_VER2 >> 24) & 0xff, (PP_VER2 >> 16) & 0xff, + (PP_VER2 >> 8) & 0xff, (PP_VER2) & 0xff, + (PP_VER1 >> 24) & 0xff, (PP_VER1 >> 16) & 0xff, + (PP_VER1 >> 8) & 0xff, (PP_VER1) & 0xff, '\0' }; +#elif CONFIG_CPU == PP5002 + char pp_version[] = { (PP_VER4 >> 8) & 0xff, PP_VER4 & 0xff, + (PP_VER3 >> 8) & 0xff, PP_VER3 & 0xff, + (PP_VER2 >> 8) & 0xff, PP_VER2 & 0xff, + (PP_VER1 >> 8) & 0xff, PP_VER1 & 0xff, '\0' }; +#endif + + lcd_setfont(FONT_SYSFIXED); + lcd_clear_display(); + + lcd_puts(0, line++, "[Hardware info]"); + +#ifdef IPOD_ARCH + lcd_putsf(0, line++, "HW rev: 0x%08lx", IPOD_HW_REVISION); +#endif + +#if defined(IPOD_COLOR) || defined(IPOD_NANO) + extern int lcd_type; /* Defined in lcd-colornano.c */ + + lcd_putsf(0, line++, "LCD type: %d", lcd_type); +#endif + + lcd_putsf(0, line++, "PP version: %s", pp_version); + + lcd_putsf(0, line++, "Est. clock (kHz): %d", perfcheck()); + + lcd_update(); + + /* wait for exit */ + while (button_get_w_tmo(HZ/10) != (DEBUG_CANCEL|BUTTON_REL)); + + lcd_setfont(FONT_UI); + return false; +} diff --git a/firmware/target/arm/pp/i2c-pp.c b/firmware/target/arm/pp/i2c-pp.c new file mode 100644 index 0000000000..58740b5c66 --- /dev/null +++ b/firmware/target/arm/pp/i2c-pp.c @@ -0,0 +1,314 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * PP502X and PP5002 I2C driver + * + * Based on code from the ipodlinux project - http://ipodlinux.org/ + * Adapted for Rockbox in November 2005 + * + * Original file: linux/arch/armnommu/mach-ipod/hardware.c + * + * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "cpu.h" +#include "kernel.h" +#include "thread.h" +#include "logf.h" +#include "system.h" +#include "i2c.h" +#include "i2c-pp.h" +#include "ascodec.h" +#include "as3514.h" + +#define I2C_CTRL (*(volatile unsigned char*)(I2C_BASE+0x00)) +#define I2C_ADDR (*(volatile unsigned char*)(I2C_BASE+0x04)) +#define I2C_DATA(X) (*(volatile unsigned char*)(I2C_BASE+0xc+(4*X))) +#define I2C_STATUS (*(volatile unsigned char*)(I2C_BASE+0x1c)) + +/* I2C_CTRL bit definitions */ +#define I2C_SEND 0x80 + +/* I2C_STATUS bit definitions */ +#define I2C_BUSY (1<<6) + +/* Local functions definitions */ +static struct mutex i2c_mtx SHAREDBSS_ATTR; + +#define POLL_TIMEOUT (HZ) + +static int pp_i2c_wait_not_busy(void) +{ + unsigned long timeout; + timeout = current_tick + POLL_TIMEOUT; + while (TIME_BEFORE(current_tick, timeout)) { + if (!(I2C_STATUS & I2C_BUSY)) { + return 0; + } + yield(); + } + + return -1; +} + +static int pp_i2c_read_bytes(unsigned int addr, int len, unsigned char *data) +{ + int i; + + if (len < 1 || len > 4) + { + return -1; + } + + if (pp_i2c_wait_not_busy() < 0) + { + return -2; + } + + { + int old_irq_level = disable_irq_save(); + + /* clear top 15 bits, left shift 1, or in 0x1 for a read */ + I2C_ADDR = ((addr << 17) >> 16) | 0x1; + + I2C_CTRL |= 0x20; + + I2C_CTRL = (I2C_CTRL & ~0x6) | ((len-1) << 1); + + I2C_CTRL |= I2C_SEND; + + restore_irq(old_irq_level); + + if (pp_i2c_wait_not_busy() < 0) + { + return -2; + } + + old_irq_level = disable_irq_save(); + + if (data) + { + for ( i = 0; i < len; i++ ) + *data++ = I2C_DATA(i); + } + + restore_irq(old_irq_level); + } + + return 0; +} + +static int pp_i2c_send_bytes(unsigned int addr, int len, unsigned char *data) +{ + int i; + + if (len < 1 || len > 4) + { + return -1; + } + + if (pp_i2c_wait_not_busy() < 0) + { + return -2; + } + + { + int old_irq_level = disable_irq_save(); + + /* clear top 15 bits, left shift 1 */ + I2C_ADDR = (addr << 17) >> 16; + + I2C_CTRL &= ~0x20; + + for ( i = 0; i < len; i++ ) + { + I2C_DATA(i) = *data++; + } + + I2C_CTRL = (I2C_CTRL & ~0x6) | ((len-1) << 1); + + I2C_CTRL |= I2C_SEND; + + restore_irq(old_irq_level); + } + + return 0; +} + +static int pp_i2c_send_byte(unsigned int addr, int data0) +{ + unsigned char data[1]; + + data[0] = data0; + + return pp_i2c_send_bytes(addr, 1, data); +} + +/* Public functions */ +void i2c_lock(void) +{ + mutex_lock(&i2c_mtx); +} + +void i2c_unlock(void) +{ + mutex_unlock(&i2c_mtx); +} + +int i2c_readbytes(unsigned int dev_addr, int addr, int len, unsigned char *data) +{ + int i, n; + + mutex_lock(&i2c_mtx); + + if (addr >= 0) + pp_i2c_send_byte(dev_addr, addr); + + i = 0; + while (len > 0) + { + n = (len < 4) ? len : 4; + + if (pp_i2c_read_bytes(dev_addr, n, data + i) < 0) + break; + + len -= n; + i += n; + } + + mutex_unlock(&i2c_mtx); + + return i; +} + +int i2c_readbyte(unsigned int dev_addr, int addr) +{ + unsigned char data; + + mutex_lock(&i2c_mtx); + pp_i2c_send_byte(dev_addr, addr); + pp_i2c_read_bytes(dev_addr, 1, &data); + mutex_unlock(&i2c_mtx); + + return (int)data; +} + +int i2c_sendbytes(unsigned int addr, int len, const unsigned char *data) +{ + int i, n; + + mutex_lock(&i2c_mtx); + + i = 0; + while (len > 0) + { + n = (len < 4) ? len : 4; + + if (pp_i2c_send_bytes(addr, n, (unsigned char *)(data + i)) < 0) + break; + + len -= n; + i += n; + } + + mutex_unlock(&i2c_mtx); + + return i; +} + +int pp_i2c_send(unsigned int addr, int data0, int data1) +{ + int retval; + unsigned char data[2]; + + data[0] = data0; + data[1] = data1; + + mutex_lock(&i2c_mtx); + retval = pp_i2c_send_bytes(addr, 2, data); + mutex_unlock(&i2c_mtx); + + return retval; +} + +void i2c_init(void) +{ + /* From ipodlinux */ + mutex_init(&i2c_mtx); + +#ifdef IPOD_MINI + /* GPIO port C disable port 0x10 */ + GPIOC_ENABLE &= ~0x10; + + /* GPIO port C disable port 0x20 */ + GPIOC_ENABLE &= ~0x20; +#endif + +#if CONFIG_I2C == I2C_PP5002 + DEV_EN |= 0x2; +#else + DEV_EN |= DEV_I2C; /* Enable I2C */ +#endif + DEV_RS |= DEV_I2C; /* Start I2C Reset */ + DEV_RS &=~DEV_I2C; /* End I2C Reset */ + +#if CONFIG_I2C == I2C_PP5020 + outl(0x0, 0x600060a4); +#if defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) || \ + defined(SAMSUNG_YH820) || defined(SAMSUNG_YH920) || \ + defined(SAMSUNG_YH925) || defined(PBELL_VIBE500) + outl(inl(0x600060a4) | 0x20, 0x600060a4); + outl(inl(0x7000c020) | 0x3, 0x7000c020); + outl(0x55, 0x7000c02c); + outl(0x54, 0x7000c030); +#else + outl(0x80 | (0 << 8), 0x600060a4); +#endif +#elif CONFIG_I2C == I2C_PP5024 +#if defined(SANSA_E200) || defined(PHILIPS_SA9200) + /* Sansa OF sets this to 0x20 first, communicates with the AS3514 + then sets it to 0x23 - this still works fine though */ + outl(0x0, 0x600060a4); + outl(0x23, 0x600060a4); +#elif defined(SANSA_C200) + /* This is the init sequence from the Sansa c200 bootloader. + I'm not sure what's really necessary. */ + pp_i2c_wait_not_busy(); + + outl(0, 0x600060a4); + outl(0x64, 0x600060a4); + + outl(0x55, 0x7000c02c); + outl(0x54, 0x7000c030); + + outl(0, 0x600060a4); + outl(0x1e, 0x600060a4); + + ascodec_write(AS3514_SUPERVISOR, 5); +#elif defined(PHILIPS_SA9200) + outl(0x0, 0x600060a4); + outl(inl(0x600060a4) | 0x20, 0x600060a4); + + outl(inl(0x7000c020) | 0x3, 0x7000c020); + outl(0x55, 0x7000c02c); + outl(0x54, 0x7000c030); +#endif +#endif + + i2c_readbyte(0x8, 0); +} diff --git a/firmware/target/arm/pp/i2s-pp.c b/firmware/target/arm/pp/i2s-pp.c new file mode 100644 index 0000000000..83f39515c4 --- /dev/null +++ b/firmware/target/arm/pp/i2s-pp.c @@ -0,0 +1,95 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Portalplayer specific code for I2S + * + * 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) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "cpu.h" +#include "i2s.h" +#if defined (SANSA_E200) || defined (SANSA_C200) +#include "audiohw.h" +#include "pcm_sampr.h" +#endif + +#if CONFIG_CPU == PP5002 +void i2s_reset(void) +{ + /* I2S device reset */ + DEV_RS |= DEV_I2S; + DEV_RS &= ~DEV_I2S; + + /* I2S controller enable */ + IISCONFIG |= IIS_ENABLE; + + /* reset DAC and ADC fifo */ + IISFIFO_CFG |= IIS_RXCLR | IIS_TXCLR; +} +#else /* PP502X */ + +/* + * Reset the I2S BIT.FORMAT I2S, 16bit, FIFO.FORMAT 32bit + */ +void i2s_reset(void) +{ + /* I2S soft reset */ + IISCONFIG |= IIS_RESET; + IISCONFIG &= ~IIS_RESET; + + /* BIT.FORMAT */ + IISCONFIG = ((IISCONFIG & ~IIS_FORMAT_MASK) | IIS_FORMAT_IIS); + /* BIT.SIZE */ + IISCONFIG = ((IISCONFIG & ~IIS_SIZE_MASK) | IIS_SIZE_16BIT); + + /* FIFO.FORMAT */ + /* If BIT.SIZE < FIFO.FORMAT low bits will be 0 */ +#ifdef HAVE_AS3514 + /* AS3514 can only operate as I2S Slave */ + IISCONFIG |= IIS_MASTER; + + /* Set I2S to 44.1kHz */ +#ifdef PHILIPS_SA9200 + /* values taken from the SA9200 OF */ + IISCLK = (IISCLK & ~0x1ff) | 31; + IISDIV = (IISDIV & ~0xc0000000) | (2 << 30); + IISDIV = (IISDIV & ~0x3f) | 16; +#elif defined (SANSA_E200) || defined (SANSA_C200) + audiohw_set_sampr_dividers(HW_FREQ_DEFAULT); +#else + IISCLK = (IISCLK & ~0x1ff) | 33; + IISDIV = 7; +#endif +#endif /* HAVE_AS3514 */ + + IISCONFIG = ((IISCONFIG & ~IIS_FIFO_FORMAT_MASK) | IIS_FIFO_FORMAT_LE16_2); + + /* RX_ATN_LVL = when 12 slots full */ + /* TX_ATN_LVL = DMA request when 4 slots empty */ + IISFIFO_CFG |= IIS_RX_FULL_LVL_12 | IIS_TX_EMPTY_LVL_4; + + /* Rx.CLR = 1, TX.CLR = 1 */ + IISFIFO_CFG |= IIS_RXCLR | IIS_TXCLR; +} + +#endif /* CONFIG_CPU == */ diff --git a/firmware/target/arm/pp/kernel-pp.c b/firmware/target/arm/pp/kernel-pp.c new file mode 100644 index 0000000000..2a00254173 --- /dev/null +++ b/firmware/target/arm/pp/kernel-pp.c @@ -0,0 +1,64 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Björn Stenberg + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" +#include "system.h" +#include "kernel.h" + +#if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE) +void TIMER1(void) +{ + /* Run through the list of tick tasks (using main core) */ + TIMER1_VAL; /* Read value to ack IRQ */ + + /* Run through the list of tick tasks using main CPU core - + wake up the COP through its control interface to provide pulse */ + call_tick_tasks(); + +#if NUM_CORES > 1 + /* Pulse the COP */ + core_wake(COP); +#endif /* NUM_CORES */ +} +#endif + +/* Must be last function called init kernel/thread initialization */ +void tick_start(unsigned int interval_in_ms) +{ +#if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE) + TIMER1_CFG = 0x0; + TIMER1_VAL; + /* enable timer */ + TIMER1_CFG = 0xc0000000 | (interval_in_ms*1000 - 1); + /* unmask interrupt source */ + CPU_INT_EN = TIMER1_MASK; +#else + /* We don't enable interrupts in the bootloader */ + (void)interval_in_ms; +#endif +} + +#ifdef HAVE_BOOTLOADER_USB_MODE +void tick_stop(void) +{ + CPU_INT_DIS = TIMER1_MASK; + TIMER1_CFG = 0; +} +#endif diff --git a/firmware/target/arm/pp/pcm-pp.c b/firmware/target/arm/pp/pcm-pp.c new file mode 100644 index 0000000000..3854206ae8 --- /dev/null +++ b/firmware/target/arm/pp/pcm-pp.c @@ -0,0 +1,734 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Michael Sevakis + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include "system.h" +#include "kernel.h" +#include "logf.h" +#include "audio.h" +#include "sound.h" +#include "pcm.h" +#include "pcm_sampr.h" +#include "pcm-internal.h" + +/** DMA **/ + +#ifdef CPU_PP502x +/* 16-bit, L-R packed into 32 bits with left in the least significant halfword */ +#define SAMPLE_SIZE 16 +/* DMA Requests from IIS, Memory to peripheral, single transfer, + wait for DMA request, interrupt on complete */ +#define DMA_PLAY_CONFIG ((DMA_REQ_IIS << DMA_CMD_REQ_ID_POS) | \ + DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \ + DMA_CMD_WAIT_REQ | DMA_CMD_INTR) +/* DMA status cannot be viewed from outside code in control because that can + * clear the interrupt from outside the handler and prevent the handler from + * from being called. Split up transfers to a reasonable size that is good as + * a timer, obtaining a keyclick position and peaking yet still keeps the + * FIQ count low. + */ +#define MAX_DMA_CHUNK_SIZE (pcm_curr_sampr >> 6) /* ~1/256 seconds */ +#else +/* 32-bit, one left 32-bit sample followed by one right 32-bit sample */ +#define SAMPLE_SIZE 32 +#endif + +struct dma_data +{ +/* NOTE: The order of size and p is important if you use assembler + optimised fiq handler, so don't change it. */ + union + { + unsigned long addr; + uint32_t *p16; /* For packed 16-16 stereo pairs */ + uint16_t *p32; /* For individual samples converted to 32-bit */ + }; + size_t size; +#if NUM_CORES > 1 + unsigned core; +#endif + int locked; + int state; +}; + +extern void *fiq_function; + +/* Dispatch to the proper handler and leave the main vector table alone */ +void fiq_handler(void) ICODE_ATTR __attribute__((naked)); +void fiq_handler(void) +{ + asm volatile ( + "ldr pc, [pc, #-4] \n" + "fiq_function: \n" + ".word 0 \n" + ); +} + +#ifdef HAVE_PCM_DMA_ADDRESS +void * pcm_dma_addr(void *addr) +{ + if (addr != NULL && (unsigned long)addr < UNCACHED_BASE_ADDR) + addr = UNCACHED_ADDR(addr); + return addr; +} +#endif + +/* TODO: Get simultaneous recording and playback to work. Just needs some tweaking */ + +/**************************************************************************** + ** Playback DMA transfer + **/ +static struct dma_data dma_play_data IBSS_ATTR = +{ + /* Initialize to a locked, stopped state */ + { .addr = 0 }, + .size = 0, +#if NUM_CORES > 1 + .core = 0x00, +#endif + .locked = 0, + .state = 0 +}; + +void pcm_dma_apply_settings(void) +{ + audiohw_set_frequency(pcm_fsel); +} + +#if defined(CPU_PP502x) +/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ +void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void) +{ + bool new_buffer = false; + register size_t size; + + DMA0_STATUS; /* Clear any pending interrupt */ + + size = (DMA0_CMD & 0xffff) + 4; /* Get size of trasfer that caused this + interrupt */ + dma_play_data.addr += size; + dma_play_data.size -= size; + + while (1) + { + if (dma_play_data.size > 0) { + size = MAX_DMA_CHUNK_SIZE; + /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less + * than a FIFO's worth of data after this transfer? */ + if (size + 16*4 > dma_play_data.size) + size = dma_play_data.size; + + /* Set the new DMA values and activate channel */ + DMA0_RAM_ADDR = dma_play_data.addr; + DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START; + + if (new_buffer) + pcm_play_dma_started_callback(); + return; + } + + new_buffer = true; + + /* Buffer empty. Try to get more. */ + pcm_play_get_more_callback((void **)&dma_play_data.addr, + &dma_play_data.size); + + if (dma_play_data.size == 0) { + /* No more data */ + return; + } + + if (dma_play_data.addr < UNCACHED_BASE_ADDR) { + /* Flush any pending cache writes */ + dma_play_data.addr = UNCACHED_ADDR(dma_play_data.addr); + commit_discard_idcache(); + } + } +} +#else +/* ASM optimised FIQ handler. Checks for the minimum allowed loop cycles by + * evalutation of free IISFIFO-slots against available source buffer words. + * Through this it is possible to move the check for IIS_TX_FREE_COUNT outside + * the loop and do some further optimization. Right after the loops (source + * buffer -> IISFIFO) are done we need to check whether we have to exit FIQ + * handler (this must be done, if all free FIFO slots were filled) or we will + * have to get some new source data. Important information kept from former + * ASM implementation (not used anymore): GCC fails to make use of the fact + * that FIQ mode has registers r8-r14 banked, and so does not need to be saved. + * This routine uses only these registers, and so will never touch the stack + * unless it actually needs to do so when calling pcm_callback_for_more. + * C version is still included below for reference and testing. + */ +#if 1 +void fiq_playback(void) ICODE_ATTR __attribute__((naked)); +void fiq_playback(void) +{ + /* r10 contains IISCONFIG address (set in crt0.S to minimise code in actual + * FIQ handler. r11 contains address of p (also set in crt0.S). Most other + * addresses we need are generated by using offsets with these two. + * r10 + 0x40 is IISFIFO_WR, and r10 + 0x0c is IISFIFO_CFG. + * r8 and r9 contains local copies of p and size respectively. + * r0-r3 and r12 is a working register. + */ + asm volatile ( + "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */ + + "mov r4, #0 \n" /* Was the callback called? */ +#if CONFIG_CPU == PP5002 + "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */ + "ldr r12, [r12] \n" +#endif + "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */ + "cmp r9, #0 \n" /* is size 0? */ + "beq .more_data \n" /* if so, ask pcmbuf for more data */ + +#if SAMPLE_SIZE == 16 + ".check_fifo: \n" + "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */ + "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 16 (PP502x) */ + + "mov r1, r0, lsr #16 \n" /* number of free FIFO slots */ + "cmp r1, r9, lsr #2 \n" /* number of words from source */ + "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */ + "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */ + + "subs r1, r1, #2 \n" + ".fifo_loop_2: \n" + "ldmgeia r8!, {r2, r12} \n" /* load four samples */ + "strge r2 , [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */ + "strge r12, [r10, %[wr]] \n" /* write sample 2-3 to IISFIFO_WR */ + "subges r1, r1, #2 \n" /* one more loop? */ + "bge .fifo_loop_2 \n" /* yes, continue */ + + "tst r1, #1 \n" /* two samples (one word) left? */ + "ldrne r12, [r8], #4 \n" /* load two samples */ + "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */ +#elif SAMPLE_SIZE == 32 + ".check_fifo: \n" + "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */ + "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */ + + "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */ + "beq .fifo_fill_complete \n" /* no complete pair? -> exit */ + "cmp r1, r9, lsr #2 \n" /* number of words from source */ + "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */ + "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */ + + ".fifo_loop: \n" + "ldr r12, [r8], #4 \n" /* load two samples */ + "mov r2 , r12, lsl #16 \n" /* put left sample at the top bits */ + "str r2 , [r10, %[wr]] \n" /* write top sample to IISFIFO_WR */ + "str r12, [r10, %[wr]] \n" /* write low sample to IISFIFO_WR*/ + "subs r1, r1, #1 \n" /* one more loop? */ + "bgt .fifo_loop \n" /* yes, continue */ + + ".fifo_fill_complete: \n" +#endif + "cmp r4, #0 \n" /* If fill came after get_more... */ + "beq .still_old_buffer \n" + "mov r4, #0 \n" + "ldr r2, =pcm_play_dma_started \n" + "ldrne r2, [r2] \n" + "cmp r2, #0 \n" + "movne lr, pc \n" + "bxne r2 \n" + + ".still_old_buffer: \n" + "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */ + "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */ + + ".more_data: \n" + "mov r4, #1 \n" /* Remember we did this */ + "ldr r2, =pcm_play_get_more_callback \n" + "mov r0, r11 \n" /* r0 = &p */ + "add r1, r11, #4 \n" /* r1 = &size */ + "mov lr, pc \n" /* call pcm_play_get_more_callback */ + "bx r2 \n" + "ldmia r11, { r8-r9 } \n" /* load new p and size */ + "cmp r9, #0 \n" + "bne .check_fifo \n" /* size != 0? refill */ + + ".exit: \n" /* (r9=0 if stopping, look above) */ + "stmia r11, { r8-r9 } \n" /* save p and size */ + "ldmfd sp!, { r0-r4, lr } \n" + "subs pc, lr, #4 \n" /* FIQ specific return sequence */ + ".ltorg \n" + : /* These must only be integers! No regs */ + : [mask]"i"(IIS_TX_FREE_MASK), + [cfg]"i"((int)&IISFIFO_CFG - (int)&IISCONFIG), + [wr]"i"((int)&IISFIFO_WR - (int)&IISCONFIG) + ); +} +#else /* C version for reference */ +void fiq_playback(void) __attribute__((interrupt ("FIQ"))) ICODE_ATTR; +/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ +void fiq_playback(void) +{ + bool new_buffer = false; + +#if CONFIG_CPU == PP5002 + inl(0xcf001040); +#endif + + do { + while (dma_play_data.size > 0) { + if (IIS_TX_FREE_COUNT < 2) { + if (new_buffer) { + new_buffer = false; + pcm_play_dma_started_callback(); + } + return; + } +#if SAMPLE_SIZE == 16 + IISFIFO_WR = *dma_play_data.p16++; +#elif SAMPLE_SIZE == 32 + IISFIFO_WR = *dma_play_data.p32++ << 16; + IISFIFO_WR = *dma_play_data.p32++ << 16; +#endif + dma_play_data.size -= 4; + } + + if (new_buffer) { + new_buffer = false; + pcm_play_dma_started_callback(); + } + + /* p is empty, get some more data */ + pcm_play_get_more_callback((void **)&dma_play_data.addr, + &dma_play_data.size); + new_buffer = true; + } while (dma_play_data.size); + + /* No more data */ +} +#endif /* ASM / C selection */ +#endif /* CPU_PP502x */ + +/* For the locks, FIQ must be disabled because the handler manipulates + IISCONFIG and the operation is not atomic - dual core support + will require other measures */ +void pcm_play_lock(void) +{ + int status = disable_fiq_save(); + + if (++dma_play_data.locked == 1) { +#ifdef CPU_PP502x + CPU_INT_DIS = DMA_MASK; +#else + IIS_IRQTX_REG &= ~IIS_IRQTX; +#endif + } + + restore_fiq(status); +} + +void pcm_play_unlock(void) +{ + int status = disable_fiq_save(); + + if (--dma_play_data.locked == 0 && dma_play_data.state != 0) { +#ifdef CPU_PP502x + CPU_INT_EN = DMA_MASK; +#else + IIS_IRQTX_REG |= IIS_IRQTX; +#endif + } + + restore_fiq(status); +} + +static void play_start_pcm(void) +{ + fiq_function = fiq_playback; + +#ifdef CPU_PP502x + /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less than a + * FIFO's worth of data after this transfer? */ + size_t size = MAX_DMA_CHUNK_SIZE; + if (size + 16*4 > dma_play_data.size) + size = dma_play_data.size; + + DMA0_RAM_ADDR = dma_play_data.addr; + DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START; + dma_play_data.state = 1; +#else + IISCONFIG &= ~IIS_TXFIFOEN; /* Stop transmitting */ + + /* Fill the FIFO or start when data is used up */ + while (1) { + if (IIS_TX_FREE_COUNT < 2 || dma_play_data.size == 0) { + IISCONFIG |= IIS_TXFIFOEN; /* Start transmitting */ + dma_play_data.state = 1; + return; + } + +#if SAMPLE_SIZE == 16 + IISFIFO_WR = *dma_play_data.p16++; +#elif SAMPLE_SIZE == 32 + IISFIFO_WR = *dma_play_data.p32++ << 16; + IISFIFO_WR = *dma_play_data.p32++ << 16; +#endif + dma_play_data.size -= 4; + } +#endif +} + +static void play_stop_pcm(void) +{ +#ifdef CPU_PP502x + unsigned long status = DMA0_STATUS; /* Snapshot- resume from this point */ + unsigned long cmd = DMA0_CMD; + size_t size = 0; + + /* Stop transfer */ + DMA0_CMD = cmd & ~(DMA_CMD_START | DMA_CMD_INTR); + + /* Wait for not busy + clear int */ + while (DMA0_STATUS & (DMA_STATUS_BUSY | DMA_STATUS_INTR)); + + if (status & DMA_STATUS_BUSY) { + /* Transfer was interrupted - leave what's left */ + size = (cmd & 0xfffc) - (status & 0xfffc); + } + else if (status & DMA_STATUS_INTR) { + /* Transfer was finished - DMA0_STATUS will have been reloaded + * automatically with size in DMA0_CMD. Setup to restart on next + * segment. */ + size = (cmd & 0xfffc) + 4; + } + /* else not an active state - size = 0 */ + + dma_play_data.addr += size; + dma_play_data.size -= size; + + if (dma_play_data.size == 0) + dma_play_data.addr = 0; /* Entire buffer has completed. */ +#else + /* Disable TX interrupt */ + IIS_IRQTX_REG &= ~IIS_IRQTX; +#endif + + /* Wait for FIFO to empty */ + while (!IIS_TX_IS_EMPTY); + + dma_play_data.state = 0; +} + +void pcm_play_dma_start(const void *addr, size_t size) +{ +#if NUM_CORES > 1 + /* This will become more important later - and different ! */ + dma_play_data.core = processor_id(); /* save initiating core */ +#endif + + pcm_play_dma_stop(); + +#ifdef CPU_PP502x + if ((unsigned long)addr < UNCACHED_BASE_ADDR) { + /* Flush any pending cache writes */ + addr = UNCACHED_ADDR(addr); + commit_discard_idcache(); + } + + dma_play_data.addr = (unsigned long)addr; + dma_play_data.size = size; + DMA0_PER_ADDR = (unsigned long)&IISFIFO_WR; + DMA0_FLAGS = DMA_FLAGS_UNK26; + DMA0_INCR = DMA_INCR_RANGE_FIXED | DMA_INCR_WIDTH_32BIT; +#else + dma_play_data.addr = (unsigned long)addr; + dma_play_data.size = size; +#endif + + play_start_pcm(); +} + +/* Stops the DMA transfer and interrupt */ +void pcm_play_dma_stop(void) +{ + play_stop_pcm(); + dma_play_data.addr = 0; + dma_play_data.size = 0; +#if NUM_CORES > 1 + dma_play_data.core = 0; /* no core in control */ +#endif +} + +void pcm_play_dma_pause(bool pause) +{ + if (pause) { + play_stop_pcm(); + } else { + play_start_pcm(); + } +} + +size_t pcm_get_bytes_waiting(void) +{ + return dma_play_data.size & ~3; +} + +void pcm_play_dma_init(void) +{ + /* Initialize default register values. */ + audiohw_init(); + +#ifdef CPU_PP502x + /* Enable DMA controller */ + DMA_MASTER_CONTROL |= DMA_MASTER_CONTROL_EN; + /* FIQ priority for DMA */ + CPU_INT_PRIORITY |= DMA_MASK; + /* Enable request?? Not setting or clearing everything doesn't seem to + * prevent it operating. Perhaps important for reliability (how requests + * are handled). */ + DMA_REQ_STATUS |= 1ul << DMA_REQ_IIS; + DMA0_STATUS; +#else + /* Set up banked registers for FIQ mode */ + + /* Use non-banked registers for scratch. */ + register volatile void *iiscfg asm("r0") = &IISCONFIG; + register volatile void *dmapd asm("r1") = &dma_play_data; + + asm volatile ( + "mrs r2, cpsr \n" /* Save mode and interrupt status */ + "msr cpsr_c, #0xd1 \n" /* Switch to FIQ mode */ + "mov r8, #0 \n" + "mov r9, #0 \n" + "mov r10, %[iiscfg] \n" + "mov r11, %[dmapd] \n" + "msr cpsr_c, r2 \n" + : + : [iiscfg]"r"(iiscfg), [dmapd]"r"(dmapd) + : "r2"); + + /* FIQ priority for I2S */ + CPU_INT_PRIORITY |= IIS_MASK; + CPU_INT_EN = IIS_MASK; +#endif + + IISCONFIG |= IIS_TXFIFOEN; +} + +void pcm_play_dma_postinit(void) +{ + audiohw_postinit(); +} + +const void * pcm_play_dma_get_peak_buffer(int *count) +{ + unsigned long addr, size; + + int status = disable_fiq_save(); + addr = dma_play_data.addr; + size = dma_play_data.size; + restore_fiq(status); + + *count = size >> 2; + return (void *)((addr + 2) & ~3); +} + +/**************************************************************************** + ** Recording DMA transfer + **/ +#ifdef HAVE_RECORDING +/* PCM recording interrupt routine lockout */ +static struct dma_data dma_rec_data IBSS_ATTR = +{ + /* Initialize to a locked, stopped state */ + { .addr = 0 }, + .size = 0, +#if NUM_CORES > 1 + .core = 0x00, +#endif + .locked = 0, + .state = 0 +}; + +/* For the locks, FIQ must be disabled because the handler manipulates + IISCONFIG and the operation is not atomic - dual core support + will require other measures */ +void pcm_rec_lock(void) +{ + int status = disable_fiq_save(); + + if (++dma_rec_data.locked == 1) + IIS_IRQRX_REG &= ~IIS_IRQRX; + + restore_fiq(status); +} + +void pcm_rec_unlock(void) +{ + int status = disable_fiq_save(); + + if (--dma_rec_data.locked == 0 && dma_rec_data.state != 0) + IIS_IRQRX_REG |= IIS_IRQRX; + + restore_fiq(status); +} + +/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ +void fiq_record(void) ICODE_ATTR __attribute__((interrupt ("FIQ"))); + +#if defined(SANSA_C200) || defined(SANSA_E200) +void fiq_record(void) +{ + register int32_t value; + + if (audio_channels == 2) { + /* RX is stereo */ + while (dma_rec_data.size > 0) { + if (IIS_RX_FULL_COUNT < 2) { + return; + } + + /* Discard every other sample since ADC clock is 1/2 LRCK */ + value = IISFIFO_RD; + IISFIFO_RD; + + *dma_rec_data.p16++ = value; + dma_rec_data.size -= 4; + + /* TODO: Figure out how to do IIS loopback */ + if (audio_output_source != AUDIO_SRC_PLAYBACK) { + if (IIS_TX_FREE_COUNT >= 16) { + /* Resync the output FIFO - it ran dry */ + IISFIFO_WR = 0; + IISFIFO_WR = 0; + } + IISFIFO_WR = value; + IISFIFO_WR = value; + } + } + } + else { + /* RX is left channel mono */ + while (dma_rec_data.size > 0) { + if (IIS_RX_FULL_COUNT < 2) { + return; + } + + /* Discard every other sample since ADC clock is 1/2 LRCK */ + value = IISFIFO_RD; + IISFIFO_RD; + + value = (uint16_t)value | (value << 16); + + *dma_rec_data.p16++ = value; + dma_rec_data.size -= 4; + + if (audio_output_source != AUDIO_SRC_PLAYBACK) { + if (IIS_TX_FREE_COUNT >= 16) { + /* Resync the output FIFO - it ran dry */ + IISFIFO_WR = 0; + IISFIFO_WR = 0; + } + + value = *((int32_t *)dma_rec_data.p16 - 1); + IISFIFO_WR = value; + IISFIFO_WR = value; + } + } + } + + pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr, + &dma_rec_data.size); +} + +#else +void fiq_record(void) +{ + while (dma_rec_data.size > 0) { + if (IIS_RX_FULL_COUNT < 2) { + return; + } + +#if SAMPLE_SIZE == 16 + *dma_rec_data.p16++ = IISFIFO_RD; +#elif SAMPLE_SIZE == 32 + *dma_rec_data.p32++ = IISFIFO_RD >> 16; + *dma_rec_data.p32++ = IISFIFO_RD >> 16; +#endif + dma_rec_data.size -= 4; + } + + pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr, + &dma_rec_data.size); +} + +#endif /* SANSA_E200 */ + +void pcm_rec_dma_stop(void) +{ + /* disable interrupt */ + IIS_IRQRX_REG &= ~IIS_IRQRX; + + dma_rec_data.state = 0; + dma_rec_data.size = 0; +#if NUM_CORES > 1 + dma_rec_data.core = 0x00; +#endif + + /* disable fifo */ + IISCONFIG &= ~IIS_RXFIFOEN; + IISFIFO_CFG |= IIS_RXCLR; +} + +void pcm_rec_dma_start(void *addr, size_t size) +{ + pcm_rec_dma_stop(); + + dma_rec_data.addr = (unsigned long)addr; + dma_rec_data.size = size; +#if NUM_CORES > 1 + /* This will become more important later - and different ! */ + dma_rec_data.core = processor_id(); /* save initiating core */ +#endif + /* setup FIQ handler */ + fiq_function = fiq_record; + + /* interrupt on full fifo, enable record fifo interrupt */ + dma_rec_data.state = 1; + + /* enable RX FIFO */ + IISCONFIG |= IIS_RXFIFOEN; + + /* enable IIS interrupt as FIQ */ + CPU_INT_PRIORITY |= IIS_MASK; + CPU_INT_EN = IIS_MASK; +} + +void pcm_rec_dma_close(void) +{ + pcm_rec_dma_stop(); +} /* pcm_close_recording */ + +void pcm_rec_dma_init(void) +{ + pcm_rec_dma_stop(); +} /* pcm_init */ + +const void * pcm_rec_dma_get_peak_buffer(void) +{ + return (void *)((unsigned long)dma_rec_data.addr & ~3); +} /* pcm_rec_dma_get_peak_buffer */ + +#endif /* HAVE_RECORDING */ diff --git a/firmware/target/arm/pp/system-pp5002.c b/firmware/target/arm/pp/system-pp5002.c new file mode 100644 index 0000000000..3186d3739a --- /dev/null +++ b/firmware/target/arm/pp/system-pp5002.c @@ -0,0 +1,227 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" + +#ifndef BOOTLOADER +#include "adc-target.h" +#include "button-target.h" + +extern void TIMER1(void); +extern void TIMER2(void); + +void __attribute__((interrupt("IRQ"))) irq_handler(void) +{ + if(CURRENT_CORE == CPU) + { + if (CPU_INT_STAT & TIMER1_MASK) + TIMER1(); + else if (CPU_INT_STAT & TIMER2_MASK) + TIMER2(); + else if (CPU_INT_STAT & GPIO_MASK) + { + if (GPIOA_INT_STAT) + ipod_3g_button_int(); +#ifdef IPOD_1G2G + if (GPIOB_INT_STAT & 0x04) + ipod_2g_adc_int(); +#endif + } + } + else + { + if (COP_INT_STAT & TIMER2_MASK) + TIMER2(); + } +} + +#endif + +#ifndef BOOTLOADER +void ICODE_ATTR __attribute__((naked)) commit_dcache(void) +{ + asm volatile( + "mov r0, #0xf0000000 \n" + "add r0, r0, #0xc000 \n" /* r0 = CACHE_FLUSH_BASE */ + "add r1, r0, #0x2000 \n" /* r1 = CACHE_FLUSH_BASE + CACHE_SIZE */ + "mov r2, #0 \n" + "1: \n" + "str r2, [r0], #16 \n" /* Commit */ + "cmp r0, r1 \n" + "blo 1b \n" + "bx lr \n" + ); +} + +void ICODE_ATTR __attribute__((naked)) commit_discard_idcache(void) +{ + asm volatile( + "mov r0, #0xf0000000 \n" + "add r2, r0, #0x4000 \n" /* r1 = CACHE_INVALIDATE_BASE */ + "add r0, r0, #0xc000 \n" /* r0 = CACHE_FLUSH_BASE */ + "add r1, r0, #0x2000 \n" /* r2 = CACHE_FLUSH_BASE + CACHE_SIZE */ + "mov r3, #0 \n" + "1: \n" + "str r3, [r0], #16 \n" /* Commit */ + "str r3, [r2], #16 \n" /* Discard */ + "cmp r0, r1 \n" + "blo 1b \n" + "bx lr \n" + ); +} + +void commit_discard_dcache(void) __attribute__((alias("commit_discard_idcache"))); + +static void ipod_init_cache(void) +{ +/* Initialising the cache in the iPod bootloader prevents Rockbox from starting */ + PROC_STAT &= ~0x700; + outl(0x4000, 0xcf004020); + + CACHE_CTL = CACHE_CTL_INIT; + + asm volatile( + "mov r0, #0xf0000000 \n" + "add r0, r0, #0x4000 \n" /* r0 = CACHE_INVALIDATE_BASE */ + "add r1, r0, #0x2000 \n" /* r1 = CACHE_INVALIDATE_BASE + CACHE_SIZE */ + "mov r2, #0 \n" + "1: \n" + "str r2, [r0], #16 \n" /* Invalidate */ + "cmp r0, r1 \n" + "blo 1b \n" + : : : "r0", "r1", "r2" + ); + + /* Cache if (addr & mask) >> 16 == (mask & match) >> 16: + * yes: 0x00000000 - 0x03ffffff + * no: 0x04000000 - 0x1fffffff + * yes: 0x20000000 - 0x23ffffff + * no: 0x24000000 - 0x3fffffff <= range containing uncached alias + */ + CACHE_MASK = 0x00001c00; + CACHE_OPERATION = 0x3fc0; + + CACHE_CTL = CACHE_CTL_INIT | CACHE_CTL_RUN; +} + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ +void set_cpu_frequency(long frequency) +#else +static void pp_set_cpu_frequency(long frequency) +#endif +{ + cpu_frequency = frequency; + + PLL_CONTROL |= 0x6000; /* make sure some enable bits are set */ + CLOCK_ENABLE = 0x01; /* select source #1 */ + + switch (frequency) + { + case CPUFREQ_MAX: + PLL_UNLOCK = 0xd19b; /* unlock frequencies > 66MHz */ + CLOCK_SOURCE = 0xa9; /* source #1: 24 Mhz, source #2..#4: PLL */ + PLL_CONTROL = 0xe000; /* PLL enabled */ + PLL_DIV = 3; /* 10/3 * 24MHz */ + PLL_MULT = 10; + udelay(200); /* wait for relock */ + break; + + case CPUFREQ_NORMAL: + CLOCK_SOURCE = 0xa9; /* source #1: 24 Mhz, source #2..#4: PLL */ + PLL_CONTROL = 0xe000; /* PLL enabled */ + PLL_DIV = 4; /* 5/4 * 24MHz */ + PLL_MULT = 5; + udelay(200); /* wait for relock */ + break; + + case CPUFREQ_SLEEP: + CLOCK_SOURCE = 0x51; /* source #2: 32kHz, #1, #2, #4: 24MHz */ + PLL_CONTROL = 0x6000; /* PLL disabled */ + udelay(10000); /* let 32kHz source stabilize? */ + break; + + default: + CLOCK_SOURCE = 0x55; /* source #1..#4: 24 Mhz */ + PLL_CONTROL = 0x6000; /* PLL disabled */ + cpu_frequency = CPUFREQ_DEFAULT; + break; + } + CLOCK_ENABLE = 0x02; /* select source #2 */ +} +#endif /* !BOOTLOADER */ + +void system_init(void) +{ +#ifndef BOOTLOADER + if (CURRENT_CORE == CPU) + { + /* Remap the flash ROM on CPU, keep hidden from COP: + * 0x00000000-0x03ffffff = 0x20000000-0x23ffffff */ + MMAP1_LOGICAL = 0x20003c00; + MMAP1_PHYSICAL = 0x00003f84; + +#if defined(IPOD_1G2G) || defined(IPOD_3G) + DEV_EN = 0x0b9f; /* don't clock unused PP5002 hardware components */ + outl(0x0035, 0xcf005004); /* DEV_EN2 ? */ +#endif + + INT_FORCED_CLR = -1; + CPU_INT_DIS = -1; + COP_INT_DIS = -1; + + GPIOA_INT_EN = 0; + GPIOB_INT_EN = 0; + GPIOC_INT_EN = 0; + GPIOD_INT_EN = 0; + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ +#if NUM_CORES > 1 + cpu_boost_init(); +#endif +#else + pp_set_cpu_frequency(CPUFREQ_MAX); +#endif + } + ipod_init_cache(); +#endif +} + +void system_reboot(void) +{ + DEV_RS |= 4; + while (1); +} + +void system_exception_wait(void) +{ + /* FIXME: we just need the right buttons */ + CPU_INT_DIS = -1; + COP_INT_DIS = -1; + + /* Halt */ + sleep_core(CURRENT_CORE); + while (1); +} + +int system_memory_guard(int newmode) +{ + (void)newmode; + return 0; +} diff --git a/firmware/target/arm/pp/system-pp502x.c b/firmware/target/arm/pp/system-pp502x.c new file mode 100644 index 0000000000..847e8a462e --- /dev/null +++ b/firmware/target/arm/pp/system-pp502x.c @@ -0,0 +1,607 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "thread.h" +#include "i2s.h" +#include "i2c-pp.h" +#include "as3514.h" +#ifdef HAVE_HOTSWAP +#include "sd-pp-target.h" +#endif +#include "button-target.h" +#include "usb_drv.h" +#ifdef HAVE_REMOTE_LCD +#include "lcd-remote-target.h" +#endif + +#if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE) +extern void TIMER1(void); +extern void TIMER2(void); +extern void SERIAL0(void); + +#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1) +static struct corelock cpufreq_cl SHAREDBSS_ATTR; +#endif + +#if defined(IPOD_VIDEO) && !defined(BOOTLOADER) +unsigned char probed_ramsize; +#endif + +void __attribute__((interrupt("IRQ"))) irq_handler(void) +{ + if(CURRENT_CORE == CPU) + { + if (CPU_INT_STAT & TIMER1_MASK) { + TIMER1(); + } + else if (CPU_INT_STAT & TIMER2_MASK) { + TIMER2(); + } +#ifdef HAVE_USBSTACK + /* Rather high priority - place near front */ + else if (CPU_INT_STAT & USB_MASK) { + usb_drv_int(); + } +#endif +#if defined(IPOD_MINI) /* Mini 1st gen only, mini 2nd gen uses iPod 4G code */ + else if (CPU_HI_INT_STAT & GPIO0_MASK) { + if ((GPIOA_INT_STAT & 0x3f) || (GPIOB_INT_STAT & 0x30)) + ipod_mini_button_int(); + if (GPIOC_INT_STAT & 0x02) + firewire_insert_int(); + if (GPIOD_INT_STAT & 0x08) + usb_insert_int(); + } +/* end IPOD_MINI */ +#elif CONFIG_KEYPAD == IPOD_4G_PAD /* except Mini 1st gen, handled above */ + else if (CPU_HI_INT_STAT & I2C_MASK) { + ipod_4g_button_int(); + } +#if defined(IPOD_COLOR) || defined(IPOD_MINI2G) || defined(IPOD_4G) + else if (CPU_HI_INT_STAT & GPIO0_MASK) { + if (GPIOC_INT_STAT & 0x02) + firewire_insert_int(); + if (GPIOD_INT_STAT & 0x08) + usb_insert_int(); + } +#elif defined(IPOD_NANO) || defined(IPOD_VIDEO) + else if (CPU_HI_INT_STAT & GPIO2_MASK) { + if (GPIOL_INT_STAT & 0x10) + usb_insert_int(); + } +#endif +/* end CONFIG_KEYPAD == IPOD_4G_PAD */ +#elif defined(IRIVER_H10) || defined(IRIVER_H10_5GB) + else if (CPU_HI_INT_STAT & GPIO2_MASK) { + if (GPIOL_INT_STAT & 0x04) + usb_insert_int(); + } +/* end IRIVER_H10 || IRIVER_H10_5GB */ +#elif defined(SANSA_E200) + else if (CPU_HI_INT_STAT & GPIO0_MASK) { +#ifdef HAVE_HOTSWAP + if (GPIOA_INT_STAT & 0x80) + microsd_int(); +#endif + if (GPIOB_INT_STAT & 0x10) + usb_insert_int(); + } + else if (CPU_HI_INT_STAT & GPIO1_MASK) { + if (GPIOF_INT_STAT & 0xff) + button_int(); + if (GPIOH_INT_STAT & 0xc0) + clickwheel_int(); + } +/* end SANSA_E200 */ +#elif defined(SANSA_C200) + else if (CPU_HI_INT_STAT & GPIO1_MASK) { + if (GPIOH_INT_STAT & 0x02) + usb_insert_int(); + } +#ifdef HAVE_HOTSWAP + else if (CPU_HI_INT_STAT & GPIO2_MASK) { + if (GPIOL_INT_STAT & 0x08) + microsd_int(); + } +#endif +/* end SANSA_C200 */ +#elif defined(MROBE_100) + else if (CPU_HI_INT_STAT & GPIO0_MASK) { + if (GPIOD_INT_STAT & 0x02) + button_int(); + if (GPIOD_INT_STAT & 0x80) + headphones_int(); + + } + else if (CPU_HI_INT_STAT & GPIO2_MASK) { + if (GPIOL_INT_STAT & 0x04) + usb_insert_int(); + } +/* end MROBE_100 */ +#elif defined(PHILIPS_SA9200) + else if (CPU_HI_INT_STAT & GPIO0_MASK) { + if (GPIOD_INT_STAT & 0x02) + button_int(); + if (GPIOB_INT_STAT & 0x40) + usb_insert_int(); + } +/* end PHILIPS_SA9200 */ +#elif defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) + else if (CPU_HI_INT_STAT & GPIO0_MASK) { + if (GPIOA_INT_STAT & 0x20) + button_int(); + } + else if (CPU_HI_INT_STAT & GPIO1_MASK) { + if (GPIOE_INT_STAT & 0x04) + usb_insert_int(); + } +/* end PHILIPS_HDD1630 || PHILIPS_HDD6330 */ +#elif defined(SAMSUNG_YH820) || defined(SAMSUNG_YH920) || defined(SAMSUNG_YH925) + else if (CPU_HI_INT_STAT & GPIO0_MASK) { + if (GPIOD_INT_STAT & 0x10) + usb_insert_int(); + } +/* end SAMSUNG_YHxxx */ +#elif defined(PBELL_VIBE500) + else if (CPU_HI_INT_STAT & GPIO0_MASK) { + if (GPIOA_INT_STAT & 0x20) + button_int(); + } + else if (CPU_HI_INT_STAT & GPIO2_MASK) { + if (GPIOL_INT_STAT & 0x04) + usb_insert_int(); + } +/* end PBELL_VIBE500 */ +#endif +#ifdef IPOD_ACCESSORY_PROTOCOL + else if (CPU_HI_INT_STAT & SER0_MASK) { + SERIAL0(); + } +#endif + } else { + if (COP_INT_STAT & TIMER2_MASK) + TIMER2(); + } +} +#endif /* BOOTLOADER || HAVE_BOOTLOADER_USB_MODE */ + +#if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE) +static void disable_all_interrupts(void) +{ + COP_HI_INT_DIS = -1; + CPU_HI_INT_DIS = -1; + HI_INT_FORCED_CLR = -1; + + COP_INT_DIS = -1; + CPU_INT_DIS = -1; + INT_FORCED_CLR = -1; + + GPIOA_INT_EN = 0; + GPIOB_INT_EN = 0; + GPIOC_INT_EN = 0; + GPIOD_INT_EN = 0; + GPIOE_INT_EN = 0; + GPIOF_INT_EN = 0; + GPIOG_INT_EN = 0; + GPIOH_INT_EN = 0; + GPIOI_INT_EN = 0; + GPIOJ_INT_EN = 0; + GPIOK_INT_EN = 0; + GPIOL_INT_EN = 0; +} + +void ICODE_ATTR commit_dcache(void) +{ + if (CACHE_CTL & CACHE_CTL_ENABLE) + { + CACHE_OPERATION |= CACHE_OP_FLUSH; + while ((CACHE_CTL & CACHE_CTL_BUSY) != 0); + nop; nop; nop; nop; + } +} + +void ICODE_ATTR commit_discard_idcache(void) +{ + if (CACHE_CTL & CACHE_CTL_ENABLE) + { + CACHE_OPERATION |= CACHE_OP_FLUSH | CACHE_OP_INVALIDATE; + while ((CACHE_CTL & CACHE_CTL_BUSY) != 0); + nop; nop; nop; nop; + } +} + +void commit_discard_dcache(void) __attribute__((alias("commit_discard_idcache"))); + +static void init_cache(void) +{ +/* Initialising the cache in the iPod bootloader may prevent Rockbox from starting + * depending on the model */ + + /* cache init mode */ + CACHE_CTL &= ~(CACHE_CTL_ENABLE | CACHE_CTL_RUN); + CACHE_CTL |= CACHE_CTL_INIT; + +#ifndef BOOTLOADER + /* what's this do? */ + CACHE_PRIORITY |= CURRENT_CORE == CPU ? 0x10 : 0x20; +#endif + + /* Cache if (addr & mask) >> 16 == (mask & match) >> 16: + * yes: 0x00000000 - 0x03ffffff + * no: 0x04000000 - 0x1fffffff + * yes: 0x20000000 - 0x23ffffff + * no: 0x24000000 - 0x3fffffff + */ + CACHE_MASK = 0x00001c00; + CACHE_OPERATION = 0xfc0; + + /* enable cache */ + CACHE_CTL |= CACHE_CTL_INIT | CACHE_CTL_ENABLE | CACHE_CTL_RUN; + nop; nop; nop; nop; +} +#endif /* BOOTLOADER || HAVE_BOOTLOADER_USB_MODE */ + +/* We need this for Sansas since we boost the cpu in their bootloader */ +#if !defined(BOOTLOADER) || (defined(SANSA_E200) || defined(SANSA_C200) || \ + defined(PHILIPS_SA9200)) +void scale_suspend_core(bool suspend) ICODE_ATTR; +void scale_suspend_core(bool suspend) +{ + unsigned int core = CURRENT_CORE; + IF_COP( unsigned int othercore = 1 - core; ) + static int oldstatus IBSS_ATTR; + + if (suspend) + { + oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS); + IF_COP( PROC_CTL(othercore) = 0x40000000; nop; ) + PROC_CTL(core) = 0x48000003; nop; + } + else + { + PROC_CTL(core) = 0x4800001f; nop; + IF_COP( PROC_CTL(othercore) = 0x00000000; nop; ) + restore_interrupt(oldstatus); + } +} + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ +void set_cpu_frequency(long frequency) ICODE_ATTR; +void set_cpu_frequency(long frequency) +#else +static void pp_set_cpu_frequency(long frequency) +#endif +{ +#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1) + corelock_lock(&cpufreq_cl); +#endif + + switch (frequency) + { + /* Note1: The PP5022 PLL must be run at >= 96MHz + * Bits 20..21 select the post divider (1/2/4/8). + * PP5026 is similar to PP5022 except it doesn't + * have this limitation (and the post divider?) + * Note2: CLOCK_SOURCE is set via 0=32kHz, 1=16MHz, + * 2=24MHz, 3=33MHz, 4=48MHz, 5=SLOW, 6=FAST, 7=PLL. + * SLOW = 24MHz / (DIV_SLOW + 1), DIV = Bits 16-19 + * FAST = PLL / (DIV_FAST + 1), DIV = Bits 20-23 */ + case CPUFREQ_SLEEP: + cpu_frequency = CPUFREQ_SLEEP; + PLL_CONTROL |= 0x0c000000; + scale_suspend_core(true); + CLOCK_SOURCE = 0x20000000; /* source #1, #2, #3, #4: 32kHz (#2 active) */ + scale_suspend_core(false); + PLL_CONTROL &= ~0x80000000; /* disable PLL */ + DEV_INIT2 &= ~INIT_PLL; /* disable PLL power */ + break; + + case CPUFREQ_MAX: + cpu_frequency = CPUFREQ_MAX; + DEV_INIT2 |= INIT_PLL; /* enable PLL power */ + PLL_CONTROL |= 0x88000000; /* enable PLL */ + scale_suspend_core(true); + CLOCK_SOURCE = 0x20002222; /* source #1, #2, #3, #4: 24MHz (#2 active) */ + DEV_TIMING1 = 0x00000303; + scale_suspend_core(false); +#if defined(IPOD_MINI2G) + MLCD_SCLK_DIV = 0x00000001; /* Mono LCD bridge serial clock divider */ +#elif defined(IPOD_NANO) + IDE0_CFG |= 0x10000000; /* set ">65MHz" bit */ +#endif +#if CONFIG_CPU == PP5020 + PLL_CONTROL = 0x8a020a03; /* 80 MHz = 10/3 * 24MHz */ + PLL_STATUS = 0xd19b; /* unlock frequencies > 66MHz */ + PLL_CONTROL = 0x8a020a03; /* repeat setup */ + udelay(500); /* wait for relock */ +#elif (CONFIG_CPU == PP5022) || (CONFIG_CPU == PP5024) + PLL_CONTROL = 0x8a121403; /* 80 MHz = (20/3 * 24MHz) / 2 */ + while (!(PLL_STATUS & 0x80000000)); /* wait for relock */ +#endif + scale_suspend_core(true); + DEV_TIMING1 = 0x00000808; + CLOCK_SOURCE = 0x20007777; /* source #1, #2, #3, #4: PLL (#2 active) */ + scale_suspend_core(false); + break; +#if 0 /******** CPUFREQ_NORMAL = 24MHz without PLL ********/ + case CPUFREQ_NORMAL: + cpu_frequency = CPUFREQ_NORMAL; + PLL_CONTROL |= 0x08000000; + scale_suspend_core(true); + CLOCK_SOURCE = 0x20002222; /* source #1, #2, #3, #4: 24MHz (#2 active) */ + DEV_TIMING1 = 0x00000303; +#if defined(IPOD_MINI2G) + MLCD_SCLK_DIV = 0x00000000; /* Mono LCD bridge serial clock divider */ +#elif defined(IPOD_NANO) + IDE0_CFG &= ~0x10000000; /* clear ">65MHz" bit */ +#endif + scale_suspend_core(false); + PLL_CONTROL &= ~0x80000000; /* disable PLL */ + DEV_INIT2 &= ~INIT_PLL; /* disable PLL power */ + break; +#else /******** CPUFREQ_NORMAL = 30MHz with PLL ********/ + case CPUFREQ_NORMAL: + cpu_frequency = CPUFREQ_NORMAL; + DEV_INIT2 |= INIT_PLL; /* enable PLL power */ + PLL_CONTROL |= 0x88000000; /* enable PLL */ + scale_suspend_core(true); + CLOCK_SOURCE = 0x20002222; /* source #1, #2, #3, #4: 24MHz (#2 active) */ + DEV_TIMING1 = 0x00000303; + scale_suspend_core(false); +#if defined(IPOD_MINI2G) + MLCD_SCLK_DIV = 0x00000000; /* Mono LCD bridge serial clock divider */ +#elif defined(IPOD_NANO) + IDE0_CFG &= ~0x10000000; /* clear ">65MHz" bit */ +#endif +#if CONFIG_CPU == PP5020 + PLL_CONTROL = 0x8a020504; /* 30 MHz = 5/4 * 24MHz */ + udelay(500); /* wait for relock */ +#elif (CONFIG_CPU == PP5022) || (CONFIG_CPU == PP5024) + PLL_CONTROL = 0x8a220501; /* 30 MHz = (5/1 * 24MHz) / 4 */ + while (!(PLL_STATUS & 0x80000000)); /* wait for relock */ +#endif + scale_suspend_core(true); + DEV_TIMING1 = 0x00000303; + CLOCK_SOURCE = 0x20007777; /* source #1, #2, #3, #4: PLL (#2 active) */ + scale_suspend_core(false); + break; +#endif /******** CPUFREQ_NORMAL end ********/ + default: + cpu_frequency = CPUFREQ_DEFAULT; + PLL_CONTROL |= 0x08000000; + scale_suspend_core(true); + CLOCK_SOURCE = 0x20002222; /* source #1, #2, #3, #4: 24MHz (#2 active) */ + DEV_TIMING1 = 0x00000303; +#if defined(IPOD_MINI2G) + MLCD_SCLK_DIV = 0x00000000; /* Mono LCD bridge serial clock divider */ +#elif defined(IPOD_NANO) + IDE0_CFG &= ~0x10000000; /* clear ">65MHz" bit */ +#endif + scale_suspend_core(false); + PLL_CONTROL &= ~0x80000000; /* disable PLL */ + DEV_INIT2 &= ~INIT_PLL; /* disable PLL power */ + break; + } + +#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1) + corelock_unlock(&cpufreq_cl); +#endif +} +#endif /* !BOOTLOADER || (SANSA_E200 || SANSA_C200 || PHILIPS_SA9200) */ + +#ifndef BOOTLOADER +void system_init(void) +{ + if (CURRENT_CORE == CPU) + { +#if defined (IRIVER_H10) || defined(IRIVER_H10_5GB) || defined(IPOD_COLOR) + /* set minimum startup configuration */ + DEV_EN = 0xc2000124; + DEV_EN2 = 0x00002000; + CACHE_PRIORITY = 0x0000003f; + GPO32_VAL = 0x20000000; + DEV_INIT1 = 0xdc000000; + DEV_INIT2 = 0x40000000; + + /* reset all allowed devices */ + DEV_RS = 0x3dfffef8; + DEV_RS2 = 0xffffdfff; + DEV_RS = 0x00000000; + DEV_RS2 = 0x00000000; +#elif defined (IPOD_VIDEO) + /* set minimum startup configuration */ + DEV_EN = 0xc2000124; + DEV_EN2 = 0x00000000; + CACHE_PRIORITY = 0x0000003f; + GPO32_VAL &= 0x00004000; + DEV_INIT1 = 0x00000000; + DEV_INIT2 = 0x40000000; + + /* reset all allowed devices */ + DEV_RS = 0x3dfffef8; + DEV_RS2 = 0xffffffff; + DEV_RS = 0x00000000; + DEV_RS2 = 0x00000000; +#elif defined (IPOD_NANO) + /* set minimum startup configuration */ + DEV_EN = 0xc2000124; + DEV_EN2 = 0x00002000; + CACHE_PRIORITY = 0x0000003f; + GPO32_VAL = 0x50000000; + DEV_INIT1 = 0xa8000000; + DEV_INIT2 = 0x40000000; + + /* reset all allowed devices */ + DEV_RS = 0x3ffffef8; + DEV_RS2 = 0xffffdfff; + DEV_RS = 0x00000000; + DEV_RS2 = 0x00000000; +#elif defined(SANSA_C200) || defined (SANSA_E200) + /* set minimum startup configuration */ + DEV_EN = 0xc4000124; + DEV_EN2 = 0x00000000; + CACHE_PRIORITY = 0x0000003f; + GPO32_VAL = 0x10000000; + DEV_INIT1 = 0x54000000; + DEV_INIT2 = 0x40000000; + + /* reset all allowed devices */ + DEV_RS = 0x3bfffef8; + DEV_RS2 = 0xffffffff; + DEV_RS = 0x00000000; + DEV_RS2 = 0x00000000; +#elif defined(PHILIPS_SA9200) + /* reset all allowed devices */ + DEV_RS = 0x3ffffef8; + DEV_RS2 = 0xffffffff; + DEV_RS = 0x00000000; + DEV_RS2 = 0x00000000; +#elif defined(IPOD_4G) + /* set minimum startup configuration */ + DEV_EN = 0xc2020124; + DEV_EN2 = 0x00000000; + CACHE_PRIORITY = 0x0000003f; + GPO32_VAL = 0x02000000; + DEV_INIT1 = 0x00000000; + DEV_INIT2 = 0x40000000; + + /* reset all allowed devices */ + DEV_RS = 0x3dfdfef8; + DEV_RS2 = 0xffffffff; + DEV_RS = 0x00000000; + DEV_RS2 = 0x00000000; +#elif defined (IPOD_MINI) + /* to be done */ +#elif defined (IPOD_MINI2G) + /* to be done */ +#elif defined (MROBE_100) + /* to be done */ +#elif defined (TATUNG_TPJ1022) + /* to be done */ +#elif defined(PBELL_VIBE500) + /* reset all allowed devices */ + DEV_RS = 0x3ffffef8; + DEV_RS2 = 0xffffffff; + DEV_RS = 0x00000000; + DEV_RS2 = 0x00000000; +#endif + +#if !defined(SANSA_E200) && !defined(SANSA_C200) && !defined(PHILIPS_SA9200) + /* Remap the flash ROM on CPU, keep hidden from COP: + * 0x00000000-0x3fffffff = 0x20000000-0x23ffffff */ + MMAP1_LOGICAL = 0x20003c00; + MMAP1_PHYSICAL = 0x00003084 | + MMAP_PHYS_READ_MASK | MMAP_PHYS_WRITE_MASK | + MMAP_PHYS_DATA_MASK | MMAP_PHYS_CODE_MASK; +#endif + + disable_all_interrupts(); + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ +#if NUM_CORES > 1 + corelock_init(&cpufreq_cl); + cpu_boost_init(); +#endif +#else + pp_set_cpu_frequency(CPUFREQ_MAX); +#endif + +#if defined(IPOD_VIDEO) + /* crt0-pp.S wrote the ram size to the last byte of the first 32MB + ram bank. See the comment there for how we determine it. */ + volatile unsigned char *end32 = (volatile unsigned char *)0x01ffffff; + probed_ramsize = *end32; +#endif + } + + init_cache(); +} + +#else /* BOOTLOADER */ + +void system_init(void) +{ + /* Only the CPU gets here in the bootloader */ +#ifdef HAVE_BOOTLOADER_USB_MODE + disable_all_interrupts(); + init_cache(); + /* Use the local vector map */ + CACHE_CTL |= CACHE_CTL_VECT_REMAP; +#endif /* HAVE_BOOTLOADER_USB_MODE */ + +#if defined(SANSA_C200) || defined(SANSA_E200) || defined(PHILIPS_SA9200) + pp_set_cpu_frequency(CPUFREQ_MAX); +#endif + /* Else the frequency should get changed upon USB connect - + * decide per-target */ +} + +#ifdef HAVE_BOOTLOADER_USB_MODE +void system_prepare_fw_start(void) +{ + disable_interrupt(IRQ_FIQ_STATUS); + tick_stop(); + disable_all_interrupts(); + /* Some OF's disable this themselves, others do not and will hang. */ + CACHE_CTL &= ~CACHE_CTL_VECT_REMAP; +} +#endif /* HAVE_BOOTLOADER_USB_MODE */ +#endif /* !BOOTLOADER */ + +void ICODE_ATTR system_reboot(void) +{ + disable_interrupt(IRQ_FIQ_STATUS); + CPU_INT_DIS = -1; + COP_INT_DIS = -1; + + /* Reboot */ +#if defined(SANSA_E200) || defined(SANSA_C200) || defined(PHILIPS_SA9200) + CACHE_CTL &= ~CACHE_CTL_VECT_REMAP; + + /* Magic used by the c200 OF: 0x23066000 + Magic used by the c200 BL: 0x23066b7b + In both cases, the OF executes these 2 commands from iram. */ + STRAP_OPT_A = 0x23066b7b; + DEV_RS = DEV_SYSTEM; +#else + DEV_RS |= DEV_SYSTEM; +#endif + /* wait until reboot kicks in */ + while (1); +} + +void system_exception_wait(void) +{ + /* FIXME: we just need the right buttons */ + CPU_INT_DIS = -1; + COP_INT_DIS = -1; + + /* Halt */ + PROC_CTL(CURRENT_CORE) = 0x40000000; + while (1); +} + +int system_memory_guard(int newmode) +{ + (void)newmode; + return 0; +} + diff --git a/firmware/target/arm/pp/thread-pp.c b/firmware/target/arm/pp/thread-pp.c new file mode 100644 index 0000000000..0836b27204 --- /dev/null +++ b/firmware/target/arm/pp/thread-pp.c @@ -0,0 +1,554 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2007 by Daniel Ankers + * + * PP5002 and PP502x SoC threading support + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#if defined(MAX_PHYS_SECTOR_SIZE) && MEMORYSIZE == 64 +/* Support a special workaround object for large-sector disks */ +#define IF_NO_SKIP_YIELD(...) __VA_ARGS__ +#endif + +#if NUM_CORES == 1 +/* Single-core variants for FORCE_SINGLE_CORE */ +static inline void core_sleep(void) +{ + sleep_core(CURRENT_CORE); + enable_irq(); +} + +/* Shared single-core build debugging version */ +void core_wake(void) +{ + /* No wakey - core already wakey (because this is it) */ +} +#else /* NUM_CORES > 1 */ +/** Model-generic PP dual-core code **/ +extern uintptr_t cpu_idlestackbegin[]; +extern uintptr_t cpu_idlestackend[]; +extern uintptr_t cop_idlestackbegin[]; +extern uintptr_t cop_idlestackend[]; +static uintptr_t * const idle_stacks[NUM_CORES] = +{ + [CPU] = cpu_idlestackbegin, + [COP] = cop_idlestackbegin +}; + +/* Core locks using Peterson's mutual exclusion algorithm */ + +/*--------------------------------------------------------------------------- + * Initialize the corelock structure. + *--------------------------------------------------------------------------- + */ +void corelock_init(struct corelock *cl) +{ + memset(cl, 0, sizeof (*cl)); +} + +#if 1 /* Assembly locks to minimize overhead */ +/*--------------------------------------------------------------------------- + * Wait for the corelock to become free and acquire it when it does. + *--------------------------------------------------------------------------- + */ +void __attribute__((naked)) corelock_lock(struct corelock *cl) +{ + /* Relies on the fact that core IDs are complementary bitmasks (0x55,0xaa) */ + asm volatile ( + "mov r1, %0 \n" /* r1 = PROCESSOR_ID */ + "ldrb r1, [r1] \n" + "strb r1, [r0, r1, lsr #7] \n" /* cl->myl[core] = core */ + "eor r2, r1, #0xff \n" /* r2 = othercore */ + "strb r2, [r0, #2] \n" /* cl->turn = othercore */ + "1: \n" + "ldrb r3, [r0, r2, lsr #7] \n" /* cl->myl[othercore] == 0 ? */ + "cmp r3, #0 \n" /* yes? lock acquired */ + "bxeq lr \n" + "ldrb r3, [r0, #2] \n" /* || cl->turn == core ? */ + "cmp r3, r1 \n" + "bxeq lr \n" /* yes? lock acquired */ + "b 1b \n" /* keep trying */ + : : "i"(&PROCESSOR_ID) + ); + (void)cl; +} + +/*--------------------------------------------------------------------------- + * Try to aquire the corelock. If free, caller gets it, otherwise return 0. + *--------------------------------------------------------------------------- + */ +int __attribute__((naked)) corelock_try_lock(struct corelock *cl) +{ + /* Relies on the fact that core IDs are complementary bitmasks (0x55,0xaa) */ + asm volatile ( + "mov r1, %0 \n" /* r1 = PROCESSOR_ID */ + "ldrb r1, [r1] \n" + "mov r3, r0 \n" + "strb r1, [r0, r1, lsr #7] \n" /* cl->myl[core] = core */ + "eor r2, r1, #0xff \n" /* r2 = othercore */ + "strb r2, [r0, #2] \n" /* cl->turn = othercore */ + "ldrb r0, [r3, r2, lsr #7] \n" /* cl->myl[othercore] == 0 ? */ + "eors r0, r0, r2 \n" /* yes? lock acquired */ + "bxne lr \n" + "ldrb r0, [r3, #2] \n" /* || cl->turn == core? */ + "ands r0, r0, r1 \n" + "streqb r0, [r3, r1, lsr #7] \n" /* if not, cl->myl[core] = 0 */ + "bx lr \n" /* return result */ + : : "i"(&PROCESSOR_ID) + ); + + return 0; + (void)cl; +} + +/*--------------------------------------------------------------------------- + * Release ownership of the corelock + *--------------------------------------------------------------------------- + */ +void __attribute__((naked)) corelock_unlock(struct corelock *cl) +{ + asm volatile ( + "mov r1, %0 \n" /* r1 = PROCESSOR_ID */ + "ldrb r1, [r1] \n" + "mov r2, #0 \n" /* cl->myl[core] = 0 */ + "strb r2, [r0, r1, lsr #7] \n" + "bx lr \n" + : : "i"(&PROCESSOR_ID) + ); + (void)cl; +} + +#else /* C versions for reference */ + +void corelock_lock(struct corelock *cl) +{ + const unsigned int core = CURRENT_CORE; + const unsigned int othercore = 1 - core; + + cl->myl[core] = core; + cl->turn = othercore; + + for (;;) + { + if (cl->myl[othercore] == 0 || cl->turn == core) + break; + } +} + +int corelock_try_lock(struct corelock *cl) +{ + const unsigned int core = CURRENT_CORE; + const unsigned int othercore = 1 - core; + + cl->myl[core] = core; + cl->turn = othercore; + + if (cl->myl[othercore] == 0 || cl->turn == core) + { + return 1; + } + + cl->myl[core] = 0; + return 0; +} + +void corelock_unlock(struct corelock *cl) +{ + cl->myl[CURRENT_CORE] = 0; +} +#endif /* ASM / C selection */ + +/*--------------------------------------------------------------------------- + * Do any device-specific inits for the threads and synchronize the kernel + * initializations. + *--------------------------------------------------------------------------- + */ +static void INIT_ATTR core_thread_init(unsigned int core) +{ + if (core == CPU) + { + /* Wake up coprocessor and let it initialize kernel and threads */ +#ifdef CPU_PP502x + MBX_MSG_CLR = 0x3f; +#endif + wake_core(COP); + /* Sleep until COP has finished */ + sleep_core(CPU); + } + else + { + /* Wake the CPU and return */ + wake_core(CPU); + } +} + +/*--------------------------------------------------------------------------- + * Switches to a stack that always resides in the Rockbox core then calls + * the final exit routine to actually finish removing the thread from the + * scheduler. + * + * Needed when a thread suicides on a core other than the main CPU since the + * stack used when idling is the stack of the last thread to run. This stack + * may not reside in the core firmware in which case the core will continue + * to use a stack from an unloaded module until another thread runs on it. + *--------------------------------------------------------------------------- + */ +static inline void NORETURN_ATTR __attribute__((always_inline)) + thread_final_exit(struct thread_entry *current) +{ + asm volatile ( + "cmp %1, #0 \n" /* CPU? */ + "ldrne r0, =commit_dcache \n" /* No? write back data */ + "movne lr, pc \n" + "bxne r0 \n" + "mov r0, %0 \n" /* copy thread parameter */ + "mov sp, %2 \n" /* switch to idle stack */ + "bl thread_final_exit_do \n" /* finish removal */ + : : "r"(current), + "r"(current->core), + "r"(&idle_stacks[current->core][IDLE_STACK_WORDS]) + : "r0", "r1", "r2", "r3", "ip", "lr"); /* Because of flush call, + force inputs out + of scratch regs */ + while (1); +} + +/*--------------------------------------------------------------------------- + * Perform core switch steps that need to take place inside switch_thread. + * + * These steps must take place while before changing the processor and after + * having entered switch_thread since switch_thread may not do a normal return + * because the stack being used for anything the compiler saved will not belong + * to the thread's destination core and it may have been recycled for other + * purposes by the time a normal context load has taken place. switch_thread + * will also clobber anything stashed in the thread's context or stored in the + * nonvolatile registers if it is saved there before the call since the + * compiler's order of operations cannot be known for certain. + */ +static void core_switch_blk_op(unsigned int core, struct thread_entry *thread) +{ + /* Flush our data to ram */ + commit_dcache(); + /* Stash thread in r4 slot */ + thread->context.r[0] = (uint32_t)thread; + /* Stash restart address in r5 slot */ + thread->context.r[1] = thread->context.start; + /* Save sp in context.sp while still running on old core */ + thread->context.sp = idle_stacks[core][IDLE_STACK_WORDS-1]; +} + +/*--------------------------------------------------------------------------- + * Machine-specific helper function for switching the processor a thread is + * running on. Basically, the thread suicides on the departing core and is + * reborn on the destination. Were it not for gcc's ill-behavior regarding + * naked functions written in C where it actually clobbers non-volatile + * registers before the intended prologue code, this would all be much + * simpler. Generic setup is done in switch_core itself. + */ + +/*--------------------------------------------------------------------------- + * This actually performs the core switch. + */ +static void __attribute__((naked)) + switch_thread_core(unsigned int core, struct thread_entry *thread) +{ + /* Pure asm for this because compiler behavior isn't sufficiently predictable. + * Stack access also isn't permitted until restoring the original stack and + * context. */ + asm volatile ( + "stmfd sp!, { r4-r11, lr } \n" /* Stack all non-volatile context on current core */ + "ldr r2, =idle_stacks \n" /* r2 = &idle_stacks[core][IDLE_STACK_WORDS] */ + "ldr r2, [r2, r0, lsl #2] \n" + "add r2, r2, %0*4 \n" + "stmfd r2!, { sp } \n" /* save original stack pointer on idle stack */ + "mov sp, r2 \n" /* switch stacks */ + "adr r2, 1f \n" /* r2 = new core restart address */ + "str r2, [r1, #40] \n" /* thread->context.start = r2 */ + "ldr pc, =switch_thread \n" /* r0 = thread after call - see load_context */ + "1: \n" + "ldr sp, [r0, #32] \n" /* Reload original sp from context structure */ + "mov r1, #0 \n" /* Clear start address */ + "str r1, [r0, #40] \n" + "ldr r0, =commit_discard_idcache \n" /* Invalidate new core's cache */ + "mov lr, pc \n" + "bx r0 \n" + "ldmfd sp!, { r4-r11, pc } \n" /* Restore non-volatile context to new core and return */ + : : "i"(IDLE_STACK_WORDS) + ); + (void)core; (void)thread; +} + +/** PP-model-specific dual-core code **/ + +#if CONFIG_CPU == PP5002 +/* PP5002 has no mailboxes - Bytes to emulate the PP502x mailbox bits */ +struct core_semaphores +{ + volatile uint8_t intend_wake; /* 00h */ + volatile uint8_t stay_awake; /* 01h */ + volatile uint8_t intend_sleep; /* 02h */ + volatile uint8_t unused; /* 03h */ +}; + +static struct core_semaphores core_semaphores[NUM_CORES] IBSS_ATTR; + +#if 1 /* Select ASM */ +/*--------------------------------------------------------------------------- + * Put core in a power-saving state if waking list wasn't repopulated and if + * no other core requested a wakeup for it to perform a task. + *--------------------------------------------------------------------------- + */ +static inline void core_sleep(unsigned int core) +{ + asm volatile ( + "mov r0, #1 \n" /* Signal intent to sleep */ + "strb r0, [%[sem], #2] \n" + "ldrb r0, [%[sem], #1] \n" /* && stay_awake == 0? */ + "cmp r0, #0 \n" + "bne 2f \n" + /* Sleep: PP5002 crashes if the instruction that puts it to sleep is + * located at 0xNNNNNNN0. 4/8/C works. This sequence makes sure + * that the correct alternative is executed. Don't change the order + * of the next 4 instructions! */ + "tst pc, #0x0c \n" + "mov r0, #0xca \n" + "strne r0, [%[ctl], %[c], lsl #2] \n" + "streq r0, [%[ctl], %[c], lsl #2] \n" + "nop \n" /* nop's needed because of pipeline */ + "nop \n" + "nop \n" + "2: \n" + "mov r0, #0 \n" /* Clear stay_awake and sleep intent */ + "strb r0, [%[sem], #1] \n" + "strb r0, [%[sem], #2] \n" + "1: \n" /* Wait for wake procedure to finish */ + "ldrb r0, [%[sem], #0] \n" + "cmp r0, #0 \n" + "bne 1b \n" + : + : [sem]"r"(&core_semaphores[core]), [c]"r"(core), + [ctl]"r"(&CPU_CTL) + : "r0" + ); + enable_irq(); +} + +/*--------------------------------------------------------------------------- + * Wake another processor core that is sleeping or prevent it from doing so + * if it was already destined. FIQ, IRQ should be disabled before calling. + *--------------------------------------------------------------------------- + */ +void core_wake(unsigned int othercore) +{ + /* avoid r0 since that contains othercore */ + asm volatile ( + "mrs r3, cpsr \n" /* Disable IRQ */ + "orr r1, r3, #0x80 \n" + "msr cpsr_c, r1 \n" + "mov r1, #1 \n" /* Signal intent to wake other core */ + "orr r1, r1, r1, lsl #8 \n" /* and set stay_awake */ + "strh r1, [%[sem], #0] \n" + "mov r2, #0x8000 \n" + "1: \n" /* If it intends to sleep, let it first */ + "ldrb r1, [%[sem], #2] \n" /* intend_sleep != 0 ? */ + "cmp r1, #1 \n" + "ldr r1, [%[st]] \n" /* && not sleeping ? */ + "tsteq r1, r2, lsr %[oc] \n" + "beq 1b \n" /* Wait for sleep or wake */ + "tst r1, r2, lsr %[oc] \n" + "ldrne r2, =0xcf004054 \n" /* If sleeping, wake it */ + "movne r1, #0xce \n" + "strne r1, [r2, %[oc], lsl #2] \n" + "mov r1, #0 \n" /* Done with wake procedure */ + "strb r1, [%[sem], #0] \n" + "msr cpsr_c, r3 \n" /* Restore IRQ */ + : + : [sem]"r"(&core_semaphores[othercore]), + [st]"r"(&PROC_STAT), + [oc]"r"(othercore) + : "r1", "r2", "r3" + ); +} + +#else /* C version for reference */ + +static inline void core_sleep(unsigned int core) +{ + /* Signal intent to sleep */ + core_semaphores[core].intend_sleep = 1; + + /* Something waking or other processor intends to wake us? */ + if (core_semaphores[core].stay_awake == 0) + { + sleep_core(core); + } + + /* Signal wake - clear wake flag */ + core_semaphores[core].stay_awake = 0; + core_semaphores[core].intend_sleep = 0; + + /* Wait for other processor to finish wake procedure */ + while (core_semaphores[core].intend_wake != 0); + + /* Enable IRQ */ + enable_irq(); +} + +void core_wake(unsigned int othercore) +{ + /* Disable interrupts - avoid reentrancy from the tick */ + int oldlevel = disable_irq_save(); + + /* Signal intent to wake other processor - set stay awake */ + core_semaphores[othercore].intend_wake = 1; + core_semaphores[othercore].stay_awake = 1; + + /* If it intends to sleep, wait until it does or aborts */ + while (core_semaphores[othercore].intend_sleep != 0 && + (PROC_STAT & PROC_SLEEPING(othercore)) == 0); + + /* If sleeping, wake it up */ + if (PROC_STAT & PROC_SLEEPING(othercore)) + wake_core(othercore); + + /* Done with wake procedure */ + core_semaphores[othercore].intend_wake = 0; + restore_irq(oldlevel); +} +#endif /* ASM/C selection */ + +#elif defined (CPU_PP502x) + +#if 1 /* Select ASM */ +/*--------------------------------------------------------------------------- + * Put core in a power-saving state if waking list wasn't repopulated and if + * no other core requested a wakeup for it to perform a task. + *--------------------------------------------------------------------------- + */ +static inline void core_sleep(unsigned int core) +{ + asm volatile ( + "mov r0, #4 \n" /* r0 = 0x4 << core */ + "mov r0, r0, lsl %[c] \n" + "str r0, [%[mbx], #4] \n" /* signal intent to sleep */ + "ldr r1, [%[mbx], #0] \n" /* && !(MBX_MSG_STAT & (0x10< ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id$ +* +* Copyright (C) 2006 Thom Johansen +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +* KIND, either express or implied. +* +****************************************************************************/ + +#include "cpu.h" +#include "system.h" +#include "timer.h" + +static long SHAREDBSS_ATTR cycles_new = 0; + +void TIMER2(void) +{ + TIMER2_VAL; /* ACK interrupt */ + if (cycles_new > 0) + { + TIMER2_CFG = 0xc0000000 | (cycles_new - 1); + cycles_new = 0; + } + if (pfn_timer != NULL) + { + cycles_new = -1; + /* "lock" the variable, in case timer_set_period() + * is called within pfn_timer() */ + pfn_timer(); + cycles_new = 0; + } +} + +bool timer_set(long cycles, bool start) +{ + if (cycles > 0x20000000 || cycles < 2) + return false; + + if (start) + { + if (pfn_unregister != NULL) + { + pfn_unregister(); + pfn_unregister = NULL; + } + CPU_INT_DIS = TIMER2_MASK; + COP_INT_DIS = TIMER2_MASK; + } + if (start || (cycles_new == -1)) /* within isr, cycles_new is "locked" */ + TIMER2_CFG = 0xc0000000 | (cycles - 1); /* enable timer */ + else + cycles_new = cycles; + + return true; +} + +bool timer_start(IF_COP_VOID(int core)) +{ + /* unmask interrupt source */ +#if NUM_CORES > 1 + if (core == COP) + COP_INT_EN = TIMER2_MASK; + else +#endif + CPU_INT_EN = TIMER2_MASK; + return true; +} + +void timer_stop(void) +{ + TIMER2_CFG = 0; /* stop timer 2 */ + CPU_INT_DIS = TIMER2_MASK; + COP_INT_DIS = TIMER2_MASK; +} diff --git a/firmware/target/arm/pp/usb-fw-pp5002.c b/firmware/target/arm/pp/usb-fw-pp5002.c new file mode 100644 index 0000000000..d296b05b2f --- /dev/null +++ b/firmware/target/arm/pp/usb-fw-pp5002.c @@ -0,0 +1,75 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2007 by Jens Arnold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "ata.h" +#include "cpu.h" +#include "string.h" +#include "system.h" +#include "usb.h" + +void usb_pin_init(void) +{ + /* TODO: add USB init for iPod 3rd gen */ + +#if defined(IPOD_1G2G) || defined(IPOD_3G) + /* GPIO C bit 7 is firewire detect */ + GPIOC_ENABLE |= 0x80; + GPIOC_OUTPUT_EN &= ~0x80; +#endif +} + +/* No different for now */ +void usb_init_device(void) __attribute__((alias("usb_pin_init"))); + +void usb_enable(bool on) +{ + /* This device specific code will eventually give way to proper USB + handling, which should be the same for all PP5002 targets. */ + if (on) + { +#ifdef IPOD_ARCH + /* For iPod, we can only do one thing with USB mode atm - reboot + into the flash-based disk-mode. This does not return. */ + + ata_sleepnow(); /* Immediately spindown the disk. */ + sleep(HZ*2); + + memcpy((void *)0x40017f00, "diskmodehotstuff\1", 17); + + system_reboot(); /* Reboot */ +#endif + } +} + +int usb_detect(void) +{ +#if defined(IPOD_1G2G) || defined(IPOD_3G) + /* GPIO C bit 7 is firewire detect */ + if (!(GPIOC_INPUT_VAL & 0x80)) + return USB_INSERTED; +#endif + + /* TODO: add USB detection for iPod 3rd gen */ + + return USB_EXTRACTED; +} +bool usb_plugged(void) __attribute__((alias("usb_detect"))); diff --git a/firmware/target/arm/pp/usb-fw-pp502x.c b/firmware/target/arm/pp/usb-fw-pp502x.c new file mode 100644 index 0000000000..5272102fad --- /dev/null +++ b/firmware/target/arm/pp/usb-fw-pp502x.c @@ -0,0 +1,308 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * + * iPod driver based on code from the ipodlinux project - http://ipodlinux.org + * Adapted for Rockbox in January 2006 + * Original file: podzilla/usb.c + * Copyright (C) 2005 Adam Johnston + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" +#include "system.h" +#include "usb.h" +#include "button.h" +#include "ata.h" +#include "string.h" +#include "usb_core.h" +#include "usb_drv.h" + +#if defined(IPOD_4G) || defined(IPOD_COLOR) \ + || defined(IPOD_MINI) || defined(IPOD_MINI2G) + /* GPIO D bit 3 is usb detect */ +#define USB_GPIO GPIOD +#define USB_GPIO_MASK 0x08 +#define USB_GPIO_VAL 0x08 + +#elif defined(IPOD_NANO) || defined(IPOD_VIDEO) + /* GPIO L bit 4 is usb detect */ +#define USB_GPIO GPIOL +#define USB_GPIO_MASK 0x10 +#define USB_GPIO_VAL 0x10 + +#elif defined(SANSA_C200) + /* GPIO H bit 1 is usb/charger detect */ +#define USB_GPIO GPIOH +#define USB_GPIO_MASK 0x02 +#define USB_GPIO_VAL 0x02 + +#elif defined(SANSA_E200) + /* GPIO B bit 4 is usb/charger detect */ +#define USB_GPIO GPIOB +#define USB_GPIO_MASK 0x10 +#define USB_GPIO_VAL 0x10 + +#elif defined(IRIVER_H10) || defined(IRIVER_H10_5GB) || defined(MROBE_100) + /* GPIO L bit 2 is usb detect */ +#define USB_GPIO GPIOL +#define USB_GPIO_MASK 0x04 +#define USB_GPIO_VAL 0x04 + +#elif defined(PHILIPS_SA9200) + /* GPIO B bit 6 (high) is usb bus power detect */ +#define USB_GPIO GPIOB +#define USB_GPIO_MASK 0x40 +#define USB_GPIO_VAL 0x40 + +#elif defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) + /* GPIO E bit 2 is usb detect */ +#define USB_GPIO GPIOE +#define USB_GPIO_MASK 0x04 +#define USB_GPIO_VAL 0x04 + +#elif defined(SAMSUNG_YH820) || defined(SAMSUNG_YH920) || defined(SAMSUNG_YH925) + /* GPIO D bit 4 is usb detect */ +#define USB_GPIO GPIOD +#define USB_GPIO_MASK 0x10 +#define USB_GPIO_VAL 0x10 + +#elif defined(TATUNG_TPJ1022) + /* GPIO ? bit ? is usb detect (dummy value)*/ +#define USB_GPIO GPIOD +#define USB_GPIO_MASK 0x10 +#define USB_GPIO_VAL 0x10 + +#elif defined(PBELL_VIBE500) + /* GPIO L bit 3 is usb detect */ +#define USB_GPIO GPIOL +#define USB_GPIO_MASK 0x04 +#define USB_GPIO_VAL 0x04 + +#else +#error No USB GPIO config specified +#endif + +#define USB_GPIO_ENABLE GPIO_ENABLE(USB_GPIO) +#define USB_GPIO_OUTPUT_EN GPIO_OUTPUT_EN(USB_GPIO) +#define USB_GPIO_INPUT_VAL GPIO_INPUT_VAL(USB_GPIO) +#define USB_GPIO_INT_EN GPIO_INT_EN(USB_GPIO) +#define USB_GPIO_INT_LEV GPIO_INT_LEV(USB_GPIO) +#define USB_GPIO_INT_CLR GPIO_INT_CLR(USB_GPIO) +#define USB_GPIO_HI_INT_MASK GPIO_HI_INT_MASK(USB_GPIO) + +static void usb_reset_controller(void) +{ + /* enable usb module */ + outl(inl(0x7000002C) | 0x3000000, 0x7000002C); + + DEV_EN |= DEV_USB0; + DEV_EN |= DEV_USB1; + + /* reset both USBs */ + DEV_RS |= DEV_USB0; + DEV_RS &=~DEV_USB0; + DEV_RS |= DEV_USB1; + DEV_RS &=~DEV_USB1; + + DEV_INIT2 |= INIT_USB; + + while ((inl(0x70000028) & 0x80) == 0); + outl(inl(0x70000028) | 0x2, 0x70000028); + udelay(100000); + XMB_RAM_CFG |= 0x47A; + + /* disable USB-devices until USB is detected via GPIO */ +#ifndef BOOTLOADER + /* Disabling USB0 in the bootloader makes the OF not load, + Also something here breaks usb pin detect in bootloader. + leave it all enabled untill rockbox main loads */ + DEV_EN &= ~DEV_USB0; + DEV_EN &= ~DEV_USB1; + DEV_INIT2 &= ~INIT_USB; +#endif +} + +/* Enable raw status pin read only - not interrupt */ +void usb_pin_init(void) +{ + GPIO_CLEAR_BITWISE(USB_GPIO_OUTPUT_EN, USB_GPIO_MASK); + GPIO_SET_BITWISE(USB_GPIO_ENABLE, USB_GPIO_MASK); +#ifdef USB_FIREWIRE_HANDLING + /* GPIO C bit 1 is firewire detect */ + GPIO_CLEAR_BITWISE(GPIOC_OUTPUT_EN, 0x02); + GPIO_SET_BITWISE(GPIOC_ENABLE, 0x02); +#endif +} + +void usb_init_device(void) +{ + usb_reset_controller(); + + /* Do one-time inits (no dependency on controller) */ + usb_drv_startup(); + + usb_pin_init(); + + /* These set INT_LEV to the inserted level so it will fire if already + * inserted at the time they are enabled. */ +#ifdef USB_STATUS_BY_EVENT + GPIO_CLEAR_BITWISE(USB_GPIO_INT_EN, USB_GPIO_MASK); + GPIO_WRITE_BITWISE(USB_GPIO_INT_LEV, USB_GPIO_VAL, USB_GPIO_MASK); + USB_GPIO_INT_CLR = USB_GPIO_MASK; + GPIO_SET_BITWISE(USB_GPIO_INT_EN, USB_GPIO_MASK); + CPU_HI_INT_EN = USB_GPIO_HI_INT_MASK; + +#ifdef USB_FIREWIRE_HANDLING + /* GPIO C bit 1 is firewire detect */ + GPIO_CLEAR_BITWISE(GPIOC_INT_EN, 0x02); + GPIO_WRITE_BITWISE(GPIOC_INT_LEV, 0x00, 0x02); + GPIOC_INT_CLR = 0x02; + GPIO_SET_BITWISE(GPIOC_INT_EN, 0x02); + CPU_HI_INT_EN = GPIO0_MASK; +#endif + CPU_INT_EN = HI_MASK; +#endif /* USB_STATUS_BY_EVENT */ +} + +void usb_enable(bool on) +{ + if (on) { + /* if USB is detected, re-enable the USB-devices, otherwise make sure it's disabled */ + DEV_EN |= DEV_USB0; + DEV_EN |= DEV_USB1; + DEV_INIT2 |= INIT_USB; + usb_core_init(); + } + else { + usb_core_exit(); + /* Disable USB devices */ + usb_reset_controller(); + } +} + +void usb_attach(void) +{ + usb_drv_attach(); +} + +bool usb_plugged(void) +{ + return (USB_GPIO_INPUT_VAL & USB_GPIO_MASK) == USB_GPIO_VAL; +} + +#ifdef USB_STATUS_BY_EVENT +/* Cannot always tell power pin from USB pin */ +static int usb_status = USB_EXTRACTED; + +static int usb_timeout_event(struct timeout *tmo) +{ + usb_status_event(tmo->data == USB_GPIO_VAL ? USB_INSERTED : USB_EXTRACTED); + return 0; +} + +void usb_insert_int(void) +{ + static struct timeout usb_oneshot; + unsigned long val = USB_GPIO_INPUT_VAL & USB_GPIO_MASK; + usb_status = (val == USB_GPIO_VAL) ? USB_INSERTED : USB_EXTRACTED; + GPIO_WRITE_BITWISE(USB_GPIO_INT_LEV, val ^ USB_GPIO_MASK, USB_GPIO_MASK); + USB_GPIO_INT_CLR = USB_GPIO_MASK; + timeout_register(&usb_oneshot, usb_timeout_event, HZ/5, val); +} + +/* USB_DETECT_BY_CORE: Called when device descriptor is requested */ +void usb_drv_usb_detect_event(void) +{ + /* Filter for invalid bus reset when unplugging by checking the pin state. */ + if(usb_plugged()) { + usb_status_event(USB_HOSTED); + } +} +#endif /* USB_STATUS_BY_EVENT */ + +#ifdef HAVE_BOOTLOADER_USB_MODE +/* Replacement function that returns all unused memory after the bootloader + * because the storage driver uses the audio buffer */ +extern unsigned char freebuffer[]; +extern unsigned char freebufferend[]; +unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size) +{ + if (buffer_size) + *buffer_size = freebufferend - freebuffer + 1; + + return freebuffer; + (void)talk_buf; +} +#endif /* HAVE_BOOTLOADER_USB_MODE */ + +void usb_drv_int_enable(bool enable) +{ + /* enable/disable USB IRQ in CPU */ + if(enable) { + CPU_INT_EN = USB_MASK; + } + else { + CPU_INT_DIS = USB_MASK; + } +} + +/* detect host or charger (INSERTED or EXTRACTED) */ +int usb_detect(void) +{ +#ifdef USB_STATUS_BY_EVENT + return usb_status; +#else + return usb_plugged() ? USB_INSERTED : USB_EXTRACTED; +#endif +} + +#ifdef USB_FIREWIRE_HANDLING +#ifdef USB_STATUS_BY_EVENT +static bool firewire_status = false; +#endif + +bool firewire_detect(void) +{ +#ifdef USB_STATUS_BY_EVENT + return firewire_status; +#else + /* GPIO C bit 1 is firewire detect */ + /* no charger detection needed for firewire */ + return (GPIOC_INPUT_VAL & 0x02) == 0x00; +#endif +} + +#ifdef USB_STATUS_BY_EVENT +static int firewire_timeout_event(struct timeout *tmo) +{ + if (tmo->data == 0x00) + usb_firewire_connect_event(); + return 0; +} + +void firewire_insert_int(void) +{ + static struct timeout firewire_oneshot; + unsigned long val = GPIOC_INPUT_VAL & 0x02; + firewire_status = val == 0x00; + GPIO_WRITE_BITWISE(GPIOC_INT_LEV, val ^ 0x02, 0x02); + GPIOC_INT_CLR = 0x02; + timeout_register(&firewire_oneshot, firewire_timeout_event, HZ/5, val); +} +#endif /* USB_STATUS_BY_EVENT */ +#endif /* USB_FIREWIRE_HANDLING */ diff --git a/firmware/target/arm/pp/wmcodec-pp.c b/firmware/target/arm/pp/wmcodec-pp.c new file mode 100644 index 0000000000..839fd90676 --- /dev/null +++ b/firmware/target/arm/pp/wmcodec-pp.c @@ -0,0 +1,112 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Portalplayer specific code for Wolfson audio codecs + * + * 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) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "system.h" +#include "audiohw.h" +#include "i2c-pp.h" +#include "i2s.h" +#include "wmcodec.h" + +#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) || \ + defined(MROBE_100) || defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) || \ + defined(PBELL_VIBE500) +/* The H10's audio codec uses an I2C address of 0x1b */ +#define I2C_AUDIO_ADDRESS 0x1b +#else +/* The iPod's audio codecs use an I2C address of 0x1a */ +#define I2C_AUDIO_ADDRESS 0x1a +#endif + + +/* + * Initialise the PP I2C and I2S. + */ +void audiohw_init(void) +{ +#ifdef CPU_PP502x + /* normal outputs for CDI and I2S pin groups */ + DEV_INIT2 &= ~0x300; + + /*mini2?*/ + DEV_INIT1 &=~0x3000000; + /*mini2?*/ + + /* I2S device reset */ + DEV_RS |= DEV_I2S; + DEV_RS &=~DEV_I2S; + + /* I2S device enable */ + DEV_EN |= DEV_I2S; + + /* enable external dev clock clocks */ + DEV_EN |= DEV_EXTCLOCKS; + + /* external dev clock to 24MHz */ + outl(inl(0x70000018) & ~0xc, 0x70000018); +#else + /* device reset */ + outl(inl(0xcf005030) | 0x80, 0xcf005030); + outl(inl(0xcf005030) & ~0x80, 0xcf005030); + + /* device enable */ + outl(inl(0xcf005000) | 0x80, 0xcf005000); + + /* GPIO D06 enable for output */ + outl(inl(0xcf00000c) | 0x40, 0xcf00000c); + outl(inl(0xcf00001c) & ~0x40, 0xcf00001c); +#ifdef IPOD_1G2G + /* bits 11,10 == 10 */ + outl(inl(0xcf004040) & ~0x400, 0xcf004040); + outl(inl(0xcf004040) | 0x800, 0xcf004040); +#else /* IPOD_3G */ + /* bits 11,10 == 01 */ + outl(inl(0xcf004040) | 0x400, 0xcf004040); + outl(inl(0xcf004040) & ~0x800, 0xcf004040); + + outl(inl(0xcf004048) & ~0x1, 0xcf004048); + + outl(inl(0xcf000004) & ~0xf, 0xcf000004); + outl(inl(0xcf004044) & ~0xf, 0xcf004044); + + /* C03 = 0 */ + outl(inl(0xcf000008) | 0x8, 0xcf000008); + outl(inl(0xcf000018) | 0x8, 0xcf000018); + outl(inl(0xcf000028) & ~0x8, 0xcf000028); +#endif /* IPOD_1G2G/3G */ +#endif + + /* reset the I2S controller into known state */ + i2s_reset(); + + audiohw_preinit(); +} + +void wmcodec_write(int reg, int data) +{ + pp_i2c_send(I2C_AUDIO_ADDRESS, (reg<<1) | ((data&0x100)>>8),data&0xff); +} diff --git a/firmware/target/arm/sandisk/boot.lds b/firmware/target/arm/sandisk/boot.lds index e3f952660c..dbdb83435d 100644 --- a/firmware/target/arm/sandisk/boot.lds +++ b/firmware/target/arm/sandisk/boot.lds @@ -2,7 +2,7 @@ /* Can't link all Sansa PP devices the same way at this time */ #ifdef HAVE_BOOTLOADER_USB_MODE -#include "../boot-pp502x-bl-usb.lds" +#include "../pp/boot-pp502x-bl-usb.lds" #else /* !HAVE_BOOTLOADER_USB_MODE */ ENTRY(start) diff --git a/firmware/target/arm/system-pp5002.c b/firmware/target/arm/system-pp5002.c deleted file mode 100644 index 3186d3739a..0000000000 --- a/firmware/target/arm/system-pp5002.c +++ /dev/null @@ -1,227 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 by Alan Korr - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "system.h" - -#ifndef BOOTLOADER -#include "adc-target.h" -#include "button-target.h" - -extern void TIMER1(void); -extern void TIMER2(void); - -void __attribute__((interrupt("IRQ"))) irq_handler(void) -{ - if(CURRENT_CORE == CPU) - { - if (CPU_INT_STAT & TIMER1_MASK) - TIMER1(); - else if (CPU_INT_STAT & TIMER2_MASK) - TIMER2(); - else if (CPU_INT_STAT & GPIO_MASK) - { - if (GPIOA_INT_STAT) - ipod_3g_button_int(); -#ifdef IPOD_1G2G - if (GPIOB_INT_STAT & 0x04) - ipod_2g_adc_int(); -#endif - } - } - else - { - if (COP_INT_STAT & TIMER2_MASK) - TIMER2(); - } -} - -#endif - -#ifndef BOOTLOADER -void ICODE_ATTR __attribute__((naked)) commit_dcache(void) -{ - asm volatile( - "mov r0, #0xf0000000 \n" - "add r0, r0, #0xc000 \n" /* r0 = CACHE_FLUSH_BASE */ - "add r1, r0, #0x2000 \n" /* r1 = CACHE_FLUSH_BASE + CACHE_SIZE */ - "mov r2, #0 \n" - "1: \n" - "str r2, [r0], #16 \n" /* Commit */ - "cmp r0, r1 \n" - "blo 1b \n" - "bx lr \n" - ); -} - -void ICODE_ATTR __attribute__((naked)) commit_discard_idcache(void) -{ - asm volatile( - "mov r0, #0xf0000000 \n" - "add r2, r0, #0x4000 \n" /* r1 = CACHE_INVALIDATE_BASE */ - "add r0, r0, #0xc000 \n" /* r0 = CACHE_FLUSH_BASE */ - "add r1, r0, #0x2000 \n" /* r2 = CACHE_FLUSH_BASE + CACHE_SIZE */ - "mov r3, #0 \n" - "1: \n" - "str r3, [r0], #16 \n" /* Commit */ - "str r3, [r2], #16 \n" /* Discard */ - "cmp r0, r1 \n" - "blo 1b \n" - "bx lr \n" - ); -} - -void commit_discard_dcache(void) __attribute__((alias("commit_discard_idcache"))); - -static void ipod_init_cache(void) -{ -/* Initialising the cache in the iPod bootloader prevents Rockbox from starting */ - PROC_STAT &= ~0x700; - outl(0x4000, 0xcf004020); - - CACHE_CTL = CACHE_CTL_INIT; - - asm volatile( - "mov r0, #0xf0000000 \n" - "add r0, r0, #0x4000 \n" /* r0 = CACHE_INVALIDATE_BASE */ - "add r1, r0, #0x2000 \n" /* r1 = CACHE_INVALIDATE_BASE + CACHE_SIZE */ - "mov r2, #0 \n" - "1: \n" - "str r2, [r0], #16 \n" /* Invalidate */ - "cmp r0, r1 \n" - "blo 1b \n" - : : : "r0", "r1", "r2" - ); - - /* Cache if (addr & mask) >> 16 == (mask & match) >> 16: - * yes: 0x00000000 - 0x03ffffff - * no: 0x04000000 - 0x1fffffff - * yes: 0x20000000 - 0x23ffffff - * no: 0x24000000 - 0x3fffffff <= range containing uncached alias - */ - CACHE_MASK = 0x00001c00; - CACHE_OPERATION = 0x3fc0; - - CACHE_CTL = CACHE_CTL_INIT | CACHE_CTL_RUN; -} - -#ifdef HAVE_ADJUSTABLE_CPU_FREQ -void set_cpu_frequency(long frequency) -#else -static void pp_set_cpu_frequency(long frequency) -#endif -{ - cpu_frequency = frequency; - - PLL_CONTROL |= 0x6000; /* make sure some enable bits are set */ - CLOCK_ENABLE = 0x01; /* select source #1 */ - - switch (frequency) - { - case CPUFREQ_MAX: - PLL_UNLOCK = 0xd19b; /* unlock frequencies > 66MHz */ - CLOCK_SOURCE = 0xa9; /* source #1: 24 Mhz, source #2..#4: PLL */ - PLL_CONTROL = 0xe000; /* PLL enabled */ - PLL_DIV = 3; /* 10/3 * 24MHz */ - PLL_MULT = 10; - udelay(200); /* wait for relock */ - break; - - case CPUFREQ_NORMAL: - CLOCK_SOURCE = 0xa9; /* source #1: 24 Mhz, source #2..#4: PLL */ - PLL_CONTROL = 0xe000; /* PLL enabled */ - PLL_DIV = 4; /* 5/4 * 24MHz */ - PLL_MULT = 5; - udelay(200); /* wait for relock */ - break; - - case CPUFREQ_SLEEP: - CLOCK_SOURCE = 0x51; /* source #2: 32kHz, #1, #2, #4: 24MHz */ - PLL_CONTROL = 0x6000; /* PLL disabled */ - udelay(10000); /* let 32kHz source stabilize? */ - break; - - default: - CLOCK_SOURCE = 0x55; /* source #1..#4: 24 Mhz */ - PLL_CONTROL = 0x6000; /* PLL disabled */ - cpu_frequency = CPUFREQ_DEFAULT; - break; - } - CLOCK_ENABLE = 0x02; /* select source #2 */ -} -#endif /* !BOOTLOADER */ - -void system_init(void) -{ -#ifndef BOOTLOADER - if (CURRENT_CORE == CPU) - { - /* Remap the flash ROM on CPU, keep hidden from COP: - * 0x00000000-0x03ffffff = 0x20000000-0x23ffffff */ - MMAP1_LOGICAL = 0x20003c00; - MMAP1_PHYSICAL = 0x00003f84; - -#if defined(IPOD_1G2G) || defined(IPOD_3G) - DEV_EN = 0x0b9f; /* don't clock unused PP5002 hardware components */ - outl(0x0035, 0xcf005004); /* DEV_EN2 ? */ -#endif - - INT_FORCED_CLR = -1; - CPU_INT_DIS = -1; - COP_INT_DIS = -1; - - GPIOA_INT_EN = 0; - GPIOB_INT_EN = 0; - GPIOC_INT_EN = 0; - GPIOD_INT_EN = 0; - -#ifdef HAVE_ADJUSTABLE_CPU_FREQ -#if NUM_CORES > 1 - cpu_boost_init(); -#endif -#else - pp_set_cpu_frequency(CPUFREQ_MAX); -#endif - } - ipod_init_cache(); -#endif -} - -void system_reboot(void) -{ - DEV_RS |= 4; - while (1); -} - -void system_exception_wait(void) -{ - /* FIXME: we just need the right buttons */ - CPU_INT_DIS = -1; - COP_INT_DIS = -1; - - /* Halt */ - sleep_core(CURRENT_CORE); - while (1); -} - -int system_memory_guard(int newmode) -{ - (void)newmode; - return 0; -} diff --git a/firmware/target/arm/system-pp502x.c b/firmware/target/arm/system-pp502x.c deleted file mode 100644 index 847e8a462e..0000000000 --- a/firmware/target/arm/system-pp502x.c +++ /dev/null @@ -1,607 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 by Alan Korr - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "system.h" -#include "thread.h" -#include "i2s.h" -#include "i2c-pp.h" -#include "as3514.h" -#ifdef HAVE_HOTSWAP -#include "sd-pp-target.h" -#endif -#include "button-target.h" -#include "usb_drv.h" -#ifdef HAVE_REMOTE_LCD -#include "lcd-remote-target.h" -#endif - -#if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE) -extern void TIMER1(void); -extern void TIMER2(void); -extern void SERIAL0(void); - -#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1) -static struct corelock cpufreq_cl SHAREDBSS_ATTR; -#endif - -#if defined(IPOD_VIDEO) && !defined(BOOTLOADER) -unsigned char probed_ramsize; -#endif - -void __attribute__((interrupt("IRQ"))) irq_handler(void) -{ - if(CURRENT_CORE == CPU) - { - if (CPU_INT_STAT & TIMER1_MASK) { - TIMER1(); - } - else if (CPU_INT_STAT & TIMER2_MASK) { - TIMER2(); - } -#ifdef HAVE_USBSTACK - /* Rather high priority - place near front */ - else if (CPU_INT_STAT & USB_MASK) { - usb_drv_int(); - } -#endif -#if defined(IPOD_MINI) /* Mini 1st gen only, mini 2nd gen uses iPod 4G code */ - else if (CPU_HI_INT_STAT & GPIO0_MASK) { - if ((GPIOA_INT_STAT & 0x3f) || (GPIOB_INT_STAT & 0x30)) - ipod_mini_button_int(); - if (GPIOC_INT_STAT & 0x02) - firewire_insert_int(); - if (GPIOD_INT_STAT & 0x08) - usb_insert_int(); - } -/* end IPOD_MINI */ -#elif CONFIG_KEYPAD == IPOD_4G_PAD /* except Mini 1st gen, handled above */ - else if (CPU_HI_INT_STAT & I2C_MASK) { - ipod_4g_button_int(); - } -#if defined(IPOD_COLOR) || defined(IPOD_MINI2G) || defined(IPOD_4G) - else if (CPU_HI_INT_STAT & GPIO0_MASK) { - if (GPIOC_INT_STAT & 0x02) - firewire_insert_int(); - if (GPIOD_INT_STAT & 0x08) - usb_insert_int(); - } -#elif defined(IPOD_NANO) || defined(IPOD_VIDEO) - else if (CPU_HI_INT_STAT & GPIO2_MASK) { - if (GPIOL_INT_STAT & 0x10) - usb_insert_int(); - } -#endif -/* end CONFIG_KEYPAD == IPOD_4G_PAD */ -#elif defined(IRIVER_H10) || defined(IRIVER_H10_5GB) - else if (CPU_HI_INT_STAT & GPIO2_MASK) { - if (GPIOL_INT_STAT & 0x04) - usb_insert_int(); - } -/* end IRIVER_H10 || IRIVER_H10_5GB */ -#elif defined(SANSA_E200) - else if (CPU_HI_INT_STAT & GPIO0_MASK) { -#ifdef HAVE_HOTSWAP - if (GPIOA_INT_STAT & 0x80) - microsd_int(); -#endif - if (GPIOB_INT_STAT & 0x10) - usb_insert_int(); - } - else if (CPU_HI_INT_STAT & GPIO1_MASK) { - if (GPIOF_INT_STAT & 0xff) - button_int(); - if (GPIOH_INT_STAT & 0xc0) - clickwheel_int(); - } -/* end SANSA_E200 */ -#elif defined(SANSA_C200) - else if (CPU_HI_INT_STAT & GPIO1_MASK) { - if (GPIOH_INT_STAT & 0x02) - usb_insert_int(); - } -#ifdef HAVE_HOTSWAP - else if (CPU_HI_INT_STAT & GPIO2_MASK) { - if (GPIOL_INT_STAT & 0x08) - microsd_int(); - } -#endif -/* end SANSA_C200 */ -#elif defined(MROBE_100) - else if (CPU_HI_INT_STAT & GPIO0_MASK) { - if (GPIOD_INT_STAT & 0x02) - button_int(); - if (GPIOD_INT_STAT & 0x80) - headphones_int(); - - } - else if (CPU_HI_INT_STAT & GPIO2_MASK) { - if (GPIOL_INT_STAT & 0x04) - usb_insert_int(); - } -/* end MROBE_100 */ -#elif defined(PHILIPS_SA9200) - else if (CPU_HI_INT_STAT & GPIO0_MASK) { - if (GPIOD_INT_STAT & 0x02) - button_int(); - if (GPIOB_INT_STAT & 0x40) - usb_insert_int(); - } -/* end PHILIPS_SA9200 */ -#elif defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) - else if (CPU_HI_INT_STAT & GPIO0_MASK) { - if (GPIOA_INT_STAT & 0x20) - button_int(); - } - else if (CPU_HI_INT_STAT & GPIO1_MASK) { - if (GPIOE_INT_STAT & 0x04) - usb_insert_int(); - } -/* end PHILIPS_HDD1630 || PHILIPS_HDD6330 */ -#elif defined(SAMSUNG_YH820) || defined(SAMSUNG_YH920) || defined(SAMSUNG_YH925) - else if (CPU_HI_INT_STAT & GPIO0_MASK) { - if (GPIOD_INT_STAT & 0x10) - usb_insert_int(); - } -/* end SAMSUNG_YHxxx */ -#elif defined(PBELL_VIBE500) - else if (CPU_HI_INT_STAT & GPIO0_MASK) { - if (GPIOA_INT_STAT & 0x20) - button_int(); - } - else if (CPU_HI_INT_STAT & GPIO2_MASK) { - if (GPIOL_INT_STAT & 0x04) - usb_insert_int(); - } -/* end PBELL_VIBE500 */ -#endif -#ifdef IPOD_ACCESSORY_PROTOCOL - else if (CPU_HI_INT_STAT & SER0_MASK) { - SERIAL0(); - } -#endif - } else { - if (COP_INT_STAT & TIMER2_MASK) - TIMER2(); - } -} -#endif /* BOOTLOADER || HAVE_BOOTLOADER_USB_MODE */ - -#if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE) -static void disable_all_interrupts(void) -{ - COP_HI_INT_DIS = -1; - CPU_HI_INT_DIS = -1; - HI_INT_FORCED_CLR = -1; - - COP_INT_DIS = -1; - CPU_INT_DIS = -1; - INT_FORCED_CLR = -1; - - GPIOA_INT_EN = 0; - GPIOB_INT_EN = 0; - GPIOC_INT_EN = 0; - GPIOD_INT_EN = 0; - GPIOE_INT_EN = 0; - GPIOF_INT_EN = 0; - GPIOG_INT_EN = 0; - GPIOH_INT_EN = 0; - GPIOI_INT_EN = 0; - GPIOJ_INT_EN = 0; - GPIOK_INT_EN = 0; - GPIOL_INT_EN = 0; -} - -void ICODE_ATTR commit_dcache(void) -{ - if (CACHE_CTL & CACHE_CTL_ENABLE) - { - CACHE_OPERATION |= CACHE_OP_FLUSH; - while ((CACHE_CTL & CACHE_CTL_BUSY) != 0); - nop; nop; nop; nop; - } -} - -void ICODE_ATTR commit_discard_idcache(void) -{ - if (CACHE_CTL & CACHE_CTL_ENABLE) - { - CACHE_OPERATION |= CACHE_OP_FLUSH | CACHE_OP_INVALIDATE; - while ((CACHE_CTL & CACHE_CTL_BUSY) != 0); - nop; nop; nop; nop; - } -} - -void commit_discard_dcache(void) __attribute__((alias("commit_discard_idcache"))); - -static void init_cache(void) -{ -/* Initialising the cache in the iPod bootloader may prevent Rockbox from starting - * depending on the model */ - - /* cache init mode */ - CACHE_CTL &= ~(CACHE_CTL_ENABLE | CACHE_CTL_RUN); - CACHE_CTL |= CACHE_CTL_INIT; - -#ifndef BOOTLOADER - /* what's this do? */ - CACHE_PRIORITY |= CURRENT_CORE == CPU ? 0x10 : 0x20; -#endif - - /* Cache if (addr & mask) >> 16 == (mask & match) >> 16: - * yes: 0x00000000 - 0x03ffffff - * no: 0x04000000 - 0x1fffffff - * yes: 0x20000000 - 0x23ffffff - * no: 0x24000000 - 0x3fffffff - */ - CACHE_MASK = 0x00001c00; - CACHE_OPERATION = 0xfc0; - - /* enable cache */ - CACHE_CTL |= CACHE_CTL_INIT | CACHE_CTL_ENABLE | CACHE_CTL_RUN; - nop; nop; nop; nop; -} -#endif /* BOOTLOADER || HAVE_BOOTLOADER_USB_MODE */ - -/* We need this for Sansas since we boost the cpu in their bootloader */ -#if !defined(BOOTLOADER) || (defined(SANSA_E200) || defined(SANSA_C200) || \ - defined(PHILIPS_SA9200)) -void scale_suspend_core(bool suspend) ICODE_ATTR; -void scale_suspend_core(bool suspend) -{ - unsigned int core = CURRENT_CORE; - IF_COP( unsigned int othercore = 1 - core; ) - static int oldstatus IBSS_ATTR; - - if (suspend) - { - oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS); - IF_COP( PROC_CTL(othercore) = 0x40000000; nop; ) - PROC_CTL(core) = 0x48000003; nop; - } - else - { - PROC_CTL(core) = 0x4800001f; nop; - IF_COP( PROC_CTL(othercore) = 0x00000000; nop; ) - restore_interrupt(oldstatus); - } -} - -#ifdef HAVE_ADJUSTABLE_CPU_FREQ -void set_cpu_frequency(long frequency) ICODE_ATTR; -void set_cpu_frequency(long frequency) -#else -static void pp_set_cpu_frequency(long frequency) -#endif -{ -#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1) - corelock_lock(&cpufreq_cl); -#endif - - switch (frequency) - { - /* Note1: The PP5022 PLL must be run at >= 96MHz - * Bits 20..21 select the post divider (1/2/4/8). - * PP5026 is similar to PP5022 except it doesn't - * have this limitation (and the post divider?) - * Note2: CLOCK_SOURCE is set via 0=32kHz, 1=16MHz, - * 2=24MHz, 3=33MHz, 4=48MHz, 5=SLOW, 6=FAST, 7=PLL. - * SLOW = 24MHz / (DIV_SLOW + 1), DIV = Bits 16-19 - * FAST = PLL / (DIV_FAST + 1), DIV = Bits 20-23 */ - case CPUFREQ_SLEEP: - cpu_frequency = CPUFREQ_SLEEP; - PLL_CONTROL |= 0x0c000000; - scale_suspend_core(true); - CLOCK_SOURCE = 0x20000000; /* source #1, #2, #3, #4: 32kHz (#2 active) */ - scale_suspend_core(false); - PLL_CONTROL &= ~0x80000000; /* disable PLL */ - DEV_INIT2 &= ~INIT_PLL; /* disable PLL power */ - break; - - case CPUFREQ_MAX: - cpu_frequency = CPUFREQ_MAX; - DEV_INIT2 |= INIT_PLL; /* enable PLL power */ - PLL_CONTROL |= 0x88000000; /* enable PLL */ - scale_suspend_core(true); - CLOCK_SOURCE = 0x20002222; /* source #1, #2, #3, #4: 24MHz (#2 active) */ - DEV_TIMING1 = 0x00000303; - scale_suspend_core(false); -#if defined(IPOD_MINI2G) - MLCD_SCLK_DIV = 0x00000001; /* Mono LCD bridge serial clock divider */ -#elif defined(IPOD_NANO) - IDE0_CFG |= 0x10000000; /* set ">65MHz" bit */ -#endif -#if CONFIG_CPU == PP5020 - PLL_CONTROL = 0x8a020a03; /* 80 MHz = 10/3 * 24MHz */ - PLL_STATUS = 0xd19b; /* unlock frequencies > 66MHz */ - PLL_CONTROL = 0x8a020a03; /* repeat setup */ - udelay(500); /* wait for relock */ -#elif (CONFIG_CPU == PP5022) || (CONFIG_CPU == PP5024) - PLL_CONTROL = 0x8a121403; /* 80 MHz = (20/3 * 24MHz) / 2 */ - while (!(PLL_STATUS & 0x80000000)); /* wait for relock */ -#endif - scale_suspend_core(true); - DEV_TIMING1 = 0x00000808; - CLOCK_SOURCE = 0x20007777; /* source #1, #2, #3, #4: PLL (#2 active) */ - scale_suspend_core(false); - break; -#if 0 /******** CPUFREQ_NORMAL = 24MHz without PLL ********/ - case CPUFREQ_NORMAL: - cpu_frequency = CPUFREQ_NORMAL; - PLL_CONTROL |= 0x08000000; - scale_suspend_core(true); - CLOCK_SOURCE = 0x20002222; /* source #1, #2, #3, #4: 24MHz (#2 active) */ - DEV_TIMING1 = 0x00000303; -#if defined(IPOD_MINI2G) - MLCD_SCLK_DIV = 0x00000000; /* Mono LCD bridge serial clock divider */ -#elif defined(IPOD_NANO) - IDE0_CFG &= ~0x10000000; /* clear ">65MHz" bit */ -#endif - scale_suspend_core(false); - PLL_CONTROL &= ~0x80000000; /* disable PLL */ - DEV_INIT2 &= ~INIT_PLL; /* disable PLL power */ - break; -#else /******** CPUFREQ_NORMAL = 30MHz with PLL ********/ - case CPUFREQ_NORMAL: - cpu_frequency = CPUFREQ_NORMAL; - DEV_INIT2 |= INIT_PLL; /* enable PLL power */ - PLL_CONTROL |= 0x88000000; /* enable PLL */ - scale_suspend_core(true); - CLOCK_SOURCE = 0x20002222; /* source #1, #2, #3, #4: 24MHz (#2 active) */ - DEV_TIMING1 = 0x00000303; - scale_suspend_core(false); -#if defined(IPOD_MINI2G) - MLCD_SCLK_DIV = 0x00000000; /* Mono LCD bridge serial clock divider */ -#elif defined(IPOD_NANO) - IDE0_CFG &= ~0x10000000; /* clear ">65MHz" bit */ -#endif -#if CONFIG_CPU == PP5020 - PLL_CONTROL = 0x8a020504; /* 30 MHz = 5/4 * 24MHz */ - udelay(500); /* wait for relock */ -#elif (CONFIG_CPU == PP5022) || (CONFIG_CPU == PP5024) - PLL_CONTROL = 0x8a220501; /* 30 MHz = (5/1 * 24MHz) / 4 */ - while (!(PLL_STATUS & 0x80000000)); /* wait for relock */ -#endif - scale_suspend_core(true); - DEV_TIMING1 = 0x00000303; - CLOCK_SOURCE = 0x20007777; /* source #1, #2, #3, #4: PLL (#2 active) */ - scale_suspend_core(false); - break; -#endif /******** CPUFREQ_NORMAL end ********/ - default: - cpu_frequency = CPUFREQ_DEFAULT; - PLL_CONTROL |= 0x08000000; - scale_suspend_core(true); - CLOCK_SOURCE = 0x20002222; /* source #1, #2, #3, #4: 24MHz (#2 active) */ - DEV_TIMING1 = 0x00000303; -#if defined(IPOD_MINI2G) - MLCD_SCLK_DIV = 0x00000000; /* Mono LCD bridge serial clock divider */ -#elif defined(IPOD_NANO) - IDE0_CFG &= ~0x10000000; /* clear ">65MHz" bit */ -#endif - scale_suspend_core(false); - PLL_CONTROL &= ~0x80000000; /* disable PLL */ - DEV_INIT2 &= ~INIT_PLL; /* disable PLL power */ - break; - } - -#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1) - corelock_unlock(&cpufreq_cl); -#endif -} -#endif /* !BOOTLOADER || (SANSA_E200 || SANSA_C200 || PHILIPS_SA9200) */ - -#ifndef BOOTLOADER -void system_init(void) -{ - if (CURRENT_CORE == CPU) - { -#if defined (IRIVER_H10) || defined(IRIVER_H10_5GB) || defined(IPOD_COLOR) - /* set minimum startup configuration */ - DEV_EN = 0xc2000124; - DEV_EN2 = 0x00002000; - CACHE_PRIORITY = 0x0000003f; - GPO32_VAL = 0x20000000; - DEV_INIT1 = 0xdc000000; - DEV_INIT2 = 0x40000000; - - /* reset all allowed devices */ - DEV_RS = 0x3dfffef8; - DEV_RS2 = 0xffffdfff; - DEV_RS = 0x00000000; - DEV_RS2 = 0x00000000; -#elif defined (IPOD_VIDEO) - /* set minimum startup configuration */ - DEV_EN = 0xc2000124; - DEV_EN2 = 0x00000000; - CACHE_PRIORITY = 0x0000003f; - GPO32_VAL &= 0x00004000; - DEV_INIT1 = 0x00000000; - DEV_INIT2 = 0x40000000; - - /* reset all allowed devices */ - DEV_RS = 0x3dfffef8; - DEV_RS2 = 0xffffffff; - DEV_RS = 0x00000000; - DEV_RS2 = 0x00000000; -#elif defined (IPOD_NANO) - /* set minimum startup configuration */ - DEV_EN = 0xc2000124; - DEV_EN2 = 0x00002000; - CACHE_PRIORITY = 0x0000003f; - GPO32_VAL = 0x50000000; - DEV_INIT1 = 0xa8000000; - DEV_INIT2 = 0x40000000; - - /* reset all allowed devices */ - DEV_RS = 0x3ffffef8; - DEV_RS2 = 0xffffdfff; - DEV_RS = 0x00000000; - DEV_RS2 = 0x00000000; -#elif defined(SANSA_C200) || defined (SANSA_E200) - /* set minimum startup configuration */ - DEV_EN = 0xc4000124; - DEV_EN2 = 0x00000000; - CACHE_PRIORITY = 0x0000003f; - GPO32_VAL = 0x10000000; - DEV_INIT1 = 0x54000000; - DEV_INIT2 = 0x40000000; - - /* reset all allowed devices */ - DEV_RS = 0x3bfffef8; - DEV_RS2 = 0xffffffff; - DEV_RS = 0x00000000; - DEV_RS2 = 0x00000000; -#elif defined(PHILIPS_SA9200) - /* reset all allowed devices */ - DEV_RS = 0x3ffffef8; - DEV_RS2 = 0xffffffff; - DEV_RS = 0x00000000; - DEV_RS2 = 0x00000000; -#elif defined(IPOD_4G) - /* set minimum startup configuration */ - DEV_EN = 0xc2020124; - DEV_EN2 = 0x00000000; - CACHE_PRIORITY = 0x0000003f; - GPO32_VAL = 0x02000000; - DEV_INIT1 = 0x00000000; - DEV_INIT2 = 0x40000000; - - /* reset all allowed devices */ - DEV_RS = 0x3dfdfef8; - DEV_RS2 = 0xffffffff; - DEV_RS = 0x00000000; - DEV_RS2 = 0x00000000; -#elif defined (IPOD_MINI) - /* to be done */ -#elif defined (IPOD_MINI2G) - /* to be done */ -#elif defined (MROBE_100) - /* to be done */ -#elif defined (TATUNG_TPJ1022) - /* to be done */ -#elif defined(PBELL_VIBE500) - /* reset all allowed devices */ - DEV_RS = 0x3ffffef8; - DEV_RS2 = 0xffffffff; - DEV_RS = 0x00000000; - DEV_RS2 = 0x00000000; -#endif - -#if !defined(SANSA_E200) && !defined(SANSA_C200) && !defined(PHILIPS_SA9200) - /* Remap the flash ROM on CPU, keep hidden from COP: - * 0x00000000-0x3fffffff = 0x20000000-0x23ffffff */ - MMAP1_LOGICAL = 0x20003c00; - MMAP1_PHYSICAL = 0x00003084 | - MMAP_PHYS_READ_MASK | MMAP_PHYS_WRITE_MASK | - MMAP_PHYS_DATA_MASK | MMAP_PHYS_CODE_MASK; -#endif - - disable_all_interrupts(); - -#ifdef HAVE_ADJUSTABLE_CPU_FREQ -#if NUM_CORES > 1 - corelock_init(&cpufreq_cl); - cpu_boost_init(); -#endif -#else - pp_set_cpu_frequency(CPUFREQ_MAX); -#endif - -#if defined(IPOD_VIDEO) - /* crt0-pp.S wrote the ram size to the last byte of the first 32MB - ram bank. See the comment there for how we determine it. */ - volatile unsigned char *end32 = (volatile unsigned char *)0x01ffffff; - probed_ramsize = *end32; -#endif - } - - init_cache(); -} - -#else /* BOOTLOADER */ - -void system_init(void) -{ - /* Only the CPU gets here in the bootloader */ -#ifdef HAVE_BOOTLOADER_USB_MODE - disable_all_interrupts(); - init_cache(); - /* Use the local vector map */ - CACHE_CTL |= CACHE_CTL_VECT_REMAP; -#endif /* HAVE_BOOTLOADER_USB_MODE */ - -#if defined(SANSA_C200) || defined(SANSA_E200) || defined(PHILIPS_SA9200) - pp_set_cpu_frequency(CPUFREQ_MAX); -#endif - /* Else the frequency should get changed upon USB connect - - * decide per-target */ -} - -#ifdef HAVE_BOOTLOADER_USB_MODE -void system_prepare_fw_start(void) -{ - disable_interrupt(IRQ_FIQ_STATUS); - tick_stop(); - disable_all_interrupts(); - /* Some OF's disable this themselves, others do not and will hang. */ - CACHE_CTL &= ~CACHE_CTL_VECT_REMAP; -} -#endif /* HAVE_BOOTLOADER_USB_MODE */ -#endif /* !BOOTLOADER */ - -void ICODE_ATTR system_reboot(void) -{ - disable_interrupt(IRQ_FIQ_STATUS); - CPU_INT_DIS = -1; - COP_INT_DIS = -1; - - /* Reboot */ -#if defined(SANSA_E200) || defined(SANSA_C200) || defined(PHILIPS_SA9200) - CACHE_CTL &= ~CACHE_CTL_VECT_REMAP; - - /* Magic used by the c200 OF: 0x23066000 - Magic used by the c200 BL: 0x23066b7b - In both cases, the OF executes these 2 commands from iram. */ - STRAP_OPT_A = 0x23066b7b; - DEV_RS = DEV_SYSTEM; -#else - DEV_RS |= DEV_SYSTEM; -#endif - /* wait until reboot kicks in */ - while (1); -} - -void system_exception_wait(void) -{ - /* FIXME: we just need the right buttons */ - CPU_INT_DIS = -1; - COP_INT_DIS = -1; - - /* Halt */ - PROC_CTL(CURRENT_CORE) = 0x40000000; - while (1); -} - -int system_memory_guard(int newmode) -{ - (void)newmode; - return 0; -} - diff --git a/firmware/target/arm/thread-pp.c b/firmware/target/arm/thread-pp.c deleted file mode 100644 index 0836b27204..0000000000 --- a/firmware/target/arm/thread-pp.c +++ /dev/null @@ -1,554 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2007 by Daniel Ankers - * - * PP5002 and PP502x SoC threading support - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#if defined(MAX_PHYS_SECTOR_SIZE) && MEMORYSIZE == 64 -/* Support a special workaround object for large-sector disks */ -#define IF_NO_SKIP_YIELD(...) __VA_ARGS__ -#endif - -#if NUM_CORES == 1 -/* Single-core variants for FORCE_SINGLE_CORE */ -static inline void core_sleep(void) -{ - sleep_core(CURRENT_CORE); - enable_irq(); -} - -/* Shared single-core build debugging version */ -void core_wake(void) -{ - /* No wakey - core already wakey (because this is it) */ -} -#else /* NUM_CORES > 1 */ -/** Model-generic PP dual-core code **/ -extern uintptr_t cpu_idlestackbegin[]; -extern uintptr_t cpu_idlestackend[]; -extern uintptr_t cop_idlestackbegin[]; -extern uintptr_t cop_idlestackend[]; -static uintptr_t * const idle_stacks[NUM_CORES] = -{ - [CPU] = cpu_idlestackbegin, - [COP] = cop_idlestackbegin -}; - -/* Core locks using Peterson's mutual exclusion algorithm */ - -/*--------------------------------------------------------------------------- - * Initialize the corelock structure. - *--------------------------------------------------------------------------- - */ -void corelock_init(struct corelock *cl) -{ - memset(cl, 0, sizeof (*cl)); -} - -#if 1 /* Assembly locks to minimize overhead */ -/*--------------------------------------------------------------------------- - * Wait for the corelock to become free and acquire it when it does. - *--------------------------------------------------------------------------- - */ -void __attribute__((naked)) corelock_lock(struct corelock *cl) -{ - /* Relies on the fact that core IDs are complementary bitmasks (0x55,0xaa) */ - asm volatile ( - "mov r1, %0 \n" /* r1 = PROCESSOR_ID */ - "ldrb r1, [r1] \n" - "strb r1, [r0, r1, lsr #7] \n" /* cl->myl[core] = core */ - "eor r2, r1, #0xff \n" /* r2 = othercore */ - "strb r2, [r0, #2] \n" /* cl->turn = othercore */ - "1: \n" - "ldrb r3, [r0, r2, lsr #7] \n" /* cl->myl[othercore] == 0 ? */ - "cmp r3, #0 \n" /* yes? lock acquired */ - "bxeq lr \n" - "ldrb r3, [r0, #2] \n" /* || cl->turn == core ? */ - "cmp r3, r1 \n" - "bxeq lr \n" /* yes? lock acquired */ - "b 1b \n" /* keep trying */ - : : "i"(&PROCESSOR_ID) - ); - (void)cl; -} - -/*--------------------------------------------------------------------------- - * Try to aquire the corelock. If free, caller gets it, otherwise return 0. - *--------------------------------------------------------------------------- - */ -int __attribute__((naked)) corelock_try_lock(struct corelock *cl) -{ - /* Relies on the fact that core IDs are complementary bitmasks (0x55,0xaa) */ - asm volatile ( - "mov r1, %0 \n" /* r1 = PROCESSOR_ID */ - "ldrb r1, [r1] \n" - "mov r3, r0 \n" - "strb r1, [r0, r1, lsr #7] \n" /* cl->myl[core] = core */ - "eor r2, r1, #0xff \n" /* r2 = othercore */ - "strb r2, [r0, #2] \n" /* cl->turn = othercore */ - "ldrb r0, [r3, r2, lsr #7] \n" /* cl->myl[othercore] == 0 ? */ - "eors r0, r0, r2 \n" /* yes? lock acquired */ - "bxne lr \n" - "ldrb r0, [r3, #2] \n" /* || cl->turn == core? */ - "ands r0, r0, r1 \n" - "streqb r0, [r3, r1, lsr #7] \n" /* if not, cl->myl[core] = 0 */ - "bx lr \n" /* return result */ - : : "i"(&PROCESSOR_ID) - ); - - return 0; - (void)cl; -} - -/*--------------------------------------------------------------------------- - * Release ownership of the corelock - *--------------------------------------------------------------------------- - */ -void __attribute__((naked)) corelock_unlock(struct corelock *cl) -{ - asm volatile ( - "mov r1, %0 \n" /* r1 = PROCESSOR_ID */ - "ldrb r1, [r1] \n" - "mov r2, #0 \n" /* cl->myl[core] = 0 */ - "strb r2, [r0, r1, lsr #7] \n" - "bx lr \n" - : : "i"(&PROCESSOR_ID) - ); - (void)cl; -} - -#else /* C versions for reference */ - -void corelock_lock(struct corelock *cl) -{ - const unsigned int core = CURRENT_CORE; - const unsigned int othercore = 1 - core; - - cl->myl[core] = core; - cl->turn = othercore; - - for (;;) - { - if (cl->myl[othercore] == 0 || cl->turn == core) - break; - } -} - -int corelock_try_lock(struct corelock *cl) -{ - const unsigned int core = CURRENT_CORE; - const unsigned int othercore = 1 - core; - - cl->myl[core] = core; - cl->turn = othercore; - - if (cl->myl[othercore] == 0 || cl->turn == core) - { - return 1; - } - - cl->myl[core] = 0; - return 0; -} - -void corelock_unlock(struct corelock *cl) -{ - cl->myl[CURRENT_CORE] = 0; -} -#endif /* ASM / C selection */ - -/*--------------------------------------------------------------------------- - * Do any device-specific inits for the threads and synchronize the kernel - * initializations. - *--------------------------------------------------------------------------- - */ -static void INIT_ATTR core_thread_init(unsigned int core) -{ - if (core == CPU) - { - /* Wake up coprocessor and let it initialize kernel and threads */ -#ifdef CPU_PP502x - MBX_MSG_CLR = 0x3f; -#endif - wake_core(COP); - /* Sleep until COP has finished */ - sleep_core(CPU); - } - else - { - /* Wake the CPU and return */ - wake_core(CPU); - } -} - -/*--------------------------------------------------------------------------- - * Switches to a stack that always resides in the Rockbox core then calls - * the final exit routine to actually finish removing the thread from the - * scheduler. - * - * Needed when a thread suicides on a core other than the main CPU since the - * stack used when idling is the stack of the last thread to run. This stack - * may not reside in the core firmware in which case the core will continue - * to use a stack from an unloaded module until another thread runs on it. - *--------------------------------------------------------------------------- - */ -static inline void NORETURN_ATTR __attribute__((always_inline)) - thread_final_exit(struct thread_entry *current) -{ - asm volatile ( - "cmp %1, #0 \n" /* CPU? */ - "ldrne r0, =commit_dcache \n" /* No? write back data */ - "movne lr, pc \n" - "bxne r0 \n" - "mov r0, %0 \n" /* copy thread parameter */ - "mov sp, %2 \n" /* switch to idle stack */ - "bl thread_final_exit_do \n" /* finish removal */ - : : "r"(current), - "r"(current->core), - "r"(&idle_stacks[current->core][IDLE_STACK_WORDS]) - : "r0", "r1", "r2", "r3", "ip", "lr"); /* Because of flush call, - force inputs out - of scratch regs */ - while (1); -} - -/*--------------------------------------------------------------------------- - * Perform core switch steps that need to take place inside switch_thread. - * - * These steps must take place while before changing the processor and after - * having entered switch_thread since switch_thread may not do a normal return - * because the stack being used for anything the compiler saved will not belong - * to the thread's destination core and it may have been recycled for other - * purposes by the time a normal context load has taken place. switch_thread - * will also clobber anything stashed in the thread's context or stored in the - * nonvolatile registers if it is saved there before the call since the - * compiler's order of operations cannot be known for certain. - */ -static void core_switch_blk_op(unsigned int core, struct thread_entry *thread) -{ - /* Flush our data to ram */ - commit_dcache(); - /* Stash thread in r4 slot */ - thread->context.r[0] = (uint32_t)thread; - /* Stash restart address in r5 slot */ - thread->context.r[1] = thread->context.start; - /* Save sp in context.sp while still running on old core */ - thread->context.sp = idle_stacks[core][IDLE_STACK_WORDS-1]; -} - -/*--------------------------------------------------------------------------- - * Machine-specific helper function for switching the processor a thread is - * running on. Basically, the thread suicides on the departing core and is - * reborn on the destination. Were it not for gcc's ill-behavior regarding - * naked functions written in C where it actually clobbers non-volatile - * registers before the intended prologue code, this would all be much - * simpler. Generic setup is done in switch_core itself. - */ - -/*--------------------------------------------------------------------------- - * This actually performs the core switch. - */ -static void __attribute__((naked)) - switch_thread_core(unsigned int core, struct thread_entry *thread) -{ - /* Pure asm for this because compiler behavior isn't sufficiently predictable. - * Stack access also isn't permitted until restoring the original stack and - * context. */ - asm volatile ( - "stmfd sp!, { r4-r11, lr } \n" /* Stack all non-volatile context on current core */ - "ldr r2, =idle_stacks \n" /* r2 = &idle_stacks[core][IDLE_STACK_WORDS] */ - "ldr r2, [r2, r0, lsl #2] \n" - "add r2, r2, %0*4 \n" - "stmfd r2!, { sp } \n" /* save original stack pointer on idle stack */ - "mov sp, r2 \n" /* switch stacks */ - "adr r2, 1f \n" /* r2 = new core restart address */ - "str r2, [r1, #40] \n" /* thread->context.start = r2 */ - "ldr pc, =switch_thread \n" /* r0 = thread after call - see load_context */ - "1: \n" - "ldr sp, [r0, #32] \n" /* Reload original sp from context structure */ - "mov r1, #0 \n" /* Clear start address */ - "str r1, [r0, #40] \n" - "ldr r0, =commit_discard_idcache \n" /* Invalidate new core's cache */ - "mov lr, pc \n" - "bx r0 \n" - "ldmfd sp!, { r4-r11, pc } \n" /* Restore non-volatile context to new core and return */ - : : "i"(IDLE_STACK_WORDS) - ); - (void)core; (void)thread; -} - -/** PP-model-specific dual-core code **/ - -#if CONFIG_CPU == PP5002 -/* PP5002 has no mailboxes - Bytes to emulate the PP502x mailbox bits */ -struct core_semaphores -{ - volatile uint8_t intend_wake; /* 00h */ - volatile uint8_t stay_awake; /* 01h */ - volatile uint8_t intend_sleep; /* 02h */ - volatile uint8_t unused; /* 03h */ -}; - -static struct core_semaphores core_semaphores[NUM_CORES] IBSS_ATTR; - -#if 1 /* Select ASM */ -/*--------------------------------------------------------------------------- - * Put core in a power-saving state if waking list wasn't repopulated and if - * no other core requested a wakeup for it to perform a task. - *--------------------------------------------------------------------------- - */ -static inline void core_sleep(unsigned int core) -{ - asm volatile ( - "mov r0, #1 \n" /* Signal intent to sleep */ - "strb r0, [%[sem], #2] \n" - "ldrb r0, [%[sem], #1] \n" /* && stay_awake == 0? */ - "cmp r0, #0 \n" - "bne 2f \n" - /* Sleep: PP5002 crashes if the instruction that puts it to sleep is - * located at 0xNNNNNNN0. 4/8/C works. This sequence makes sure - * that the correct alternative is executed. Don't change the order - * of the next 4 instructions! */ - "tst pc, #0x0c \n" - "mov r0, #0xca \n" - "strne r0, [%[ctl], %[c], lsl #2] \n" - "streq r0, [%[ctl], %[c], lsl #2] \n" - "nop \n" /* nop's needed because of pipeline */ - "nop \n" - "nop \n" - "2: \n" - "mov r0, #0 \n" /* Clear stay_awake and sleep intent */ - "strb r0, [%[sem], #1] \n" - "strb r0, [%[sem], #2] \n" - "1: \n" /* Wait for wake procedure to finish */ - "ldrb r0, [%[sem], #0] \n" - "cmp r0, #0 \n" - "bne 1b \n" - : - : [sem]"r"(&core_semaphores[core]), [c]"r"(core), - [ctl]"r"(&CPU_CTL) - : "r0" - ); - enable_irq(); -} - -/*--------------------------------------------------------------------------- - * Wake another processor core that is sleeping or prevent it from doing so - * if it was already destined. FIQ, IRQ should be disabled before calling. - *--------------------------------------------------------------------------- - */ -void core_wake(unsigned int othercore) -{ - /* avoid r0 since that contains othercore */ - asm volatile ( - "mrs r3, cpsr \n" /* Disable IRQ */ - "orr r1, r3, #0x80 \n" - "msr cpsr_c, r1 \n" - "mov r1, #1 \n" /* Signal intent to wake other core */ - "orr r1, r1, r1, lsl #8 \n" /* and set stay_awake */ - "strh r1, [%[sem], #0] \n" - "mov r2, #0x8000 \n" - "1: \n" /* If it intends to sleep, let it first */ - "ldrb r1, [%[sem], #2] \n" /* intend_sleep != 0 ? */ - "cmp r1, #1 \n" - "ldr r1, [%[st]] \n" /* && not sleeping ? */ - "tsteq r1, r2, lsr %[oc] \n" - "beq 1b \n" /* Wait for sleep or wake */ - "tst r1, r2, lsr %[oc] \n" - "ldrne r2, =0xcf004054 \n" /* If sleeping, wake it */ - "movne r1, #0xce \n" - "strne r1, [r2, %[oc], lsl #2] \n" - "mov r1, #0 \n" /* Done with wake procedure */ - "strb r1, [%[sem], #0] \n" - "msr cpsr_c, r3 \n" /* Restore IRQ */ - : - : [sem]"r"(&core_semaphores[othercore]), - [st]"r"(&PROC_STAT), - [oc]"r"(othercore) - : "r1", "r2", "r3" - ); -} - -#else /* C version for reference */ - -static inline void core_sleep(unsigned int core) -{ - /* Signal intent to sleep */ - core_semaphores[core].intend_sleep = 1; - - /* Something waking or other processor intends to wake us? */ - if (core_semaphores[core].stay_awake == 0) - { - sleep_core(core); - } - - /* Signal wake - clear wake flag */ - core_semaphores[core].stay_awake = 0; - core_semaphores[core].intend_sleep = 0; - - /* Wait for other processor to finish wake procedure */ - while (core_semaphores[core].intend_wake != 0); - - /* Enable IRQ */ - enable_irq(); -} - -void core_wake(unsigned int othercore) -{ - /* Disable interrupts - avoid reentrancy from the tick */ - int oldlevel = disable_irq_save(); - - /* Signal intent to wake other processor - set stay awake */ - core_semaphores[othercore].intend_wake = 1; - core_semaphores[othercore].stay_awake = 1; - - /* If it intends to sleep, wait until it does or aborts */ - while (core_semaphores[othercore].intend_sleep != 0 && - (PROC_STAT & PROC_SLEEPING(othercore)) == 0); - - /* If sleeping, wake it up */ - if (PROC_STAT & PROC_SLEEPING(othercore)) - wake_core(othercore); - - /* Done with wake procedure */ - core_semaphores[othercore].intend_wake = 0; - restore_irq(oldlevel); -} -#endif /* ASM/C selection */ - -#elif defined (CPU_PP502x) - -#if 1 /* Select ASM */ -/*--------------------------------------------------------------------------- - * Put core in a power-saving state if waking list wasn't repopulated and if - * no other core requested a wakeup for it to perform a task. - *--------------------------------------------------------------------------- - */ -static inline void core_sleep(unsigned int core) -{ - asm volatile ( - "mov r0, #4 \n" /* r0 = 0x4 << core */ - "mov r0, r0, lsl %[c] \n" - "str r0, [%[mbx], #4] \n" /* signal intent to sleep */ - "ldr r1, [%[mbx], #0] \n" /* && !(MBX_MSG_STAT & (0x10< ) \___| < | \_\ ( <_> > < < -* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ -* \/ \/ \/ \/ \/ -* $Id$ -* -* Copyright (C) 2006 Thom Johansen -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -* KIND, either express or implied. -* -****************************************************************************/ - -#include "cpu.h" -#include "system.h" -#include "timer.h" - -static long SHAREDBSS_ATTR cycles_new = 0; - -void TIMER2(void) -{ - TIMER2_VAL; /* ACK interrupt */ - if (cycles_new > 0) - { - TIMER2_CFG = 0xc0000000 | (cycles_new - 1); - cycles_new = 0; - } - if (pfn_timer != NULL) - { - cycles_new = -1; - /* "lock" the variable, in case timer_set_period() - * is called within pfn_timer() */ - pfn_timer(); - cycles_new = 0; - } -} - -bool timer_set(long cycles, bool start) -{ - if (cycles > 0x20000000 || cycles < 2) - return false; - - if (start) - { - if (pfn_unregister != NULL) - { - pfn_unregister(); - pfn_unregister = NULL; - } - CPU_INT_DIS = TIMER2_MASK; - COP_INT_DIS = TIMER2_MASK; - } - if (start || (cycles_new == -1)) /* within isr, cycles_new is "locked" */ - TIMER2_CFG = 0xc0000000 | (cycles - 1); /* enable timer */ - else - cycles_new = cycles; - - return true; -} - -bool timer_start(IF_COP_VOID(int core)) -{ - /* unmask interrupt source */ -#if NUM_CORES > 1 - if (core == COP) - COP_INT_EN = TIMER2_MASK; - else -#endif - CPU_INT_EN = TIMER2_MASK; - return true; -} - -void timer_stop(void) -{ - TIMER2_CFG = 0; /* stop timer 2 */ - CPU_INT_DIS = TIMER2_MASK; - COP_INT_DIS = TIMER2_MASK; -} diff --git a/firmware/target/arm/usb-fw-pp5002.c b/firmware/target/arm/usb-fw-pp5002.c deleted file mode 100644 index d296b05b2f..0000000000 --- a/firmware/target/arm/usb-fw-pp5002.c +++ /dev/null @@ -1,75 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2007 by Jens Arnold - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "config.h" -#include "ata.h" -#include "cpu.h" -#include "string.h" -#include "system.h" -#include "usb.h" - -void usb_pin_init(void) -{ - /* TODO: add USB init for iPod 3rd gen */ - -#if defined(IPOD_1G2G) || defined(IPOD_3G) - /* GPIO C bit 7 is firewire detect */ - GPIOC_ENABLE |= 0x80; - GPIOC_OUTPUT_EN &= ~0x80; -#endif -} - -/* No different for now */ -void usb_init_device(void) __attribute__((alias("usb_pin_init"))); - -void usb_enable(bool on) -{ - /* This device specific code will eventually give way to proper USB - handling, which should be the same for all PP5002 targets. */ - if (on) - { -#ifdef IPOD_ARCH - /* For iPod, we can only do one thing with USB mode atm - reboot - into the flash-based disk-mode. This does not return. */ - - ata_sleepnow(); /* Immediately spindown the disk. */ - sleep(HZ*2); - - memcpy((void *)0x40017f00, "diskmodehotstuff\1", 17); - - system_reboot(); /* Reboot */ -#endif - } -} - -int usb_detect(void) -{ -#if defined(IPOD_1G2G) || defined(IPOD_3G) - /* GPIO C bit 7 is firewire detect */ - if (!(GPIOC_INPUT_VAL & 0x80)) - return USB_INSERTED; -#endif - - /* TODO: add USB detection for iPod 3rd gen */ - - return USB_EXTRACTED; -} -bool usb_plugged(void) __attribute__((alias("usb_detect"))); diff --git a/firmware/target/arm/usb-fw-pp502x.c b/firmware/target/arm/usb-fw-pp502x.c deleted file mode 100644 index 5272102fad..0000000000 --- a/firmware/target/arm/usb-fw-pp502x.c +++ /dev/null @@ -1,308 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 by Linus Nielsen Feltzing - * - * iPod driver based on code from the ipodlinux project - http://ipodlinux.org - * Adapted for Rockbox in January 2006 - * Original file: podzilla/usb.c - * Copyright (C) 2005 Adam Johnston - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "config.h" -#include "system.h" -#include "usb.h" -#include "button.h" -#include "ata.h" -#include "string.h" -#include "usb_core.h" -#include "usb_drv.h" - -#if defined(IPOD_4G) || defined(IPOD_COLOR) \ - || defined(IPOD_MINI) || defined(IPOD_MINI2G) - /* GPIO D bit 3 is usb detect */ -#define USB_GPIO GPIOD -#define USB_GPIO_MASK 0x08 -#define USB_GPIO_VAL 0x08 - -#elif defined(IPOD_NANO) || defined(IPOD_VIDEO) - /* GPIO L bit 4 is usb detect */ -#define USB_GPIO GPIOL -#define USB_GPIO_MASK 0x10 -#define USB_GPIO_VAL 0x10 - -#elif defined(SANSA_C200) - /* GPIO H bit 1 is usb/charger detect */ -#define USB_GPIO GPIOH -#define USB_GPIO_MASK 0x02 -#define USB_GPIO_VAL 0x02 - -#elif defined(SANSA_E200) - /* GPIO B bit 4 is usb/charger detect */ -#define USB_GPIO GPIOB -#define USB_GPIO_MASK 0x10 -#define USB_GPIO_VAL 0x10 - -#elif defined(IRIVER_H10) || defined(IRIVER_H10_5GB) || defined(MROBE_100) - /* GPIO L bit 2 is usb detect */ -#define USB_GPIO GPIOL -#define USB_GPIO_MASK 0x04 -#define USB_GPIO_VAL 0x04 - -#elif defined(PHILIPS_SA9200) - /* GPIO B bit 6 (high) is usb bus power detect */ -#define USB_GPIO GPIOB -#define USB_GPIO_MASK 0x40 -#define USB_GPIO_VAL 0x40 - -#elif defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) - /* GPIO E bit 2 is usb detect */ -#define USB_GPIO GPIOE -#define USB_GPIO_MASK 0x04 -#define USB_GPIO_VAL 0x04 - -#elif defined(SAMSUNG_YH820) || defined(SAMSUNG_YH920) || defined(SAMSUNG_YH925) - /* GPIO D bit 4 is usb detect */ -#define USB_GPIO GPIOD -#define USB_GPIO_MASK 0x10 -#define USB_GPIO_VAL 0x10 - -#elif defined(TATUNG_TPJ1022) - /* GPIO ? bit ? is usb detect (dummy value)*/ -#define USB_GPIO GPIOD -#define USB_GPIO_MASK 0x10 -#define USB_GPIO_VAL 0x10 - -#elif defined(PBELL_VIBE500) - /* GPIO L bit 3 is usb detect */ -#define USB_GPIO GPIOL -#define USB_GPIO_MASK 0x04 -#define USB_GPIO_VAL 0x04 - -#else -#error No USB GPIO config specified -#endif - -#define USB_GPIO_ENABLE GPIO_ENABLE(USB_GPIO) -#define USB_GPIO_OUTPUT_EN GPIO_OUTPUT_EN(USB_GPIO) -#define USB_GPIO_INPUT_VAL GPIO_INPUT_VAL(USB_GPIO) -#define USB_GPIO_INT_EN GPIO_INT_EN(USB_GPIO) -#define USB_GPIO_INT_LEV GPIO_INT_LEV(USB_GPIO) -#define USB_GPIO_INT_CLR GPIO_INT_CLR(USB_GPIO) -#define USB_GPIO_HI_INT_MASK GPIO_HI_INT_MASK(USB_GPIO) - -static void usb_reset_controller(void) -{ - /* enable usb module */ - outl(inl(0x7000002C) | 0x3000000, 0x7000002C); - - DEV_EN |= DEV_USB0; - DEV_EN |= DEV_USB1; - - /* reset both USBs */ - DEV_RS |= DEV_USB0; - DEV_RS &=~DEV_USB0; - DEV_RS |= DEV_USB1; - DEV_RS &=~DEV_USB1; - - DEV_INIT2 |= INIT_USB; - - while ((inl(0x70000028) & 0x80) == 0); - outl(inl(0x70000028) | 0x2, 0x70000028); - udelay(100000); - XMB_RAM_CFG |= 0x47A; - - /* disable USB-devices until USB is detected via GPIO */ -#ifndef BOOTLOADER - /* Disabling USB0 in the bootloader makes the OF not load, - Also something here breaks usb pin detect in bootloader. - leave it all enabled untill rockbox main loads */ - DEV_EN &= ~DEV_USB0; - DEV_EN &= ~DEV_USB1; - DEV_INIT2 &= ~INIT_USB; -#endif -} - -/* Enable raw status pin read only - not interrupt */ -void usb_pin_init(void) -{ - GPIO_CLEAR_BITWISE(USB_GPIO_OUTPUT_EN, USB_GPIO_MASK); - GPIO_SET_BITWISE(USB_GPIO_ENABLE, USB_GPIO_MASK); -#ifdef USB_FIREWIRE_HANDLING - /* GPIO C bit 1 is firewire detect */ - GPIO_CLEAR_BITWISE(GPIOC_OUTPUT_EN, 0x02); - GPIO_SET_BITWISE(GPIOC_ENABLE, 0x02); -#endif -} - -void usb_init_device(void) -{ - usb_reset_controller(); - - /* Do one-time inits (no dependency on controller) */ - usb_drv_startup(); - - usb_pin_init(); - - /* These set INT_LEV to the inserted level so it will fire if already - * inserted at the time they are enabled. */ -#ifdef USB_STATUS_BY_EVENT - GPIO_CLEAR_BITWISE(USB_GPIO_INT_EN, USB_GPIO_MASK); - GPIO_WRITE_BITWISE(USB_GPIO_INT_LEV, USB_GPIO_VAL, USB_GPIO_MASK); - USB_GPIO_INT_CLR = USB_GPIO_MASK; - GPIO_SET_BITWISE(USB_GPIO_INT_EN, USB_GPIO_MASK); - CPU_HI_INT_EN = USB_GPIO_HI_INT_MASK; - -#ifdef USB_FIREWIRE_HANDLING - /* GPIO C bit 1 is firewire detect */ - GPIO_CLEAR_BITWISE(GPIOC_INT_EN, 0x02); - GPIO_WRITE_BITWISE(GPIOC_INT_LEV, 0x00, 0x02); - GPIOC_INT_CLR = 0x02; - GPIO_SET_BITWISE(GPIOC_INT_EN, 0x02); - CPU_HI_INT_EN = GPIO0_MASK; -#endif - CPU_INT_EN = HI_MASK; -#endif /* USB_STATUS_BY_EVENT */ -} - -void usb_enable(bool on) -{ - if (on) { - /* if USB is detected, re-enable the USB-devices, otherwise make sure it's disabled */ - DEV_EN |= DEV_USB0; - DEV_EN |= DEV_USB1; - DEV_INIT2 |= INIT_USB; - usb_core_init(); - } - else { - usb_core_exit(); - /* Disable USB devices */ - usb_reset_controller(); - } -} - -void usb_attach(void) -{ - usb_drv_attach(); -} - -bool usb_plugged(void) -{ - return (USB_GPIO_INPUT_VAL & USB_GPIO_MASK) == USB_GPIO_VAL; -} - -#ifdef USB_STATUS_BY_EVENT -/* Cannot always tell power pin from USB pin */ -static int usb_status = USB_EXTRACTED; - -static int usb_timeout_event(struct timeout *tmo) -{ - usb_status_event(tmo->data == USB_GPIO_VAL ? USB_INSERTED : USB_EXTRACTED); - return 0; -} - -void usb_insert_int(void) -{ - static struct timeout usb_oneshot; - unsigned long val = USB_GPIO_INPUT_VAL & USB_GPIO_MASK; - usb_status = (val == USB_GPIO_VAL) ? USB_INSERTED : USB_EXTRACTED; - GPIO_WRITE_BITWISE(USB_GPIO_INT_LEV, val ^ USB_GPIO_MASK, USB_GPIO_MASK); - USB_GPIO_INT_CLR = USB_GPIO_MASK; - timeout_register(&usb_oneshot, usb_timeout_event, HZ/5, val); -} - -/* USB_DETECT_BY_CORE: Called when device descriptor is requested */ -void usb_drv_usb_detect_event(void) -{ - /* Filter for invalid bus reset when unplugging by checking the pin state. */ - if(usb_plugged()) { - usb_status_event(USB_HOSTED); - } -} -#endif /* USB_STATUS_BY_EVENT */ - -#ifdef HAVE_BOOTLOADER_USB_MODE -/* Replacement function that returns all unused memory after the bootloader - * because the storage driver uses the audio buffer */ -extern unsigned char freebuffer[]; -extern unsigned char freebufferend[]; -unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size) -{ - if (buffer_size) - *buffer_size = freebufferend - freebuffer + 1; - - return freebuffer; - (void)talk_buf; -} -#endif /* HAVE_BOOTLOADER_USB_MODE */ - -void usb_drv_int_enable(bool enable) -{ - /* enable/disable USB IRQ in CPU */ - if(enable) { - CPU_INT_EN = USB_MASK; - } - else { - CPU_INT_DIS = USB_MASK; - } -} - -/* detect host or charger (INSERTED or EXTRACTED) */ -int usb_detect(void) -{ -#ifdef USB_STATUS_BY_EVENT - return usb_status; -#else - return usb_plugged() ? USB_INSERTED : USB_EXTRACTED; -#endif -} - -#ifdef USB_FIREWIRE_HANDLING -#ifdef USB_STATUS_BY_EVENT -static bool firewire_status = false; -#endif - -bool firewire_detect(void) -{ -#ifdef USB_STATUS_BY_EVENT - return firewire_status; -#else - /* GPIO C bit 1 is firewire detect */ - /* no charger detection needed for firewire */ - return (GPIOC_INPUT_VAL & 0x02) == 0x00; -#endif -} - -#ifdef USB_STATUS_BY_EVENT -static int firewire_timeout_event(struct timeout *tmo) -{ - if (tmo->data == 0x00) - usb_firewire_connect_event(); - return 0; -} - -void firewire_insert_int(void) -{ - static struct timeout firewire_oneshot; - unsigned long val = GPIOC_INPUT_VAL & 0x02; - firewire_status = val == 0x00; - GPIO_WRITE_BITWISE(GPIOC_INT_LEV, val ^ 0x02, 0x02); - GPIOC_INT_CLR = 0x02; - timeout_register(&firewire_oneshot, firewire_timeout_event, HZ/5, val); -} -#endif /* USB_STATUS_BY_EVENT */ -#endif /* USB_FIREWIRE_HANDLING */ diff --git a/firmware/target/arm/wmcodec-pp.c b/firmware/target/arm/wmcodec-pp.c deleted file mode 100644 index 839fd90676..0000000000 --- a/firmware/target/arm/wmcodec-pp.c +++ /dev/null @@ -1,112 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Portalplayer specific code for Wolfson audio codecs - * - * 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) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "system.h" -#include "audiohw.h" -#include "i2c-pp.h" -#include "i2s.h" -#include "wmcodec.h" - -#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) || \ - defined(MROBE_100) || defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) || \ - defined(PBELL_VIBE500) -/* The H10's audio codec uses an I2C address of 0x1b */ -#define I2C_AUDIO_ADDRESS 0x1b -#else -/* The iPod's audio codecs use an I2C address of 0x1a */ -#define I2C_AUDIO_ADDRESS 0x1a -#endif - - -/* - * Initialise the PP I2C and I2S. - */ -void audiohw_init(void) -{ -#ifdef CPU_PP502x - /* normal outputs for CDI and I2S pin groups */ - DEV_INIT2 &= ~0x300; - - /*mini2?*/ - DEV_INIT1 &=~0x3000000; - /*mini2?*/ - - /* I2S device reset */ - DEV_RS |= DEV_I2S; - DEV_RS &=~DEV_I2S; - - /* I2S device enable */ - DEV_EN |= DEV_I2S; - - /* enable external dev clock clocks */ - DEV_EN |= DEV_EXTCLOCKS; - - /* external dev clock to 24MHz */ - outl(inl(0x70000018) & ~0xc, 0x70000018); -#else - /* device reset */ - outl(inl(0xcf005030) | 0x80, 0xcf005030); - outl(inl(0xcf005030) & ~0x80, 0xcf005030); - - /* device enable */ - outl(inl(0xcf005000) | 0x80, 0xcf005000); - - /* GPIO D06 enable for output */ - outl(inl(0xcf00000c) | 0x40, 0xcf00000c); - outl(inl(0xcf00001c) & ~0x40, 0xcf00001c); -#ifdef IPOD_1G2G - /* bits 11,10 == 10 */ - outl(inl(0xcf004040) & ~0x400, 0xcf004040); - outl(inl(0xcf004040) | 0x800, 0xcf004040); -#else /* IPOD_3G */ - /* bits 11,10 == 01 */ - outl(inl(0xcf004040) | 0x400, 0xcf004040); - outl(inl(0xcf004040) & ~0x800, 0xcf004040); - - outl(inl(0xcf004048) & ~0x1, 0xcf004048); - - outl(inl(0xcf000004) & ~0xf, 0xcf000004); - outl(inl(0xcf004044) & ~0xf, 0xcf004044); - - /* C03 = 0 */ - outl(inl(0xcf000008) | 0x8, 0xcf000008); - outl(inl(0xcf000018) | 0x8, 0xcf000018); - outl(inl(0xcf000028) & ~0x8, 0xcf000028); -#endif /* IPOD_1G2G/3G */ -#endif - - /* reset the I2S controller into known state */ - i2s_reset(); - - audiohw_preinit(); -} - -void wmcodec_write(int reg, int data) -{ - pp_i2c_send(I2C_AUDIO_ADDRESS, (reg<<1) | ((data&0x100)>>8),data&0xff); -} -- cgit v1.2.3