diff options
Diffstat (limited to 'arch/blackfin/include')
44 files changed, 2356 insertions, 707 deletions
diff --git a/arch/blackfin/include/asm/atomic.h b/arch/blackfin/include/asm/atomic.h index 25776c19064b..94b2a9b19451 100644 --- a/arch/blackfin/include/asm/atomic.h +++ b/arch/blackfin/include/asm/atomic.h @@ -15,104 +15,159 @@ */ #define ATOMIC_INIT(i) { (i) } - -#define atomic_read(v) ((v)->counter) #define atomic_set(v, i) (((v)->counter) = i) -static __inline__ void atomic_add(int i, atomic_t * v) +#ifdef CONFIG_SMP + +#define atomic_read(v) __raw_uncached_fetch_asm(&(v)->counter) + +asmlinkage int __raw_uncached_fetch_asm(const volatile int *ptr); + +asmlinkage int __raw_atomic_update_asm(volatile int *ptr, int value); + +asmlinkage int __raw_atomic_clear_asm(volatile int *ptr, int value); + +asmlinkage int __raw_atomic_set_asm(volatile int *ptr, int value); + +asmlinkage int __raw_atomic_xor_asm(volatile int *ptr, int value); + +asmlinkage int __raw_atomic_test_asm(const volatile int *ptr, int value); + +static inline void atomic_add(int i, atomic_t *v) +{ + __raw_atomic_update_asm(&v->counter, i); +} + +static inline void atomic_sub(int i, atomic_t *v) +{ + __raw_atomic_update_asm(&v->counter, -i); +} + +static inline int atomic_add_return(int i, atomic_t *v) +{ + return __raw_atomic_update_asm(&v->counter, i); +} + +static inline int atomic_sub_return(int i, atomic_t *v) +{ + return __raw_atomic_update_asm(&v->counter, -i); +} + +static inline void atomic_inc(volatile atomic_t *v) +{ + __raw_atomic_update_asm(&v->counter, 1); +} + +static inline void atomic_dec(volatile atomic_t *v) +{ + __raw_atomic_update_asm(&v->counter, -1); +} + +static inline void atomic_clear_mask(int mask, atomic_t *v) +{ + __raw_atomic_clear_asm(&v->counter, mask); +} + +static inline void atomic_set_mask(int mask, atomic_t *v) +{ + __raw_atomic_set_asm(&v->counter, mask); +} + +static inline int atomic_test_mask(int mask, atomic_t *v) +{ + return __raw_atomic_test_asm(&v->counter, mask); +} + +/* Atomic operations are already serializing */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + +#else /* !CONFIG_SMP */ + +#define atomic_read(v) ((v)->counter) + +static inline void atomic_add(int i, atomic_t *v) { long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter += i; - local_irq_restore(flags); + local_irq_restore_hw(flags); } -static __inline__ void atomic_sub(int i, atomic_t * v) +static inline void atomic_sub(int i, atomic_t *v) { long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter -= i; - local_irq_restore(flags); + local_irq_restore_hw(flags); } -static inline int atomic_add_return(int i, atomic_t * v) +static inline int atomic_add_return(int i, atomic_t *v) { int __temp = 0; long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter += i; __temp = v->counter; - local_irq_restore(flags); + local_irq_restore_hw(flags); return __temp; } -#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) -static inline int atomic_sub_return(int i, atomic_t * v) +static inline int atomic_sub_return(int i, atomic_t *v) { int __temp = 0; long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter -= i; __temp = v->counter; - local_irq_restore(flags); + local_irq_restore_hw(flags); return __temp; } -static __inline__ void atomic_inc(volatile atomic_t * v) +static inline void atomic_inc(volatile atomic_t *v) { long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter++; - local_irq_restore(flags); + local_irq_restore_hw(flags); } -#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) -#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) - -#define atomic_add_unless(v, a, u) \ -({ \ - int c, old; \ - c = atomic_read(v); \ - while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \ - c = old; \ - c != (u); \ -}) -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) - -static __inline__ void atomic_dec(volatile atomic_t * v) +static inline void atomic_dec(volatile atomic_t *v) { long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter--; - local_irq_restore(flags); + local_irq_restore_hw(flags); } -static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t * v) +static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) { long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter &= ~mask; - local_irq_restore(flags); + local_irq_restore_hw(flags); } -static __inline__ void atomic_set_mask(unsigned int mask, atomic_t * v) +static inline void atomic_set_mask(unsigned int mask, atomic_t *v) { long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter |= mask; - local_irq_restore(flags); + local_irq_restore_hw(flags); } /* Atomic operations are already serializing */ @@ -121,9 +176,25 @@ static __inline__ void atomic_set_mask(unsigned int mask, atomic_t * v) #define smp_mb__before_atomic_inc() barrier() #define smp_mb__after_atomic_inc() barrier() +#endif /* !CONFIG_SMP */ + +#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) #define atomic_dec_return(v) atomic_sub_return(1,(v)) #define atomic_inc_return(v) atomic_add_return(1,(v)) +#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) +#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) + +#define atomic_add_unless(v, a, u) \ +({ \ + int c, old; \ + c = atomic_read(v); \ + while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \ + c = old; \ + c != (u); \ +}) +#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) + /* * atomic_inc_and_test - increment and test * @v: pointer of type atomic_t diff --git a/arch/blackfin/include/asm/bfin-global.h b/arch/blackfin/include/asm/bfin-global.h index 77295666c34b..daffc0684e75 100644 --- a/arch/blackfin/include/asm/bfin-global.h +++ b/arch/blackfin/include/asm/bfin-global.h @@ -47,6 +47,9 @@ # define DMA_UNCACHED_REGION (0) #endif +extern void bfin_setup_caches(unsigned int cpu); +extern void bfin_setup_cpudata(unsigned int cpu); + extern unsigned long get_cclk(void); extern unsigned long get_sclk(void); extern unsigned long sclk_to_usecs(unsigned long sclk); @@ -58,8 +61,6 @@ extern void dump_bfin_trace_buffer(void); /* init functions only */ extern int init_arch_irq(void); -extern void bfin_icache_init(void); -extern void bfin_dcache_init(void); extern void init_exception_vectors(void); extern void program_IAR(void); @@ -110,7 +111,7 @@ extern unsigned long memory_mtd_start, memory_mtd_end, mtd_size; #ifdef CONFIG_BFIN_ICACHE_LOCK extern void cache_grab_lock(int way); -extern void cache_lock(int way); +extern void bfin_cache_lock(int way); #endif #endif diff --git a/arch/blackfin/include/asm/bfin5xx_spi.h b/arch/blackfin/include/asm/bfin5xx_spi.h index 9fa19158e38d..1306e6b22946 100644 --- a/arch/blackfin/include/asm/bfin5xx_spi.h +++ b/arch/blackfin/include/asm/bfin5xx_spi.h @@ -1,22 +1,12 @@ -/************************************************************ - -* Copyright (C) 2006-2008, Analog Devices. All Rights Reserved -* -* FILE bfin5xx_spi.h -* PROGRAMMER(S): Luke Yang (Analog Devices Inc.) -* -* -* DATE OF CREATION: March. 10th 2006 -* -* SYNOPSIS: -* -* DESCRIPTION: header file for SPI controller driver for Blackfin5xx. -************************************************************** - -* MODIFICATION HISTORY: -* March 10, 2006 bfin5xx_spi.h Created. (Luke Yang) - -************************************************************/ +/* + * Blackfin On-Chip SPI Driver + * + * Copyright 2004-2008 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ #ifndef _SPI_CHANNEL_H_ #define _SPI_CHANNEL_H_ diff --git a/arch/blackfin/include/asm/bfin_sdh.h b/arch/blackfin/include/asm/bfin_sdh.h new file mode 100644 index 000000000000..d61d5497c590 --- /dev/null +++ b/arch/blackfin/include/asm/bfin_sdh.h @@ -0,0 +1,19 @@ +/* + * bfin_sdh.h - Blackfin SDH definitions + * + * Copyright 2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __BFIN_SDH_H__ +#define __BFIN_SDH_H__ + +struct bfin_sd_host { + int dma_chan; + int irq_int0; + int irq_int1; + u16 pin_req[7]; +}; + +#endif diff --git a/arch/blackfin/include/asm/bfin_sport.h b/arch/blackfin/include/asm/bfin_sport.h index c76ed8def302..fe88a2c19213 100644 --- a/arch/blackfin/include/asm/bfin_sport.h +++ b/arch/blackfin/include/asm/bfin_sport.h @@ -120,9 +120,6 @@ struct sport_register { #define SPORT_IOC_MAGIC 'P' #define SPORT_IOC_CONFIG _IOWR('P', 0x01, struct sport_config) -/* Test purpose */ -#define ENABLE_AD73311 _IOWR('P', 0x02, int) - struct sport_dev { struct cdev cdev; /* Char device structure */ diff --git a/arch/blackfin/include/asm/bfrom.h b/arch/blackfin/include/asm/bfrom.h index cfe8024c3b2f..9e4be5e5e767 100644 --- a/arch/blackfin/include/asm/bfrom.h +++ b/arch/blackfin/include/asm/bfrom.h @@ -43,6 +43,11 @@ __attribute__((__noreturn__)) static inline void bfrom_SoftReset(void *new_stack) { while (1) + /* + * We don't declare the SP as clobbered on purpose, since + * it confuses the heck out of the compiler, and this function + * never returns + */ __asm__ __volatile__( "sp = %[stack];" "jump (%[bfrom_syscontrol]);" diff --git a/arch/blackfin/include/asm/bitops.h b/arch/blackfin/include/asm/bitops.h index c428e4106f89..21b036eadab1 100644 --- a/arch/blackfin/include/asm/bitops.h +++ b/arch/blackfin/include/asm/bitops.h @@ -7,7 +7,6 @@ #include <linux/compiler.h> #include <asm/byteorder.h> /* swab32 */ -#include <asm/system.h> /* save_flags */ #ifdef __KERNEL__ @@ -20,80 +19,107 @@ #include <asm-generic/bitops/sched.h> #include <asm-generic/bitops/ffz.h> -static __inline__ void set_bit(int nr, volatile unsigned long *addr) +#ifdef CONFIG_SMP + +#include <linux/linkage.h> + +asmlinkage int __raw_bit_set_asm(volatile unsigned long *addr, int nr); + +asmlinkage int __raw_bit_clear_asm(volatile unsigned long *addr, int nr); + +asmlinkage int __raw_bit_toggle_asm(volatile unsigned long *addr, int nr); + +asmlinkage int __raw_bit_test_set_asm(volatile unsigned long *addr, int nr); + +asmlinkage int __raw_bit_test_clear_asm(volatile unsigned long *addr, int nr); + +asmlinkage int __raw_bit_test_toggle_asm(volatile unsigned long *addr, int nr); + +asmlinkage int __raw_bit_test_asm(const volatile unsigned long *addr, int nr); + +static inline void set_bit(int nr, volatile unsigned long *addr) { - int *a = (int *)addr; - int mask; - unsigned long flags; + volatile unsigned long *a = addr + (nr >> 5); + __raw_bit_set_asm(a, nr & 0x1f); +} - a += nr >> 5; - mask = 1 << (nr & 0x1f); - local_irq_save(flags); - *a |= mask; - local_irq_restore(flags); +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + volatile unsigned long *a = addr + (nr >> 5); + __raw_bit_clear_asm(a, nr & 0x1f); } -static __inline__ void __set_bit(int nr, volatile unsigned long *addr) +static inline void change_bit(int nr, volatile unsigned long *addr) { - int *a = (int *)addr; - int mask; + volatile unsigned long *a = addr + (nr >> 5); + __raw_bit_toggle_asm(a, nr & 0x1f); +} - a += nr >> 5; - mask = 1 << (nr & 0x1f); - *a |= mask; +static inline int test_bit(int nr, const volatile unsigned long *addr) +{ + volatile const unsigned long *a = addr + (nr >> 5); + return __raw_bit_test_asm(a, nr & 0x1f) != 0; } -/* - * clear_bit() doesn't provide any barrier for the compiler. - */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + volatile unsigned long *a = addr + (nr >> 5); + return __raw_bit_test_set_asm(a, nr & 0x1f); +} + +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + volatile unsigned long *a = addr + (nr >> 5); + return __raw_bit_test_clear_asm(a, nr & 0x1f); +} + +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + volatile unsigned long *a = addr + (nr >> 5); + return __raw_bit_test_toggle_asm(a, nr & 0x1f); +} + +#else /* !CONFIG_SMP */ + +#include <asm/system.h> /* save_flags */ -static __inline__ void clear_bit(int nr, volatile unsigned long *addr) +static inline void set_bit(int nr, volatile unsigned long *addr) { int *a = (int *)addr; int mask; unsigned long flags; a += nr >> 5; mask = 1 << (nr & 0x1f); - local_irq_save(flags); - *a &= ~mask; - local_irq_restore(flags); + local_irq_save_hw(flags); + *a |= mask; + local_irq_restore_hw(flags); } -static __inline__ void __clear_bit(int nr, volatile unsigned long *addr) +static inline void clear_bit(int nr, volatile unsigned long *addr) { int *a = (int *)addr; int mask; - + unsigned long flags; a += nr >> 5; mask = 1 << (nr & 0x1f); + local_irq_save_hw(flags); *a &= ~mask; + local_irq_restore_hw(flags); } -static __inline__ void change_bit(int nr, volatile unsigned long *addr) +static inline void change_bit(int nr, volatile unsigned long *addr) { int mask, flags; unsigned long *ADDR = (unsigned long *)addr; ADDR += nr >> 5; mask = 1 << (nr & 31); - local_irq_save(flags); - *ADDR ^= mask; - local_irq_restore(flags); -} - -static __inline__ void __change_bit(int nr, volatile unsigned long *addr) -{ - int mask; - unsigned long *ADDR = (unsigned long *)addr; - - ADDR += nr >> 5; - mask = 1 << (nr & 31); + local_irq_save_hw(flags); *ADDR ^= mask; + local_irq_restore_hw(flags); } -static __inline__ int test_and_set_bit(int nr, void *addr) +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) { int mask, retval; volatile unsigned int *a = (volatile unsigned int *)addr; @@ -101,27 +127,31 @@ static __inline__ int test_and_set_bit(int nr, void *addr) a += nr >> 5; mask = 1 << (nr & 0x1f); - local_irq_save(flags); + local_irq_save_hw(flags); retval = (mask & *a) != 0; *a |= mask; - local_irq_restore(flags); + local_irq_restore_hw(flags); return retval; } -static __inline__ int __test_and_set_bit(int nr, volatile unsigned long *addr) +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) { int mask, retval; volatile unsigned int *a = (volatile unsigned int *)addr; + unsigned long flags; a += nr >> 5; mask = 1 << (nr & 0x1f); + local_irq_save_hw(flags); retval = (mask & *a) != 0; - *a |= mask; + *a &= ~mask; + local_irq_restore_hw(flags); + return retval; } -static __inline__ int test_and_clear_bit(int nr, volatile unsigned long *addr) +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) { int mask, retval; volatile unsigned int *a = (volatile unsigned int *)addr; @@ -129,15 +159,52 @@ static __inline__ int test_and_clear_bit(int nr, volatile unsigned long *addr) a += nr >> 5; mask = 1 << (nr & 0x1f); - local_irq_save(flags); + local_irq_save_hw(flags); retval = (mask & *a) != 0; + *a ^= mask; + local_irq_restore_hw(flags); + return retval; +} + +#endif /* CONFIG_SMP */ + +/* + * clear_bit() doesn't provide any barrier for the compiler. + */ +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() + +static inline void __set_bit(int nr, volatile unsigned long *addr) +{ + int *a = (int *)addr; + int mask; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a |= mask; +} + +static inline void __clear_bit(int nr, volatile unsigned long *addr) +{ + int *a = (int *)addr; + int mask; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); *a &= ~mask; - local_irq_restore(flags); +} - return retval; +static inline void __change_bit(int nr, volatile unsigned long *addr) +{ + int mask; + unsigned long *ADDR = (unsigned long *)addr; + + ADDR += nr >> 5; + mask = 1 << (nr & 31); + *ADDR ^= mask; } -static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long *addr) +static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) { int mask, retval; volatile unsigned int *a = (volatile unsigned int *)addr; @@ -145,26 +212,23 @@ static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long *addr) a += nr >> 5; mask = 1 << (nr & 0x1f); retval = (mask & *a) != 0; - *a &= ~mask; + *a |= mask; return retval; } -static __inline__ int test_and_change_bit(int nr, volatile unsigned long *addr) +static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) { int mask, retval; volatile unsigned int *a = (volatile unsigned int *)addr; - unsigned long flags; a += nr >> 5; mask = 1 << (nr & 0x1f); - local_irq_save(flags); retval = (mask & *a) != 0; - *a ^= mask; - local_irq_restore(flags); + *a &= ~mask; return retval; } -static __inline__ int __test_and_change_bit(int nr, +static inline int __test_and_change_bit(int nr, volatile unsigned long *addr) { int mask, retval; @@ -177,16 +241,7 @@ static __inline__ int __test_and_change_bit(int nr, return retval; } -/* - * This routine doesn't need to be atomic. - */ -static __inline__ int __constant_test_bit(int nr, const void *addr) -{ - return ((1UL << (nr & 31)) & - (((const volatile unsigned int *)addr)[nr >> 5])) != 0; -} - -static __inline__ int __test_bit(int nr, const void *addr) +static inline int __test_bit(int nr, const void *addr) { int *a = (int *)addr; int mask; @@ -196,10 +251,16 @@ static __inline__ int __test_bit(int nr, const void *addr) return ((mask & *a) != 0); } -#define test_bit(nr,addr) \ -(__builtin_constant_p(nr) ? \ - __constant_test_bit((nr),(addr)) : \ - __test_bit((nr),(addr))) +#ifndef CONFIG_SMP +/* + * This routine doesn't need irq save and restore ops in UP + * context. + */ +static inline int test_bit(int nr, const void *addr) +{ + return __test_bit(nr, addr); +} +#endif #include <asm-generic/bitops/find.h> #include <asm-generic/bitops/hweight.h> diff --git a/arch/blackfin/include/asm/blackfin.h b/arch/blackfin/include/asm/blackfin.h index 8749b0e321ab..8bb2cb139756 100644 --- a/arch/blackfin/include/asm/blackfin.h +++ b/arch/blackfin/include/asm/blackfin.h @@ -6,11 +6,6 @@ #ifndef _BLACKFIN_H_ #define _BLACKFIN_H_ -#define LO(con32) ((con32) & 0xFFFF) -#define lo(con32) ((con32) & 0xFFFF) -#define HI(con32) (((con32) >> 16) & 0xFFFF) -#define hi(con32) (((con32) >> 16) & 0xFFFF) - #include <mach/anomaly.h> #ifndef __ASSEMBLY__ @@ -65,6 +60,11 @@ static inline void CSYNC(void) #else /* __ASSEMBLY__ */ +#define LO(con32) ((con32) & 0xFFFF) +#define lo(con32) ((con32) & 0xFFFF) +#define HI(con32) (((con32) >> 16) & 0xFFFF) +#define hi(con32) (((con32) >> 16) & 0xFFFF) + /* SSYNC & CSYNC implementations for assembly files */ #define ssync(x) SSYNC(x) diff --git a/arch/blackfin/include/asm/cache.h b/arch/blackfin/include/asm/cache.h index 023d72133b5a..86637814cf25 100644 --- a/arch/blackfin/include/asm/cache.h +++ b/arch/blackfin/include/asm/cache.h @@ -12,6 +12,11 @@ #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) #define SMP_CACHE_BYTES L1_CACHE_BYTES +#ifdef CONFIG_SMP +#define __cacheline_aligned +#else +#define ____cacheline_aligned + /* * Put cacheline_aliged data to L1 data memory */ @@ -21,9 +26,33 @@ __section__(".data_l1.cacheline_aligned"))) #endif +#endif + /* * largest L1 which this arch supports */ #define L1_CACHE_SHIFT_MAX 5 +#if defined(CONFIG_SMP) && \ + !defined(CONFIG_BFIN_CACHE_COHERENT) && \ + defined(CONFIG_BFIN_DCACHE) +#define __ARCH_SYNC_CORE_DCACHE +#ifndef __ASSEMBLY__ +asmlinkage void __raw_smp_mark_barrier_asm(void); +asmlinkage void __raw_smp_check_barrier_asm(void); + +static inline void smp_mark_barrier(void) +{ + __raw_smp_mark_barrier_asm(); +} +static inline void smp_check_barrier(void) +{ + __raw_smp_check_barrier_asm(); +} + +void resync_core_dcache(void); +#endif +#endif + + #endif diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h index 4403415583fa..1b040f5b4feb 100644 --- a/arch/blackfin/include/asm/cacheflush.h +++ b/arch/blackfin/include/asm/cacheflush.h @@ -35,6 +35,7 @@ extern void blackfin_icache_flush_range(unsigned long start_address, unsigned lo extern void blackfin_dcache_flush_range(unsigned long start_address, unsigned long end_address); extern void blackfin_dcache_invalidate_range(unsigned long start_address, unsigned long end_address); extern void blackfin_dflush_page(void *page); +extern void blackfin_invalidate_entire_dcache(void); #define flush_dcache_mmap_lock(mapping) do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) @@ -44,12 +45,20 @@ extern void blackfin_dflush_page(void *page); #define flush_cache_vmap(start, end) do { } while (0) #define flush_cache_vunmap(start, end) do { } while (0) +#ifdef CONFIG_SMP +#define flush_icache_range_others(start, end) \ + smp_icache_flush_range_others((start), (end)) +#else +#define flush_icache_range_others(start, end) do { } while (0) +#endif + static inline void flush_icache_range(unsigned start, unsigned end) { #if defined(CONFIG_BFIN_DCACHE) && defined(CONFIG_BFIN_ICACHE) # if defined(CONFIG_BFIN_WT) blackfin_icache_flush_range((start), (end)); + flush_icache_range_others(start, end); # else blackfin_icache_dcache_flush_range((start), (end)); # endif @@ -58,6 +67,7 @@ static inline void flush_icache_range(unsigned start, unsigned end) # if defined(CONFIG_BFIN_ICACHE) blackfin_icache_flush_range((start), (end)); + flush_icache_range_others(start, end); # endif # if defined(CONFIG_BFIN_DCACHE) blackfin_dcache_flush_range((start), (end)); @@ -66,10 +76,12 @@ static inline void flush_icache_range(unsigned start, unsigned end) #endif } -#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ -do { memcpy(dst, src, len); \ - flush_icache_range ((unsigned) (dst), (unsigned) (dst) + (len)); \ +#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ +do { memcpy(dst, src, len); \ + flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len)); \ + flush_icache_range_others((unsigned long) (dst), (unsigned long) (dst) + (len));\ } while (0) + #define copy_from_user_page(vma, page, vaddr, dst, src, len) memcpy(dst, src, len) #if defined(CONFIG_BFIN_DCACHE) @@ -82,7 +94,7 @@ do { memcpy(dst, src, len); \ # define flush_dcache_page(page) blackfin_dflush_page(page_address(page)) #else # define flush_dcache_range(start,end) do { } while (0) -# define flush_dcache_page(page) do { } while (0) +# define flush_dcache_page(page) do { } while (0) #endif extern unsigned long reserved_mem_dcache_on; diff --git a/arch/blackfin/include/asm/checksum.h b/arch/blackfin/include/asm/checksum.h index 6f6af2b8e9e0..f67289a0d8d2 100644 --- a/arch/blackfin/include/asm/checksum.h +++ b/arch/blackfin/include/asm/checksum.h @@ -78,7 +78,8 @@ csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len, "%0 = %0 + %4;\n\t" "NOP;\n\t" : "=d" (sum) - : "d" (daddr), "d" (saddr), "d" ((ntohs(len)<<16)+proto*256), "d" (1), "0"(sum)); + : "d" (daddr), "d" (saddr), "d" ((ntohs(len)<<16)+proto*256), "d" (1), "0"(sum) + : "CC"); return (sum); } diff --git a/arch/blackfin/include/asm/context.S b/arch/blackfin/include/asm/context.S index c0e630edfb9a..16561ab18b38 100644 --- a/arch/blackfin/include/asm/context.S +++ b/arch/blackfin/include/asm/context.S @@ -303,9 +303,14 @@ RETI = [sp++]; RETS = [sp++]; - p0.h = _irq_flags; - p0.l = _irq_flags; +#ifdef CONFIG_SMP + GET_PDA(p0, r0); + r0 = [p0 + PDA_IRQFLAGS]; +#else + p0.h = _bfin_irq_flags; + p0.l = _bfin_irq_flags; r0 = [p0]; +#endif sti r0; sp += 4; /* Skip Reserved */ @@ -353,3 +358,41 @@ csync; .endm +.macro save_context_cplb + [--sp] = (R7:0, P5:0); + [--sp] = fp; + + [--sp] = a0.x; + [--sp] = a0.w; + [--sp] = a1.x; + [--sp] = a1.w; + + [--sp] = LC0; + [--sp] = LC1; + [--sp] = LT0; + [--sp] = LT1; + [--sp] = LB0; + [--sp] = LB1; + + [--sp] = RETS; +.endm + +.macro restore_context_cplb + RETS = [sp++]; + + LB1 = [sp++]; + LB0 = [sp++]; + LT1 = [sp++]; + LT0 = [sp++]; + LC1 = [sp++]; + LC0 = [sp++]; + + a1.w = [sp++]; + a1.x = [sp++]; + a0.w = [sp++]; + a0.x = [sp++]; + + fp = [sp++]; + + (R7:0, P5:0) = [SP++]; +.endm diff --git a/arch/blackfin/include/asm/cplb-mpu.h b/arch/blackfin/include/asm/cplb-mpu.h deleted file mode 100644 index 75c67b99d607..000000000000 --- a/arch/blackfin/include/asm/cplb-mpu.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * File: include/asm-blackfin/cplbinit.h - * Based on: - * Author: - * - * Created: - * Description: - * - * Modified: - * Copyright 2004-2006 Analog Devices Inc. - * - * Bugs: Enter bugs at http://blackfin.uclinux.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 program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see the file COPYING, or write - * to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __ASM_BFIN_CPLB_MPU_H -#define __ASM_BFIN_CPLB_MPU_H - -struct cplb_entry { - unsigned long data, addr; -}; - -struct mem_region { - unsigned long start, end; - unsigned long dcplb_data; - unsigned long icplb_data; -}; - -extern struct cplb_entry dcplb_tbl[MAX_CPLBS]; -extern struct cplb_entry icplb_tbl[MAX_CPLBS]; -extern int first_switched_icplb; -extern int first_mask_dcplb; -extern int first_switched_dcplb; - -extern int nr_dcplb_miss, nr_icplb_miss, nr_icplb_supv_miss, nr_dcplb_prot; -extern int nr_cplb_flush; - -extern int page_mask_order; -extern int page_mask_nelts; - -extern unsigned long *current_rwx_mask; - -extern void flush_switched_cplbs(void); -extern void set_mask_dcplbs(unsigned long *); - -extern void __noreturn panic_cplb_error(int seqstat, struct pt_regs *); - -#endif /* __ASM_BFIN_CPLB_MPU_H */ diff --git a/arch/blackfin/include/asm/cplb.h b/arch/blackfin/include/asm/cplb.h index 9e8b4035fcec..ad566ff9ad16 100644 --- a/arch/blackfin/include/asm/cplb.h +++ b/arch/blackfin/include/asm/cplb.h @@ -30,7 +30,6 @@ #ifndef _CPLB_H #define _CPLB_H -#include <asm/blackfin.h> #include <mach/anomaly.h> #define SDRAM_IGENERIC (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO) @@ -55,13 +54,24 @@ #endif #define L1_DMEMORY (CPLB_LOCK | CPLB_COMMON) + +#ifdef CONFIG_SMP +#define L2_ATTR (INITIAL_T | I_CPLB | D_CPLB) +#define L2_IMEMORY (CPLB_COMMON | CPLB_LOCK) +#define L2_DMEMORY (CPLB_COMMON | CPLB_LOCK) + +#else #ifdef CONFIG_BFIN_L2_CACHEABLE #define L2_IMEMORY (SDRAM_IGENERIC) #define L2_DMEMORY (SDRAM_DGENERIC) #else #define L2_IMEMORY (CPLB_COMMON) #define L2_DMEMORY (CPLB_COMMON) -#endif +#endif /* CONFIG_BFIN_L2_CACHEABLE */ + +#define L2_ATTR (INITIAL_T | SWITCH_T | I_CPLB | D_CPLB) +#endif /* CONFIG_SMP */ + #define SDRAM_DNON_CHBL (CPLB_COMMON) #define SDRAM_EBIU (CPLB_COMMON) #define SDRAM_OOPS (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY) @@ -71,14 +81,7 @@ #define SIZE_1M 0x00100000 /* 1M */ #define SIZE_4M 0x00400000 /* 4M */ -#ifdef CONFIG_MPU #define MAX_CPLBS 16 -#else -#define MAX_CPLBS (16 * 2) -#endif - -#define ASYNC_MEMORY_CPLB_COVERAGE ((ASYNC_BANK0_SIZE + ASYNC_BANK1_SIZE + \ - ASYNC_BANK2_SIZE + ASYNC_BANK3_SIZE) / SIZE_4M) #define CPLB_ENABLE_ICACHE_P 0 #define CPLB_ENABLE_DCACHE_P 1 @@ -113,4 +116,8 @@ #define CPLB_INOCACHE CPLB_USER_RD | CPLB_VALID #define CPLB_IDOCACHE CPLB_INOCACHE | CPLB_L1_CHBL +#define FAULT_RW (1 << 16) +#define FAULT_USERSUPV (1 << 17) +#define FAULT_CPLBBITS 0x0000ffff + #endif /* _CPLB_H */ diff --git a/arch/blackfin/include/asm/cplbinit.h b/arch/blackfin/include/asm/cplbinit.h index f845b41147ba..05b14a631d0c 100644 --- a/arch/blackfin/include/asm/cplbinit.h +++ b/arch/blackfin/include/asm/cplbinit.h @@ -32,61 +32,56 @@ #include <asm/blackfin.h> #include <asm/cplb.h> +#include <linux/threads.h> -#ifdef CONFIG_MPU - -#include <asm/cplb-mpu.h> - +#ifdef CONFIG_CPLB_SWITCH_TAB_L1 +# define PDT_ATTR __attribute__((l1_data)) #else +# define PDT_ATTR +#endif -#define INITIAL_T 0x1 -#define SWITCH_T 0x2 -#define I_CPLB 0x4 -#define D_CPLB 0x8 - -#define IN_KERNEL 1 - -enum -{ZERO_P, L1I_MEM, L1D_MEM, SDRAM_KERN , SDRAM_RAM_MTD, SDRAM_DMAZ, RES_MEM, ASYNC_MEM, L2_MEM}; - -struct cplb_desc { - u32 start; /* start address */ - u32 end; /* end address */ - u32 psize; /* prefered size if any otherwise 1MB or 4MB*/ - u16 attr;/* attributes */ - u16 i_conf;/* I-CPLB DATA */ - u16 d_conf;/* D-CPLB DATA */ - u16 valid;/* valid */ - const s8 name[30];/* name */ +struct cplb_entry { + unsigned long data, addr; }; -struct cplb_tab { - u_long *tab; - u16 pos; - u16 size; +struct cplb_boundary { + unsigned long eaddr; /* End of this region. */ + unsigned long data; /* CPLB data value. */ }; -extern u_long icplb_table[]; -extern u_long dcplb_table[]; +extern struct cplb_boundary dcplb_bounds[]; +extern struct cplb_boundary icplb_bounds[]; +extern int dcplb_nr_bounds, icplb_nr_bounds; -/* Till here we are discussing about the static memory management model. - * However, the operating envoronments commonly define more CPLB - * descriptors to cover the entire addressable memory than will fit into - * the available on-chip 16 CPLB MMRs. When this happens, the below table - * will be used which will hold all the potentially required CPLB descriptors - * - * This is how Page descriptor Table is implemented in uClinux/Blackfin. - */ +extern struct cplb_entry dcplb_tbl[NR_CPUS][MAX_CPLBS]; +extern struct cplb_entry icplb_tbl[NR_CPUS][MAX_CPLBS]; +extern int first_switched_icplb; +extern int first_switched_dcplb; -extern u_long ipdt_table[]; -extern u_long dpdt_table[]; -#ifdef CONFIG_CPLB_INFO -extern u_long ipdt_swapcount_table[]; -extern u_long dpdt_swapcount_table[]; -#endif +extern int nr_dcplb_miss[], nr_icplb_miss[], nr_icplb_supv_miss[]; +extern int nr_dcplb_prot[], nr_cplb_flush[]; + +#ifdef CONFIG_MPU + +extern int first_mask_dcplb; + +extern int page_mask_order; +extern int page_mask_nelts; + +extern unsigned long *current_rwx_mask[NR_CPUS]; + +extern void flush_switched_cplbs(unsigned int); +extern void set_mask_dcplbs(unsigned long *, unsigned int); + +extern void __noreturn panic_cplb_error(int seqstat, struct pt_regs *); #endif /* CONFIG_MPU */ -extern void generate_cplb_tables(void); +extern void bfin_icache_init(struct cplb_entry *icplb_tbl); +extern void bfin_dcache_init(struct cplb_entry *icplb_tbl); +#if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE) +extern void generate_cplb_tables_all(void); +extern void generate_cplb_tables_cpu(unsigned int cpu); +#endif #endif diff --git a/arch/blackfin/include/asm/cpu.h b/arch/blackfin/include/asm/cpu.h new file mode 100644 index 000000000000..c2594ef877f6 --- /dev/null +++ b/arch/blackfin/include/asm/cpu.h @@ -0,0 +1,41 @@ +/* + * File: arch/blackfin/include/asm/cpu.h. + * Author: Philippe Gerum <rpm@xenomai.org> + * + * Copyright 2007 Analog Devices Inc. + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __ASM_BLACKFIN_CPU_H +#define __ASM_BLACKFIN_CPU_H + +#include <linux/percpu.h> + +struct task_struct; + +struct blackfin_cpudata { + struct cpu cpu; + struct task_struct *idle; + unsigned int imemctl; + unsigned int dmemctl; + unsigned long loops_per_jiffy; + unsigned long dcache_invld_count; +}; + +DECLARE_PER_CPU(struct blackfin_cpudata, cpu_data); + +#endif diff --git a/arch/blackfin/include/asm/dma.h b/arch/blackfin/include/asm/dma.h index 6509733bb0f6..e4f7b8043f02 100644 --- a/arch/blackfin/include/asm/dma.h +++ b/arch/blackfin/include/asm/dma.h @@ -1,44 +1,17 @@ /* - * File: include/asm-blackfin/simple_bf533_dma.h - * Based on: none - original work - * Author: LG Soft India - * Copyright (C) 2004-2005 Analog Devices Inc. - * Created: Tue Sep 21 2004 - * Description: This file contains the major Data structures and constants - * used for DMA Implementation in BF533 - * Modified: + * dma.h - Blackfin DMA defines/structures/etc... * - * Bugs: Enter bugs at http://blackfin.uclinux.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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. - * If not, write to the Free Software Foundation, - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Copyright 2004-2008 Analog Devices Inc. + * Licensed under the GPL-2 or later. */ #ifndef _BLACKFIN_DMA_H_ #define _BLACKFIN_DMA_H_ -#include <asm/io.h> -#include <linux/slab.h> -#include <asm/irq.h> -#include <asm/signal.h> - -#include <linux/kernel.h> -#include <mach/dma.h> -#include <linux/mm.h> #include <linux/interrupt.h> +#include <mach/dma.h> #include <asm/blackfin.h> +#include <asm/page.h> #define MAX_DMA_ADDRESS PAGE_OFFSET @@ -79,7 +52,7 @@ enum dma_chan_status { #define DMA_SYNC_RESTART 1 struct dmasg { - unsigned long next_desc_addr; + void *next_desc_addr; unsigned long start_addr; unsigned short cfg; unsigned short x_count; @@ -89,7 +62,7 @@ struct dmasg { } __attribute__((packed)); struct dma_register { - unsigned long next_desc_ptr; /* DMA Next Descriptor Pointer register */ + void *next_desc_ptr; /* DMA Next Descriptor Pointer register */ unsigned long start_addr; /* DMA Start address register */ unsigned short cfg; /* DMA Configuration register */ @@ -109,7 +82,7 @@ struct dma_register { short y_modify; /* DMA y_modify register */ unsigned short dummy5; - unsigned long curr_desc_ptr; /* DMA Current Descriptor Pointer + void *curr_desc_ptr; /* DMA Current Descriptor Pointer register */ unsigned long curr_addr_ptr; /* DMA Current Address Pointer register */ @@ -131,19 +104,15 @@ struct dma_register { }; -typedef irqreturn_t(*dma_interrupt_t) (int irq, void *dev_id); - +struct mutex; struct dma_channel { struct mutex dmalock; - char *device_id; + const char *device_id; enum dma_chan_status chan_status; - struct dma_register *regs; + volatile struct dma_register *regs; struct dmasg *sg; /* large mode descriptor */ - unsigned int ctrl_num; /* controller number */ - dma_interrupt_t irq_callback; + unsigned int irq; void *data; - unsigned int dma_enable_flag; - unsigned int loopback_flag; #ifdef CONFIG_PM unsigned short saved_peripheral_map; #endif @@ -157,49 +126,132 @@ void blackfin_dma_resume(void); /******************************************************************************* * DMA API's *******************************************************************************/ -/* functions to set register mode */ -void set_dma_start_addr(unsigned int channel, unsigned long addr); -void set_dma_next_desc_addr(unsigned int channel, unsigned long addr); -void set_dma_curr_desc_addr(unsigned int channel, unsigned long addr); -void set_dma_x_count(unsigned int channel, unsigned short x_count); -void set_dma_x_modify(unsigned int channel, short x_modify); -void set_dma_y_count(unsigned int channel, unsigned short y_count); -void set_dma_y_modify(unsigned int channel, short y_modify); -void set_dma_config(unsigned int channel, unsigned short config); -unsigned short set_bfin_dma_config(char direction, char flow_mode, - char intr_mode, char dma_mode, char width, - char syncmode); -void set_dma_curr_addr(unsigned int channel, unsigned long addr); - -/* get curr status for polling */ -unsigned short get_dma_curr_irqstat(unsigned int channel); -unsigned short get_dma_curr_xcount(unsigned int channel); -unsigned short get_dma_curr_ycount(unsigned int channel); -unsigned long get_dma_next_desc_ptr(unsigned int channel); -unsigned long get_dma_curr_desc_ptr(unsigned int channel); -unsigned long get_dma_curr_addr(unsigned int channel); - -/* set large DMA mode descriptor */ -void set_dma_sg(unsigned int channel, struct dmasg *sg, int nr_sg); - -/* check if current channel is in use */ -int dma_channel_active(unsigned int channel); - -/* common functions must be called in any mode */ +extern struct dma_channel dma_ch[MAX_DMA_CHANNELS]; +extern struct dma_register *dma_io_base_addr[MAX_DMA_CHANNELS]; +extern int channel2irq(unsigned int channel); + +static inline void set_dma_start_addr(unsigned int channel, unsigned long addr) +{ + dma_ch[channel].regs->start_addr = addr; +} +static inline void set_dma_next_desc_addr(unsigned int channel, void *addr) +{ + dma_ch[channel].regs->next_desc_ptr = addr; +} +static inline void set_dma_curr_desc_addr(unsigned int channel, void *addr) +{ + dma_ch[channel].regs->curr_desc_ptr = addr; +} +static inline void set_dma_x_count(unsigned int channel, unsigned short x_count) +{ + dma_ch[channel].regs->x_count = x_count; +} +static inline void set_dma_y_count(unsigned int channel, unsigned short y_count) +{ + dma_ch[channel].regs->y_count = y_count; +} +static inline void set_dma_x_modify(unsigned int channel, short x_modify) +{ + dma_ch[channel].regs->x_modify = x_modify; +} +static inline void set_dma_y_modify(unsigned int channel, short y_modify) +{ + dma_ch[channel].regs->y_modify = y_modify; +} +static inline void set_dma_config(unsigned int channel, unsigned short config) +{ + dma_ch[channel].regs->cfg = config; +} +static inline void set_dma_curr_addr(unsigned int channel, unsigned long addr) +{ + dma_ch[channel].regs->curr_addr_ptr = addr; +} + +static inline unsigned short +set_bfin_dma_config(char direction, char flow_mode, + char intr_mode, char dma_mode, char width, char syncmode) +{ + return (direction << 1) | (width << 2) | (dma_mode << 4) | + (intr_mode << 6) | (flow_mode << 12) | (syncmode << 5); +} + +static inline unsigned short get_dma_curr_irqstat(unsigned int channel) +{ + return dma_ch[channel].regs->irq_status; +} +static inline unsigned short get_dma_curr_xcount(unsigned int channel) +{ + return dma_ch[channel].regs->curr_x_count; +} +static inline unsigned short get_dma_curr_ycount(unsigned int channel) +{ + return dma_ch[channel].regs->curr_y_count; +} +static inline void *get_dma_next_desc_ptr(unsigned int channel) +{ + return dma_ch[channel].regs->next_desc_ptr; +} +static inline void *get_dma_curr_desc_ptr(unsigned int channel) +{ + return dma_ch[channel].regs->curr_desc_ptr; +} +static inline unsigned short get_dma_config(unsigned int channel) +{ + return dma_ch[channel].regs->cfg; +} +static inline unsigned long get_dma_curr_addr(unsigned int channel) +{ + return dma_ch[channel].regs->curr_addr_ptr; +} + +static inline void set_dma_sg(unsigned int channel, struct dmasg *sg, int ndsize) +{ + dma_ch[channel].regs->cfg = + (dma_ch[channel].regs->cfg & ~(0xf << 8)) | + ((ndsize & 0xf) << 8); + dma_ch[channel].regs->next_desc_ptr = sg; +} + +static inline int dma_channel_active(unsigned int channel) +{ + if (dma_ch[channel].chan_status == DMA_CHANNEL_FREE) + return 0; + else + return 1; +} + +static inline void disable_dma(unsigned int channel) +{ + dma_ch[channel].regs->cfg &= ~DMAEN; + SSYNC(); + dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED; +} +static inline void enable_dma(unsigned int channel) +{ + dma_ch[channel].regs->curr_x_count = 0; + dma_ch[channel].regs->curr_y_count = 0; + dma_ch[channel].regs->cfg |= DMAEN; + dma_ch[channel].chan_status = DMA_CHANNEL_ENABLED; +} void free_dma(unsigned int channel); -int dma_channel_active(unsigned int channel); /* check if a channel is in use */ -void disable_dma(unsigned int channel); -void enable_dma(unsigned int channel); -int request_dma(unsigned int channel, char *device_id); -int set_dma_callback(unsigned int channel, dma_interrupt_t callback, - void *data); -void dma_disable_irq(unsigned int channel); -void dma_enable_irq(unsigned int channel); -void clear_dma_irqstat(unsigned int channel); +int request_dma(unsigned int channel, const char *device_id); +int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data); + +static inline void dma_disable_irq(unsigned int channel) +{ + disable_irq(dma_ch[channel].irq); +} +static inline void dma_enable_irq(unsigned int channel) +{ + enable_irq(dma_ch[channel].irq); +} +static inline void clear_dma_irqstat(unsigned int channel) +{ + dma_ch[channel].regs->irq_status = DMA_DONE | DMA_ERR; +} + void *dma_memcpy(void *dest, const void *src, size_t count); void *safe_dma_memcpy(void *dest, const void *src, size_t count); - -extern int channel2irq(unsigned int channel); -extern struct dma_register *dma_io_base_addr[MAX_BLACKFIN_DMA_CHANNEL]; +void blackfin_dma_early_init(void); #endif diff --git a/arch/blackfin/include/asm/entry.h b/arch/blackfin/include/asm/entry.h index c4f721e0d00d..b30a2968e274 100644 --- a/arch/blackfin/include/asm/entry.h +++ b/arch/blackfin/include/asm/entry.h @@ -27,6 +27,14 @@ #define SAVE_ALL_SYS save_context_no_interrupts /* This is used for all normal interrupts. It saves a minimum of registers to the stack, loads the IRQ number, and jumps to common code. */ +#ifdef CONFIG_IPIPE +# define LOAD_IPIPE_IPEND \ + P0.l = lo(IPEND); \ + P0.h = hi(IPEND); \ + R1 = [P0]; +#else +# define LOAD_IPIPE_IPEND +#endif #define INTERRUPT_ENTRY(N) \ [--sp] = SYSCFG; \ \ @@ -34,6 +42,7 @@ [--sp] = R0; /*orig_r0*/ \ [--sp] = (R7:0,P5:0); \ R0 = (N); \ + LOAD_IPIPE_IPEND \ jump __common_int_entry; /* For timer interrupts, we need to save IPEND, since the user_mode @@ -53,9 +62,11 @@ /* This one pushes RETI without using CLI. Interrupts are enabled. */ #define SAVE_CONTEXT_SYSCALL save_context_syscall #define SAVE_CONTEXT save_context_with_interrupts +#define SAVE_CONTEXT_CPLB save_context_cplb #define RESTORE_ALL_SYS restore_context_no_interrupts #define RESTORE_CONTEXT restore_context_with_interrupts +#define RESTORE_CONTEXT_CPLB restore_context_cplb #endif /* __ASSEMBLY__ */ #endif /* __BFIN_ENTRY_H */ diff --git a/arch/blackfin/include/asm/gpio.h b/arch/blackfin/include/asm/gpio.h index ad33ac271fd9..9477d82fcad2 100644 --- a/arch/blackfin/include/asm/gpio.h +++ b/arch/blackfin/include/asm/gpio.h @@ -84,11 +84,14 @@ #ifndef __ARCH_BLACKFIN_GPIO_H__ #define __ARCH_BLACKFIN_GPIO_H__ -#define gpio_bank(x) ((x) >> 4) -#define gpio_bit(x) (1<<((x) & 0xF)) -#define gpio_sub_n(x) ((x) & 0xF) +#define gpio_bank(x) ((x) >> 4) +#define gpio_bit(x) (1<<((x) & 0xF)) +#define gpio_sub_n(x) ((x) & 0xF) -#define GPIO_BANKSIZE 16 +#define GPIO_BANKSIZE 16 +#define GPIO_BANK_NUM DIV_ROUND_UP(MAX_BLACKFIN_GPIOS, GPIO_BANKSIZE) + +#include <mach/gpio.h> #define GPIO_0 0 #define GPIO_1 1 @@ -139,151 +142,9 @@ #define GPIO_46 46 #define GPIO_47 47 - #define PERIPHERAL_USAGE 1 #define GPIO_USAGE 0 -#ifdef BF533_FAMILY -#define MAX_BLACKFIN_GPIOS 16 - -#define GPIO_PF0 0 -#define GPIO_PF1 1 -#define GPIO_PF2 2 -#define GPIO_PF3 3 -#define GPIO_PF4 4 -#define GPIO_PF5 5 -#define GPIO_PF6 6 -#define GPIO_PF7 7 -#define GPIO_PF8 8 -#define GPIO_PF9 9 -#define GPIO_PF10 10 -#define GPIO_PF11 11 -#define GPIO_PF12 12 -#define GPIO_PF13 13 -#define GPIO_PF14 14 -#define GPIO_PF15 15 - -#endif - -#if defined(BF527_FAMILY) || defined(BF537_FAMILY) -#define MAX_BLACKFIN_GPIOS 48 - -#define GPIO_PF0 0 -#define GPIO_PF1 1 -#define GPIO_PF2 2 -#define GPIO_PF3 3 -#define GPIO_PF4 4 -#define GPIO_PF5 5 -#define GPIO_PF6 6 -#define GPIO_PF7 7 -#define GPIO_PF8 8 -#define GPIO_PF9 9 -#define GPIO_PF10 10 -#define GPIO_PF11 11 -#define GPIO_PF12 12 -#define GPIO_PF13 13 -#define GPIO_PF14 14 -#define GPIO_PF15 15 -#define GPIO_PG0 16 -#define GPIO_PG1 17 -#define GPIO_PG2 18 -#define GPIO_PG3 19 -#define GPIO_PG4 20 -#define GPIO_PG5 21 -#define GPIO_PG6 22 -#define GPIO_PG7 23 -#define GPIO_PG8 24 -#define GPIO_PG9 25 -#define GPIO_PG10 26 -#define GPIO_PG11 27 -#define GPIO_PG12 28 -#define GPIO_PG13 29 -#define GPIO_PG14 30 -#define GPIO_PG15 31 -#define GPIO_PH0 32 -#define GPIO_PH1 33 -#define GPIO_PH2 34 -#define GPIO_PH3 35 -#define GPIO_PH4 36 -#define GPIO_PH5 37 -#define GPIO_PH6 38 -#define GPIO_PH7 39 -#define GPIO_PH8 40 -#define GPIO_PH9 41 -#define GPIO_PH10 42 -#define GPIO_PH11 43 -#define GPIO_PH12 44 -#define GPIO_PH13 45 -#define GPIO_PH14 46 -#define GPIO_PH15 47 - -#define PORT_F GPIO_PF0 -#define PORT_G GPIO_PG0 -#define PORT_H GPIO_PH0 - -#endif - -#ifdef BF548_FAMILY -#include <mach/gpio.h> -#endif - -#ifdef BF561_FAMILY -#define MAX_BLACKFIN_GPIOS 48 - -#define GPIO_PF0 0 -#define GPIO_PF1 1 -#define GPIO_PF2 2 -#define GPIO_PF3 3 -#define GPIO_PF4 4 -#define GPIO_PF5 5 -#define GPIO_PF6 6 -#define GPIO_PF7 7 -#define GPIO_PF8 8 -#define GPIO_PF9 9 -#define GPIO_PF10 10 -#define GPIO_PF11 11 -#define GPIO_PF12 12 -#define GPIO_PF13 13 -#define GPIO_PF14 14 -#define GPIO_PF15 15 -#define GPIO_PF16 16 -#define GPIO_PF17 17 -#define GPIO_PF18 18 -#define GPIO_PF19 19 -#define GPIO_PF20 20 -#define GPIO_PF21 21 -#define GPIO_PF22 22 -#define GPIO_PF23 23 -#define GPIO_PF24 24 -#define GPIO_PF25 25 -#define GPIO_PF26 26 -#define GPIO_PF27 27 -#define GPIO_PF28 28 -#define GPIO_PF29 29 -#define GPIO_PF30 30 -#define GPIO_PF31 31 -#define GPIO_PF32 32 -#define GPIO_PF33 33 -#define GPIO_PF34 34 -#define GPIO_PF35 35 -#define GPIO_PF36 36 -#define GPIO_PF37 37 -#define GPIO_PF38 38 -#define GPIO_PF39 39 -#define GPIO_PF40 40 -#define GPIO_PF41 41 -#define GPIO_PF42 42 -#define GPIO_PF43 43 -#define GPIO_PF44 44 -#define GPIO_PF45 45 -#define GPIO_PF46 46 -#define GPIO_PF47 47 - -#define PORT_FIO0 GPIO_0 -#define PORT_FIO1 GPIO_16 -#define PORT_FIO2 GPIO_32 -#endif - #ifndef __ASSEMBLY__ /*********************************************************** @@ -425,20 +286,77 @@ struct gpio_port_s { * MODIFICATION HISTORY : **************************************************************/ -int gpio_request(unsigned, const char *); -void gpio_free(unsigned); - -void gpio_set_value(unsigned gpio, int arg); -int gpio_get_value(unsigned gpio); +int bfin_gpio_request(unsigned gpio, const char *label); +void bfin_gpio_free(unsigned gpio); +int bfin_gpio_irq_request(unsigned gpio, const char *label); +void bfin_gpio_irq_free(unsigned gpio); +int bfin_gpio_direction_input(unsigned gpio); +int bfin_gpio_direction_output(unsigned gpio, int value); +int bfin_gpio_get_value(unsigned gpio); +void bfin_gpio_set_value(unsigned gpio, int value); #ifndef BF548_FAMILY -#define gpio_set_value(gpio, value) set_gpio_data(gpio, value) +#define bfin_gpio_set_value(gpio, value) set_gpio_data(gpio, value) #endif -int gpio_direction_input(unsigned gpio); -int gpio_direction_output(unsigned gpio, int value); +#ifdef CONFIG_GPIOLIB +#include <asm-generic/gpio.h> /* cansleep wrappers */ + +static inline int gpio_get_value(unsigned int gpio) +{ + if (gpio < MAX_BLACKFIN_GPIOS) + return bfin_gpio_get_value(gpio); + else + return __gpio_get_value(gpio); +} + +static inline void gpio_set_value(unsigned int gpio, int value) +{ + if (gpio < MAX_BLACKFIN_GPIOS) + bfin_gpio_set_value(gpio, value); + else + __gpio_set_value(gpio, value); +} + +static inline int gpio_cansleep(unsigned int gpio) +{ + return __gpio_cansleep(gpio); +} + +#else /* !CONFIG_GPIOLIB */ + +static inline int gpio_request(unsigned gpio, const char *label) +{ + return bfin_gpio_request(gpio, label); +} + +static inline void gpio_free(unsigned gpio) +{ + return bfin_gpio_free(gpio); +} + +static inline int gpio_direction_input(unsigned gpio) +{ + return bfin_gpio_direction_input(gpio); +} + +static inline int gpio_direction_output(unsigned gpio, int value) +{ + return bfin_gpio_direction_output(gpio, value); +} + +static inline int gpio_get_value(unsigned gpio) +{ + return bfin_gpio_get_value(gpio); +} + +static inline void gpio_set_value(unsigned gpio, int value) +{ + return bfin_gpio_set_value(gpio, value); +} #include <asm-generic/gpio.h> /* cansleep wrappers */ +#endif /* !CONFIG_GPIOLIB */ #include <asm/irq.h> static inline int gpio_to_irq(unsigned gpio) diff --git a/arch/blackfin/include/asm/hardirq.h b/arch/blackfin/include/asm/hardirq.h index b6b19f1b9dab..717181a1749b 100644 --- a/arch/blackfin/include/asm/hardirq.h +++ b/arch/blackfin/include/asm/hardirq.h @@ -42,4 +42,6 @@ typedef struct { #define __ARCH_IRQ_EXIT_IRQS_DISABLED 1 +extern void ack_bad_irq(unsigned int irq); + #endif diff --git a/arch/blackfin/include/asm/io.h b/arch/blackfin/include/asm/io.h index 7dc77a21fdf3..63b2d8c78570 100644 --- a/arch/blackfin/include/asm/io.h +++ b/arch/blackfin/include/asm/io.h @@ -94,12 +94,12 @@ static inline unsigned int readl(const volatile void __iomem *addr) #define outw_p(x,addr) outw(x,addr) #define outl_p(x,addr) outl(x,addr) -#define ioread8_rep(a,d,c) insb(a,d,c) -#define ioread16_rep(a,d,c) insw(a,d,c) -#define ioread32_rep(a,d,c) insl(a,d,c) -#define iowrite8_rep(a,s,c) outsb(a,s,c) -#define iowrite16_rep(a,s,c) outsw(a,s,c) -#define iowrite32_rep(a,s,c) outsl(a,s,c) +#define ioread8_rep(a,d,c) readsb(a,d,c) +#define ioread16_rep(a,d,c) readsw(a,d,c) +#define ioread32_rep(a,d,c) readsl(a,d,c) +#define iowrite8_rep(a,s,c) writesb(a,s,c) +#define iowrite16_rep(a,s,c) writesw(a,s,c) +#define iowrite32_rep(a,s,c) writesl(a,s,c) #define ioread8(X) readb(X) #define ioread16(X) readw(X) @@ -108,6 +108,8 @@ static inline unsigned int readl(const volatile void __iomem *addr) #define iowrite16(val,X) writew(val,X) #define iowrite32(val,X) writel(val,X) +#define mmiowb() wmb() + #define IO_SPACE_LIMIT 0xffffffff /* Values for nocacheflag and cmode */ diff --git a/arch/blackfin/include/asm/ipipe.h b/arch/blackfin/include/asm/ipipe.h new file mode 100644 index 000000000000..76f53d8b9a0d --- /dev/null +++ b/arch/blackfin/include/asm/ipipe.h @@ -0,0 +1,278 @@ +/* -*- linux-c -*- + * include/asm-blackfin/ipipe.h + * + * Copyright (C) 2002-2007 Philippe Gerum. + * + * 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, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ASM_BLACKFIN_IPIPE_H +#define __ASM_BLACKFIN_IPIPE_H + +#ifdef CONFIG_IPIPE + +#include <linux/cpumask.h> +#include <linux/list.h> +#include <linux/threads.h> +#include <linux/irq.h> +#include <linux/ipipe_percpu.h> +#include <asm/ptrace.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/atomic.h> +#include <asm/traps.h> + +#define IPIPE_ARCH_STRING "1.8-00" +#define IPIPE_MAJOR_NUMBER 1 +#define IPIPE_MINOR_NUMBER 8 +#define IPIPE_PATCH_NUMBER 0 + +#ifdef CONFIG_SMP +#error "I-pipe/blackfin: SMP not implemented" +#else /* !CONFIG_SMP */ +#define ipipe_processor_id() 0 +#endif /* CONFIG_SMP */ + +#define prepare_arch_switch(next) \ +do { \ + ipipe_schedule_notify(current, next); \ + local_irq_disable_hw(); \ +} while (0) + +#define task_hijacked(p) \ + ({ \ + int __x__ = ipipe_current_domain != ipipe_root_domain; \ + /* We would need to clear the SYNC flag for the root domain */ \ + /* over the current processor in SMP mode. */ \ + local_irq_enable_hw(); __x__; \ + }) + +struct ipipe_domain; + +struct ipipe_sysinfo { + + int ncpus; /* Number of CPUs on board */ + u64 cpufreq; /* CPU frequency (in Hz) */ + + /* Arch-dependent block */ + + struct { + unsigned tmirq; /* Timer tick IRQ */ + u64 tmfreq; /* Timer frequency */ + } archdep; +}; + +#define ipipe_read_tsc(t) \ + ({ \ + unsigned long __cy2; \ + __asm__ __volatile__ ("1: %0 = CYCLES2\n" \ + "%1 = CYCLES\n" \ + "%2 = CYCLES2\n" \ + "CC = %2 == %0\n" \ + "if ! CC jump 1b\n" \ + : "=r" (((unsigned long *)&t)[1]), \ + "=r" (((unsigned long *)&t)[0]), \ + "=r" (__cy2) \ + : /*no input*/ : "CC"); \ + t; \ + }) + +#define ipipe_cpu_freq() __ipipe_core_clock +#define ipipe_tsc2ns(_t) (((unsigned long)(_t)) * __ipipe_freq_scale) +#define ipipe_tsc2us(_t) (ipipe_tsc2ns(_t) / 1000 + 1) + +/* Private interface -- Internal use only */ + +#define __ipipe_check_platform() do { } while (0) + +#define __ipipe_init_platform() do { } while (0) + +extern atomic_t __ipipe_irq_lvdepth[IVG15 + 1]; + +extern unsigned long __ipipe_irq_lvmask; + +extern struct ipipe_domain ipipe_root; + +/* enable/disable_irqdesc _must_ be used in pairs. */ + +void __ipipe_enable_irqdesc(struct ipipe_domain *ipd, + unsigned irq); + +void __ipipe_disable_irqdesc(struct ipipe_domain *ipd, + unsigned irq); + +#define __ipipe_enable_irq(irq) (irq_desc[irq].chip->unmask(irq)) + +#define __ipipe_disable_irq(irq) (irq_desc[irq].chip->mask(irq)) + +#define __ipipe_lock_root() \ + set_bit(IPIPE_ROOTLOCK_FLAG, &ipipe_root_domain->flags) + +#define __ipipe_unlock_root() \ + clear_bit(IPIPE_ROOTLOCK_FLAG, &ipipe_root_domain->flags) + +void __ipipe_enable_pipeline(void); + +#define __ipipe_hook_critical_ipi(ipd) do { } while (0) + +#define __ipipe_sync_pipeline(syncmask) \ + do { \ + struct ipipe_domain *ipd = ipipe_current_domain; \ + if (likely(ipd != ipipe_root_domain || !test_bit(IPIPE_ROOTLOCK_FLAG, &ipd->flags))) \ + __ipipe_sync_stage(syncmask); \ + } while (0) + +void __ipipe_handle_irq(unsigned irq, struct pt_regs *regs); + +int __ipipe_get_irq_priority(unsigned irq); + +int __ipipe_get_irqthread_priority(unsigned irq); + +void __ipipe_stall_root_raw(void); + +void __ipipe_unstall_root_raw(void); + +void __ipipe_serial_debug(const char *fmt, ...); + +DECLARE_PER_CPU(struct pt_regs, __ipipe_tick_regs); + +extern unsigned long __ipipe_core_clock; + +extern unsigned long __ipipe_freq_scale; + +extern unsigned long __ipipe_irq_tail_hook; + +static inline unsigned long __ipipe_ffnz(unsigned long ul) +{ + return ffs(ul) - 1; +} + +#define __ipipe_run_irqtail() /* Must be a macro */ \ + do { \ + asmlinkage void __ipipe_call_irqtail(void); \ + unsigned long __pending; \ + CSYNC(); \ + __pending = bfin_read_IPEND(); \ + if (__pending & 0x8000) { \ + __pending &= ~0x8010; \ + if (__pending && (__pending & (__pending - 1)) == 0) \ + __ipipe_call_irqtail(); \ + } \ + } while (0) + +#define __ipipe_run_isr(ipd, irq) \ + do { \ + if (ipd == ipipe_root_domain) { \ + /* \ + * Note: the I-pipe implements a threaded interrupt model on \ + * this arch for Linux external IRQs. The interrupt handler we \ + * call here only wakes up the associated IRQ thread. \ + */ \ + if (ipipe_virtual_irq_p(irq)) { \ + /* No irqtail here; virtual interrupts have no effect \ + on IPEND so there is no need for processing \ + deferral. */ \ + local_irq_enable_nohead(ipd); \ + ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \ + local_irq_disable_nohead(ipd); \ + } else \ + /* \ + * No need to run the irqtail here either; \ + * we can't be preempted by hw IRQs, so \ + * non-Linux IRQs cannot stack over the short \ + * thread wakeup code. Which in turn means \ + * that no irqtail condition could be pending \ + * for domains above Linux in the pipeline. \ + */ \ + ipd->irqs[irq].handler(irq, &__raw_get_cpu_var(__ipipe_tick_regs)); \ + } else { \ + __clear_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \ + local_irq_enable_nohead(ipd); \ + ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \ + /* Attempt to exit the outer interrupt level before \ + * starting the deferred IRQ processing. */ \ + local_irq_disable_nohead(ipd); \ + __ipipe_run_irqtail(); \ + __set_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \ + } \ + } while (0) + +#define __ipipe_syscall_watched_p(p, sc) \ + (((p)->flags & PF_EVNOTIFY) || (unsigned long)sc >= NR_syscalls) + +void ipipe_init_irq_threads(void); + +int ipipe_start_irq_thread(unsigned irq, struct irq_desc *desc); + +#define IS_SYSIRQ(irq) ((irq) > IRQ_CORETMR && (irq) <= SYS_IRQS) +#define IS_GPIOIRQ(irq) ((irq) >= GPIO_IRQ_BASE && (irq) < NR_IRQS) + +#define IRQ_SYSTMR IRQ_TIMER0 +#define IRQ_PRIOTMR CONFIG_IRQ_TIMER0 + +#if defined(CONFIG_BF531) || defined(CONFIG_BF532) || defined(CONFIG_BF533) +#define PRIO_GPIODEMUX(irq) CONFIG_PFA +#elif defined(CONFIG_BF534) || defined(CONFIG_BF536) || defined(CONFIG_BF537) +#define PRIO_GPIODEMUX(irq) CONFIG_IRQ_PROG_INTA +#elif defined(CONFIG_BF52x) +#define PRIO_GPIODEMUX(irq) ((irq) == IRQ_PORTF_INTA ? CONFIG_IRQ_PORTF_INTA : \ + (irq) == IRQ_PORTG_INTA ? CONFIG_IRQ_PORTG_INTA : \ + (irq) == IRQ_PORTH_INTA ? CONFIG_IRQ_PORTH_INTA : \ + -1) +#elif defined(CONFIG_BF561) +#define PRIO_GPIODEMUX(irq) ((irq) == IRQ_PROG0_INTA ? CONFIG_IRQ_PROG0_INTA : \ + (irq) == IRQ_PROG1_INTA ? CONFIG_IRQ_PROG1_INTA : \ + (irq) == IRQ_PROG2_INTA ? CONFIG_IRQ_PROG2_INTA : \ + -1) +#define bfin_write_TIMER_DISABLE(val) bfin_write_TMRS8_DISABLE(val) +#define bfin_write_TIMER_ENABLE(val) bfin_write_TMRS8_ENABLE(val) +#define bfin_write_TIMER_STATUS(val) bfin_write_TMRS8_STATUS(val) +#define bfin_read_TIMER_STATUS() bfin_read_TMRS8_STATUS() +#elif defined(CONFIG_BF54x) +#define PRIO_GPIODEMUX(irq) ((irq) == IRQ_PINT0 ? CONFIG_IRQ_PINT0 : \ + (irq) == IRQ_PINT1 ? CONFIG_IRQ_PINT1 : \ + (irq) == IRQ_PINT2 ? CONFIG_IRQ_PINT2 : \ + (irq) == IRQ_PINT3 ? CONFIG_IRQ_PINT3 : \ + -1) +#define bfin_write_TIMER_DISABLE(val) bfin_write_TIMER_DISABLE0(val) +#define bfin_write_TIMER_ENABLE(val) bfin_write_TIMER_ENABLE0(val) +#define bfin_write_TIMER_STATUS(val) bfin_write_TIMER_STATUS0(val) +#define bfin_read_TIMER_STATUS(val) bfin_read_TIMER_STATUS0(val) +#else +# error "no PRIO_GPIODEMUX() for this part" +#endif + +#define __ipipe_root_tick_p(regs) ((regs->ipend & 0x10) != 0) + +#else /* !CONFIG_IPIPE */ + +#define task_hijacked(p) 0 +#define ipipe_trap_notify(t, r) 0 + +#define __ipipe_stall_root_raw() do { } while (0) +#define __ipipe_unstall_root_raw() do { } while (0) + +#define ipipe_init_irq_threads() do { } while (0) +#define ipipe_start_irq_thread(irq, desc) 0 + +#define IRQ_SYSTMR IRQ_CORETMR +#define IRQ_PRIOTMR IRQ_CORETMR + +#define __ipipe_root_tick_p(regs) 1 + +#endif /* !CONFIG_IPIPE */ + +#endif /* !__ASM_BLACKFIN_IPIPE_H */ diff --git a/arch/blackfin/include/asm/ipipe_base.h b/arch/blackfin/include/asm/ipipe_base.h new file mode 100644 index 000000000000..cb1025aeabcf --- /dev/null +++ b/arch/blackfin/include/asm/ipipe_base.h @@ -0,0 +1,80 @@ +/* -*- linux-c -*- + * include/asm-blackfin/_baseipipe.h + * + * Copyright (C) 2007 Philippe Gerum. + * + * 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, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ASM_BLACKFIN_IPIPE_BASE_H +#define __ASM_BLACKFIN_IPIPE_BASE_H + +#ifdef CONFIG_IPIPE + +#define IPIPE_NR_XIRQS NR_IRQS +#define IPIPE_IRQ_ISHIFT 5 /* 2^5 for 32bits arch. */ + +/* Blackfin-specific, global domain flags */ +#define IPIPE_ROOTLOCK_FLAG 1 /* Lock pipeline for root */ + + /* Blackfin traps -- i.e. exception vector numbers */ +#define IPIPE_NR_FAULTS 52 /* We leave a gap after VEC_ILL_RES. */ +/* Pseudo-vectors used for kernel events */ +#define IPIPE_FIRST_EVENT IPIPE_NR_FAULTS +#define IPIPE_EVENT_SYSCALL (IPIPE_FIRST_EVENT) +#define IPIPE_EVENT_SCHEDULE (IPIPE_FIRST_EVENT + 1) +#define IPIPE_EVENT_SIGWAKE (IPIPE_FIRST_EVENT + 2) +#define IPIPE_EVENT_SETSCHED (IPIPE_FIRST_EVENT + 3) +#define IPIPE_EVENT_INIT (IPIPE_FIRST_EVENT + 4) +#define IPIPE_EVENT_EXIT (IPIPE_FIRST_EVENT + 5) +#define IPIPE_EVENT_CLEANUP (IPIPE_FIRST_EVENT + 6) +#define IPIPE_LAST_EVENT IPIPE_EVENT_CLEANUP +#define IPIPE_NR_EVENTS (IPIPE_LAST_EVENT + 1) + +#define IPIPE_TIMER_IRQ IRQ_CORETMR + +#ifndef __ASSEMBLY__ + +#include <linux/bitops.h> + +extern int test_bit(int nr, const void *addr); + + +extern unsigned long __ipipe_root_status; /* Alias to ipipe_root_cpudom_var(status) */ + +static inline void __ipipe_stall_root(void) +{ + volatile unsigned long *p = &__ipipe_root_status; + set_bit(0, p); +} + +static inline unsigned long __ipipe_test_and_stall_root(void) +{ + volatile unsigned long *p = &__ipipe_root_status; + return test_and_set_bit(0, p); +} + +static inline unsigned long __ipipe_test_root(void) +{ + const unsigned long *p = &__ipipe_root_status; + return test_bit(0, p); +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* CONFIG_IPIPE */ + +#endif /* !__ASM_BLACKFIN_IPIPE_BASE_H */ diff --git a/arch/blackfin/include/asm/irq.h b/arch/blackfin/include/asm/irq.h index 89f59e18af93..3d977909ce7d 100644 --- a/arch/blackfin/include/asm/irq.h +++ b/arch/blackfin/include/asm/irq.h @@ -17,56 +17,272 @@ #ifndef _BFIN_IRQ_H_ #define _BFIN_IRQ_H_ +/* SYS_IRQS and NR_IRQS are defined in <mach-bf5xx/irq.h>*/ #include <mach/irq.h> -#include <asm/ptrace.h> - -/******************************************************************************* - ***** INTRODUCTION *********** - * On the Blackfin, the interrupt structure allows remmapping of the hardware - * levels. - * - I'm going to assume that the H/W level is going to stay at the default - * settings. If someone wants to go through and abstart this out, feel free - * to mod the interrupt numbering scheme. - * - I'm abstracting the interrupts so that uClinux does not know anything - * about the H/W levels. If you want to change the H/W AND keep the abstracted - * levels that uClinux sees, you should be able to do most of it here. - * - I've left the "abstract" numbering sparce in case someone wants to pull the - * interrupts apart (just the TX/RX for the various devices) - *******************************************************************************/ +#include <asm/pda.h> +#include <asm/processor.h> -/* SYS_IRQS and NR_IRQS are defined in <mach-bf5xx/irq.h>*/ +#ifdef CONFIG_SMP +/* Forward decl needed due to cdef inter dependencies */ +static inline uint32_t __pure bfin_dspid(void); +# define blackfin_core_id() (bfin_dspid() & 0xff) +# define bfin_irq_flags cpu_pda[blackfin_core_id()].imask +#else +extern unsigned long bfin_irq_flags; +#endif -/* - * Machine specific interrupt sources. - * - * Adding an interrupt service routine for a source with this bit - * set indicates a special machine specific interrupt source. - * The machine specific files define these sources. - * - * The IRQ_MACHSPEC bit is now gone - the only thing it did was to - * introduce unnecessary overhead. - * - * All interrupt handling is actually machine specific so it is better - * to use function pointers, as used by the Sparc port, and select the - * interrupt handling functions when initializing the kernel. This way - * we save some unnecessary overhead at run-time. - * 01/11/97 - Jes - */ +#ifdef CONFIG_IPIPE + +#include <linux/ipipe_trace.h> + +void __ipipe_unstall_root(void); + +void __ipipe_restore_root(unsigned long flags); + +#ifdef CONFIG_DEBUG_HWERR +# define __all_masked_irq_flags 0x3f +# define __save_and_cli_hw(x) \ + __asm__ __volatile__( \ + "cli %0;" \ + "sti %1;" \ + : "=&d"(x) \ + : "d" (0x3F) \ + ) +#else +# define __all_masked_irq_flags 0x1f +# define __save_and_cli_hw(x) \ + __asm__ __volatile__( \ + "cli %0;" \ + : "=&d"(x) \ + ) +#endif + +#define irqs_enabled_from_flags_hw(x) ((x) != __all_masked_irq_flags) +#define raw_irqs_disabled_flags(flags) (!irqs_enabled_from_flags_hw(flags)) +#define local_test_iflag_hw(x) irqs_enabled_from_flags_hw(x) -extern void ack_bad_irq(unsigned int irq); +#define local_save_flags(x) \ + do { \ + (x) = __ipipe_test_root() ? \ + __all_masked_irq_flags : bfin_irq_flags; \ + } while (0) -static __inline__ int irq_canonicalize(int irq) +#define local_irq_save(x) \ + do { \ + (x) = __ipipe_test_and_stall_root(); \ + } while (0) + +#define local_irq_restore(x) __ipipe_restore_root(x) +#define local_irq_disable() __ipipe_stall_root() +#define local_irq_enable() __ipipe_unstall_root() +#define irqs_disabled() __ipipe_test_root() + +#define local_save_flags_hw(x) \ + __asm__ __volatile__( \ + "cli %0;" \ + "sti %0;" \ + : "=d"(x) \ + ) + +#define irqs_disabled_hw() \ + ({ \ + unsigned long flags; \ + local_save_flags_hw(flags); \ + !irqs_enabled_from_flags_hw(flags); \ + }) + +static inline unsigned long raw_mangle_irq_bits(int virt, unsigned long real) { - return irq; + /* Merge virtual and real interrupt mask bits into a single + 32bit word. */ + return (real & ~(1 << 31)) | ((virt != 0) << 31); +} + +static inline int raw_demangle_irq_bits(unsigned long *x) +{ + int virt = (*x & (1 << 31)) != 0; + *x &= ~(1L << 31); + return virt; } -/* count of spurious interrupts */ -/* extern volatile unsigned int num_spurious; */ +#ifdef CONFIG_IPIPE_TRACE_IRQSOFF + +#define local_irq_disable_hw() \ + do { \ + int _tmp_dummy; \ + if (!irqs_disabled_hw()) \ + ipipe_trace_begin(0x80000000); \ + __asm__ __volatile__ ("cli %0;" : "=d" (_tmp_dummy) : ); \ + } while (0) + +#define local_irq_enable_hw() \ + do { \ + if (irqs_disabled_hw()) \ + ipipe_trace_end(0x80000000); \ + __asm__ __volatile__ ("sti %0;" : : "d"(bfin_irq_flags)); \ + } while (0) + +#define local_irq_save_hw(x) \ + do { \ + __save_and_cli_hw(x); \ + if (local_test_iflag_hw(x)) \ + ipipe_trace_begin(0x80000001); \ + } while (0) + +#define local_irq_restore_hw(x) \ + do { \ + if (local_test_iflag_hw(x)) { \ + ipipe_trace_end(0x80000001); \ + local_irq_enable_hw_notrace(); \ + } \ + } while (0) + +#define local_irq_disable_hw_notrace() \ + do { \ + int _tmp_dummy; \ + __asm__ __volatile__ ("cli %0;" : "=d" (_tmp_dummy) : ); \ + } while (0) + +#define local_irq_enable_hw_notrace() \ + __asm__ __volatile__( \ + "sti %0;" \ + : \ + : "d"(bfin_irq_flags) \ + ) -#ifndef NO_IRQ -#define NO_IRQ ((unsigned int)(-1)) +#define local_irq_save_hw_notrace(x) __save_and_cli_hw(x) + +#define local_irq_restore_hw_notrace(x) \ + do { \ + if (local_test_iflag_hw(x)) \ + local_irq_enable_hw_notrace(); \ + } while (0) + +#else /* CONFIG_IPIPE_TRACE_IRQSOFF */ + +#define local_irq_enable_hw() \ + __asm__ __volatile__( \ + "sti %0;" \ + : \ + : "d"(bfin_irq_flags) \ + ) + +#define local_irq_disable_hw() \ + do { \ + int _tmp_dummy; \ + __asm__ __volatile__ ( \ + "cli %0;" \ + : "=d" (_tmp_dummy)); \ + } while (0) + +#define local_irq_restore_hw(x) \ + do { \ + if (irqs_enabled_from_flags_hw(x)) \ + local_irq_enable_hw(); \ + } while (0) + +#define local_irq_save_hw(x) __save_and_cli_hw(x) + +#define local_irq_disable_hw_notrace() local_irq_disable_hw() +#define local_irq_enable_hw_notrace() local_irq_enable_hw() +#define local_irq_save_hw_notrace(x) local_irq_save_hw(x) +#define local_irq_restore_hw_notrace(x) local_irq_restore_hw(x) + +#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */ + +#else /* !CONFIG_IPIPE */ + +/* + * Interrupt configuring macros. + */ +#define local_irq_disable() \ + do { \ + int __tmp_dummy; \ + __asm__ __volatile__( \ + "cli %0;" \ + : "=d" (__tmp_dummy) \ + ); \ + } while (0) + +#define local_irq_enable() \ + __asm__ __volatile__( \ + "sti %0;" \ + : \ + : "d" (bfin_irq_flags) \ + ) + +#ifdef CONFIG_DEBUG_HWERR +# define __save_and_cli(x) \ + __asm__ __volatile__( \ + "cli %0;" \ + "sti %1;" \ + : "=&d" (x) \ + : "d" (0x3F) \ + ) +#else +# define __save_and_cli(x) \ + __asm__ __volatile__( \ + "cli %0;" \ + : "=&d" (x) \ + ) #endif -#define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1)) +#define local_save_flags(x) \ + __asm__ __volatile__( \ + "cli %0;" \ + "sti %0;" \ + : "=d" (x) \ + ) + +#ifdef CONFIG_DEBUG_HWERR +#define irqs_enabled_from_flags(x) (((x) & ~0x3f) != 0) +#else +#define irqs_enabled_from_flags(x) ((x) != 0x1f) +#endif + +#define local_irq_restore(x) \ + do { \ + if (irqs_enabled_from_flags(x)) \ + local_irq_enable(); \ + } while (0) + +/* For spinlocks etc */ +#define local_irq_save(x) __save_and_cli(x) + +#define irqs_disabled() \ +({ \ + unsigned long flags; \ + local_save_flags(flags); \ + !irqs_enabled_from_flags(flags); \ +}) + +#define local_irq_save_hw(x) local_irq_save(x) +#define local_irq_restore_hw(x) local_irq_restore(x) +#define local_irq_enable_hw() local_irq_enable() +#define local_irq_disable_hw() local_irq_disable() +#define irqs_disabled_hw() irqs_disabled() + +#endif /* !CONFIG_IPIPE */ + +#if ANOMALY_05000244 && defined(CONFIG_BFIN_ICACHE) +# define NOP_PAD_ANOMALY_05000244 "nop; nop;" +#else +# define NOP_PAD_ANOMALY_05000244 +#endif + +#define idle_with_irq_disabled() \ + __asm__ __volatile__( \ + NOP_PAD_ANOMALY_05000244 \ + ".align 8;" \ + "sti %0;" \ + "idle;" \ + : \ + : "d" (bfin_irq_flags) \ + ) + +static inline int irq_canonicalize(int irq) +{ + return irq; +} #endif /* _BFIN_IRQ_H_ */ diff --git a/arch/blackfin/include/asm/l1layout.h b/arch/blackfin/include/asm/l1layout.h index c13ded777828..79dbefaa5bef 100644 --- a/arch/blackfin/include/asm/l1layout.h +++ b/arch/blackfin/include/asm/l1layout.h @@ -8,6 +8,7 @@ #include <asm/blackfin.h> +#ifndef CONFIG_SMP #ifndef __ASSEMBLY__ /* Data that is "mapped" into the process VM at the start of the L1 scratch @@ -24,8 +25,10 @@ struct l1_scratch_task_info }; /* A pointer to the structure in memory. */ -#define L1_SCRATCH_TASK_INFO ((struct l1_scratch_task_info *)L1_SCRATCH_START) +#define L1_SCRATCH_TASK_INFO ((struct l1_scratch_task_info *)\ + get_l1_scratch_start()) #endif +#endif #endif diff --git a/arch/blackfin/include/asm/mem_init.h b/arch/blackfin/include/asm/mem_init.h new file mode 100644 index 000000000000..255a9316ad36 --- /dev/null +++ b/arch/blackfin/include/asm/mem_init.h @@ -0,0 +1,364 @@ +/* + * arch/blackfin/include/asm/mem_init.h - reprogram clocks / memory + * + * Copyright 2004-2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#if defined(EBIU_SDGCTL) +#if defined(CONFIG_MEM_MT48LC16M16A2TG_75) || \ + defined(CONFIG_MEM_MT48LC64M4A2FB_7E) || \ + defined(CONFIG_MEM_MT48LC16M8A2TG_75) || \ + defined(CONFIG_MEM_GENERIC_BOARD) || \ + defined(CONFIG_MEM_MT48LC32M8A2_75) || \ + defined(CONFIG_MEM_MT48LC8M32B2B5_7) || \ + defined(CONFIG_MEM_MT48LC32M16A2TG_75) || \ + defined(CONFIG_MEM_MT48LC32M8A2_75) +#if (CONFIG_SCLK_HZ > 119402985) +#define SDRAM_tRP TRP_2 +#define SDRAM_tRP_num 2 +#define SDRAM_tRAS TRAS_7 +#define SDRAM_tRAS_num 7 +#define SDRAM_tRCD TRCD_2 +#define SDRAM_tWR TWR_2 +#endif +#if (CONFIG_SCLK_HZ > 104477612) && (CONFIG_SCLK_HZ <= 119402985) +#define SDRAM_tRP TRP_2 +#define SDRAM_tRP_num 2 +#define SDRAM_tRAS TRAS_6 +#define SDRAM_tRAS_num 6 +#define SDRAM_tRCD TRCD_2 +#define SDRAM_tWR TWR_2 +#endif +#if (CONFIG_SCLK_HZ > 89552239) && (CONFIG_SCLK_HZ <= 104477612) +#define SDRAM_tRP TRP_2 +#define SDRAM_tRP_num 2 +#define SDRAM_tRAS TRAS_5 +#define SDRAM_tRAS_num 5 +#define SDRAM_tRCD TRCD_2 +#define SDRAM_tWR TWR_2 +#endif +#if (CONFIG_SCLK_HZ > 74626866) && (CONFIG_SCLK_HZ <= 89552239) +#define SDRAM_tRP TRP_2 +#define SDRAM_tRP_num 2 +#define SDRAM_tRAS TRAS_4 +#define SDRAM_tRAS_num 4 +#define SDRAM_tRCD TRCD_2 +#define SDRAM_tWR TWR_2 +#endif +#if (CONFIG_SCLK_HZ > 66666667) && (CONFIG_SCLK_HZ <= 74626866) +#define SDRAM_tRP TRP_2 +#define SDRAM_tRP_num 2 +#define SDRAM_tRAS TRAS_3 +#define SDRAM_tRAS_num 3 +#define SDRAM_tRCD TRCD_2 +#define SDRAM_tWR TWR_2 +#endif +#if (CONFIG_SCLK_HZ > 59701493) && (CONFIG_SCLK_HZ <= 66666667) +#define SDRAM_tRP TRP_1 +#define SDRAM_tRP_num 1 +#define SDRAM_tRAS TRAS_4 +#define SDRAM_tRAS_num 3 +#define SDRAM_tRCD TRCD_1 +#define SDRAM_tWR TWR_2 +#endif +#if (CONFIG_SCLK_HZ > 44776119) && (CONFIG_SCLK_HZ <= 59701493) +#define SDRAM_tRP TRP_1 +#define SDRAM_tRP_num 1 +#define SDRAM_tRAS TRAS_3 +#define SDRAM_tRAS_num 3 +#define SDRAM_tRCD TRCD_1 +#define SDRAM_tWR TWR_2 +#endif +#if (CONFIG_SCLK_HZ > 29850746) && (CONFIG_SCLK_HZ <= 44776119) +#define SDRAM_tRP TRP_1 +#define SDRAM_tRP_num 1 +#define SDRAM_tRAS TRAS_2 +#define SDRAM_tRAS_num 2 +#define SDRAM_tRCD TRCD_1 +#define SDRAM_tWR TWR_2 +#endif +#if (CONFIG_SCLK_HZ <= 29850746) +#define SDRAM_tRP TRP_1 +#define SDRAM_tRP_num 1 +#define SDRAM_tRAS TRAS_1 +#define SDRAM_tRAS_num 1 +#define SDRAM_tRCD TRCD_1 +#define SDRAM_tWR TWR_2 +#endif +#endif + +#if defined(CONFIG_MEM_MT48LC16M8A2TG_75) || \ + defined(CONFIG_MEM_MT48LC8M32B2B5_7) + /*SDRAM INFORMATION: */ +#define SDRAM_Tref 64 /* Refresh period in milliseconds */ +#define SDRAM_NRA 4096 /* Number of row addresses in SDRAM */ +#define SDRAM_CL CL_3 +#endif + +#if defined(CONFIG_MEM_MT48LC32M8A2_75) || \ + defined(CONFIG_MEM_MT48LC64M4A2FB_7E) || \ + defined(CONFIG_MEM_GENERIC_BOARD) || \ + defined(CONFIG_MEM_MT48LC32M16A2TG_75) || \ + defined(CONFIG_MEM_MT48LC16M16A2TG_75) || \ + defined(CONFIG_MEM_MT48LC32M8A2_75) + /*SDRAM INFORMATION: */ +#define SDRAM_Tref 64 /* Refresh period in milliseconds */ +#define SDRAM_NRA 8192 /* Number of row addresses in SDRAM */ +#define SDRAM_CL CL_3 +#endif + + +#ifdef CONFIG_BFIN_KERNEL_CLOCK_MEMINIT_CALC +/* Equation from section 17 (p17-46) of BF533 HRM */ +#define mem_SDRRC (((CONFIG_SCLK_HZ / 1000) * SDRAM_Tref) / SDRAM_NRA) - (SDRAM_tRAS_num + SDRAM_tRP_num) + +/* Enable SCLK Out */ +#define mem_SDGCTL (0x80000000 | SCTLE | SDRAM_CL | SDRAM_tRAS | SDRAM_tRP | SDRAM_tRCD | SDRAM_tWR | PSS) +#else +#define mem_SDRRC CONFIG_MEM_SDRRC +#define mem_SDGCTL CONFIG_MEM_SDGCTL +#endif +#endif + + +#if defined(EBIU_DDRCTL0) +#define MIN_DDR_SCLK(x) (x*(CONFIG_SCLK_HZ/1000/1000)/1000 + 1) +#define MAX_DDR_SCLK(x) (x*(CONFIG_SCLK_HZ/1000/1000)/1000) +#define DDR_CLK_HZ(x) (1000*1000*1000/x) + +#if defined(CONFIG_MEM_MT46V32M16_6T) +#define DDR_SIZE DEVSZ_512 +#define DDR_WIDTH DEVWD_16 +#define DDR_MAX_tCK 13 + +#define DDR_tRC DDR_TRC(MIN_DDR_SCLK(60)) +#define DDR_tRAS DDR_TRAS(MIN_DDR_SCLK(42)) +#define DDR_tRP DDR_TRP(MIN_DDR_SCLK(15)) +#define DDR_tRFC DDR_TRFC(MIN_DDR_SCLK(72)) +#define DDR_tREFI DDR_TREFI(MAX_DDR_SCLK(7800)) + +#define DDR_tRCD DDR_TRCD(MIN_DDR_SCLK(15)) +#define DDR_tWTR DDR_TWTR(1) +#define DDR_tMRD DDR_TMRD(MIN_DDR_SCLK(12)) +#define DDR_tWR DDR_TWR(MIN_DDR_SCLK(15)) +#endif + +#if defined(CONFIG_MEM_MT46V32M16_5B) +#define DDR_SIZE DEVSZ_512 +#define DDR_WIDTH DEVWD_16 +#define DDR_MAX_tCK 13 + +#define DDR_tRC DDR_TRC(MIN_DDR_SCLK(55)) +#define DDR_tRAS DDR_TRAS(MIN_DDR_SCLK(40)) +#define DDR_tRP DDR_TRP(MIN_DDR_SCLK(15)) +#define DDR_tRFC DDR_TRFC(MIN_DDR_SCLK(70)) +#define DDR_tREFI DDR_TREFI(MAX_DDR_SCLK(7800)) + +#define DDR_tRCD DDR_TRCD(MIN_DDR_SCLK(15)) +#define DDR_tWTR DDR_TWTR(2) +#define DDR_tMRD DDR_TMRD(MIN_DDR_SCLK(10)) +#define DDR_tWR DDR_TWR(MIN_DDR_SCLK(15)) +#endif + +#if defined(CONFIG_MEM_GENERIC_BOARD) +#define DDR_SIZE DEVSZ_512 +#define DDR_WIDTH DEVWD_16 +#define DDR_MAX_tCK 13 + +#define DDR_tRCD DDR_TRCD(3) +#define DDR_tWTR DDR_TWTR(2) +#define DDR_tWR DDR_TWR(2) +#define DDR_tMRD DDR_TMRD(2) +#define DDR_tRP DDR_TRP(3) +#define DDR_tRAS DDR_TRAS(7) +#define DDR_tRC DDR_TRC(10) +#define DDR_tRFC DDR_TRFC(12) +#define DDR_tREFI DDR_TREFI(1288) +#endif + +#if (CONFIG_SCLK_HZ < DDR_CLK_HZ(DDR_MAX_tCK)) +# error "CONFIG_SCLK_HZ is too small (<DDR_CLK_HZ(DDR_MAX_tCK) Hz)." +#elif(CONFIG_SCLK_HZ <= 133333333) +# define DDR_CL CL_2 +#else +# error "CONFIG_SCLK_HZ is too large (>133333333 Hz)." +#endif + +#ifdef CONFIG_BFIN_KERNEL_CLOCK_MEMINIT_CALC +#define mem_DDRCTL0 (DDR_tRP | DDR_tRAS | DDR_tRC | DDR_tRFC | DDR_tREFI) +#define mem_DDRCTL1 (DDR_DATWIDTH | EXTBANK_1 | DDR_SIZE | DDR_WIDTH | DDR_tWTR \ + | DDR_tMRD | DDR_tWR | DDR_tRCD) +#define mem_DDRCTL2 DDR_CL +#else +#define mem_DDRCTL0 CONFIG_MEM_DDRCTL0 +#define mem_DDRCTL1 CONFIG_MEM_DDRCTL1 +#define mem_DDRCTL2 CONFIG_MEM_DDRCTL2 +#endif +#endif + +#if defined CONFIG_CLKIN_HALF +#define CLKIN_HALF 1 +#else +#define CLKIN_HALF 0 +#endif + +#if defined CONFIG_PLL_BYPASS +#define PLL_BYPASS 1 +#else +#define PLL_BYPASS 0 +#endif + +/***************************************Currently Not Being Used *********************************/ + +#if defined(CONFIG_FLASH_SPEED_BWAT) && \ +defined(CONFIG_FLASH_SPEED_BRAT) && \ +defined(CONFIG_FLASH_SPEED_BHT) && \ +defined(CONFIG_FLASH_SPEED_BST) && \ +defined(CONFIG_FLASH_SPEED_BTT) + +#define flash_EBIU_AMBCTL_WAT ((CONFIG_FLASH_SPEED_BWAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1 +#define flash_EBIU_AMBCTL_RAT ((CONFIG_FLASH_SPEED_BRAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1 +#define flash_EBIU_AMBCTL_HT ((CONFIG_FLASH_SPEED_BHT * 4) / (4000000000 / CONFIG_SCLK_HZ)) +#define flash_EBIU_AMBCTL_ST ((CONFIG_FLASH_SPEED_BST * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1 +#define flash_EBIU_AMBCTL_TT ((CONFIG_FLASH_SPEED_BTT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1 + +#if (flash_EBIU_AMBCTL_TT > 3) +#define flash_EBIU_AMBCTL0_TT B0TT_4 +#endif +#if (flash_EBIU_AMBCTL_TT == 3) +#define flash_EBIU_AMBCTL0_TT B0TT_3 +#endif +#if (flash_EBIU_AMBCTL_TT == 2) +#define flash_EBIU_AMBCTL0_TT B0TT_2 +#endif +#if (flash_EBIU_AMBCTL_TT < 2) +#define flash_EBIU_AMBCTL0_TT B0TT_1 +#endif + +#if (flash_EBIU_AMBCTL_ST > 3) +#define flash_EBIU_AMBCTL0_ST B0ST_4 +#endif +#if (flash_EBIU_AMBCTL_ST == 3) +#define flash_EBIU_AMBCTL0_ST B0ST_3 +#endif +#if (flash_EBIU_AMBCTL_ST == 2) +#define flash_EBIU_AMBCTL0_ST B0ST_2 +#endif +#if (flash_EBIU_AMBCTL_ST < 2) +#define flash_EBIU_AMBCTL0_ST B0ST_1 +#endif + +#if (flash_EBIU_AMBCTL_HT > 2) +#define flash_EBIU_AMBCTL0_HT B0HT_3 +#endif +#if (flash_EBIU_AMBCTL_HT == 2) +#define flash_EBIU_AMBCTL0_HT B0HT_2 +#endif +#if (flash_EBIU_AMBCTL_HT == 1) +#define flash_EBIU_AMBCTL0_HT B0HT_1 +#endif +#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT == 0) +#define flash_EBIU_AMBCTL0_HT B0HT_0 +#endif +#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT != 0) +#define flash_EBIU_AMBCTL0_HT B0HT_1 +#endif + +#if (flash_EBIU_AMBCTL_WAT > 14) +#define flash_EBIU_AMBCTL0_WAT B0WAT_15 +#endif +#if (flash_EBIU_AMBCTL_WAT == 14) +#define flash_EBIU_AMBCTL0_WAT B0WAT_14 +#endif +#if (flash_EBIU_AMBCTL_WAT == 13) +#define flash_EBIU_AMBCTL0_WAT B0WAT_13 +#endif +#if (flash_EBIU_AMBCTL_WAT == 12) +#define flash_EBIU_AMBCTL0_WAT B0WAT_12 +#endif +#if (flash_EBIU_AMBCTL_WAT == 11) +#define flash_EBIU_AMBCTL0_WAT B0WAT_11 +#endif +#if (flash_EBIU_AMBCTL_WAT == 10) +#define flash_EBIU_AMBCTL0_WAT B0WAT_10 +#endif +#if (flash_EBIU_AMBCTL_WAT == 9) +#define flash_EBIU_AMBCTL0_WAT B0WAT_9 +#endif +#if (flash_EBIU_AMBCTL_WAT == 8) +#define flash_EBIU_AMBCTL0_WAT B0WAT_8 +#endif +#if (flash_EBIU_AMBCTL_WAT == 7) +#define flash_EBIU_AMBCTL0_WAT B0WAT_7 +#endif +#if (flash_EBIU_AMBCTL_WAT == 6) +#define flash_EBIU_AMBCTL0_WAT B0WAT_6 +#endif +#if (flash_EBIU_AMBCTL_WAT == 5) +#define flash_EBIU_AMBCTL0_WAT B0WAT_5 +#endif +#if (flash_EBIU_AMBCTL_WAT == 4) +#define flash_EBIU_AMBCTL0_WAT B0WAT_4 +#endif +#if (flash_EBIU_AMBCTL_WAT == 3) +#define flash_EBIU_AMBCTL0_WAT B0WAT_3 +#endif +#if (flash_EBIU_AMBCTL_WAT == 2) +#define flash_EBIU_AMBCTL0_WAT B0WAT_2 +#endif +#if (flash_EBIU_AMBCTL_WAT == 1) +#define flash_EBIU_AMBCTL0_WAT B0WAT_1 +#endif + +#if (flash_EBIU_AMBCTL_RAT > 14) +#define flash_EBIU_AMBCTL0_RAT B0RAT_15 +#endif +#if (flash_EBIU_AMBCTL_RAT == 14) +#define flash_EBIU_AMBCTL0_RAT B0RAT_14 +#endif +#if (flash_EBIU_AMBCTL_RAT == 13) +#define flash_EBIU_AMBCTL0_RAT B0RAT_13 +#endif +#if (flash_EBIU_AMBCTL_RAT == 12) +#define flash_EBIU_AMBCTL0_RAT B0RAT_12 +#endif +#if (flash_EBIU_AMBCTL_RAT == 11) +#define flash_EBIU_AMBCTL0_RAT B0RAT_11 +#endif +#if (flash_EBIU_AMBCTL_RAT == 10) +#define flash_EBIU_AMBCTL0_RAT B0RAT_10 +#endif +#if (flash_EBIU_AMBCTL_RAT == 9) +#define flash_EBIU_AMBCTL0_RAT B0RAT_9 +#endif +#if (flash_EBIU_AMBCTL_RAT == 8) +#define flash_EBIU_AMBCTL0_RAT B0RAT_8 +#endif +#if (flash_EBIU_AMBCTL_RAT == 7) +#define flash_EBIU_AMBCTL0_RAT B0RAT_7 +#endif +#if (flash_EBIU_AMBCTL_RAT == 6) +#define flash_EBIU_AMBCTL0_RAT B0RAT_6 +#endif +#if (flash_EBIU_AMBCTL_RAT == 5) +#define flash_EBIU_AMBCTL0_RAT B0RAT_5 +#endif +#if (flash_EBIU_AMBCTL_RAT == 4) +#define flash_EBIU_AMBCTL0_RAT B0RAT_4 +#endif +#if (flash_EBIU_AMBCTL_RAT == 3) +#define flash_EBIU_AMBCTL0_RAT B0RAT_3 +#endif +#if (flash_EBIU_AMBCTL_RAT == 2) +#define flash_EBIU_AMBCTL0_RAT B0RAT_2 +#endif +#if (flash_EBIU_AMBCTL_RAT == 1) +#define flash_EBIU_AMBCTL0_RAT B0RAT_1 +#endif + +#define flash_EBIU_AMBCTL0 \ + (flash_EBIU_AMBCTL0_WAT | flash_EBIU_AMBCTL0_RAT | flash_EBIU_AMBCTL0_HT | \ + flash_EBIU_AMBCTL0_ST | flash_EBIU_AMBCTL0_TT | CONFIG_FLASH_SPEED_RDYEN) +#endif diff --git a/arch/blackfin/include/asm/mem_map.h b/arch/blackfin/include/asm/mem_map.h index 88d04a707708..e92b31051bb7 100644 --- a/arch/blackfin/include/asm/mem_map.h +++ b/arch/blackfin/include/asm/mem_map.h @@ -9,4 +9,79 @@ #include <mach/mem_map.h> +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_SMP +static inline ulong get_l1_scratch_start_cpu(int cpu) +{ + return (cpu) ? COREB_L1_SCRATCH_START : COREA_L1_SCRATCH_START; +} +static inline ulong get_l1_code_start_cpu(int cpu) +{ + return (cpu) ? COREB_L1_CODE_START : COREA_L1_CODE_START; +} +static inline ulong get_l1_data_a_start_cpu(int cpu) +{ + return (cpu) ? COREB_L1_DATA_A_START : COREA_L1_DATA_A_START; +} +static inline ulong get_l1_data_b_start_cpu(int cpu) +{ + return (cpu) ? COREB_L1_DATA_B_START : COREA_L1_DATA_B_START; +} + +static inline ulong get_l1_scratch_start(void) +{ + return get_l1_scratch_start_cpu(blackfin_core_id()); +} +static inline ulong get_l1_code_start(void) +{ + return get_l1_code_start_cpu(blackfin_core_id()); +} +static inline ulong get_l1_data_a_start(void) +{ + return get_l1_data_a_start_cpu(blackfin_core_id()); +} +static inline ulong get_l1_data_b_start(void) +{ + return get_l1_data_b_start_cpu(blackfin_core_id()); +} + +#else /* !CONFIG_SMP */ + +static inline ulong get_l1_scratch_start_cpu(int cpu) +{ + return L1_SCRATCH_START; +} +static inline ulong get_l1_code_start_cpu(int cpu) +{ + return L1_CODE_START; +} +static inline ulong get_l1_data_a_start_cpu(int cpu) +{ + return L1_DATA_A_START; +} +static inline ulong get_l1_data_b_start_cpu(int cpu) +{ + return L1_DATA_B_START; +} +static inline ulong get_l1_scratch_start(void) +{ + return get_l1_scratch_start_cpu(0); +} +static inline ulong get_l1_code_start(void) +{ + return get_l1_code_start_cpu(0); +} +static inline ulong get_l1_data_a_start(void) +{ + return get_l1_data_a_start_cpu(0); +} +static inline ulong get_l1_data_b_start(void) +{ + return get_l1_data_b_start_cpu(0); +} + +#endif /* CONFIG_SMP */ +#endif /* __ASSEMBLY__ */ + #endif /* _MEM_MAP_H_ */ diff --git a/arch/blackfin/include/asm/mmu_context.h b/arch/blackfin/include/asm/mmu_context.h index 35593dda2a4d..944e29faae48 100644 --- a/arch/blackfin/include/asm/mmu_context.h +++ b/arch/blackfin/include/asm/mmu_context.h @@ -37,6 +37,10 @@ #include <asm/pgalloc.h> #include <asm/cplbinit.h> +/* Note: L1 stacks are CPU-private things, so we bluntly disable this + feature in SMP mode, and use the per-CPU scratch SRAM bank only to + store the PDA instead. */ + extern void *current_l1_stack_save; extern int nr_l1stack_tasks; extern void *l1_stack_base; @@ -88,12 +92,15 @@ activate_l1stack(struct mm_struct *mm, unsigned long sp_base) static inline void switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm, struct task_struct *tsk) { +#ifdef CONFIG_MPU + unsigned int cpu = smp_processor_id(); +#endif if (prev_mm == next_mm) return; #ifdef CONFIG_MPU - if (prev_mm->context.page_rwx_mask == current_rwx_mask) { - flush_switched_cplbs(); - set_mask_dcplbs(next_mm->context.page_rwx_mask); + if (prev_mm->context.page_rwx_mask == current_rwx_mask[cpu]) { + flush_switched_cplbs(cpu); + set_mask_dcplbs(next_mm->context.page_rwx_mask, cpu); } #endif @@ -138,9 +145,10 @@ static inline void protect_page(struct mm_struct *mm, unsigned long addr, static inline void update_protections(struct mm_struct *mm) { - if (mm->context.page_rwx_mask == current_rwx_mask) { - flush_switched_cplbs(); - set_mask_dcplbs(mm->context.page_rwx_mask); + unsigned int cpu = smp_processor_id(); + if (mm->context.page_rwx_mask == current_rwx_mask[cpu]) { + flush_switched_cplbs(cpu); + set_mask_dcplbs(mm->context.page_rwx_mask, cpu); } } #endif @@ -165,6 +173,9 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm) static inline void destroy_context(struct mm_struct *mm) { struct sram_list_struct *tmp; +#ifdef CONFIG_MPU + unsigned int cpu = smp_processor_id(); +#endif #ifdef CONFIG_APP_STACK_L1 if (current_l1_stack_save == mm->context.l1_stack_save) @@ -179,8 +190,8 @@ static inline void destroy_context(struct mm_struct *mm) kfree(tmp); } #ifdef CONFIG_MPU - if (current_rwx_mask == mm->context.page_rwx_mask) - current_rwx_mask = NULL; + if (current_rwx_mask[cpu] == mm->context.page_rwx_mask) + current_rwx_mask[cpu] = NULL; free_pages((unsigned long)mm->context.page_rwx_mask, page_mask_order); #endif } diff --git a/arch/blackfin/include/asm/mutex-dec.h b/arch/blackfin/include/asm/mutex-dec.h new file mode 100644 index 000000000000..0134151656af --- /dev/null +++ b/arch/blackfin/include/asm/mutex-dec.h @@ -0,0 +1,112 @@ +/* + * include/asm-generic/mutex-dec.h + * + * Generic implementation of the mutex fastpath, based on atomic + * decrement/increment. + */ +#ifndef _ASM_GENERIC_MUTEX_DEC_H +#define _ASM_GENERIC_MUTEX_DEC_H + +/** + * __mutex_fastpath_lock - try to take the lock by moving the count + * from 1 to a 0 value + * @count: pointer of type atomic_t + * @fail_fn: function to call if the original value was not 1 + * + * Change the count from 1 to a value lower than 1, and call <fail_fn> if + * it wasn't 1 originally. This function MUST leave the value lower than + * 1 even when the "1" assertion wasn't true. + */ +static inline void +__mutex_fastpath_lock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *)) +{ + if (unlikely(atomic_dec_return(count) < 0)) + fail_fn(count); + else + smp_mb(); +} + +/** + * __mutex_fastpath_lock_retval - try to take the lock by moving the count + * from 1 to a 0 value + * @count: pointer of type atomic_t + * @fail_fn: function to call if the original value was not 1 + * + * Change the count from 1 to a value lower than 1, and call <fail_fn> if + * it wasn't 1 originally. This function returns 0 if the fastpath succeeds, + * or anything the slow path function returns. + */ +static inline int +__mutex_fastpath_lock_retval(atomic_t *count, fastcall int (*fail_fn)(atomic_t *)) +{ + if (unlikely(atomic_dec_return(count) < 0)) + return fail_fn(count); + else { + smp_mb(); + return 0; + } +} + +/** + * __mutex_fastpath_unlock - try to promote the count from 0 to 1 + * @count: pointer of type atomic_t + * @fail_fn: function to call if the original value was not 0 + * + * Try to promote the count from 0 to 1. If it wasn't 0, call <fail_fn>. + * In the failure case, this function is allowed to either set the value to + * 1, or to set it to a value lower than 1. + * + * If the implementation sets it to a value of lower than 1, then the + * __mutex_slowpath_needs_to_unlock() macro needs to return 1, it needs + * to return 0 otherwise. + */ +static inline void +__mutex_fastpath_unlock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *)) +{ + smp_mb(); + if (unlikely(atomic_inc_return(count) <= 0)) + fail_fn(count); +} + +#define __mutex_slowpath_needs_to_unlock() 1 + +/** + * __mutex_fastpath_trylock - try to acquire the mutex, without waiting + * + * @count: pointer of type atomic_t + * @fail_fn: fallback function + * + * Change the count from 1 to a value lower than 1, and return 0 (failure) + * if it wasn't 1 originally, or return 1 (success) otherwise. This function + * MUST leave the value lower than 1 even when the "1" assertion wasn't true. + * Additionally, if the value was < 0 originally, this function must not leave + * it to 0 on failure. + * + * If the architecture has no effective trylock variant, it should call the + * <fail_fn> spinlock-based trylock variant unconditionally. + */ +static inline int +__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) +{ + /* + * We have two variants here. The cmpxchg based one is the best one + * because it never induce a false contention state. It is included + * here because architectures using the inc/dec algorithms over the + * xchg ones are much more likely to support cmpxchg natively. + * + * If not we fall back to the spinlock based variant - that is + * just as efficient (and simpler) as a 'destructive' probing of + * the mutex state would be. + */ +#ifdef __HAVE_ARCH_CMPXCHG + if (likely(atomic_cmpxchg(count, 1, 0) == 1)) { + smp_mb(); + return 1; + } + return 0; +#else + return fail_fn(count); +#endif +} + +#endif diff --git a/arch/blackfin/include/asm/mutex.h b/arch/blackfin/include/asm/mutex.h index 458c1f7fbc18..5d399256bf06 100644 --- a/arch/blackfin/include/asm/mutex.h +++ b/arch/blackfin/include/asm/mutex.h @@ -6,4 +6,67 @@ * implementation. (see asm-generic/mutex-xchg.h for details) */ +#ifndef _ASM_MUTEX_H +#define _ASM_MUTEX_H + +#ifndef CONFIG_SMP #include <asm-generic/mutex-dec.h> +#else + +static inline void +__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *)) +{ + if (unlikely(atomic_dec_return(count) < 0)) + fail_fn(count); + else + smp_mb(); +} + +static inline int +__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *)) +{ + if (unlikely(atomic_dec_return(count) < 0)) + return fail_fn(count); + else { + smp_mb(); + return 0; + } +} + +static inline void +__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) +{ + smp_mb(); + if (unlikely(atomic_inc_return(count) <= 0)) + fail_fn(count); +} + +#define __mutex_slowpath_needs_to_unlock() 1 + +static inline int +__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) +{ + /* + * We have two variants here. The cmpxchg based one is the best one + * because it never induce a false contention state. It is included + * here because architectures using the inc/dec algorithms over the + * xchg ones are much more likely to support cmpxchg natively. + * + * If not we fall back to the spinlock based variant - that is + * just as efficient (and simpler) as a 'destructive' probing of + * the mutex state would be. + */ +#ifdef __HAVE_ARCH_CMPXCHG + if (likely(atomic_cmpxchg(count, 1, 0) == 1)) { + smp_mb(); + return 1; + } + return 0; +#else + return fail_fn(count); +#endif +} + +#endif + +#endif diff --git a/arch/blackfin/include/asm/pda.h b/arch/blackfin/include/asm/pda.h new file mode 100644 index 000000000000..bd8d4a7efeb2 --- /dev/null +++ b/arch/blackfin/include/asm/pda.h @@ -0,0 +1,70 @@ +/* + * File: arch/blackfin/include/asm/pda.h + * Author: Philippe Gerum <rpm@xenomai.org> + * + * Copyright 2007 Analog Devices Inc. + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ASM_BLACKFIN_PDA_H +#define _ASM_BLACKFIN_PDA_H + +#include <mach/anomaly.h> + +#ifndef __ASSEMBLY__ + +struct blackfin_pda { /* Per-processor Data Area */ + struct blackfin_pda *next; + + unsigned long syscfg; +#ifdef CONFIG_SMP + unsigned long imask; /* Current IMASK value */ +#endif + + unsigned long *ipdt; /* Start of switchable I-CPLB table */ + unsigned long *ipdt_swapcount; /* Number of swaps in ipdt */ + unsigned long *dpdt; /* Start of switchable D-CPLB table */ + unsigned long *dpdt_swapcount; /* Number of swaps in dpdt */ + + /* + * Single instructions can have multiple faults, which + * need to be handled by traps.c, in irq5. We store + * the exception cause to ensure we don't miss a + * double fault condition + */ + unsigned long ex_iptr; + unsigned long ex_optr; + unsigned long ex_buf[4]; + unsigned long ex_imask; /* Saved imask from exception */ + unsigned long *ex_stack; /* Exception stack space */ + +#ifdef ANOMALY_05000261 + unsigned long last_cplb_fault_retx; +#endif + unsigned long dcplb_fault_addr; + unsigned long icplb_fault_addr; + unsigned long retx; + unsigned long seqstat; +}; + +extern struct blackfin_pda cpu_pda[]; + +void reserve_pda(void); + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_BLACKFIN_PDA_H */ diff --git a/arch/blackfin/include/asm/percpu.h b/arch/blackfin/include/asm/percpu.h index 78dd61f6b39f..797c0c165069 100644 --- a/arch/blackfin/include/asm/percpu.h +++ b/arch/blackfin/include/asm/percpu.h @@ -3,4 +3,14 @@ #include <asm-generic/percpu.h> -#endif /* __ARCH_BLACKFIN_PERCPU__ */ +#ifdef CONFIG_MODULES +#define PERCPU_MODULE_RESERVE 8192 +#else +#define PERCPU_MODULE_RESERVE 0 +#endif + +#define PERCPU_ENOUGH_ROOM \ + (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) + \ + PERCPU_MODULE_RESERVE) + +#endif /* __ARCH_BLACKFIN_PERCPU__ */ diff --git a/arch/blackfin/include/asm/pgtable.h b/arch/blackfin/include/asm/pgtable.h index f11684e4ade7..783c8f7f8f8c 100644 --- a/arch/blackfin/include/asm/pgtable.h +++ b/arch/blackfin/include/asm/pgtable.h @@ -29,6 +29,7 @@ typedef pte_t *pte_addr_t; #define PAGE_COPY __pgprot(0) /* these mean nothing to NO_MM */ #define PAGE_READONLY __pgprot(0) /* these mean nothing to NO_MM */ #define PAGE_KERNEL __pgprot(0) /* these mean nothing to NO_MM */ +#define pgprot_noncached(prot) (prot) extern void paging_init(void); diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h index e3e9b41fa8db..0eece23b41c7 100644 --- a/arch/blackfin/include/asm/processor.h +++ b/arch/blackfin/include/asm/processor.h @@ -24,6 +24,14 @@ static inline void wrusp(unsigned long usp) __asm__ __volatile__("usp = %0;\n\t"::"da"(usp)); } +static inline unsigned long __get_SP(void) +{ + unsigned long sp; + + __asm__ __volatile__("%0 = sp;\n\t" : "=da"(sp)); + return sp; +} + /* * User space process size: 1st byte beyond user address space. * Fairly meaningless on nommu. Parts of user programs can be scattered @@ -57,6 +65,7 @@ struct thread_struct { * pass the data segment into user programs if it exists, * it can't hurt anything as far as I can tell */ +#ifndef CONFIG_SMP #define start_thread(_regs, _pc, _usp) \ do { \ set_fs(USER_DS); \ @@ -70,6 +79,16 @@ do { \ sizeof(*L1_SCRATCH_TASK_INFO)); \ wrusp(_usp); \ } while(0) +#else +#define start_thread(_regs, _pc, _usp) \ +do { \ + set_fs(USER_DS); \ + (_regs)->pc = (_pc); \ + if (current->mm) \ + (_regs)->p5 = current->mm->start_data; \ + wrusp(_usp); \ +} while (0) +#endif /* Forward declaration, a strange C thing */ struct task_struct; @@ -106,7 +125,8 @@ unsigned long get_wchan(struct task_struct *p); eip; }) #define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp) -#define cpu_relax() barrier() +#define cpu_relax() smp_mb() + /* Get the Silicon Revision of the chip */ static inline uint32_t __pure bfin_revid(void) @@ -137,7 +157,11 @@ static inline uint32_t __pure bfin_revid(void) static inline uint16_t __pure bfin_cpuid(void) { return (bfin_read_CHIPID() & CHIPID_FAMILY) >> 12; +} +static inline uint32_t __pure bfin_dspid(void) +{ + return bfin_read_DSPID(); } static inline uint32_t __pure bfin_compiled_revid(void) @@ -154,6 +178,8 @@ static inline uint32_t __pure bfin_compiled_revid(void) return 4; #elif defined(CONFIG_BF_REV_0_5) return 5; +#elif defined(CONFIG_BF_REV_0_6) + return 6; #elif defined(CONFIG_BF_REV_ANY) return 0xffff; #else diff --git a/arch/blackfin/include/asm/reboot.h b/arch/blackfin/include/asm/reboot.h index 6d448b5f5985..4856d62b7467 100644 --- a/arch/blackfin/include/asm/reboot.h +++ b/arch/blackfin/include/asm/reboot.h @@ -1,7 +1,7 @@ /* - * include/asm-blackfin/reboot.h - shutdown/reboot header + * reboot.h - shutdown/reboot header * - * Copyright 2004-2007 Analog Devices Inc. + * Copyright 2004-2008 Analog Devices Inc. * * Licensed under the GPL-2 or later. */ diff --git a/arch/blackfin/include/asm/rwlock.h b/arch/blackfin/include/asm/rwlock.h new file mode 100644 index 000000000000..4a724b378971 --- /dev/null +++ b/arch/blackfin/include/asm/rwlock.h @@ -0,0 +1,6 @@ +#ifndef _ASM_BLACKFIN_RWLOCK_H +#define _ASM_BLACKFIN_RWLOCK_H + +#define RW_LOCK_BIAS 0x01000000 + +#endif diff --git a/arch/blackfin/include/asm/serial.h b/arch/blackfin/include/asm/serial.h index 994dd869558c..3a47606c858b 100644 --- a/arch/blackfin/include/asm/serial.h +++ b/arch/blackfin/include/asm/serial.h @@ -3,3 +3,4 @@ */ #define SERIAL_EXTRA_IRQ_FLAGS IRQF_TRIGGER_HIGH +#define BASE_BAUD (1843200 / 16) diff --git a/arch/blackfin/include/asm/smp.h b/arch/blackfin/include/asm/smp.h new file mode 100644 index 000000000000..118deeeae7c0 --- /dev/null +++ b/arch/blackfin/include/asm/smp.h @@ -0,0 +1,44 @@ +/* + * File: arch/blackfin/include/asm/smp.h + * Author: Philippe Gerum <rpm@xenomai.org> + * + * Copyright 2007 Analog Devices Inc. + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __ASM_BLACKFIN_SMP_H +#define __ASM_BLACKFIN_SMP_H + +#include <linux/kernel.h> +#include <linux/threads.h> +#include <linux/cpumask.h> +#include <linux/cache.h> +#include <asm/blackfin.h> +#include <mach/smp.h> + +#define raw_smp_processor_id() blackfin_core_id() + +extern char coreb_trampoline_start, coreb_trampoline_end; + +struct corelock_slot { + int lock; +}; + +void smp_icache_flush_range_others(unsigned long start, + unsigned long end); + +#endif /* !__ASM_BLACKFIN_SMP_H */ diff --git a/arch/blackfin/include/asm/spinlock.h b/arch/blackfin/include/asm/spinlock.h index 64e908a50646..0249ac319476 100644 --- a/arch/blackfin/include/asm/spinlock.h +++ b/arch/blackfin/include/asm/spinlock.h @@ -1,6 +1,89 @@ #ifndef __BFIN_SPINLOCK_H #define __BFIN_SPINLOCK_H -#error blackfin architecture does not support SMP spin lock yet +#include <asm/atomic.h> -#endif +asmlinkage int __raw_spin_is_locked_asm(volatile int *ptr); +asmlinkage void __raw_spin_lock_asm(volatile int *ptr); +asmlinkage int __raw_spin_trylock_asm(volatile int *ptr); +asmlinkage void __raw_spin_unlock_asm(volatile int *ptr); +asmlinkage void __raw_read_lock_asm(volatile int *ptr); +asmlinkage int __raw_read_trylock_asm(volatile int *ptr); +asmlinkage void __raw_read_unlock_asm(volatile int *ptr); +asmlinkage void __raw_write_lock_asm(volatile int *ptr); +asmlinkage int __raw_write_trylock_asm(volatile int *ptr); +asmlinkage void __raw_write_unlock_asm(volatile int *ptr); + +static inline int __raw_spin_is_locked(raw_spinlock_t *lock) +{ + return __raw_spin_is_locked_asm(&lock->lock); +} + +static inline void __raw_spin_lock(raw_spinlock_t *lock) +{ + __raw_spin_lock_asm(&lock->lock); +} + +#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) + +static inline int __raw_spin_trylock(raw_spinlock_t *lock) +{ + return __raw_spin_trylock_asm(&lock->lock); +} + +static inline void __raw_spin_unlock(raw_spinlock_t *lock) +{ + __raw_spin_unlock_asm(&lock->lock); +} + +static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock) +{ + while (__raw_spin_is_locked(lock)) + cpu_relax(); +} + +static inline int __raw_read_can_lock(raw_rwlock_t *rw) +{ + return __raw_uncached_fetch_asm(&rw->lock) > 0; +} + +static inline int __raw_write_can_lock(raw_rwlock_t *rw) +{ + return __raw_uncached_fetch_asm(&rw->lock) == RW_LOCK_BIAS; +} + +static inline void __raw_read_lock(raw_rwlock_t *rw) +{ + __raw_read_lock_asm(&rw->lock); +} + +static inline int __raw_read_trylock(raw_rwlock_t *rw) +{ + return __raw_read_trylock_asm(&rw->lock); +} + +static inline void __raw_read_unlock(raw_rwlock_t *rw) +{ + __raw_read_unlock_asm(&rw->lock); +} + +static inline void __raw_write_lock(raw_rwlock_t *rw) +{ + __raw_write_lock_asm(&rw->lock); +} + +static inline int __raw_write_trylock(raw_rwlock_t *rw) +{ + return __raw_write_trylock_asm(&rw->lock); +} + +static inline void __raw_write_unlock(raw_rwlock_t *rw) +{ + __raw_write_unlock_asm(&rw->lock); +} + +#define _raw_spin_relax(lock) cpu_relax() +#define _raw_read_relax(lock) cpu_relax() +#define _raw_write_relax(lock) cpu_relax() + +#endif /* !__BFIN_SPINLOCK_H */ diff --git a/arch/blackfin/include/asm/spinlock_types.h b/arch/blackfin/include/asm/spinlock_types.h new file mode 100644 index 000000000000..b1e3c4c7b382 --- /dev/null +++ b/arch/blackfin/include/asm/spinlock_types.h @@ -0,0 +1,22 @@ +#ifndef __ASM_SPINLOCK_TYPES_H +#define __ASM_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +#include <asm/rwlock.h> + +typedef struct { + volatile unsigned int lock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 0 } + +typedef struct { + volatile unsigned int lock; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } + +#endif diff --git a/arch/blackfin/include/asm/system.h b/arch/blackfin/include/asm/system.h index 8f1627d8bf09..a4c8254bec55 100644 --- a/arch/blackfin/include/asm/system.h +++ b/arch/blackfin/include/asm/system.h @@ -37,114 +37,98 @@ #include <linux/linkage.h> #include <linux/compiler.h> #include <mach/anomaly.h> +#include <asm/pda.h> +#include <asm/processor.h> +#include <asm/irq.h> /* - * Interrupt configuring macros. + * Force strict CPU ordering. */ +#define nop() __asm__ __volatile__ ("nop;\n\t" : : ) +#define mb() __asm__ __volatile__ ("" : : : "memory") +#define rmb() __asm__ __volatile__ ("" : : : "memory") +#define wmb() __asm__ __volatile__ ("" : : : "memory") +#define set_mb(var, value) do { (void) xchg(&var, value); } while (0) +#define read_barrier_depends() do { } while(0) -extern unsigned long irq_flags; - -#define local_irq_enable() \ - __asm__ __volatile__( \ - "sti %0;" \ - : \ - : "d" (irq_flags) \ - ) - -#define local_irq_disable() \ - do { \ - int __tmp_dummy; \ - __asm__ __volatile__( \ - "cli %0;" \ - : "=d" (__tmp_dummy) \ - ); \ - } while (0) - -#if ANOMALY_05000244 && defined(CONFIG_BFIN_ICACHE) -# define NOP_PAD_ANOMALY_05000244 "nop; nop;" -#else -# define NOP_PAD_ANOMALY_05000244 -#endif - -#define idle_with_irq_disabled() \ - __asm__ __volatile__( \ - NOP_PAD_ANOMALY_05000244 \ - ".align 8;" \ - "sti %0;" \ - "idle;" \ - : \ - : "d" (irq_flags) \ - ) - -#ifdef CONFIG_DEBUG_HWERR -# define __save_and_cli(x) \ - __asm__ __volatile__( \ - "cli %0;" \ - "sti %1;" \ - : "=&d" (x) \ - : "d" (0x3F) \ - ) -#else -# define __save_and_cli(x) \ - __asm__ __volatile__( \ - "cli %0;" \ - : "=&d" (x) \ - ) -#endif - -#define local_save_flags(x) \ - __asm__ __volatile__( \ - "cli %0;" \ - "sti %0;" \ - : "=d" (x) \ - ) +#ifdef CONFIG_SMP +asmlinkage unsigned long __raw_xchg_1_asm(volatile void *ptr, unsigned long value); +asmlinkage unsigned long __raw_xchg_2_asm(volatile void *ptr, unsigned long value); +asmlinkage unsigned long __raw_xchg_4_asm(volatile void *ptr, unsigned long value); +asmlinkage unsigned long __raw_cmpxchg_1_asm(volatile void *ptr, + unsigned long new, unsigned long old); +asmlinkage unsigned long __raw_cmpxchg_2_asm(volatile void *ptr, + unsigned long new, unsigned long old); +asmlinkage unsigned long __raw_cmpxchg_4_asm(volatile void *ptr, + unsigned long new, unsigned long old); + +#ifdef __ARCH_SYNC_CORE_DCACHE +# define smp_mb() do { barrier(); smp_check_barrier(); smp_mark_barrier(); } while (0) +# define smp_rmb() do { barrier(); smp_check_barrier(); } while (0) +# define smp_wmb() do { barrier(); smp_mark_barrier(); } while (0) +#define smp_read_barrier_depends() do { barrier(); smp_check_barrier(); } while (0) -#ifdef CONFIG_DEBUG_HWERR -#define irqs_enabled_from_flags(x) (((x) & ~0x3f) != 0) #else -#define irqs_enabled_from_flags(x) ((x) != 0x1f) +# define smp_mb() barrier() +# define smp_rmb() barrier() +# define smp_wmb() barrier() +#define smp_read_barrier_depends() barrier() #endif -#define local_irq_restore(x) \ - do { \ - if (irqs_enabled_from_flags(x)) \ - local_irq_enable(); \ - } while (0) +static inline unsigned long __xchg(unsigned long x, volatile void *ptr, + int size) +{ + unsigned long tmp; -/* For spinlocks etc */ -#define local_irq_save(x) __save_and_cli(x) + switch (size) { + case 1: + tmp = __raw_xchg_1_asm(ptr, x); + break; + case 2: + tmp = __raw_xchg_2_asm(ptr, x); + break; + case 4: + tmp = __raw_xchg_4_asm(ptr, x); + break; + } -#define irqs_disabled() \ -({ \ - unsigned long flags; \ - local_save_flags(flags); \ - !irqs_enabled_from_flags(flags); \ -}) + return tmp; +} /* - * Force strict CPU ordering. + * Atomic compare and exchange. Compare OLD with MEM, if identical, + * store NEW in MEM. Return the initial value in MEM. Success is + * indicated by comparing RETURN with OLD. */ -#define nop() asm volatile ("nop;\n\t"::) -#define mb() asm volatile ("" : : :"memory") -#define rmb() asm volatile ("" : : :"memory") -#define wmb() asm volatile ("" : : :"memory") -#define set_mb(var, value) do { (void) xchg(&var, value); } while (0) +static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, + unsigned long new, int size) +{ + unsigned long tmp; -#define read_barrier_depends() do { } while(0) + switch (size) { + case 1: + tmp = __raw_cmpxchg_1_asm(ptr, new, old); + break; + case 2: + tmp = __raw_cmpxchg_2_asm(ptr, new, old); + break; + case 4: + tmp = __raw_cmpxchg_4_asm(ptr, new, old); + break; + } + + return tmp; +} +#define cmpxchg(ptr, o, n) \ + ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \ + (unsigned long)(n), sizeof(*(ptr)))) + +#else /* !CONFIG_SMP */ -#ifdef CONFIG_SMP -#define smp_mb() mb() -#define smp_rmb() rmb() -#define smp_wmb() wmb() -#define smp_read_barrier_depends() read_barrier_depends() -#else #define smp_mb() barrier() #define smp_rmb() barrier() #define smp_wmb() barrier() #define smp_read_barrier_depends() do { } while(0) -#endif - -#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) struct __xchg_dummy { unsigned long a[100]; @@ -157,7 +141,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, unsigned long tmp = 0; unsigned long flags = 0; - local_irq_save(flags); + local_irq_save_hw(flags); switch (size) { case 1: @@ -179,7 +163,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); break; } - local_irq_restore(flags); + local_irq_restore_hw(flags); return tmp; } @@ -194,9 +178,12 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, (unsigned long)(n), sizeof(*(ptr)))) #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) -#ifndef CONFIG_SMP #include <asm-generic/cmpxchg.h> -#endif + +#endif /* !CONFIG_SMP */ + +#define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) +#define tas(ptr) ((void)xchg((ptr), 1)) #define prepare_to_switch() do { } while(0) @@ -205,10 +192,12 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, * ptr isn't the current task, in which case it does nothing. */ -#include <asm/blackfin.h> +#include <asm/l1layout.h> +#include <asm/mem_map.h> asmlinkage struct task_struct *resume(struct task_struct *prev, struct task_struct *next); +#ifndef CONFIG_SMP #define switch_to(prev,next,last) \ do { \ memcpy (&task_thread_info(prev)->l1_task_info, L1_SCRATCH_TASK_INFO, \ @@ -217,5 +206,11 @@ do { \ sizeof *L1_SCRATCH_TASK_INFO); \ (last) = resume (prev, next); \ } while (0) +#else +#define switch_to(prev, next, last) \ +do { \ + (last) = resume(prev, next); \ +} while (0) +#endif -#endif /* _BLACKFIN_SYSTEM_H */ +#endif /* _BLACKFIN_SYSTEM_H */ diff --git a/arch/blackfin/include/asm/thread_info.h b/arch/blackfin/include/asm/thread_info.h index 642769329d12..e721ce55956c 100644 --- a/arch/blackfin/include/asm/thread_info.h +++ b/arch/blackfin/include/asm/thread_info.h @@ -44,6 +44,7 @@ */ #define THREAD_SIZE_ORDER 1 #define THREAD_SIZE 8192 /* 2 pages */ +#define STACK_WARN (THREAD_SIZE/8) #ifndef __ASSEMBLY__ @@ -62,7 +63,9 @@ struct thread_info { int preempt_count; /* 0 => preemptable, <0 => BUG */ mm_segment_t addr_limit; /* address limit */ struct restart_block restart_block; +#ifndef CONFIG_SMP struct l1_scratch_task_info l1_task_info; +#endif }; /* @@ -90,7 +93,7 @@ __attribute_const__ static inline struct thread_info *current_thread_info(void) { struct thread_info *ti; - __asm__("%0 = sp;": "=&d"(ti): + __asm__("%0 = sp;" : "=da"(ti) : ); return (struct thread_info *)((long)ti & ~((long)THREAD_SIZE-1)); } diff --git a/arch/blackfin/include/asm/uaccess.h b/arch/blackfin/include/asm/uaccess.h index d928b8099056..3248033531e6 100644 --- a/arch/blackfin/include/asm/uaccess.h +++ b/arch/blackfin/include/asm/uaccess.h @@ -149,54 +149,42 @@ static inline int bad_user_access_length(void) : /* no outputs */ \ :"d" (x),"a" (__ptr(p)) : "memory") -#define get_user(x,p) \ - ({ \ - int _err = 0; \ - typeof(*(p)) *_p = (p); \ - if (!access_ok(VERIFY_READ, _p, sizeof(*(_p)))) { \ - _err = -EFAULT; \ - } \ - else { \ - switch (sizeof(*(_p))) { \ - case 1: \ - __get_user_asm(x, _p, B,(Z)); \ - break; \ - case 2: \ - __get_user_asm(x, _p, W,(Z)); \ - break; \ - case 4: \ - __get_user_asm(x, _p, , ); \ - break; \ - case 8: { \ - unsigned long _xl, _xh; \ - __get_user_asm(_xl, ((unsigned long *)_p)+0, , ); \ - __get_user_asm(_xh, ((unsigned long *)_p)+1, , ); \ - ((unsigned long *)&x)[0] = _xl; \ - ((unsigned long *)&x)[1] = _xh; \ - } break; \ - default: \ - x = 0; \ - printk(KERN_INFO "get_user_bad: %s:%d %s\n", \ - __FILE__, __LINE__, __func__); \ - _err = __get_user_bad(); \ - break; \ - } \ - } \ - _err; \ - }) +#define get_user(x, ptr) \ +({ \ + int _err = 0; \ + unsigned long _val = 0; \ + const typeof(*(ptr)) __user *_p = (ptr); \ + const size_t ptr_size = sizeof(*(_p)); \ + if (likely(access_ok(VERIFY_READ, _p, ptr_size))) { \ + BUILD_BUG_ON(ptr_size >= 8); \ + switch (ptr_size) { \ + case 1: \ + __get_user_asm(_val, _p, B,(Z)); \ + break; \ + case 2: \ + __get_user_asm(_val, _p, W,(Z)); \ + break; \ + case 4: \ + __get_user_asm(_val, _p, , ); \ + break; \ + } \ + } else \ + _err = -EFAULT; \ + x = (typeof(*(ptr)))_val; \ + _err; \ +}) #define __get_user(x,p) get_user(x,p) #define __get_user_bad() (bad_user_access_length(), (-EFAULT)) -#define __get_user_asm(x,p,bhw,option) \ - { \ - unsigned long _tmp; \ - __asm__ ("%0 =" #bhw "[%1]"#option";\n\t" \ - : "=d" (_tmp) \ - : "a" (__ptr(p))); \ - (x) = (__typeof__(*(p))) _tmp; \ - } +#define __get_user_asm(x, ptr, bhw, option) \ +({ \ + __asm__ __volatile__ ( \ + "%0 =" #bhw "[%1]" #option ";" \ + : "=d" (x) \ + : "a" (__ptr(ptr))); \ +}) #define __copy_from_user(to, from, n) copy_from_user(to, from, n) #define __copy_to_user(to, from, n) copy_to_user(to, from, n) @@ -209,8 +197,8 @@ static inline int bad_user_access_length(void) #define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n))\ return retval; }) -static inline long copy_from_user(void *to, - const void __user * from, unsigned long n) +static inline unsigned long __must_check +copy_from_user(void *to, const void __user *from, unsigned long n) { if (access_ok(VERIFY_READ, from, n)) memcpy(to, from, n); @@ -219,8 +207,8 @@ static inline long copy_from_user(void *to, return 0; } -static inline long copy_to_user(void *to, - const void __user * from, unsigned long n) +static inline unsigned long __must_check +copy_to_user(void *to, const void __user *from, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) memcpy(to, from, n); @@ -233,8 +221,8 @@ static inline long copy_to_user(void *to, * Copy a null terminated string from userspace. */ -static inline long strncpy_from_user(char *dst, - const char *src, long count) +static inline long __must_check +strncpy_from_user(char *dst, const char *src, long count) { char *tmp; if (!access_ok(VERIFY_READ, src, 1)) @@ -260,7 +248,8 @@ static inline long strnlen_user(const char *src, long n) * Zero Userspace */ -static inline unsigned long __clear_user(void *to, unsigned long n) +static inline unsigned long __must_check +__clear_user(void *to, unsigned long n) { memset(to, 0, n); return 0; diff --git a/arch/blackfin/include/asm/xor.h b/arch/blackfin/include/asm/xor.h new file mode 100644 index 000000000000..c82eb12a5b18 --- /dev/null +++ b/arch/blackfin/include/asm/xor.h @@ -0,0 +1 @@ +#include <asm-generic/xor.h> |