From d95c39072ace1a7aeaad3ee49ed668399b4862bd Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Fri, 13 Apr 2007 20:55:48 +0000 Subject: [PATCH] Portal Player: Add invalidate_icache and flush_icache. Flush the cache on the core for newborn threads. In doing so, move more ARM stuff to the target tree and organize it to make a clean job of it. If anything isn't appropriate for some particular device give a hollar or even just fix it by some added #ifdefing. I was informed that the PP targets are register compatible so I'm going off that advice. The Sansa likes it though. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13144 a1c6a512-1295-4272-9138-f99709370657 --- firmware/export/system.h | 167 +----------------- firmware/rolo.c | 6 +- .../{system-target.h => system-meg-fx.h} | 1 + .../target/arm/sandisk/sansa-e200/lcd-e200.c | 14 +- firmware/target/arm/system-pp.h | 49 +++++ firmware/target/arm/system-target.h | 155 ++++++++++++++++ firmware/target/coldfire/system-target.h | 4 + firmware/thread.c | 47 ++++- 8 files changed, 263 insertions(+), 180 deletions(-) rename firmware/target/arm/gigabeat/meg-fx/{system-target.h => system-meg-fx.h} (97%) create mode 100644 firmware/target/arm/system-pp.h create mode 100644 firmware/target/arm/system-target.h diff --git a/firmware/export/system.h b/firmware/export/system.h index b32d1d3a21..19ce7a4d6a 100644 --- a/firmware/export/system.h +++ b/firmware/export/system.h @@ -29,24 +29,6 @@ extern void system_init(void); extern long cpu_frequency; -#ifdef CPU_PP -#define inl(a) (*(volatile unsigned long *) (a)) -#define outl(a,b) (*(volatile unsigned long *) (b) = (a)) -#define inb(a) (*(volatile unsigned char *) (a)) -#define outb(a,b) (*(volatile unsigned char *) (b) = (a)) -#define inw(a) (*(volatile unsigned short *) (a)) -#define outw(a,b) (*(volatile unsigned short *) (b) = (a)) -extern unsigned int ipod_hw_rev; - -static inline void udelay(unsigned usecs) -{ - unsigned stop = USEC_TIMER + usecs; - while (TIME_BEFORE(USEC_TIMER, stop)); -} - -unsigned int current_core(void); -#endif - struct flash_header { unsigned long magic; unsigned long length; @@ -173,10 +155,6 @@ int get_cpu_boost_counter(void); #define H_TO_BE32(x) (x) #endif - -#define nop \ - asm volatile ("nop") - /* gcc 3.4 changed the format of the constraints */ #if (__GNUC__ >= 3) && (__GNUC_MINOR__ > 3) || (__GNUC__ >= 4) #define I_CONSTRAINT "I08" @@ -196,141 +174,7 @@ enum { }; #ifndef SIMULATOR -#if defined(CPU_COLDFIRE) || (CONFIG_CPU == S3C2440) || (CONFIG_CPU == SH7034) #include "system-target.h" -#endif -#endif - -#ifndef SIMULATOR - -#if defined(CPU_ARM) - -/* TODO: Implement set_irq_level and check CPU frequencies */ - -#if CONFIG_CPU == S3C2440 - -#define CPUFREQ_DEFAULT 98784000 -#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 -#define CPUFREQ_DEFAULT 24000000 -#define CPUFREQ_NORMAL_MULT 10 -#define CPUFREQ_NORMAL 30000000 -#define CPUFREQ_MAX_MULT 25 -#define CPUFREQ_MAX 75000000 - -#endif - -static inline uint16_t swap16(uint16_t value) - /* - result[15..8] = value[ 7..0]; - result[ 7..0] = value[15..8]; - */ -{ - return (value >> 8) | (value << 8); -} - -static inline uint32_t swap32(uint32_t value) - /* - result[31..24] = value[ 7.. 0]; - result[23..16] = value[15.. 8]; - result[15.. 8] = value[23..16]; - result[ 7.. 0] = value[31..24]; - */ -{ - uint32_t tmp; - - asm volatile ( - "eor %1, %0, %0, ror #16 \n\t" - "bic %1, %1, #0xff0000 \n\t" - "mov %0, %0, ror #8 \n\t" - "eor %0, %0, %1, lsr #8 \n\t" - : "+r" (value), "=r" (tmp) - ); - return value; -} - -static inline uint32_t swap_odd_even32(uint32_t value) -{ - /* - result[31..24],[15.. 8] = value[23..16],[ 7.. 0] - result[23..16],[ 7.. 0] = value[31..24],[15.. 8] - */ - uint32_t tmp; - - asm volatile ( /* ABCD */ - "bic %1, %0, #0x00ff00 \n\t" /* AB.D */ - "bic %0, %0, #0xff0000 \n\t" /* A.CD */ - "mov %0, %0, lsr #8 \n\t" /* .A.C */ - "orr %0, %0, %1, lsl #8 \n\t" /* B.D.|.A.C */ - : "+r" (value), "=r" (tmp) /* BADC */ - ); - return value; -} - -#define HIGHEST_IRQ_LEVEL (1) - -static inline int set_irq_level(int level) -{ - unsigned long cpsr; - /* Read the old level and set the new one */ - asm volatile ("mrs %0,cpsr" : "=r" (cpsr)); - asm volatile ("msr cpsr_c,%0" - : : "r" ((cpsr & ~0x80) | (level << 7))); - return (cpsr >> 7) & 1; -} - -static inline void set_fiq_handler(void(*fiq_handler)(void)) -{ - /* Install the FIQ handler */ - *((unsigned int*)(15*4)) = (unsigned int)fiq_handler; -} - -static inline void enable_fiq(void) -{ - /* Clear FIQ disable bit */ - asm volatile ( - "mrs r0, cpsr \n"\ - "bic r0, r0, #0x40 \n"\ - "msr cpsr_c, r0 " - : : : "r0" - ); -} - -static inline void disable_fiq(void) -{ - /* Set FIQ disable bit */ - asm volatile ( - "mrs r0, cpsr \n"\ - "orr r0, r0, #0x40 \n"\ - "msr cpsr_c, r0 " - : : : "r0" - ); -} - -#if CONFIG_CPU != S3C2440 -#define invalidate_icache() -#endif - -#if CONFIG_CPU == PNX0101 -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 - #else /* SIMULATOR */ static inline uint16_t swap16(uint16_t value) @@ -365,8 +209,15 @@ static inline uint32_t swap_odd_even32(uint32_t value) return (t >> 8) | ((t ^ value) << 8); } -#define invalidate_icache() - #endif /* !SIMULATOR */ +/* Just define these as empty if not declared */ +#ifndef HAVE_INVALIDATE_ICACHE +#define invalidate_icache() +#endif + +#ifndef HAVE_FLUSH_ICACHE +#define flush_icache() +#endif + #endif /* __SYSTEM_H__ */ diff --git a/firmware/rolo.c b/firmware/rolo.c index 0689e8be5b..0375a7ac82 100644 --- a/firmware/rolo.c +++ b/firmware/rolo.c @@ -49,8 +49,7 @@ void rolo_restart_cop(void) ICODE_ATTR; void rolo_restart_cop(void) { /* Invalidate cache */ - outl(inl(0xf000f044) | 0x6, 0xf000f044); - while ((CACHE_CTL & 0x8000) != 0) {} + invalidate_icache(); /* Disable cache */ CACHE_CTL = CACHE_DISABLE; @@ -119,8 +118,7 @@ void rolo_restart(const unsigned char* source, unsigned char* dest, cpu_message = 0; /* Flush cache */ - outl(inl(0xf000f044) | 0x2, 0xf000f044); - while ((CACHE_CTL & 0x8000) != 0) {} + flush_icache(); /* Disable cache */ CACHE_CTL = CACHE_DISABLE; diff --git a/firmware/target/arm/gigabeat/meg-fx/system-target.h b/firmware/target/arm/gigabeat/meg-fx/system-meg-fx.h similarity index 97% rename from firmware/target/arm/gigabeat/meg-fx/system-target.h rename to firmware/target/arm/gigabeat/meg-fx/system-meg-fx.h index e5d15d643e..7d598af360 100644 --- a/firmware/target/arm/gigabeat/meg-fx/system-target.h +++ b/firmware/target/arm/gigabeat/meg-fx/system-meg-fx.h @@ -19,6 +19,7 @@ #include "mmu-meg-fx.h" +#define HAVE_INVALIDATE_ICACHE static inline void invalidate_icache(void) { clean_dcache(); diff --git a/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c b/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c index 3e8246b367..93d79633b1 100644 --- a/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c +++ b/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c @@ -112,16 +112,6 @@ static inline void lcd_write_reg(unsigned int reg, unsigned int data) lcd_send_msg(0x72, data); } -static inline void cache_flush(void) -{ -#ifndef BOOTLOADER - outl(inl(0xf000f044) | 0x2, 0xf000f044); - while ((CACHE_CTL & 0x8000) != 0) - { - } -#endif -} - /* The LCD controller gets passed the address of the framebuffer, but can only use the physical, not the remapped, address. This is a quick and dirty way of correcting it */ @@ -271,7 +261,7 @@ inline void lcd_update_rect(int x, int y, int width, int height) memcpy(((char*)&lcd_driver_framebuffer)+(y * sizeof(fb_data) * LCD_WIDTH), ((char *)&lcd_framebuffer)+(y * sizeof(fb_data) * LCD_WIDTH), ((height * sizeof(fb_data) * LCD_WIDTH))); - cache_flush(); + flush_icache(); /* Restart DMA */ LCD_REG_6 |= 1; @@ -287,7 +277,7 @@ inline void lcd_update(void) /* Copy the Rockbox framebuffer to the second framebuffer */ memcpy(lcd_driver_framebuffer, lcd_framebuffer, sizeof(fb_data) * LCD_WIDTH * LCD_HEIGHT); - cache_flush(); + flush_icache(); /* Restart DMA */ LCD_REG_6 |= 1; diff --git a/firmware/target/arm/system-pp.h b/firmware/target/arm/system-pp.h new file mode 100644 index 0000000000..05fd8b6edf --- /dev/null +++ b/firmware/target/arm/system-pp.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * Copyright (C) 2007 by Michael Sevakis + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#define inl(a) (*(volatile unsigned long *) (a)) +#define outl(a,b) (*(volatile unsigned long *) (b) = (a)) +#define inb(a) (*(volatile unsigned char *) (a)) +#define outb(a,b) (*(volatile unsigned char *) (b) = (a)) +#define inw(a) (*(volatile unsigned short *) (a)) +#define outw(a,b) (*(volatile unsigned short *) (b) = (a)) +extern unsigned int ipod_hw_rev; + +static inline void udelay(unsigned usecs) +{ + unsigned stop = USEC_TIMER + usecs; + while (TIME_BEFORE(USEC_TIMER, stop)); +} + +unsigned int current_core(void); + +#define HAVE_INVALIDATE_ICACHE +static inline void invalidate_icache(void) +{ + outl(inl(0xf000f044) | 0x6, 0xf000f044); + while ((CACHE_CTL & 0x8000) != 0); +} + +#define HAVE_FLUSH_ICACHE +static inline void flush_icache(void) +{ + outl(inl(0xf000f044) | 0x2, 0xf000f044); + while ((CACHE_CTL & 0x8000) != 0); +} diff --git a/firmware/target/arm/system-target.h b/firmware/target/arm/system-target.h new file mode 100644 index 0000000000..ceb8be2079 --- /dev/null +++ b/firmware/target/arm/system-target.h @@ -0,0 +1,155 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef SYSTEM_TARGET_H +#define SYSTEM_TARGET_H + +#define nop \ + asm volatile ("nop") + +/* This gets too complicated otherwise with all the ARM variation and would + have conflicts with another system-target.h elsewhere so include a + subheader from here. */ + +#ifdef CPU_PP +#include "system-pp.h" +#elif CONFIG_CPU == S3C2440 +#include "system-meg-fx.h" +#endif + +/* TODO: Implement set_irq_level and check CPU frequencies */ + +#if CONFIG_CPU == S3C2440 + +#define CPUFREQ_DEFAULT 98784000 +#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 +#define CPUFREQ_DEFAULT 24000000 +#define CPUFREQ_NORMAL_MULT 10 +#define CPUFREQ_NORMAL 30000000 +#define CPUFREQ_MAX_MULT 25 +#define CPUFREQ_MAX 75000000 + +#endif + +static inline uint16_t swap16(uint16_t value) + /* + result[15..8] = value[ 7..0]; + result[ 7..0] = value[15..8]; + */ +{ + return (value >> 8) | (value << 8); +} + +static inline uint32_t swap32(uint32_t value) + /* + result[31..24] = value[ 7.. 0]; + result[23..16] = value[15.. 8]; + result[15.. 8] = value[23..16]; + result[ 7.. 0] = value[31..24]; + */ +{ + uint32_t tmp; + + asm volatile ( + "eor %1, %0, %0, ror #16 \n\t" + "bic %1, %1, #0xff0000 \n\t" + "mov %0, %0, ror #8 \n\t" + "eor %0, %0, %1, lsr #8 \n\t" + : "+r" (value), "=r" (tmp) + ); + return value; +} + +static inline uint32_t swap_odd_even32(uint32_t value) +{ + /* + result[31..24],[15.. 8] = value[23..16],[ 7.. 0] + result[23..16],[ 7.. 0] = value[31..24],[15.. 8] + */ + uint32_t tmp; + + asm volatile ( /* ABCD */ + "bic %1, %0, #0x00ff00 \n\t" /* AB.D */ + "bic %0, %0, #0xff0000 \n\t" /* A.CD */ + "mov %0, %0, lsr #8 \n\t" /* .A.C */ + "orr %0, %0, %1, lsl #8 \n\t" /* B.D.|.A.C */ + : "+r" (value), "=r" (tmp) /* BADC */ + ); + return value; +} + +#define HIGHEST_IRQ_LEVEL (1) + +static inline int set_irq_level(int level) +{ + unsigned long cpsr; + /* Read the old level and set the new one */ + asm volatile ("mrs %0,cpsr" : "=r" (cpsr)); + asm volatile ("msr cpsr_c,%0" + : : "r" ((cpsr & ~0x80) | (level << 7))); + return (cpsr >> 7) & 1; +} + +static inline void set_fiq_handler(void(*fiq_handler)(void)) +{ + /* Install the FIQ handler */ + *((unsigned int*)(15*4)) = (unsigned int)fiq_handler; +} + +static inline void enable_fiq(void) +{ + /* Clear FIQ disable bit */ + asm volatile ( + "mrs r0, cpsr \n"\ + "bic r0, r0, #0x40 \n"\ + "msr cpsr_c, r0 " + : : : "r0" + ); +} + +static inline void disable_fiq(void) +{ + /* Set FIQ disable bit */ + asm volatile ( + "mrs r0, cpsr \n"\ + "orr r0, r0, #0x40 \n"\ + "msr cpsr_c, r0 " + : : : "r0" + ); +} + +#if CONFIG_CPU == PNX0101 +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 /* SYSTEM_TARGET_H */ diff --git a/firmware/target/coldfire/system-target.h b/firmware/target/coldfire/system-target.h index 40542353be..6f1b2eb4ae 100644 --- a/firmware/target/coldfire/system-target.h +++ b/firmware/target/coldfire/system-target.h @@ -19,6 +19,9 @@ #ifndef SYSTEM_TARGET_H #define SYSTEM_TARGET_H +#define nop \ + asm volatile ("trapf") + #define or_l(mask, address) \ asm \ ("or.l %0,(%1)" \ @@ -147,6 +150,7 @@ static inline uint32_t swap_odd_even32(uint32_t value) return value; } +#define HAVE_INVALIDATE_ICACHE static inline void invalidate_icache(void) { asm volatile ("move.l #0x01000000,%d0\n" diff --git a/firmware/thread.c b/firmware/thread.c index a803e4f78d..275f04d029 100644 --- a/firmware/thread.c +++ b/firmware/thread.c @@ -64,12 +64,15 @@ int *cop_stackend = stackend; #endif #if NUM_CORES > 1 +#if 0 static long cores_locked IBSS_ATTR; #define LOCK(...) do { } while (test_and_set(&cores_locked, 1)) #define UNLOCK(...) cores_locked = 0 +#endif #warning "Core locking mechanism should be fixed on H10/4G!" + inline void lock_cores(void) { #if 0 @@ -125,15 +128,47 @@ static inline void store_context(void* addr) * Load non-volatile context. *--------------------------------------------------------------------------- */ +static void start_thread(void (*thread_func)(void), const void* addr) __attribute__((naked)); +static void start_thread(void (*thread_func)(void), const void* addr) +{ + /* r0 = thread_func, r1 = addr */ +#if NUM_CORES > 1 + asm volatile ( + "mov r2, #0 \n" + "str r2, [r1, #40] \n" + "ldr r1, =0xf000f044 \n" /* invalidate this core's cache */ + "ldr r2, [r1] \n" + "orr r2, r2, #6 \n" + "str r2, [r1] \n" + "ldr r1, =0x6000c000 \n" + "1: \n" + "ldr r2, [r1] \n" + "tst r2, #0x8000 \n" + "bne 1b \n" + "mov pc, r0 \n" + : : : "r1", "r2" + ); +#else + asm volatile ( + "mov r2, #0 \n" + "str r2, [r1, #40] \n" + "mov pc, r0 \n" + : : : "r1", "r2" + ); +#endif + (void)thread_func; + (void)addr; + (void)start_thread; +} + static inline void load_context(const void* addr) { asm volatile( - "ldmia %0, { r4-r11, sp, lr }\n" /* load regs r4 to r14 from context */ - "ldr r0, [%0, #40] \n" /* load start pointer */ - "mov r1, #0 \n" - "cmp r0, r1 \n" /* check for NULL */ - "strne r1, [%0, #40] \n" /* if it's NULL, we're already running */ - "movne pc, r0 \n" /* not already running, so jump to start */ + "ldmia %0, { r4-r11, sp, lr } \n" /* load regs r4 to r14 from context */ + "ldr r0, [%0, #40] \n" /* load start pointer */ + "cmp r0, #0 \n" /* check for NULL */ + "movne r1, %0 \n" /* if not already running, jump to start */ + "ldrne pc, =start_thread \n" : : "r" (addr) : "r0", "r1" ); }