diff options
Diffstat (limited to 'arch/arm')
35 files changed, 1093 insertions, 483 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 475950c8a831..ee8a9ad7bbd9 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -67,10 +67,6 @@ config GENERIC_BUST_SPINLOCK config GENERIC_ISA_DMA bool -config GENERIC_IOMAP - bool - default y - config FIQ bool @@ -202,6 +198,11 @@ config ARCH_H720X help This enables support for systems based on the Hynix HMS720x +config ARCH_AAEC2000 + bool "Agilent AAEC-2000 based" + help + This enables support for systems based on the Agilent AAEC-2000 + endchoice source "arch/arm/mach-clps711x/Kconfig" @@ -234,6 +235,8 @@ source "arch/arm/mach-h720x/Kconfig" source "arch/arm/mach-versatile/Kconfig" +source "arch/arm/mach-aaec2000/Kconfig" + # Definitions to make life easier config ARCH_ACORN bool @@ -277,7 +280,7 @@ config ISA_DMA_API default y config PCI - bool "PCI support" if ARCH_INTEGRATOR_AP + bool "PCI support" if ARCH_INTEGRATOR_AP || ARCH_VERSATILE_PB help Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 2277e3d179cc..8330495e2448 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -97,6 +97,7 @@ textaddr-$(CONFIG_ARCH_FORTUNET) := 0xc0008000 machine-$(CONFIG_ARCH_VERSATILE) := versatile machine-$(CONFIG_ARCH_IMX) := imx machine-$(CONFIG_ARCH_H720X) := h720x + machine-$(CONFIG_ARCH_AAEC2000) := aaec2000 ifeq ($(CONFIG_ARCH_EBSA110),y) # This is what happens if you forget the IOCS16 line. diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 5797b1b100a1..9d63a01214eb 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -30,6 +30,8 @@ #include <linux/dmapool.h> #include <linux/list.h> +#include <asm/cacheflush.h> + #undef DEBUG #undef STATS @@ -302,12 +304,24 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, DO_STATS ( device_info->bounce_count++ ); - if ((dir == DMA_FROM_DEVICE) || - (dir == DMA_BIDIRECTIONAL)) { + if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { + unsigned long ptr; + dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n", __func__, buf->safe, buf->ptr, size); memcpy(buf->ptr, buf->safe, size); + + /* + * DMA buffers must have the same cache properties + * as if they were really used for DMA - which means + * data must be written back to RAM. Note that + * we don't use dmac_flush_range() here for the + * bidirectional case because we know the cache + * lines will be coherent with the data written. + */ + ptr = (unsigned long)buf->ptr; + dmac_clean_range(ptr, ptr + size); } free_safe_buffer(device_info, buf); } diff --git a/arch/arm/common/sharpsl_param.c b/arch/arm/common/sharpsl_param.c index c2c557a224c2..c94864c5b1af 100644 --- a/arch/arm/common/sharpsl_param.c +++ b/arch/arm/common/sharpsl_param.c @@ -22,7 +22,7 @@ * them early in the boot process, then pass them to the appropriate drivers. * Not all devices use all paramaters but the format is common to all. */ -#ifdef ARCH_SA1100 +#ifdef CONFIG_ARCH_SA1100 #define PARAM_BASE 0xe8ffc000 #else #define PARAM_BASE 0xa0000a00 diff --git a/arch/arm/configs/enp2611_defconfig b/arch/arm/configs/enp2611_defconfig index e8f9fccffe84..06fae4b62774 100644 --- a/arch/arm/configs/enp2611_defconfig +++ b/arch/arm/configs/enp2611_defconfig @@ -50,7 +50,13 @@ CONFIG_BASE_SMALL=0 # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y # # System Type diff --git a/arch/arm/configs/ixdp2400_defconfig b/arch/arm/configs/ixdp2400_defconfig index 4fd663ecbe39..810a450a55d2 100644 --- a/arch/arm/configs/ixdp2400_defconfig +++ b/arch/arm/configs/ixdp2400_defconfig @@ -50,7 +50,13 @@ CONFIG_BASE_SMALL=0 # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y # # System Type diff --git a/arch/arm/configs/ixdp2401_defconfig b/arch/arm/configs/ixdp2401_defconfig index 6f51c98084a3..72e1b940e975 100644 --- a/arch/arm/configs/ixdp2401_defconfig +++ b/arch/arm/configs/ixdp2401_defconfig @@ -50,7 +50,13 @@ CONFIG_BASE_SMALL=0 # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y # # System Type diff --git a/arch/arm/configs/ixdp2800_defconfig b/arch/arm/configs/ixdp2800_defconfig index 7be3521f91fc..1592e45f0278 100644 --- a/arch/arm/configs/ixdp2800_defconfig +++ b/arch/arm/configs/ixdp2800_defconfig @@ -50,7 +50,13 @@ CONFIG_BASE_SMALL=0 # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y # # System Type diff --git a/arch/arm/configs/ixdp2801_defconfig b/arch/arm/configs/ixdp2801_defconfig index cd84a20f30f1..f1afe3d09ec6 100644 --- a/arch/arm/configs/ixdp2801_defconfig +++ b/arch/arm/configs/ixdp2801_defconfig @@ -50,7 +50,13 @@ CONFIG_BASE_SMALL=0 # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y # # System Type diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 4a2af55e134b..3e1b0327e4d7 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -6,7 +6,7 @@ AFLAGS_head.o := -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR) # Object file lists. -obj-y := arch.o compat.o dma.o entry-armv.o entry-common.o irq.o \ +obj-y := compat.o dma.o entry-armv.o entry-common.o irq.o \ process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \ time.o traps.o diff --git a/arch/arm/kernel/arch.c b/arch/arm/kernel/arch.c deleted file mode 100644 index 4e02fbeb10a6..000000000000 --- a/arch/arm/kernel/arch.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * linux/arch/arm/kernel/arch.c - * - * Architecture specific fixups. - */ -#include <linux/config.h> -#include <linux/init.h> -#include <linux/types.h> - -#include <asm/elf.h> -#include <asm/page.h> -#include <asm/setup.h> -#include <asm/mach/arch.h> - -unsigned int vram_size; - -#ifdef CONFIG_ARCH_ACORN - -unsigned int memc_ctrl_reg; -unsigned int number_mfm_drives; - -static int __init parse_tag_acorn(const struct tag *tag) -{ - memc_ctrl_reg = tag->u.acorn.memc_control_reg; - number_mfm_drives = tag->u.acorn.adfsdrives; - - switch (tag->u.acorn.vram_pages) { - case 512: - vram_size += PAGE_SIZE * 256; - case 256: - vram_size += PAGE_SIZE * 256; - default: - break; - } -#if 0 - if (vram_size) { - desc->video_start = 0x02000000; - desc->video_end = 0x02000000 + vram_size; - } -#endif - return 0; -} - -__tagtable(ATAG_ACORN, parse_tag_acorn); - -#endif diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 45ed036336e0..34892758f098 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -145,7 +145,8 @@ int __init __cpu_up(unsigned int cpu) pgd_free(pgd); if (ret) { - printk(KERN_CRIT "cpu_up: processor %d failed to boot\n", cpu); + printk(KERN_CRIT "CPU%u: processor failed to boot\n", cpu); + /* * FIXME: We need to clean up the new idle thread. --rmk */ diff --git a/arch/arm/lib/ashldi3.c b/arch/arm/lib/ashldi3.c index 130f5a839669..b62875cfd8f8 100644 --- a/arch/arm/lib/ashldi3.c +++ b/arch/arm/lib/ashldi3.c @@ -31,31 +31,26 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" -DItype -__ashldi3 (DItype u, word_type b) +s64 __ashldi3(s64 u, int b) { - DIunion w; - word_type bm; - DIunion uu; - - if (b == 0) - return u; - - uu.ll = u; - - bm = (sizeof (SItype) * BITS_PER_UNIT) - b; - if (bm <= 0) - { - w.s.low = 0; - w.s.high = (USItype)uu.s.low << -bm; - } - else - { - USItype carries = (USItype)uu.s.low >> bm; - w.s.low = (USItype)uu.s.low << b; - w.s.high = ((USItype)uu.s.high << b) | carries; - } - - return w.ll; + DIunion w; + int bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof(s32) * BITS_PER_UNIT) - b; + if (bm <= 0) { + w.s.low = 0; + w.s.high = (u32) uu.s.low << -bm; + } else { + u32 carries = (u32) uu.s.low >> bm; + w.s.low = (u32) uu.s.low << b; + w.s.high = ((u32) uu.s.high << b) | carries; + } + + return w.ll; } - diff --git a/arch/arm/lib/ashrdi3.c b/arch/arm/lib/ashrdi3.c index 71625d218f8d..9a8600a7543f 100644 --- a/arch/arm/lib/ashrdi3.c +++ b/arch/arm/lib/ashrdi3.c @@ -31,31 +31,27 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" -DItype -__ashrdi3 (DItype u, word_type b) +s64 __ashrdi3(s64 u, int b) { - DIunion w; - word_type bm; - DIunion uu; - - if (b == 0) - return u; - - uu.ll = u; - - bm = (sizeof (SItype) * BITS_PER_UNIT) - b; - if (bm <= 0) - { - /* w.s.high = 1..1 or 0..0 */ - w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1); - w.s.low = uu.s.high >> -bm; - } - else - { - USItype carries = (USItype)uu.s.high << bm; - w.s.high = uu.s.high >> b; - w.s.low = ((USItype)uu.s.low >> b) | carries; - } - - return w.ll; + DIunion w; + int bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof(s32) * BITS_PER_UNIT) - b; + if (bm <= 0) { + /* w.s.high = 1..1 or 0..0 */ + w.s.high = uu.s.high >> (sizeof(s32) * BITS_PER_UNIT - 1); + w.s.low = uu.s.high >> -bm; + } else { + u32 carries = (u32) uu.s.high << bm; + w.s.high = uu.s.high >> b; + w.s.low = ((u32) uu.s.low >> b) | carries; + } + + return w.ll; } diff --git a/arch/arm/lib/gcclib.h b/arch/arm/lib/gcclib.h index 65314a3d9e27..8b6dcc656de7 100644 --- a/arch/arm/lib/gcclib.h +++ b/arch/arm/lib/gcclib.h @@ -1,25 +1,22 @@ /* gcclib.h -- definitions for various functions 'borrowed' from gcc-2.95.3 */ /* I Molton 29/07/01 */ -#define BITS_PER_UNIT 8 -#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT) +#include <linux/types.h> -typedef unsigned int UQItype __attribute__ ((mode (QI))); -typedef int SItype __attribute__ ((mode (SI))); -typedef unsigned int USItype __attribute__ ((mode (SI))); -typedef int DItype __attribute__ ((mode (DI))); -typedef int word_type __attribute__ ((mode (__word__))); -typedef unsigned int UDItype __attribute__ ((mode (DI))); +#define BITS_PER_UNIT 8 +#define SI_TYPE_SIZE (sizeof(s32) * BITS_PER_UNIT) #ifdef __ARMEB__ - struct DIstruct {SItype high, low;}; +struct DIstruct { + s32 high, low; +}; #else - struct DIstruct {SItype low, high;}; +struct DIstruct { + s32 low, high; +}; #endif -typedef union -{ - struct DIstruct s; - DItype ll; +typedef union { + struct DIstruct s; + s64 ll; } DIunion; - diff --git a/arch/arm/lib/longlong.h b/arch/arm/lib/longlong.h index 179eea4edc35..90ae647e4d76 100644 --- a/arch/arm/lib/longlong.h +++ b/arch/arm/lib/longlong.h @@ -26,18 +26,18 @@ #define __BITS4 (SI_TYPE_SIZE / 4) #define __ll_B (1L << (SI_TYPE_SIZE / 2)) -#define __ll_lowpart(t) ((USItype) (t) % __ll_B) -#define __ll_highpart(t) ((USItype) (t) / __ll_B) +#define __ll_lowpart(t) ((u32) (t) % __ll_B) +#define __ll_highpart(t) ((u32) (t) / __ll_B) /* Define auxiliary asm macros. 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) - multiplies two USItype integers MULTIPLER and MULTIPLICAND, - and generates a two-part USItype product in HIGH_PROD and + multiplies two u32 integers MULTIPLER and MULTIPLICAND, + and generates a two-part u32 product in HIGH_PROD and LOW_PROD. - 2) __umulsidi3(a,b) multiplies two USItype integers A and B, - and returns a UDItype product. This is just a variant of umul_ppmm. + 2) __umulsidi3(a,b) multiplies two u32 integers A and B, + and returns a u64 product. This is just a variant of umul_ppmm. 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, denominator) divides a two-word unsigned integer, composed by the @@ -77,23 +77,23 @@ #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ __asm__ ("adds %1, %4, %5 \n\ adc %0, %2, %3" \ - : "=r" ((USItype) (sh)), \ - "=&r" ((USItype) (sl)) \ - : "%r" ((USItype) (ah)), \ - "rI" ((USItype) (bh)), \ - "%r" ((USItype) (al)), \ - "rI" ((USItype) (bl))) + : "=r" ((u32) (sh)), \ + "=&r" ((u32) (sl)) \ + : "%r" ((u32) (ah)), \ + "rI" ((u32) (bh)), \ + "%r" ((u32) (al)), \ + "rI" ((u32) (bl))) #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ __asm__ ("subs %1, %4, %5 \n\ sbc %0, %2, %3" \ - : "=r" ((USItype) (sh)), \ - "=&r" ((USItype) (sl)) \ - : "r" ((USItype) (ah)), \ - "rI" ((USItype) (bh)), \ - "r" ((USItype) (al)), \ - "rI" ((USItype) (bl))) + : "=r" ((u32) (sh)), \ + "=&r" ((u32) (sl)) \ + : "r" ((u32) (ah)), \ + "rI" ((u32) (bh)), \ + "r" ((u32) (al)), \ + "rI" ((u32) (bl))) #define umul_ppmm(xh, xl, a, b) \ -{register USItype __t0, __t1, __t2; \ +{register u32 __t0, __t1, __t2; \ __asm__ ("%@ Inlined umul_ppmm \n\ mov %2, %5, lsr #16 \n\ mov %0, %6, lsr #16 \n\ @@ -107,14 +107,14 @@ addcs %0, %0, #65536 \n\ adds %1, %1, %3, lsl #16 \n\ adc %0, %0, %3, lsr #16" \ - : "=&r" ((USItype) (xh)), \ - "=r" ((USItype) (xl)), \ + : "=&r" ((u32) (xh)), \ + "=r" ((u32) (xl)), \ "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ - : "r" ((USItype) (a)), \ - "r" ((USItype) (b)));} + : "r" ((u32) (a)), \ + "r" ((u32) (b)));} #define UMUL_TIME 20 #define UDIV_TIME 100 -#endif /* __arm__ */ +#endif /* __arm__ */ #define __umulsidi3(u, v) \ ({DIunion __w; \ @@ -123,14 +123,14 @@ #define __udiv_qrnnd_c(q, r, n1, n0, d) \ do { \ - USItype __d1, __d0, __q1, __q0; \ - USItype __r1, __r0, __m; \ + u32 __d1, __d0, __q1, __q0; \ + u32 __r1, __r0, __m; \ __d1 = __ll_highpart (d); \ __d0 = __ll_lowpart (d); \ \ __r1 = (n1) % __d1; \ __q1 = (n1) / __d1; \ - __m = (USItype) __q1 * __d0; \ + __m = (u32) __q1 * __d0; \ __r1 = __r1 * __ll_B | __ll_highpart (n0); \ if (__r1 < __m) \ { \ @@ -143,7 +143,7 @@ \ __r0 = __r1 % __d1; \ __q0 = __r1 / __d1; \ - __m = (USItype) __q0 * __d0; \ + __m = (u32) __q0 * __d0; \ __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ if (__r0 < __m) \ { \ @@ -154,7 +154,7 @@ } \ __r0 -= __m; \ \ - (q) = (USItype) __q1 * __ll_B | __q0; \ + (q) = (u32) __q1 * __ll_B | __q0; \ (r) = __r0; \ } while (0) @@ -163,14 +163,14 @@ #define count_leading_zeros(count, x) \ do { \ - USItype __xr = (x); \ - USItype __a; \ + u32 __xr = (x); \ + u32 __a; \ \ if (SI_TYPE_SIZE <= 32) \ { \ - __a = __xr < ((USItype)1<<2*__BITS4) \ - ? (__xr < ((USItype)1<<__BITS4) ? 0 : __BITS4) \ - : (__xr < ((USItype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ + __a = __xr < ((u32)1<<2*__BITS4) \ + ? (__xr < ((u32)1<<__BITS4) ? 0 : __BITS4) \ + : (__xr < ((u32)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ } \ else \ { \ diff --git a/arch/arm/lib/lshrdi3.c b/arch/arm/lib/lshrdi3.c index b666f1bad451..3681f49d2b6e 100644 --- a/arch/arm/lib/lshrdi3.c +++ b/arch/arm/lib/lshrdi3.c @@ -31,31 +31,26 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" -DItype -__lshrdi3 (DItype u, word_type b) +s64 __lshrdi3(s64 u, int b) { - DIunion w; - word_type bm; - DIunion uu; - - if (b == 0) - return u; - - uu.ll = u; - - bm = (sizeof (SItype) * BITS_PER_UNIT) - b; - if (bm <= 0) - { - w.s.high = 0; - w.s.low = (USItype)uu.s.high >> -bm; - } - else - { - USItype carries = (USItype)uu.s.high << bm; - w.s.high = (USItype)uu.s.high >> b; - w.s.low = ((USItype)uu.s.low >> b) | carries; - } - - return w.ll; + DIunion w; + int bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof(s32) * BITS_PER_UNIT) - b; + if (bm <= 0) { + w.s.high = 0; + w.s.low = (u32) uu.s.high >> -bm; + } else { + u32 carries = (u32) uu.s.high << bm; + w.s.high = (u32) uu.s.high >> b; + w.s.low = ((u32) uu.s.low >> b) | carries; + } + + return w.ll; } - diff --git a/arch/arm/lib/muldi3.c b/arch/arm/lib/muldi3.c index 44d611b1cfdb..0a3b93313f18 100644 --- a/arch/arm/lib/muldi3.c +++ b/arch/arm/lib/muldi3.c @@ -32,7 +32,7 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" #define umul_ppmm(xh, xl, a, b) \ -{register USItype __t0, __t1, __t2; \ +{register u32 __t0, __t1, __t2; \ __asm__ ("%@ Inlined umul_ppmm \n\ mov %2, %5, lsr #16 \n\ mov %0, %6, lsr #16 \n\ @@ -46,32 +46,27 @@ Boston, MA 02111-1307, USA. */ addcs %0, %0, #65536 \n\ adds %1, %1, %3, lsl #16 \n\ adc %0, %0, %3, lsr #16" \ - : "=&r" ((USItype) (xh)), \ - "=r" ((USItype) (xl)), \ + : "=&r" ((u32) (xh)), \ + "=r" ((u32) (xl)), \ "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ - : "r" ((USItype) (a)), \ - "r" ((USItype) (b)));} - + : "r" ((u32) (a)), \ + "r" ((u32) (b)));} #define __umulsidi3(u, v) \ ({DIunion __w; \ umul_ppmm (__w.s.high, __w.s.low, u, v); \ __w.ll; }) - -DItype -__muldi3 (DItype u, DItype v) +s64 __muldi3(s64 u, s64 v) { - DIunion w; - DIunion uu, vv; + DIunion w; + DIunion uu, vv; - uu.ll = u, - vv.ll = v; + uu.ll = u, vv.ll = v; - w.ll = __umulsidi3 (uu.s.low, vv.s.low); - w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high - + (USItype) uu.s.high * (USItype) vv.s.low); + w.ll = __umulsidi3(uu.s.low, vv.s.low); + w.s.high += ((u32) uu.s.low * (u32) vv.s.high + + (u32) uu.s.high * (u32) vv.s.low); - return w.ll; + return w.ll; } - diff --git a/arch/arm/lib/ucmpdi2.c b/arch/arm/lib/ucmpdi2.c index 6c6ae63efa02..57f3f2df3850 100644 --- a/arch/arm/lib/ucmpdi2.c +++ b/arch/arm/lib/ucmpdi2.c @@ -31,21 +31,19 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" -word_type -__ucmpdi2 (DItype a, DItype b) +int __ucmpdi2(s64 a, s64 b) { - DIunion au, bu; - - au.ll = a, bu.ll = b; - - if ((USItype) au.s.high < (USItype) bu.s.high) - return 0; - else if ((USItype) au.s.high > (USItype) bu.s.high) - return 2; - if ((USItype) au.s.low < (USItype) bu.s.low) - return 0; - else if ((USItype) au.s.low > (USItype) bu.s.low) - return 2; - return 1; + DIunion au, bu; + + au.ll = a, bu.ll = b; + + if ((u32) au.s.high < (u32) bu.s.high) + return 0; + else if ((u32) au.s.high > (u32) bu.s.high) + return 2; + if ((u32) au.s.low < (u32) bu.s.low) + return 0; + else if ((u32) au.s.low > (u32) bu.s.low) + return 2; + return 1; } - diff --git a/arch/arm/lib/udivdi3.c b/arch/arm/lib/udivdi3.c index d25195f673f4..e343be4c6642 100644 --- a/arch/arm/lib/udivdi3.c +++ b/arch/arm/lib/udivdi3.c @@ -32,211 +32,191 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" #include "longlong.h" -static const UQItype __clz_tab[] = -{ - 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +static const u8 __clz_tab[] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, }; -UDItype -__udivmoddi4 (UDItype n, UDItype d, UDItype *rp) +u64 __udivmoddi4(u64 n, u64 d, u64 * rp) { - DIunion ww; - DIunion nn, dd; - DIunion rr; - USItype d0, d1, n0, n1, n2; - USItype q0, q1; - USItype b, bm; - - nn.ll = n; - dd.ll = d; - - d0 = dd.s.low; - d1 = dd.s.high; - n0 = nn.s.low; - n1 = nn.s.high; - - if (d1 == 0) - { - if (d0 > n1) - { - /* 0q = nn / 0D */ - - count_leading_zeros (bm, d0); - - if (bm != 0) - { - /* Normalize, i.e. make the most significant bit of the - denominator set. */ - - d0 = d0 << bm; - n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm)); - n0 = n0 << bm; - } - - udiv_qrnnd (q0, n0, n1, n0, d0); - q1 = 0; - - /* Remainder in n0 >> bm. */ - } - else - { - /* qq = NN / 0d */ - - if (d0 == 0) - d0 = 1 / d0; /* Divide intentionally by zero. */ - - count_leading_zeros (bm, d0); - - if (bm == 0) - { - /* From (n1 >= d0) /\ (the most significant bit of d0 is set), - conclude (the most significant bit of n1 is set) /\ (the - leading quotient digit q1 = 1). - - This special case is necessary, not an optimization. - (Shifts counts of SI_TYPE_SIZE are undefined.) */ - - n1 -= d0; - q1 = 1; - } - else - { - /* Normalize. */ - - b = SI_TYPE_SIZE - bm; - - d0 = d0 << bm; - n2 = n1 >> b; - n1 = (n1 << bm) | (n0 >> b); - n0 = n0 << bm; - - udiv_qrnnd (q1, n1, n2, n1, d0); - } - - /* n1 != d0... */ - - udiv_qrnnd (q0, n0, n1, n0, d0); - - /* Remainder in n0 >> bm. */ - } - - if (rp != 0) - { - rr.s.low = n0 >> bm; - rr.s.high = 0; - *rp = rr.ll; - } - } - else - { - if (d1 > n1) - { - /* 00 = nn / DD */ - - q0 = 0; - q1 = 0; - - /* Remainder in n1n0. */ - if (rp != 0) - { - rr.s.low = n0; - rr.s.high = n1; - *rp = rr.ll; - } - } - else - { - /* 0q = NN / dd */ - - count_leading_zeros (bm, d1); - if (bm == 0) - { - /* From (n1 >= d1) /\ (the most significant bit of d1 is set), - conclude (the most significant bit of n1 is set) /\ (the - quotient digit q0 = 0 or 1). - - This special case is necessary, not an optimization. */ - - /* The condition on the next line takes advantage of that - n1 >= d1 (true due to program flow). */ - if (n1 > d1 || n0 >= d0) - { - q0 = 1; - sub_ddmmss (n1, n0, n1, n0, d1, d0); - } - else - q0 = 0; - - q1 = 0; - - if (rp != 0) - { - rr.s.low = n0; - rr.s.high = n1; - *rp = rr.ll; - } - } - else - { - USItype m1, m0; - /* Normalize. */ - - b = SI_TYPE_SIZE - bm; - - d1 = (d1 << bm) | (d0 >> b); - d0 = d0 << bm; - n2 = n1 >> b; - n1 = (n1 << bm) | (n0 >> b); - n0 = n0 << bm; - - udiv_qrnnd (q0, n1, n2, n1, d1); - umul_ppmm (m1, m0, q0, d0); - - if (m1 > n1 || (m1 == n1 && m0 > n0)) - { - q0--; - sub_ddmmss (m1, m0, m1, m0, d1, d0); - } - - q1 = 0; - - /* Remainder in (n1n0 - m1m0) >> bm. */ - if (rp != 0) - { - sub_ddmmss (n1, n0, n1, n0, m1, m0); - rr.s.low = (n1 << b) | (n0 >> bm); - rr.s.high = n1 >> bm; - *rp = rr.ll; - } - } - } - } - - ww.s.low = q0; - ww.s.high = q1; - return ww.ll; + DIunion ww; + DIunion nn, dd; + DIunion rr; + u32 d0, d1, n0, n1, n2; + u32 q0, q1; + u32 b, bm; + + nn.ll = n; + dd.ll = d; + + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; + + if (d1 == 0) { + if (d0 > n1) { + /* 0q = nn / 0D */ + + count_leading_zeros(bm, d0); + + if (bm != 0) { + /* Normalize, i.e. make the most significant bit of the + denominator set. */ + + d0 = d0 << bm; + n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm)); + n0 = n0 << bm; + } + + udiv_qrnnd(q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0 >> bm. */ + } else { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + count_leading_zeros(bm, d0); + + if (bm == 0) { + /* From (n1 >= d0) /\ (the most significant bit of d0 is set), + conclude (the most significant bit of n1 is set) /\ (the + leading quotient digit q1 = 1). + + This special case is necessary, not an optimization. + (Shifts counts of SI_TYPE_SIZE are undefined.) */ + + n1 -= d0; + q1 = 1; + } else { + /* Normalize. */ + + b = SI_TYPE_SIZE - bm; + + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd(q1, n1, n2, n1, d0); + } + + /* n1 != d0... */ + + udiv_qrnnd(q0, n0, n1, n0, d0); + + /* Remainder in n0 >> bm. */ + } + + if (rp != 0) { + rr.s.low = n0 >> bm; + rr.s.high = 0; + *rp = rr.ll; + } + } else { + if (d1 > n1) { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + if (rp != 0) { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } else { + /* 0q = NN / dd */ + + count_leading_zeros(bm, d1); + if (bm == 0) { + /* From (n1 >= d1) /\ (the most significant bit of d1 is set), + conclude (the most significant bit of n1 is set) /\ (the + quotient digit q0 = 0 or 1). + + This special case is necessary, not an optimization. */ + + /* The condition on the next line takes advantage of that + n1 >= d1 (true due to program flow). */ + if (n1 > d1 || n0 >= d0) { + q0 = 1; + sub_ddmmss(n1, n0, n1, n0, d1, d0); + } else + q0 = 0; + + q1 = 0; + + if (rp != 0) { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } else { + u32 m1, m0; + /* Normalize. */ + + b = SI_TYPE_SIZE - bm; + + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd(q0, n1, n2, n1, d1); + umul_ppmm(m1, m0, q0, d0); + + if (m1 > n1 || (m1 == n1 && m0 > n0)) { + q0--; + sub_ddmmss(m1, m0, m1, m0, d1, d0); + } + + q1 = 0; + + /* Remainder in (n1n0 - m1m0) >> bm. */ + if (rp != 0) { + sub_ddmmss(n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; + } + } + } + } + + ww.s.low = q0; + ww.s.high = q1; + return ww.ll; } -UDItype -__udivdi3 (UDItype n, UDItype d) +u64 __udivdi3(u64 n, u64 d) { - return __udivmoddi4 (n, d, (UDItype *) 0); + return __udivmoddi4(n, d, (u64 *) 0); } -UDItype -__umoddi3 (UDItype u, UDItype v) +u64 __umoddi3(u64 u, u64 v) { - UDItype w; + u64 w; - (void) __udivmoddi4 (u ,v, &w); + (void)__udivmoddi4(u, v, &w); - return w; + return w; } - diff --git a/arch/arm/mach-aaec2000/Kconfig b/arch/arm/mach-aaec2000/Kconfig new file mode 100644 index 000000000000..5e4bef93754c --- /dev/null +++ b/arch/arm/mach-aaec2000/Kconfig @@ -0,0 +1,11 @@ +if ARCH_AAEC2000 + +menu "Agilent AAEC-2000 Implementations" + +config MACH_AAED2000 + bool "Agilent AAED-2000 Development Platform" + select CPU_ARM920T + +endmenu + +endif diff --git a/arch/arm/mach-aaec2000/Makefile b/arch/arm/mach-aaec2000/Makefile new file mode 100644 index 000000000000..20ec83896c37 --- /dev/null +++ b/arch/arm/mach-aaec2000/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the linux kernel. +# + +# Common support (must be linked before board specific support) +obj-y += core.o + +# Specific board support +obj-$(CONFIG_MACH_AAED2000) += aaed2000.o diff --git a/arch/arm/mach-aaec2000/aaed2000.c b/arch/arm/mach-aaec2000/aaed2000.c new file mode 100644 index 000000000000..5417ca3f4621 --- /dev/null +++ b/arch/arm/mach-aaec2000/aaed2000.c @@ -0,0 +1,48 @@ +/* + * linux/arch/arm/mach-aaec2000/aaed2000.c + * + * Support for the Agilent AAED-2000 Development Platform. + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/major.h> +#include <linux/interrupt.h> + +#include <asm/setup.h> +#include <asm/memory.h> +#include <asm/mach-types.h> +#include <asm/hardware.h> +#include <asm/irq.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include "core.h" + +static void __init aaed2000_init_irq(void) +{ + aaec2000_init_irq(); +} + +static void __init aaed2000_map_io(void) +{ + aaec2000_map_io(); +} + +MACHINE_START(AAED2000, "Agilent AAED-2000 Development Platform") + MAINTAINER("Nicolas Bellido Y Ortega") + BOOT_MEM(0xf0000000, PIO_BASE, VIO_BASE) + MAPIO(aaed2000_map_io) + INITIRQ(aaed2000_init_irq) + .timer = &aaec2000_timer, +MACHINE_END diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c new file mode 100644 index 000000000000..fc145b3768fa --- /dev/null +++ b/arch/arm/mach-aaec2000/core.c @@ -0,0 +1,157 @@ +/* + * linux/arch/arm/mach-aaec2000/core.c + * + * Code common to all AAEC-2000 machines + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/timex.h> +#include <linux/signal.h> + +#include <asm/hardware.h> +#include <asm/irq.h> + +#include <asm/mach/irq.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> + +/* + * Common I/O mapping: + * + * Static virtual address mappings are as follow: + * + * 0xf8000000-0xf8001ffff: Devices connected to APB bus + * 0xf8002000-0xf8003ffff: Devices connected to AHB bus + * + * Below 0xe8000000 is reserved for vm allocation. + * + * The machine specific code must provide the extra mapping beside the + * default mapping provided here. + */ +static struct map_desc standard_io_desc[] __initdata = { + /* virtual physical length type */ + { VIO_APB_BASE, PIO_APB_BASE, IO_APB_LENGTH, MT_DEVICE }, + { VIO_AHB_BASE, PIO_AHB_BASE, IO_AHB_LENGTH, MT_DEVICE } +}; + +void __init aaec2000_map_io(void) +{ + iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); +} + +/* + * Interrupt handling routines + */ +static void aaec2000_int_ack(unsigned int irq) +{ + IRQ_INTSR = 1 << irq; +} + +static void aaec2000_int_mask(unsigned int irq) +{ + IRQ_INTENC |= (1 << irq); +} + +static void aaec2000_int_unmask(unsigned int irq) +{ + IRQ_INTENS |= (1 << irq); +} + +static struct irqchip aaec2000_irq_chip = { + .ack = aaec2000_int_ack, + .mask = aaec2000_int_mask, + .unmask = aaec2000_int_unmask, +}; + +void __init aaec2000_init_irq(void) +{ + unsigned int i; + + for (i = 0; i < NR_IRQS; i++) { + set_irq_handler(i, do_level_IRQ); + set_irq_chip(i, &aaec2000_irq_chip); + set_irq_flags(i, IRQF_VALID); + } + + /* Disable all interrupts */ + IRQ_INTENC = 0xffffffff; + + /* Clear any pending interrupts */ + IRQ_INTSR = IRQ_INTSR; +} + +/* + * Time keeping + */ +/* IRQs are disabled before entering here from do_gettimeofday() */ +static unsigned long aaec2000_gettimeoffset(void) +{ + unsigned long ticks_to_match, elapsed, usec; + + /* Get ticks before next timer match */ + ticks_to_match = TIMER1_LOAD - TIMER1_VAL; + + /* We need elapsed ticks since last match */ + elapsed = LATCH - ticks_to_match; + + /* Now, convert them to usec */ + usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH; + + return usec; +} + +/* We enter here with IRQs enabled */ +static irqreturn_t +aaec2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* TODO: Check timer accuracy */ + write_seqlock(&xtime_lock); + + timer_tick(regs); + TIMER1_CLEAR = 1; + + write_sequnlock(&xtime_lock); + + return IRQ_HANDLED; +} + +static struct irqaction aaec2000_timer_irq = { + .name = "AAEC-2000 Timer Tick", + .flags = SA_INTERRUPT, + .handler = aaec2000_timer_interrupt +}; + +static void __init aaec2000_timer_init(void) +{ + /* Disable timer 1 */ + TIMER1_CTRL = 0; + + /* We have somehow to generate a 100Hz clock. + * We then use the 508KHz timer in periodic mode. + */ + TIMER1_LOAD = LATCH; + TIMER1_CLEAR = 1; /* Clear interrupt */ + + setup_irq(INT_TMR1_OFL, &aaec2000_timer_irq); + + TIMER1_CTRL = TIMER_CTRL_ENABLE | + TIMER_CTRL_PERIODIC | + TIMER_CTRL_CLKSEL_508K; +} + +struct sys_timer aaec2000_timer = { + .init = aaec2000_timer_init, + .offset = aaec2000_gettimeoffset, +}; + diff --git a/arch/arm/mach-aaec2000/core.h b/arch/arm/mach-aaec2000/core.h new file mode 100644 index 000000000000..91893d848c16 --- /dev/null +++ b/arch/arm/mach-aaec2000/core.h @@ -0,0 +1,16 @@ +/* + * linux/arch/arm/mach-aaec2000/core.h + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +struct sys_timer; + +extern struct sys_timer aaec2000_timer; +extern void __init aaec2000_map_io(void); +extern void __init aaec2000_init_irq(void); diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index d302f0405fd2..bd1e5e3c9d34 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -227,7 +227,6 @@ integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * primary CPU */ if (hard_smp_processor_id() == 0) { - nmi_tick(); timer_tick(regs); #ifdef CONFIG_SMP smp_send_timer(); diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index 4f3c3d5c781c..fc0555596d6d 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c @@ -162,12 +162,13 @@ void __init ixp2000_map_io(void) static unsigned ticks_per_jiffy; static unsigned ticks_per_usec; static unsigned next_jiffy_time; +static volatile unsigned long *missing_jiffy_timer_csr; unsigned long ixp2000_gettimeoffset (void) { unsigned long offset; - offset = next_jiffy_time - *IXP2000_T4_CSR; + offset = next_jiffy_time - *missing_jiffy_timer_csr; return offset / ticks_per_usec; } @@ -179,7 +180,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* clear timer 1 */ ixp2000_reg_write(IXP2000_T1_CLR, 1); - while ((next_jiffy_time - *IXP2000_T4_CSR) > ticks_per_jiffy) { + while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) { timer_tick(regs); next_jiffy_time -= ticks_per_jiffy; } @@ -197,20 +198,37 @@ static struct irqaction ixp2000_timer_irq = { void __init ixp2000_init_time(unsigned long tick_rate) { - ixp2000_reg_write(IXP2000_T1_CLR, 0); - ixp2000_reg_write(IXP2000_T4_CLR, 0); - ticks_per_jiffy = (tick_rate + HZ/2) / HZ; ticks_per_usec = tick_rate / 1000000; + /* + * We use timer 1 as our timer interrupt. + */ + ixp2000_reg_write(IXP2000_T1_CLR, 0); ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy - 1); ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7)); /* - * We use T4 as a monotonic counter to track missed jiffies + * We use a second timer as a monotonic counter for tracking + * missed jiffies. The IXP2000 has four timers, but if we're + * on an A-step IXP2800, timer 2 and 3 don't work, so on those + * chips we use timer 4. Timer 4 is the only timer that can + * be used for the watchdog, so we use timer 2 if we're on a + * non-buggy chip. */ - ixp2000_reg_write(IXP2000_T4_CLD, -1); - ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7)); + if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) { + printk(KERN_INFO "Enabling IXP2800 erratum #25 workaround\n"); + + ixp2000_reg_write(IXP2000_T4_CLR, 0); + ixp2000_reg_write(IXP2000_T4_CLD, -1); + ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7)); + missing_jiffy_timer_csr = IXP2000_T4_CSR; + } else { + ixp2000_reg_write(IXP2000_T2_CLR, 0); + ixp2000_reg_write(IXP2000_T2_CLD, -1); + ixp2000_reg_write(IXP2000_T2_CTL, (1 << 7)); + missing_jiffy_timer_csr = IXP2000_T2_CSR; + } next_jiffy_time = 0xffffffff; /* register for interrupt */ diff --git a/arch/arm/mach-versatile/Makefile b/arch/arm/mach-versatile/Makefile index 5d608837757a..ba81e70ed813 100644 --- a/arch/arm/mach-versatile/Makefile +++ b/arch/arm/mach-versatile/Makefile @@ -5,3 +5,4 @@ obj-y := core.o clock.o obj-$(CONFIG_ARCH_VERSATILE_PB) += versatile_pb.o obj-$(CONFIG_MACH_VERSATILE_AB) += versatile_ab.o +obj-$(CONFIG_PCI) += pci.o diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 302c2a7b9b63..6a7cbea5e098 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -196,11 +196,15 @@ static struct map_desc versatile_io_desc[] __initdata = { #ifdef CONFIG_DEBUG_LL { IO_ADDRESS(VERSATILE_UART0_BASE), VERSATILE_UART0_BASE, SZ_4K, MT_DEVICE }, #endif -#ifdef FIXME - { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M, MT_DEVICE }, - { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M, MT_DEVICE }, - { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_512K, MT_DEVICE }, - { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K, MT_DEVICE }, +#ifdef CONFIG_PCI + { IO_ADDRESS(VERSATILE_PCI_CORE_BASE), VERSATILE_PCI_CORE_BASE, SZ_4K, MT_DEVICE }, + { VERSATILE_PCI_VIRT_BASE, VERSATILE_PCI_BASE, VERSATILE_PCI_BASE_SIZE, MT_DEVICE }, + { VERSATILE_PCI_CFG_VIRT_BASE, VERSATILE_PCI_CFG_BASE, VERSATILE_PCI_CFG_BASE_SIZE, MT_DEVICE }, +#if 0 + { VERSATILE_PCI_VIRT_MEM_BASE0, VERSATILE_PCI_MEM_BASE0, SZ_16M, MT_DEVICE }, + { VERSATILE_PCI_VIRT_MEM_BASE1, VERSATILE_PCI_MEM_BASE1, SZ_16M, MT_DEVICE }, + { VERSATILE_PCI_VIRT_MEM_BASE2, VERSATILE_PCI_MEM_BASE2, SZ_16M, MT_DEVICE }, +#endif #endif }; diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c new file mode 100644 index 000000000000..d1565e851f0e --- /dev/null +++ b/arch/arm/mach-versatile/pci.c @@ -0,0 +1,360 @@ +/* + * linux/arch/arm/mach-versatile/pci.c + * + * (C) Copyright Koninklijke Philips Electronics NV 2004. All rights reserved. + * You can redistribute and/or modify this software under the terms of version 2 + * of the GNU General Public License as published by the Free Software Foundation. + * THIS SOFTWARE IS PROVIDED "AS IS" 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. + * Koninklijke Philips Electronics nor its subsidiaries is obligated to provide any support for this software. + * + * ARM Versatile PCI driver. + * + * 14/04/2005 Initial version, colin.king@philips.com + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/mach/pci.h> +#include <asm/mach-types.h> + +/* + * these spaces are mapped using the following base registers: + * + * Usage Local Bus Memory Base/Map registers used + * + * Mem 50000000 - 5FFFFFFF LB_BASE0/LB_MAP0, non prefetch + * Mem 60000000 - 6FFFFFFF LB_BASE1/LB_MAP1, prefetch + * IO 44000000 - 4FFFFFFF LB_BASE2/LB_MAP2, IO + * Cfg 42000000 - 42FFFFFF PCI config + * + */ +#define SYS_PCICTL IO_ADDRESS(VERSATILE_SYS_PCICTL) +#define PCI_IMAP0 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0) +#define PCI_IMAP1 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4) +#define PCI_IMAP2 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8) +#define PCI_SMAP0 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10) +#define PCI_SMAP1 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14) +#define PCI_SMAP2 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18) +#define PCI_SELFID IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc) + +#define DEVICE_ID_OFFSET 0x00 +#define CSR_OFFSET 0x04 +#define CLASS_ID_OFFSET 0x08 + +#define VP_PCI_DEVICE_ID 0x030010ee +#define VP_PCI_CLASS_ID 0x0b400000 + +static unsigned long pci_slot_ignore = 0; + +static int __init versatile_pci_slot_ignore(char *str) +{ + int retval; + int slot; + + while ((retval = get_option(&str,&slot))) { + if ((slot < 0) || (slot > 31)) { + printk("Illegal slot value: %d\n",slot); + } else { + pci_slot_ignore |= (1 << slot); + } + } + return 1; +} + +__setup("pci_slot_ignore=", versatile_pci_slot_ignore); + + +static unsigned long __pci_addr(struct pci_bus *bus, + unsigned int devfn, int offset) +{ + unsigned int busnr = bus->number; + + /* + * Trap out illegal values + */ + if (offset > 255) + BUG(); + if (busnr > 255) + BUG(); + if (devfn > 255) + BUG(); + + return (VERSATILE_PCI_CFG_VIRT_BASE | (busnr << 16) | + (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | offset); +} + +static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *val) +{ + unsigned long addr = __pci_addr(bus, devfn, where); + u32 v; + int slot = PCI_SLOT(devfn); + + if (pci_slot_ignore & (1 << slot)) { + /* Ignore this slot */ + switch (size) { + case 1: + v = 0xff; + break; + case 2: + v = 0xffff; + break; + default: + v = 0xffffffff; + } + } else { + switch (size) { + case 1: + addr &= ~3; + v = __raw_readb(addr); + break; + + case 2: + v = __raw_readl(addr & ~3); + if (addr & 2) v >>= 16; + v &= 0xffff; + break; + + default: + addr &= ~3; + v = __raw_readl(addr); + break; + } + } + + *val = v; + return PCIBIOS_SUCCESSFUL; +} + +static int versatile_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 val) +{ + unsigned long addr = __pci_addr(bus, devfn, where); + int slot = PCI_SLOT(devfn); + + if (pci_slot_ignore & (1 << slot)) { + return PCIBIOS_SUCCESSFUL; + } + + switch (size) { + case 1: + __raw_writeb((u8)val, addr); + break; + + case 2: + __raw_writew((u16)val, addr); + break; + + case 4: + __raw_writel(val, addr); + break; + } + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops pci_versatile_ops = { + .read = versatile_read_config, + .write = versatile_write_config, +}; + +static struct resource io_mem = { + .name = "PCI I/O space", + .start = VERSATILE_PCI_MEM_BASE0, + .end = VERSATILE_PCI_MEM_BASE0+VERSATILE_PCI_MEM_BASE0_SIZE-1, + .flags = IORESOURCE_IO, +}; + +static struct resource non_mem = { + .name = "PCI non-prefetchable", + .start = VERSATILE_PCI_MEM_BASE1, + .end = VERSATILE_PCI_MEM_BASE1+VERSATILE_PCI_MEM_BASE1_SIZE-1, + .flags = IORESOURCE_MEM, +}; + +static struct resource pre_mem = { + .name = "PCI prefetchable", + .start = VERSATILE_PCI_MEM_BASE2, + .end = VERSATILE_PCI_MEM_BASE2+VERSATILE_PCI_MEM_BASE2_SIZE-1, + .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH, +}; + +static int __init pci_versatile_setup_resources(struct resource **resource) +{ + int ret = 0; + + ret = request_resource(&iomem_resource, &io_mem); + if (ret) { + printk(KERN_ERR "PCI: unable to allocate I/O " + "memory region (%d)\n", ret); + goto out; + } + ret = request_resource(&iomem_resource, &non_mem); + if (ret) { + printk(KERN_ERR "PCI: unable to allocate non-prefetchable " + "memory region (%d)\n", ret); + goto release_io_mem; + } + ret = request_resource(&iomem_resource, &pre_mem); + if (ret) { + printk(KERN_ERR "PCI: unable to allocate prefetchable " + "memory region (%d)\n", ret); + goto release_non_mem; + } + + /* + * bus->resource[0] is the IO resource for this bus + * bus->resource[1] is the mem resource for this bus + * bus->resource[2] is the prefetch mem resource for this bus + */ + resource[0] = &io_mem; + resource[1] = &non_mem; + resource[2] = &pre_mem; + + goto out; + + release_non_mem: + release_resource(&non_mem); + release_io_mem: + release_resource(&io_mem); + out: + return ret; +} + +int __init pci_versatile_setup(int nr, struct pci_sys_data *sys) +{ + int ret = 0; + int i; + int myslot = -1; + unsigned long val; + + if (nr == 0) { + sys->mem_offset = 0; + ret = pci_versatile_setup_resources(sys->resource); + if (ret < 0) { + printk("pci_versatile_setup: resources... oops?\n"); + goto out; + } + } else { + printk("pci_versatile_setup: resources... nr == 0??\n"); + goto out; + } + + __raw_writel(VERSATILE_PCI_MEM_BASE0 >> 28,PCI_IMAP0); + __raw_writel(VERSATILE_PCI_MEM_BASE1 >> 28,PCI_IMAP1); + __raw_writel(VERSATILE_PCI_MEM_BASE2 >> 28,PCI_IMAP2); + + __raw_writel(1, SYS_PCICTL); + + val = __raw_readl(SYS_PCICTL); + if (!(val & 1)) { + printk("Not plugged into PCI backplane!\n"); + ret = -EIO; + goto out; + } + + /* + * We need to discover the PCI core first to configure itself + * before the main PCI probing is performed + */ + for (i=0; i<32; i++) { + if ((__raw_readl(VERSATILE_PCI_VIRT_BASE+(i<<11)+DEVICE_ID_OFFSET) == VP_PCI_DEVICE_ID) && + (__raw_readl(VERSATILE_PCI_VIRT_BASE+(i<<11)+CLASS_ID_OFFSET) == VP_PCI_CLASS_ID)) { + myslot = i; + + __raw_writel(myslot, PCI_SELFID); + val = __raw_readl(VERSATILE_PCI_CFG_VIRT_BASE+(myslot<<11)+CSR_OFFSET); + val |= (1<<2); + __raw_writel(val, VERSATILE_PCI_CFG_VIRT_BASE+(myslot<<11)+CSR_OFFSET); + break; + } + } + + if (myslot == -1) { + printk("Cannot find PCI core!\n"); + ret = -EIO; + } else { + printk("PCI core found (slot %d)\n",myslot); + /* Do not to map Versatile FPGA PCI device + into memory space as we are short of + mappable memory */ + pci_slot_ignore |= (1 << myslot); + ret = 1; + } + + out: + return ret; +} + + +struct pci_bus *pci_versatile_scan_bus(int nr, struct pci_sys_data *sys) +{ + return pci_scan_bus(sys->busnr, &pci_versatile_ops, sys); +} + +/* + * V3_LB_BASE? - local bus address + * V3_LB_MAP? - pci bus address + */ +void __init pci_versatile_preinit(void) +{ +} + +void __init pci_versatile_postinit(void) +{ +} + + +/* + * map the specified device/slot/pin to an IRQ. Different backplanes may need to modify this. + */ +static int __init versatile_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq; + int devslot = PCI_SLOT(dev->devfn); + + /* slot, pin, irq + 24 1 27 + 25 1 28 untested + 26 1 29 + 27 1 30 untested + */ + + irq = 27 + ((slot + pin + 2) % 3); /* Fudged */ + + printk("map irq: slot %d, pin %d, devslot %d, irq: %d\n",slot,pin,devslot,irq); + + return irq; +} + +static struct hw_pci versatile_pci __initdata = { + .swizzle = NULL, + .map_irq = versatile_map_irq, + .nr_controllers = 1, + .setup = pci_versatile_setup, + .scan = pci_versatile_scan_bus, + .preinit = pci_versatile_preinit, + .postinit = pci_versatile_postinit, +}; + +static int __init versatile_pci_init(void) +{ + pci_common_init(&versatile_pci); + return 0; +} + +subsys_initcall(versatile_pci_init); diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 3fefb43c67f7..95606b4a3ba6 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -62,7 +62,7 @@ config CPU_ARM720T # ARM920T config CPU_ARM920T bool "Support ARM920T processor" if !ARCH_S3C2410 - depends on ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX + depends on ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX || ARCH_AAEC2000 default y if ARCH_S3C2410 select CPU_32v4 select CPU_ABRT_EV4T diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c index a8c00236bd3d..27d041574ea7 100644 --- a/arch/arm/mm/copypage-v6.c +++ b/arch/arm/mm/copypage-v6.c @@ -30,8 +30,6 @@ static DEFINE_SPINLOCK(v6_lock); -#define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT) - /* * Copy the user page. No aliasing to deal with so we can just * attack the kernel's existing mapping of these pages. @@ -55,7 +53,7 @@ void v6_clear_user_page_nonaliasing(void *kaddr, unsigned long vaddr) */ void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vaddr) { - unsigned int offset = DCACHE_COLOUR(vaddr); + unsigned int offset = CACHE_COLOUR(vaddr); unsigned long from, to; /* @@ -95,7 +93,7 @@ void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vadd */ void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr) { - unsigned int offset = DCACHE_COLOUR(vaddr); + unsigned int offset = CACHE_COLOUR(vaddr); unsigned long to = to_address + (offset << PAGE_SHIFT); /* diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 01967ddeef53..be4ab3d73c91 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -77,9 +77,8 @@ no_pmd: } static void -make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, int dirty) +make_coherent(struct address_space *mapping, struct vm_area_struct *vma, unsigned long addr, unsigned long pfn) { - struct address_space *mapping = page_mapping(page); struct mm_struct *mm = vma->vm_mm; struct vm_area_struct *mpnt; struct prio_tree_iter iter; @@ -87,9 +86,6 @@ make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, pgoff_t pgoff; int aliases = 0; - if (!mapping) - return; - pgoff = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT); /* @@ -115,9 +111,11 @@ make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, if (aliases) adjust_pte(vma, addr); else - flush_cache_page(vma, addr, page_to_pfn(page)); + flush_cache_page(vma, addr, pfn); } +void __flush_dcache_page(struct address_space *mapping, struct page *page); + /* * Take care of architecture specific things when placing a new PTE into * a page table, or changing an existing PTE. Basically, there are two @@ -134,29 +132,22 @@ make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) { unsigned long pfn = pte_pfn(pte); + struct address_space *mapping; struct page *page; if (!pfn_valid(pfn)) return; + page = pfn_to_page(pfn); - if (page_mapping(page)) { + mapping = page_mapping(page); + if (mapping) { int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); - if (dirty) { - /* - * This is our first userspace mapping of this page. - * Ensure that the physical page is coherent with - * the kernel mapping. - * - * FIXME: only need to do this on VIVT and aliasing - * VIPT cache architectures. We can do that - * by choosing whether to set this bit... - */ - __cpuc_flush_dcache_page(page_address(page)); - } + if (dirty) + __flush_dcache_page(mapping, page); if (cache_is_vivt()) - make_coherent(vma, addr, page, dirty); + make_coherent(mapping, vma, addr, pfn); } } diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 4085ed983e46..191788fb18d1 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -37,13 +37,8 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr) #define flush_pfn_alias(pfn,vaddr) do { } while (0) #endif -static void __flush_dcache_page(struct address_space *mapping, struct page *page) +void __flush_dcache_page(struct address_space *mapping, struct page *page) { - struct mm_struct *mm = current->active_mm; - struct vm_area_struct *mpnt; - struct prio_tree_iter iter; - pgoff_t pgoff; - /* * Writeback any data associated with the kernel mapping of this * page. This ensures that data in the physical page is mutually @@ -52,24 +47,21 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page __cpuc_flush_dcache_page(page_address(page)); /* - * If there's no mapping pointer here, then this page isn't - * visible to userspace yet, so there are no cache lines - * associated with any other aliases. - */ - if (!mapping) - return; - - /* - * This is a page cache page. If we have a VIPT cache, we - * only need to do one flush - which would be at the relevant + * If this is a page cache page, and we have an aliasing VIPT cache, + * we only need to do one flush - which would be at the relevant * userspace colour, which is congruent with page->index. */ - if (cache_is_vipt()) { - if (cache_is_vipt_aliasing()) - flush_pfn_alias(page_to_pfn(page), - page->index << PAGE_CACHE_SHIFT); - return; - } + if (mapping && cache_is_vipt_aliasing()) + flush_pfn_alias(page_to_pfn(page), + page->index << PAGE_CACHE_SHIFT); +} + +static void __flush_dcache_aliases(struct address_space *mapping, struct page *page) +{ + struct mm_struct *mm = current->active_mm; + struct vm_area_struct *mpnt; + struct prio_tree_iter iter; + pgoff_t pgoff; /* * There are possible user space mappings of this page: @@ -116,12 +108,12 @@ void flush_dcache_page(struct page *page) { struct address_space *mapping = page_mapping(page); - if (cache_is_vipt_nonaliasing()) - return; - if (mapping && !mapping_mapped(mapping)) set_bit(PG_dcache_dirty, &page->flags); - else + else { __flush_dcache_page(mapping, page); + if (mapping && cache_is_vivt()) + __flush_dcache_aliases(mapping, page); + } } EXPORT_SYMBOL(flush_dcache_page); diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 00bb8fd37a59..7110e54182b1 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -170,3 +170,50 @@ void __iounmap(void __iomem *addr) vfree((void *) (PAGE_MASK & (unsigned long) addr)); } EXPORT_SYMBOL(__iounmap); + +#ifdef __io +void __iomem *ioport_map(unsigned long port, unsigned int nr) +{ + return __io(port); +} +EXPORT_SYMBOL(ioport_map); + +void ioport_unmap(void __iomem *addr) +{ +} +EXPORT_SYMBOL(ioport_unmap); +#endif + +#ifdef CONFIG_PCI +#include <linux/pci.h> +#include <linux/ioport.h> + +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len || !start) + return NULL; + if (maxlen && len > maxlen) + len = maxlen; + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) { + if (flags & IORESOURCE_CACHEABLE) + return ioremap(start, len); + return ioremap_nocache(start, len); + } + return NULL; +} +EXPORT_SYMBOL(pci_iomap); + +void pci_iounmap(struct pci_dev *dev, void __iomem *addr) +{ + if ((unsigned long)addr >= VMALLOC_START && + (unsigned long)addr < VMALLOC_END) + iounmap(addr); +} +EXPORT_SYMBOL(pci_iounmap); +#endif |