PNX0101 changes:
Make PNX0101-specific system.c and crt0.S. Add new register names from LPC2880 user manual. Add support for timer. Enable CPU frequency changing. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12904 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
7d9ff93b79
commit
cd630c9e0a
12 changed files with 795 additions and 127 deletions
|
@ -278,6 +278,9 @@ drivers/i2c-pnx0101.c
|
|||
#elif CONFIG_I2C == I2C_S3C2440
|
||||
/* no i2c driver yet */
|
||||
#endif
|
||||
#if CONFIG_CPU == PNX0101
|
||||
target/arm/system-pnx0101.c
|
||||
#endif
|
||||
#if defined(CPU_PP)
|
||||
#ifdef BOOTLOADER
|
||||
target/arm/crt0-pp-bl.S
|
||||
|
@ -286,6 +289,8 @@ target/arm/pcm-pp.c
|
|||
target/arm/audio-pp.c
|
||||
target/arm/crt0-pp.S
|
||||
#endif
|
||||
#elif CONFIG_CPU == PNX0101
|
||||
target/arm/crt0-pnx0101.S
|
||||
#elif defined(CPU_ARM)
|
||||
target/arm/crt0.S
|
||||
#endif /* defined(CPU_*) */
|
||||
|
|
|
@ -9,6 +9,8 @@ OUTPUT_FORMAT(elf32-littlearm)
|
|||
OUTPUT_ARCH(arm)
|
||||
#ifdef CPU_PP
|
||||
INPUT(target/arm/crt0-pp.o)
|
||||
#elif CONFIG_CPU == PNX0101
|
||||
INPUT(target/arm/crt0-pnx0101.o)
|
||||
#elif defined(CPU_ARM)
|
||||
INPUT(target/arm/crt0.o)
|
||||
#endif
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
#define CONFIG_BACKLIGHT BL_IRIVER_IFP7XX /* port controlled */
|
||||
|
||||
/* Define this to the CPU frequency */
|
||||
#define CPU_FREQ 30000000
|
||||
#define CPU_FREQ 48000000
|
||||
|
||||
#define CONFIG_LCD LCD_IFP7XX
|
||||
|
||||
|
@ -98,7 +98,7 @@
|
|||
#define HAVE_GDB_API
|
||||
|
||||
/* Define this if you have adjustable CPU frequency */
|
||||
//#define HAVE_ADJUSTABLE_CPU_FREQ
|
||||
#define HAVE_ADJUSTABLE_CPU_FREQ
|
||||
|
||||
#define BOOTFILE_EXT "iriver"
|
||||
#define BOOTFILE "rockbox." BOOTFILE_EXT
|
||||
|
|
|
@ -78,4 +78,147 @@
|
|||
|
||||
#define CODECVOL (*(volatile unsigned long *)0x80200398)
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
/* Clock generation unit */
|
||||
|
||||
struct pnx0101_cgu {
|
||||
unsigned long base_scr[12];
|
||||
unsigned long base_fs1[12];
|
||||
unsigned long base_fs2[12];
|
||||
unsigned long base_ssr[12];
|
||||
unsigned long clk_pcr[73];
|
||||
unsigned long clk_psr[73];
|
||||
unsigned long clk_esr[67];
|
||||
unsigned long base_bcr[3];
|
||||
unsigned long base_fdc[18];
|
||||
};
|
||||
|
||||
#define CGU (*(volatile struct pnx0101_cgu *)0x80004000)
|
||||
|
||||
#define PNX0101_SEL_STAGE_SYS 0
|
||||
#define PNX0101_SEL_STAGE_APB0 1
|
||||
#define PNX0101_SEL_STAGE_APB1 2
|
||||
#define PNX0101_SEL_STAGE_APB3 3
|
||||
#define PNX0101_SEL_STAGE_DAIO 9
|
||||
|
||||
#define PNX0101_HIPREC_FDC 16
|
||||
|
||||
#define PNX0101_FIRST_DIV_SYS 0
|
||||
#define PNX0101_N_DIV_SYS 7
|
||||
#define PNX0101_FIRST_DIV_APB0 7
|
||||
#define PNX0101_N_DIV_APB0 2
|
||||
#define PNX0101_FIRST_DIV_APB1 9
|
||||
#define PNX0101_N_DIV_APB1 1
|
||||
#define PNX0101_FIRST_DIV_APB3 10
|
||||
#define PNX0101_N_DIV_APB3 1
|
||||
#define PNX0101_FIRST_DIV_DAIO 12
|
||||
#define PNX0101_N_DIV_DAIO 6
|
||||
|
||||
#define PNX0101_BCR_SYS 0
|
||||
#define PNX0101_BCR_APB0 1
|
||||
#define PNX0101_BCR_DAIO 2
|
||||
|
||||
#define PNX0101_FIRST_ESR_SYS 0
|
||||
#define PNX0101_N_ESR_SYS 28
|
||||
#define PNX0101_FIRST_ESR_APB0 28
|
||||
#define PNX0101_N_ESR_APB0 9
|
||||
#define PNX0101_FIRST_ESR_APB1 37
|
||||
#define PNX0101_N_ESR_APB1 4
|
||||
#define PNX0101_FIRST_ESR_APB3 41
|
||||
#define PNX0101_N_ESR_APB3 16
|
||||
#define PNX0101_FIRST_ESR_DAIO 58
|
||||
#define PNX0101_N_ESR_DAIO 9
|
||||
|
||||
#define PNX0101_ESR_APB1 0x25
|
||||
#define PNX0101_ESR_T0 0x26
|
||||
#define PNX0101_ESR_T1 0x27
|
||||
#define PNX0101_ESR_I2C 0x28
|
||||
|
||||
#define PNX0101_CLOCK_APB1 0x25
|
||||
#define PNX0101_CLOCK_T0 0x26
|
||||
#define PNX0101_CLOCK_T1 0x27
|
||||
#define PNX0101_CLOCK_I2C 0x28
|
||||
|
||||
#define PNX0101_MAIN_CLOCK_FAST 1
|
||||
#define PNX0101_MAIN_CLOCK_MAIN_PLL 9
|
||||
|
||||
struct pnx0101_pll {
|
||||
unsigned long hpfin;
|
||||
unsigned long hpmdec;
|
||||
unsigned long hpndec;
|
||||
unsigned long hppdec;
|
||||
unsigned long hpmode;
|
||||
unsigned long hpstat;
|
||||
unsigned long hpack;
|
||||
unsigned long hpreq;
|
||||
unsigned long hppad1;
|
||||
unsigned long hppad2;
|
||||
unsigned long hppad3;
|
||||
unsigned long hpselr;
|
||||
unsigned long hpseli;
|
||||
unsigned long hpselp;
|
||||
unsigned long lpfin;
|
||||
unsigned long lppdn;
|
||||
unsigned long lpmbyp;
|
||||
unsigned long lplock;
|
||||
unsigned long lpdbyp;
|
||||
unsigned long lpmsel;
|
||||
unsigned long lppsel;
|
||||
};
|
||||
|
||||
#define PLL (*(volatile struct pnx0101_pll *)0x80004cac)
|
||||
|
||||
struct pnx0101_emc {
|
||||
unsigned long control;
|
||||
unsigned long status;
|
||||
};
|
||||
|
||||
#define EMC (*(volatile struct pnx0101_emc *)0x80008000)
|
||||
|
||||
struct pnx0101_emcstatic {
|
||||
unsigned long config;
|
||||
unsigned long waitwen;
|
||||
unsigned long waitoen;
|
||||
unsigned long waitrd;
|
||||
unsigned long waitpage;
|
||||
unsigned long waitwr;
|
||||
unsigned long waitturn;
|
||||
};
|
||||
|
||||
#define EMCSTATIC0 (*(volatile struct pnx0101_emcstatic *)0x80008200)
|
||||
#define EMCSTATIC1 (*(volatile struct pnx0101_emcstatic *)0x80008220)
|
||||
#define EMCSTATIC2 (*(volatile struct pnx0101_emcstatic *)0x80008240)
|
||||
|
||||
/* Timers */
|
||||
|
||||
struct pnx0101_timer {
|
||||
unsigned long load;
|
||||
unsigned long value;
|
||||
unsigned long ctrl;
|
||||
unsigned long clr;
|
||||
};
|
||||
|
||||
#define TIMER0 (*(volatile struct pnx0101_timer *)0x80020000)
|
||||
#define TIMER1 (*(volatile struct pnx0101_timer *)0x80020400)
|
||||
|
||||
/* Interrupt controller */
|
||||
|
||||
#define IRQ_TIMER0 5
|
||||
#define IRQ_TIMER1 6
|
||||
#define IRQ_DMA 28
|
||||
|
||||
#define INTPRIOMASK ((volatile unsigned long *)0x80300000)
|
||||
#define INTVECTOR ((volatile unsigned long *)0x80300100)
|
||||
#define INTPENDING (*(volatile unsigned long *)0x80300200)
|
||||
#define INTFEATURES (*(volatile unsigned long *)0x80300300)
|
||||
#define INTREQ ((volatile unsigned long *)0x80300400)
|
||||
|
||||
#define INTREQ_WEPRIO 0x10000000
|
||||
#define INTREQ_WETARGET 0x08000000
|
||||
#define INTREQ_WEENABLE 0x04000000
|
||||
#define INTREQ_WEACTVLO 0x02000000
|
||||
|
||||
#endif /* ASM */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -296,6 +296,12 @@ static inline unsigned long swap32(unsigned long value)
|
|||
#define CPUFREQ_NORMAL 98784000
|
||||
#define CPUFREQ_MAX 296352000
|
||||
|
||||
#elif CONFIG_CPU == PNX0101
|
||||
|
||||
#define CPUFREQ_DEFAULT 12000000
|
||||
#define CPUFREQ_NORMAL 48000000
|
||||
#define CPUFREQ_MAX 60000000
|
||||
|
||||
#else
|
||||
|
||||
#define CPUFREQ_DEFAULT_MULT 8
|
||||
|
@ -385,6 +391,7 @@ typedef void (*interrupt_handler_t)(void);
|
|||
|
||||
void irq_set_int_handler(int n, interrupt_handler_t handler);
|
||||
void irq_enable_int(int n);
|
||||
void irq_disable_int(int n);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#elif defined(CPU_COLDFIRE)
|
||||
/* timer is based on busclk == cpuclk/2 */
|
||||
#define TIMER_FREQ (CPU_FREQ/2)
|
||||
#elif CONFIG_CPU == PNX0101
|
||||
#define TIMER_FREQ 3000000
|
||||
#else
|
||||
#define TIMER_FREQ CPU_FREQ
|
||||
#endif
|
||||
|
|
|
@ -594,23 +594,21 @@ void timer_handler(void)
|
|||
|
||||
current_tick++;
|
||||
|
||||
TIMERR0C = 1;
|
||||
TIMER0.clr = 0;
|
||||
}
|
||||
|
||||
void tick_start(unsigned int interval_in_ms)
|
||||
{
|
||||
TIMERR08 &= ~0x80;
|
||||
TIMERR0C = 1;
|
||||
TIMERR08 &= ~0x80;
|
||||
TIMERR08 |= 0x40;
|
||||
TIMERR00 = 3000000 * interval_in_ms / 1000;
|
||||
TIMERR08 &= ~0xc;
|
||||
TIMERR0C = 1;
|
||||
TIMER0.ctrl &= ~0x80; /* Disable the counter */
|
||||
TIMER0.ctrl |= 0x40; /* Reload after counting down to zero */
|
||||
TIMER0.load = 3000000 * interval_in_ms / 1000;
|
||||
TIMER0.ctrl &= ~0xc; /* No prescaler */
|
||||
TIMER0.clr = 1; /* Clear the interrupt request */
|
||||
|
||||
irq_set_int_handler(4, timer_handler);
|
||||
irq_enable_int(4);
|
||||
irq_set_int_handler(IRQ_TIMER0, timer_handler);
|
||||
irq_enable_int(IRQ_TIMER0);
|
||||
|
||||
TIMERR08 |= 0x80;
|
||||
TIMER0.ctrl |= 0x80; /* Enable the counter */
|
||||
}
|
||||
#elif CONFIG_CPU == S3C2440
|
||||
void tick_start(unsigned int interval_in_ms)
|
||||
|
|
|
@ -982,93 +982,6 @@ int system_memory_guard(int newmode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#elif CONFIG_CPU==PNX0101
|
||||
|
||||
interrupt_handler_t interrupt_vector[0x1d] __attribute__ ((section(".idata")));
|
||||
|
||||
#define IRQ_REG(reg) (*(volatile unsigned long *)(0x80300000 + (reg)))
|
||||
|
||||
static inline unsigned long irq_read(int reg)
|
||||
{
|
||||
unsigned long v, v2;
|
||||
do
|
||||
{
|
||||
v = IRQ_REG(reg);
|
||||
v2 = IRQ_REG(reg);
|
||||
} while (v != v2);
|
||||
return v;
|
||||
}
|
||||
|
||||
#define IRQ_WRITE_WAIT(reg, val, cond) \
|
||||
do { unsigned long v, v2; \
|
||||
do { \
|
||||
IRQ_REG(reg) = (val); \
|
||||
v = IRQ_REG(reg); \
|
||||
v2 = IRQ_REG(reg); \
|
||||
} while ((v != v2) || !(cond)); \
|
||||
} while (0);
|
||||
|
||||
static void undefined_int(void)
|
||||
{
|
||||
}
|
||||
|
||||
void irq(void)
|
||||
{
|
||||
int n = irq_read(0x100) >> 3;
|
||||
(*(interrupt_vector[n]))();
|
||||
}
|
||||
|
||||
void fiq(void)
|
||||
{
|
||||
}
|
||||
|
||||
void irq_enable_int(int n)
|
||||
{
|
||||
IRQ_WRITE_WAIT(0x404 + n * 4, 0x4010000, v & 0x10000);
|
||||
}
|
||||
|
||||
void irq_set_int_handler(int n, interrupt_handler_t handler)
|
||||
{
|
||||
interrupt_vector[n + 1] = handler;
|
||||
}
|
||||
|
||||
void system_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* turn off watchdog */
|
||||
(*(volatile unsigned long *)0x80002804) = 0;
|
||||
|
||||
/*
|
||||
IRQ_WRITE_WAIT(0x100, 0, v == 0);
|
||||
IRQ_WRITE_WAIT(0x104, 0, v == 0);
|
||||
IRQ_WRITE_WAIT(0, 0, v == 0);
|
||||
IRQ_WRITE_WAIT(4, 0, v == 0);
|
||||
*/
|
||||
|
||||
for (i = 0; i < 0x1c; i++)
|
||||
{
|
||||
IRQ_WRITE_WAIT(0x404 + i * 4, 0x1e000001, (v & 0x3010f) == 1);
|
||||
IRQ_WRITE_WAIT(0x404 + i * 4, 0x4000000, (v & 0x10000) == 0);
|
||||
IRQ_WRITE_WAIT(0x404 + i * 4, 0x10000001, (v & 0xf) == 1);
|
||||
interrupt_vector[i + 1] = undefined_int;
|
||||
}
|
||||
interrupt_vector[0] = undefined_int;
|
||||
}
|
||||
|
||||
|
||||
void system_reboot(void)
|
||||
{
|
||||
(*(volatile unsigned long *)0x80002804) = 1;
|
||||
while (1);
|
||||
}
|
||||
|
||||
int system_memory_guard(int newmode)
|
||||
{
|
||||
(void)newmode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CPU_ARM */
|
||||
#endif /* CONFIG_CPU */
|
||||
|
||||
|
|
229
firmware/target/arm/crt0-pnx0101.S
Normal file
229
firmware/target/arm/crt0-pnx0101.S
Normal file
|
@ -0,0 +1,229 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id: crt0.S 11850 2006-12-29 02:49:12Z markun $
|
||||
*
|
||||
* Copyright (C) 2002 by Linus Nielsen Feltzing
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#define ASM /* do not include structure definitions from pnx0101.h */
|
||||
|
||||
#include "config.h"
|
||||
#include "cpu.h"
|
||||
|
||||
.section .init.text,"ax",%progbits
|
||||
|
||||
.global start
|
||||
start:
|
||||
|
||||
/* Arm 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 <leachbj@bouncycastle.org>
|
||||
*
|
||||
*/
|
||||
|
||||
msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ */
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
#ifndef DEBUG
|
||||
ldr r0, =0x80105000
|
||||
mov r1, #1
|
||||
str r1, [r0, #4]
|
||||
mov r1, #0
|
||||
str r1, [r0, #4]
|
||||
1: ldr r1, [r0]
|
||||
cmp r1, #0
|
||||
bne 1b
|
||||
mov r1, #0x74
|
||||
str r1, [r0, #8]
|
||||
mov r1, #2
|
||||
str r1, [r0, #0x18]
|
||||
mov r1, #2
|
||||
str r1, [r0, #0x20]
|
||||
mov r1, #82
|
||||
str r1, [r0, #0x28]
|
||||
mov r1, #100
|
||||
str r1, [r0, #0x2c]
|
||||
mov r1, #0x120
|
||||
str r1, [r0, #0x30]
|
||||
mov r1, #6
|
||||
str r1, [r0, #4]
|
||||
ldr r0, =1f
|
||||
mov r15, r0
|
||||
1:
|
||||
#endif /* !DEBUG */
|
||||
|
||||
#ifndef DEBUG
|
||||
/* 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
|
||||
#else
|
||||
ldr r1, =vectors
|
||||
ldr r0, =irq_handler
|
||||
str r0, [r1, #24]
|
||||
ldr r0, =fiq_handler
|
||||
str r0, [r1, #28]
|
||||
#endif
|
||||
|
||||
#ifndef STUB
|
||||
/* Zero out IBSS */
|
||||
ldr r2, =_iedata
|
||||
ldr r3, =_iend
|
||||
mov r4, #0
|
||||
1:
|
||||
cmp r3, r2
|
||||
strhi r4, [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
|
||||
#endif /* !STUB */
|
||||
#endif /* !BOOTLOADER */
|
||||
|
||||
/* Initialise bss section to zero */
|
||||
ldr r2, =_edata
|
||||
ldr r3, =_end
|
||||
mov r4, #0
|
||||
1:
|
||||
cmp r3, r2
|
||||
strhi r4, [r2], #4
|
||||
bhi 1b
|
||||
|
||||
/* Set up some stack and munge it with 0xdeadbeef */
|
||||
ldr sp, =stackend
|
||||
mov r3, sp
|
||||
ldr r2, =stackbegin
|
||||
ldr r4, =0xdeadbeef
|
||||
1:
|
||||
cmp r3, r2
|
||||
strhi r4, [r2], #4
|
||||
bhi 1b
|
||||
|
||||
/* Set up stack for IRQ mode */
|
||||
msr cpsr_c, #0xd2
|
||||
ldr sp, =irq_stack
|
||||
/* Set up stack for FIQ mode */
|
||||
msr cpsr_c, #0xd1
|
||||
ldr sp, =fiq_stack
|
||||
|
||||
/* Let abort and undefined modes use IRQ stack */
|
||||
msr cpsr_c, #0xd7
|
||||
ldr sp, =irq_stack
|
||||
msr cpsr_c, #0xdb
|
||||
ldr sp, =irq_stack
|
||||
/* Switch to supervisor mode */
|
||||
msr cpsr_c, #0xd3
|
||||
ldr sp, =stackend
|
||||
bl main
|
||||
/* main() should never return */
|
||||
|
||||
/* 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
|
||||
|
||||
#ifndef STUB
|
||||
.global irq
|
||||
.global fiq
|
||||
.global UIE
|
||||
#endif
|
||||
|
||||
/* 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:
|
||||
mov r0, lr
|
||||
mov r1, #0
|
||||
b UIE
|
||||
|
||||
/* We run supervisor mode most of the time, and should never see a software
|
||||
exception being thrown. Perhaps make it illegal and call UIE?
|
||||
*/
|
||||
software_int_handler:
|
||||
reserved_handler:
|
||||
movs pc, lr
|
||||
|
||||
prefetch_abort_handler:
|
||||
sub r0, lr, #4
|
||||
mov r1, #1
|
||||
b UIE
|
||||
|
||||
fiq_handler:
|
||||
@ Branch straight to FIQ handler in pcm_playback.c. This also handles the
|
||||
@ the correct return sequence.
|
||||
stmfd sp!, {r0-r7, r12, lr}
|
||||
bl fiq
|
||||
ldmfd sp!, {r0-r7, r12, lr}
|
||||
subs pc, lr, #4
|
||||
|
||||
data_abort_handler:
|
||||
sub r0, lr, #8
|
||||
mov r1, #2
|
||||
b UIE
|
||||
|
||||
irq_handler:
|
||||
#ifndef STUB
|
||||
stmfd sp!, {r0-r11, r12, lr}
|
||||
bl irq
|
||||
ldmfd sp!, {r0-r11, r12, lr}
|
||||
#endif
|
||||
subs pc, lr, #4
|
||||
|
||||
#ifdef STUB
|
||||
UIE:
|
||||
b UIE
|
||||
#endif
|
||||
|
||||
/* 256 words of IRQ stack */
|
||||
.space 256*4
|
||||
irq_stack:
|
||||
|
||||
/* 256 words of FIQ stack */
|
||||
.space 256*4
|
||||
fiq_stack:
|
|
@ -34,30 +34,6 @@ start:
|
|||
msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ */
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
#if CONFIG_CPU == PNX0101
|
||||
|
||||
#ifndef DEBUG
|
||||
ldr r0, =0x80105000
|
||||
mov r1, #1
|
||||
str r1, [r0, #4]
|
||||
mov r1, #0
|
||||
str r1, [r0, #4]
|
||||
1: ldr r1, [r0]
|
||||
cmp r1, #0
|
||||
bne 1b
|
||||
mov r1, #0x74
|
||||
str r1, [r0, #8]
|
||||
mov r1, #2
|
||||
str r1, [r0, #0x18]
|
||||
mov r1, #0x120
|
||||
str r1, [r0, #0x30]
|
||||
mov r1, #6
|
||||
str r1, [r0, #4]
|
||||
ldr r0, =1f
|
||||
mov r15, r0
|
||||
1:
|
||||
#endif /* !DEBUG */
|
||||
#endif /* chipset specific */
|
||||
|
||||
#ifndef DEBUG
|
||||
/* Copy exception handler code to address 0 */
|
||||
|
|
351
firmware/target/arm/system-pnx0101.c
Normal file
351
firmware/target/arm/system-pnx0101.c
Normal file
|
@ -0,0 +1,351 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id: $
|
||||
*
|
||||
* Copyright (C) 2007 by Tomasz Malesinski
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "pnx0101.h"
|
||||
#include "system.h"
|
||||
|
||||
static struct
|
||||
{
|
||||
unsigned char freq;
|
||||
unsigned char sys_mult;
|
||||
unsigned char sys_div;
|
||||
unsigned char mem_conf[9];
|
||||
}
|
||||
perf_modes[3] ICONST_ATTR =
|
||||
{
|
||||
{12, 4, 4, {2, 1, 1, 1, 1, 1, 1, 1, 1, 0}},
|
||||
{48, 4, 1, {5, 4, 1, 4, 4, 1, 3, 3, 1, 0}},
|
||||
{60, 5, 1, {6, 5, 1, 5, 5, 1, 4, 3, 1, 1}}
|
||||
};
|
||||
|
||||
static int performance_mode, bus_divider;
|
||||
|
||||
static void cgu_set_sel_stage_input(int clock, int input)
|
||||
{
|
||||
int s = CGU.base_ssr[clock];
|
||||
if (s & 1)
|
||||
CGU.base_fs2[clock] = input;
|
||||
else
|
||||
CGU.base_fs1[clock] = input;
|
||||
CGU.base_scr[clock] = (s & 3) ^ 3;
|
||||
}
|
||||
|
||||
static void cgu_reset_sel_stage_clocks(int first_esr, int n_esr,
|
||||
int first_div, int n_div)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n_esr; i++)
|
||||
CGU.clk_esr[first_esr + i] = 0;
|
||||
for (i = 0; i < n_div; i++)
|
||||
CGU.base_fdc[first_div + i] = 0;
|
||||
}
|
||||
|
||||
static void cgu_configure_div(int div, int n, int m)
|
||||
{
|
||||
int msub, madd, div_size, max_n;
|
||||
unsigned long cfg;
|
||||
|
||||
if (n == m)
|
||||
{
|
||||
CGU.base_fdc[div] = CGU.base_fdc[div] & ~1;
|
||||
return;
|
||||
}
|
||||
|
||||
msub = -n;
|
||||
madd = m - n;
|
||||
div_size = (div == PNX0101_HIPREC_FDC) ? 10 : 8;
|
||||
max_n = 1 << div_size;
|
||||
while ((madd << 1) < max_n && (msub << 1) >= -max_n)
|
||||
{
|
||||
madd <<= 1;
|
||||
msub <<= 1;
|
||||
}
|
||||
cfg = (((msub << div_size) | madd) << 3) | 4;
|
||||
CGU.base_fdc[div] = CGU.base_fdc[div] & ~1;
|
||||
CGU.base_fdc[div] = cfg | 2;
|
||||
CGU.base_fdc[div] = cfg;
|
||||
CGU.base_fdc[div] = cfg | 1;
|
||||
}
|
||||
|
||||
static void cgu_connect_div_to_clock(int rel_div, int esr)
|
||||
{
|
||||
CGU.clk_esr[esr] = (rel_div << 1) | 1;
|
||||
}
|
||||
|
||||
static void cgu_disconnect_div_from_clock(int esr)
|
||||
{
|
||||
CGU.clk_esr[esr] = 0;
|
||||
}
|
||||
|
||||
static void cgu_enable_clock(int clock)
|
||||
{
|
||||
CGU.clk_pcr[clock] |= 1;
|
||||
}
|
||||
|
||||
static void cgu_start_sel_stage_dividers(int bcr)
|
||||
{
|
||||
CGU.base_bcr[bcr] = 1;
|
||||
}
|
||||
|
||||
/* Convert a pointer that points to IRAM (0x4xxxx) to a pointer that
|
||||
points to the uncached page (0x0xxxx) that is also mapped to IRAM. */
|
||||
static inline void *noncached(void *p) {
|
||||
return (void *)(((unsigned long)p) & 0xffff);
|
||||
}
|
||||
|
||||
/* TODO: if it works, then comment it */
|
||||
static void do_set_mem_timings(int mode) ICODE_ATTR;
|
||||
static void do_set_mem_timings(int mode)
|
||||
{
|
||||
unsigned char *mem_conf = noncached(perf_modes[mode].mem_conf);
|
||||
int old_irq = set_irq_level(HIGHEST_IRQ_LEVEL);
|
||||
while ((EMC.status & 3) != 0);
|
||||
EMC.control = 5;
|
||||
EMCSTATIC0.waitrd = mem_conf[0];
|
||||
EMCSTATIC0.waitwr = mem_conf[1];
|
||||
EMCSTATIC1.waitrd = mem_conf[3];
|
||||
EMCSTATIC1.waitwr = mem_conf[4];
|
||||
EMCSTATIC2.waitrd = mem_conf[6];
|
||||
EMCSTATIC2.waitwr = mem_conf[7];
|
||||
EMCSTATIC0.waitoen = mem_conf[2];
|
||||
EMCSTATIC1.waitoen = mem_conf[5];
|
||||
EMCSTATIC2.waitoen = mem_conf[8];
|
||||
#ifndef DEBUG
|
||||
EMCSTATIC1.config = mem_conf[9] ? 0x80081 : 0x81;
|
||||
#endif
|
||||
EMC.control = 1;
|
||||
set_irq_level(old_irq);
|
||||
}
|
||||
|
||||
static void emc_set_mem_timings(int mode) {
|
||||
void (*f)(int) = noncached(do_set_mem_timings);
|
||||
(*f)(mode);
|
||||
}
|
||||
|
||||
/*
|
||||
static void do_enable_write_buffers(int on) ICODE_ATTR;
|
||||
static void do_enable_write_buffers(int on) {
|
||||
int old_irq = set_irq_level(HIGHEST_IRQ_LEVEL);
|
||||
while ((EMC.status & 3) != 0);
|
||||
EMC.control = 5;
|
||||
EMCSTATIC1.config = on ? 0x80081 : 0x81;
|
||||
EMC.control = 1;
|
||||
set_irq_level(old_irq);
|
||||
}
|
||||
|
||||
void emc_enable_write_buffers(int on) {
|
||||
void (*f)(int) = noncached(do_enable_write_buffers);
|
||||
(*f)(on);
|
||||
}
|
||||
*/
|
||||
|
||||
/* can it be replaced? */
|
||||
static void cgu_busy_wait(int n)
|
||||
{
|
||||
while (n > 0)
|
||||
{
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
static void cgu_set_sys_mult(int i)
|
||||
{
|
||||
cgu_set_sel_stage_input(PNX0101_SEL_STAGE_SYS, PNX0101_MAIN_CLOCK_FAST);
|
||||
cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB3, PNX0101_MAIN_CLOCK_FAST);
|
||||
|
||||
PLL.lppdn = 1;
|
||||
PLL.lpfin = 1;
|
||||
PLL.lpmbyp = 0;
|
||||
PLL.lpdbyp = 0;
|
||||
PLL.lppsel = 1;
|
||||
PLL.lpmsel = i - 1;
|
||||
PLL.lppdn = 0;
|
||||
while (!PLL.lplock);
|
||||
|
||||
cgu_configure_div(PNX0101_FIRST_DIV_SYS + 1, 1, (i == 5) ? 15 : 12);
|
||||
cgu_connect_div_to_clock(1, 0x11);
|
||||
cgu_enable_clock(0x11);
|
||||
cgu_start_sel_stage_dividers(PNX0101_BCR_SYS);
|
||||
|
||||
cgu_set_sel_stage_input(PNX0101_SEL_STAGE_SYS,
|
||||
PNX0101_MAIN_CLOCK_MAIN_PLL);
|
||||
cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB3,
|
||||
PNX0101_MAIN_CLOCK_MAIN_PLL);
|
||||
}
|
||||
|
||||
static void pnx0101_set_performance_mode(int mode)
|
||||
{
|
||||
int old = performance_mode;
|
||||
if (perf_modes[old].freq < perf_modes[mode].freq)
|
||||
{
|
||||
emc_set_mem_timings(mode);
|
||||
if (perf_modes[old].sys_mult != perf_modes[mode].sys_mult)
|
||||
cgu_set_sys_mult(perf_modes[mode].sys_mult);
|
||||
if (perf_modes[old].sys_div != perf_modes[mode].sys_div)
|
||||
cgu_configure_div(bus_divider, 1, perf_modes[mode].sys_div);
|
||||
}
|
||||
else if (perf_modes[old].freq > perf_modes[mode].freq)
|
||||
{
|
||||
if (perf_modes[old].sys_mult != perf_modes[mode].sys_mult)
|
||||
cgu_set_sys_mult(perf_modes[mode].sys_mult);
|
||||
if (perf_modes[old].sys_div != perf_modes[mode].sys_div)
|
||||
cgu_configure_div(bus_divider, 1, perf_modes[mode].sys_div);
|
||||
emc_set_mem_timings(mode);
|
||||
}
|
||||
performance_mode = mode;
|
||||
}
|
||||
|
||||
static void pnx0101_init_clocks(void)
|
||||
{
|
||||
bus_divider = PNX0101_FIRST_DIV_SYS + (CGU.clk_esr[0] >> 1);
|
||||
performance_mode = 0;
|
||||
pnx0101_set_performance_mode(2);
|
||||
/*
|
||||
#ifndef DEBUG
|
||||
emc_enable_write_buffers(1);
|
||||
#endif
|
||||
*/
|
||||
cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB1,
|
||||
PNX0101_MAIN_CLOCK_FAST);
|
||||
cgu_reset_sel_stage_clocks(PNX0101_FIRST_ESR_APB1, PNX0101_N_ESR_APB1,
|
||||
PNX0101_FIRST_DIV_APB1, PNX0101_N_DIV_APB1);
|
||||
cgu_configure_div(PNX0101_FIRST_DIV_APB1, 1, 4);
|
||||
cgu_connect_div_to_clock(0, PNX0101_ESR_APB1);
|
||||
cgu_connect_div_to_clock(0, PNX0101_ESR_T0);
|
||||
cgu_connect_div_to_clock(0, PNX0101_ESR_T1);
|
||||
cgu_connect_div_to_clock(0, PNX0101_ESR_I2C);
|
||||
cgu_enable_clock(PNX0101_CLOCK_APB1);
|
||||
cgu_enable_clock(PNX0101_CLOCK_T0);
|
||||
cgu_enable_clock(PNX0101_CLOCK_T1);
|
||||
cgu_enable_clock(PNX0101_CLOCK_I2C);
|
||||
}
|
||||
|
||||
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
||||
void set_cpu_frequency(long frequency)
|
||||
{
|
||||
switch (frequency)
|
||||
{
|
||||
case CPUFREQ_MAX:
|
||||
pnx0101_set_performance_mode(2);
|
||||
cpu_frequency = CPUFREQ_MAX;
|
||||
break;
|
||||
case CPUFREQ_NORMAL:
|
||||
pnx0101_set_performance_mode(1);
|
||||
cpu_frequency = CPUFREQ_NORMAL;
|
||||
break;
|
||||
case CPUFREQ_DEFAULT:
|
||||
default:
|
||||
pnx0101_set_performance_mode(0);
|
||||
cpu_frequency = CPUFREQ_DEFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
interrupt_handler_t interrupt_vector[0x1d] __attribute__ ((section(".idata")));
|
||||
|
||||
#define IRQ_READ(reg, dest) \
|
||||
do { unsigned long v2; \
|
||||
do { \
|
||||
dest = (reg); \
|
||||
v2 = (reg); \
|
||||
} while ((dest != v2)); \
|
||||
} while (0);
|
||||
|
||||
#define IRQ_WRITE_WAIT(reg, val, cond) \
|
||||
do { unsigned long v, v2; \
|
||||
do { \
|
||||
(reg) = (val); \
|
||||
v = (reg); \
|
||||
v2 = (reg); \
|
||||
} while ((v != v2) || !(cond)); \
|
||||
} while (0);
|
||||
|
||||
static void undefined_int(void)
|
||||
{
|
||||
}
|
||||
|
||||
void irq(void)
|
||||
{
|
||||
int n;
|
||||
IRQ_READ(INTVECTOR[0], n)
|
||||
(*(interrupt_vector[n >> 3]))();
|
||||
}
|
||||
|
||||
void fiq(void)
|
||||
{
|
||||
}
|
||||
|
||||
void irq_enable_int(int n)
|
||||
{
|
||||
IRQ_WRITE_WAIT(INTREQ[n], INTREQ_WEENABLE | INTREQ_ENABLE, v & 0x10000);
|
||||
}
|
||||
|
||||
void irq_disable_int(int n)
|
||||
{
|
||||
IRQ_WRITE_WAIT(INTREQ[n], INTREQ_WEENABLE, (v & 0x10000) == 0);
|
||||
}
|
||||
|
||||
void irq_set_int_handler(int n, interrupt_handler_t handler)
|
||||
{
|
||||
interrupt_vector[n] = handler;
|
||||
}
|
||||
|
||||
void system_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* turn off watchdog */
|
||||
(*(volatile unsigned long *)0x80002804) = 0;
|
||||
|
||||
/*
|
||||
IRQ_WRITE_WAIT(INTVECTOR[0], 0, v == 0);
|
||||
IRQ_WRITE_WAIT(INTVECTOR[1], 0, v == 0);
|
||||
IRQ_WRITE_WAIT(INTPRIOMASK[0], 0, v == 0);
|
||||
IRQ_WRITE_WAIT(INTPRIOMASK[1], 0, v == 0);
|
||||
*/
|
||||
|
||||
for (i = 0; i < 0x1c; i++)
|
||||
{
|
||||
IRQ_WRITE_WAIT(INTREQ[i],
|
||||
INTREQ_WEPRIO | INTREQ_WETARGET |
|
||||
INTREQ_WEENABLE | INTREQ_WEACTVLO | 1,
|
||||
(v & 0x3010f) == 1);
|
||||
IRQ_WRITE_WAIT(INTREQ[i], INTREQ_WEENABLE, (v & 0x10000) == 0);
|
||||
IRQ_WRITE_WAIT(INTREQ[i], INTREQ_WEPRIO | 1, (v & 0xf) == 1);
|
||||
interrupt_vector[i + 1] = undefined_int;
|
||||
}
|
||||
interrupt_vector[0] = undefined_int;
|
||||
pnx0101_init_clocks();
|
||||
}
|
||||
|
||||
|
||||
void system_reboot(void)
|
||||
{
|
||||
(*(volatile unsigned long *)0x80002804) = 1;
|
||||
while (1);
|
||||
}
|
||||
|
||||
int system_memory_guard(int newmode)
|
||||
{
|
||||
(void)newmode;
|
||||
return 0;
|
||||
}
|
|
@ -28,7 +28,7 @@ static void (*pfn_timer)(void) = NULL; /* timer callback */
|
|||
static void (*pfn_unregister)(void) = NULL; /* unregister callback */
|
||||
#ifdef CPU_COLDFIRE
|
||||
static int base_prescale;
|
||||
#elif defined CPU_PP
|
||||
#elif defined CPU_PP || CONFIG_CPU == PNX0101
|
||||
static long cycles_new = 0;
|
||||
#endif
|
||||
|
||||
|
@ -67,6 +67,24 @@ void TIMER2(void)
|
|||
cycles_new = 0;
|
||||
}
|
||||
}
|
||||
#elif CONFIG_CPU == PNX0101
|
||||
void TIMER1_ISR(void)
|
||||
{
|
||||
if (cycles_new > 0)
|
||||
{
|
||||
TIMER1.load = 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;
|
||||
}
|
||||
TIMER1.clr = 1; /* clear the interrupt */
|
||||
}
|
||||
#endif /* CONFIG_CPU */
|
||||
|
||||
static bool timer_set(long cycles, bool start)
|
||||
|
@ -85,8 +103,26 @@ static bool timer_set(long cycles, bool start)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_CPU == PNX0101 /* TODO: Implement for iFP */
|
||||
(void)start;
|
||||
#if CONFIG_CPU == PNX0101
|
||||
if (start)
|
||||
{
|
||||
if (pfn_unregister != NULL)
|
||||
{
|
||||
pfn_unregister();
|
||||
pfn_unregister = NULL;
|
||||
}
|
||||
TIMER1.ctrl &= ~0x80; /* disable the counter */
|
||||
TIMER1.ctrl |= 0x40; /* reload after counting down to zero */
|
||||
TIMER1.ctrl &= ~0xc; /* no prescaler */
|
||||
TIMER1.clr = 1; /* clear an interrupt event */
|
||||
}
|
||||
if (start || (cycles_new == -1)) /* within isr, cycles_new is "locked" */
|
||||
{ /* enable timer */
|
||||
TIMER1.load = cycles - 1;
|
||||
TIMER1.ctrl |= 0x80; /* enable the counter */
|
||||
}
|
||||
else
|
||||
cycles_new = cycles;
|
||||
#endif
|
||||
|
||||
#if CONFIG_CPU == SH7034
|
||||
|
@ -229,6 +265,9 @@ bool timer_register(int reg_prio, void (*unregister_callback)(void),
|
|||
#elif defined(CPU_PP)
|
||||
/* unmask interrupt source */
|
||||
CPU_INT_EN = TIMER2_MASK;
|
||||
#elif CONFIG_CPU == PNX0101
|
||||
irq_set_int_handler(IRQ_TIMER1, TIMER1_ISR);
|
||||
irq_enable_int(IRQ_TIMER1);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
@ -249,6 +288,9 @@ void timer_unregister(void)
|
|||
#elif defined(CPU_PP)
|
||||
TIMER2_CFG = 0; /* stop timer 2 */
|
||||
CPU_INT_CLR = TIMER2_MASK;
|
||||
#elif CONFIG_CPU == PNX0101
|
||||
TIMER1.ctrl &= ~0x80; /* disable timer 1 */
|
||||
irq_disable_int(5);
|
||||
#endif
|
||||
pfn_timer = NULL;
|
||||
pfn_unregister = NULL;
|
||||
|
|
Loading…
Reference in a new issue