From efe90d273b6f365d37c0f82fbbd68a40982c3265 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 8 Dec 2006 15:22:20 +0000 Subject: [ARM] Handle HWCAP_VFP in VFP support code Don't set HWCAP_VFP in the processor support file; not only does it depend on the processor features, but it also depends on the support code being present. Therefore, only set it if the support code detects that we have a VFP coprocessor attached. Also, move the VFP handling of the coprocessor access register into the VFP support code. Signed-off-by: Russell King --- include/asm-arm/system.h | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h index f05fbe31576c..f60faccf01fa 100644 --- a/include/asm-arm/system.h +++ b/include/asm-arm/system.h @@ -139,19 +139,36 @@ static inline int cpu_is_xsc3(void) #define cpu_is_xscale() 1 #endif -#define set_cr(x) \ - __asm__ __volatile__( \ - "mcr p15, 0, %0, c1, c0, 0 @ set CR" \ - : : "r" (x) : "cc") - -#define get_cr() \ - ({ \ - unsigned int __val; \ - __asm__ __volatile__( \ - "mrc p15, 0, %0, c1, c0, 0 @ get CR" \ - : "=r" (__val) : : "cc"); \ - __val; \ - }) +static inline unsigned int get_cr(void) +{ + unsigned int val; + asm("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val) : : "cc"); + return val; +} + +static inline void set_cr(unsigned int val) +{ + asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR" + : : "r" (val) : "cc"); +} + +#define CPACC_FULL(n) (3 << (n * 2)) +#define CPACC_SVC(n) (1 << (n * 2)) +#define CPACC_DISABLE(n) (0 << (n * 2)) + +static inline unsigned int get_copro_access(void) +{ + unsigned int val; + asm("mrc p15, 0, %0, c1, c0, 2 @ get copro access" + : "=r" (val) : : "cc"); + return val; +} + +static inline void set_copro_access(unsigned int val) +{ + asm volatile("mcr p15, 0, %0, c1, c0, 2 @ set copro access" + : : "r" (val) : "cc"); +} extern unsigned long cr_no_alignment; /* defined in entry-armv.S */ extern unsigned long cr_alignment; /* defined in entry-armv.S */ -- cgit v1.2.3-59-g8ed1b From 9fddda232ca2de4d40ba9c3890e27bdb4f4f8bbd Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 8 Dec 2006 00:08:33 +0100 Subject: [ARM] 4004/1: S3C24XX: UDC remove implict addition of VA to regs Remove the implicit addition of a virtual address to the UDC registers. This should have been done by ioremap() in the driver, not by a static map. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- include/asm-arm/arch-s3c2410/regs-udc.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/asm-arm/arch-s3c2410/regs-udc.h b/include/asm-arm/arch-s3c2410/regs-udc.h index 487861d5b49a..3c8354619b60 100644 --- a/include/asm-arm/arch-s3c2410/regs-udc.h +++ b/include/asm-arm/arch-s3c2410/regs-udc.h @@ -11,8 +11,7 @@ #ifndef __ASM_ARCH_REGS_UDC_H #define __ASM_ARCH_REGS_UDC_H - -#define S3C2410_USBDREG(x) ((x) + S3C24XX_VA_USBDEV) +#define S3C2410_USBDREG(x) (x) #define S3C2410_UDC_FUNC_ADDR_REG S3C2410_USBDREG(0x0140) #define S3C2410_UDC_PWR_REG S3C2410_USBDREG(0x0144) @@ -136,8 +135,8 @@ #define S3C2410_UDC_OCSR2_ISO (1<<6) // R/W #define S3C2410_UDC_OCSR2_DMAIEN (1<<5) // R/W -#define S3C2410_UDC_SETIX(x) \ - __raw_writel(S3C2410_UDC_INDEX_ ## x, S3C2410_UDC_INDEX_REG); +#define S3C2410_UDC_SETIX(base,x) \ + writel(S3C2410_UDC_INDEX_ ## x, base+S3C2410_UDC_INDEX_REG); #define S3C2410_UDC_EP0_CSR_OPKRDY (1<<0) -- cgit v1.2.3-59-g8ed1b From bca0b8e75f6b7cf52cf52c967286b72d84f9b37e Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 9 Dec 2006 16:41:55 +0000 Subject: [ARM] Add sys_*at syscalls Later glibc requires the *at syscalls. Add them. Signed-off-by: Russell King --- arch/arm/kernel/calls.S | 13 +++++++++++++ include/asm-arm/unistd.h | 13 +++++++++++++ 2 files changed, 26 insertions(+) (limited to 'include') diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 3173924a9b60..e8f74363328c 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -331,6 +331,19 @@ CALL(sys_mbind) /* 320 */ CALL(sys_get_mempolicy) CALL(sys_set_mempolicy) + CALL(sys_openat) + CALL(sys_mkdirat) + CALL(sys_mknodat) +/* 325 */ CALL(sys_fchownat) + CALL(sys_futimesat) + CALL(sys_fstatat64) + CALL(sys_unlinkat) + CALL(sys_renameat) +/* 330 */ CALL(sys_linkat) + CALL(sys_symlinkat) + CALL(sys_readlinkat) + CALL(sys_fchmodat) + CALL(sys_faccessat) #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index d44c629d8424..32b06eb52819 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h @@ -347,6 +347,19 @@ #define __NR_mbind (__NR_SYSCALL_BASE+319) #define __NR_get_mempolicy (__NR_SYSCALL_BASE+320) #define __NR_set_mempolicy (__NR_SYSCALL_BASE+321) +#define __NR_openat (__NR_SYSCALL_BASE+322) +#define __NR_mkdirat (__NR_SYSCALL_BASE+323) +#define __NR_mknodat (__NR_SYSCALL_BASE+324) +#define __NR_fchownat (__NR_SYSCALL_BASE+325) +#define __NR_futimesat (__NR_SYSCALL_BASE+326) +#define __NR_fstatat64 (__NR_SYSCALL_BASE+327) +#define __NR_unlinkat (__NR_SYSCALL_BASE+328) +#define __NR_renameat (__NR_SYSCALL_BASE+329) +#define __NR_linkat (__NR_SYSCALL_BASE+330) +#define __NR_symlinkat (__NR_SYSCALL_BASE+331) +#define __NR_readlinkat (__NR_SYSCALL_BASE+332) +#define __NR_fchmodat (__NR_SYSCALL_BASE+333) +#define __NR_faccessat (__NR_SYSCALL_BASE+334) /* * The following SWIs are ARM private. -- cgit v1.2.3-59-g8ed1b From ad1ae2fe7fe68414ef29eab3c87b48841f8b72f2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 13 Dec 2006 14:34:43 +0000 Subject: [ARM] Unuse another Linux PTE bit L_PTE_ASID is not really required to be stored in every PTE, since we can identify it via the address passed to set_pte_at(). So, create set_pte_ext() which takes the address of the PTE to set, the Linux PTE value, and the additional CPU PTE bits which aren't encoded in the Linux PTE value. Signed-off-by: Russell King --- arch/arm/mm/consistent.c | 2 +- arch/arm/mm/copypage-v4mc.c | 2 +- arch/arm/mm/copypage-v6.c | 6 +++--- arch/arm/mm/copypage-xscale.c | 2 +- arch/arm/mm/fault-armv.c | 2 +- arch/arm/mm/flush.c | 2 +- arch/arm/mm/ioremap.c | 4 ++-- arch/arm/mm/mmu.c | 8 +------- arch/arm/mm/pgd.c | 2 +- arch/arm/mm/proc-arm1020.S | 4 ++-- arch/arm/mm/proc-arm1020e.S | 4 ++-- arch/arm/mm/proc-arm1022.S | 6 +++--- arch/arm/mm/proc-arm1026.S | 6 +++--- arch/arm/mm/proc-arm6_7.S | 10 +++++----- arch/arm/mm/proc-arm720.S | 6 +++--- arch/arm/mm/proc-arm920.S | 6 +++--- arch/arm/mm/proc-arm922.S | 6 +++--- arch/arm/mm/proc-arm925.S | 6 +++--- arch/arm/mm/proc-arm926.S | 6 +++--- arch/arm/mm/proc-sa110.S | 6 +++--- arch/arm/mm/proc-sa1100.S | 6 +++--- arch/arm/mm/proc-syms.c | 2 +- arch/arm/mm/proc-v6.S | 30 ++++++++++++++++-------------- arch/arm/mm/proc-xsc3.S | 6 +++--- arch/arm/mm/proc-xscale.S | 6 +++--- include/asm-arm/cpu-multi32.h | 7 ++++--- include/asm-arm/cpu-single.h | 4 ++-- include/asm-arm/pgtable.h | 11 +++++++---- 28 files changed, 84 insertions(+), 84 deletions(-) (limited to 'include') diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c index b797217e82be..6a9c362fef5e 100644 --- a/arch/arm/mm/consistent.c +++ b/arch/arm/mm/consistent.c @@ -238,7 +238,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, * x86 does not mark the pages reserved... */ SetPageReserved(page); - set_pte(pte, mk_pte(page, prot)); + set_pte_ext(pte, mk_pte(page, prot), 0); page++; pte++; off++; diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c index df1645e14b4c..408b05ae6b9b 100644 --- a/arch/arm/mm/copypage-v4mc.c +++ b/arch/arm/mm/copypage-v4mc.c @@ -71,7 +71,7 @@ void v4_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr) { spin_lock(&minicache_lock); - set_pte(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot)); + set_pte_ext(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot), 0); flush_tlb_kernel_page(0xffff8000); mc_copy_user_page((void *)0xffff8000, kto); diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c index 3d0d3a963d20..865777dec161 100644 --- a/arch/arm/mm/copypage-v6.c +++ b/arch/arm/mm/copypage-v6.c @@ -70,8 +70,8 @@ static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned lo */ spin_lock(&v6_lock); - set_pte(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, PAGE_KERNEL)); - set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, PAGE_KERNEL)); + set_pte_ext(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, PAGE_KERNEL), 0); + set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, PAGE_KERNEL), 0); from = from_address + (offset << PAGE_SHIFT); to = to_address + (offset << PAGE_SHIFT); @@ -110,7 +110,7 @@ static void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr) */ spin_lock(&v6_lock); - set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, PAGE_KERNEL)); + set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, PAGE_KERNEL), 0); flush_tlb_kernel_page(to); clear_page((void *)to); diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c index 84ebe0aa379e..aea5da723596 100644 --- a/arch/arm/mm/copypage-xscale.c +++ b/arch/arm/mm/copypage-xscale.c @@ -93,7 +93,7 @@ void xscale_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr) { spin_lock(&minicache_lock); - set_pte(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot)); + set_pte_ext(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot), 0); flush_tlb_kernel_page(COPYPAGE_MINICACHE); mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto); diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 7fc1b35a6746..cf95c5d0ce4c 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -61,7 +61,7 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address) if (pte_present(entry) && pte_val(entry) & shared_pte_mask) { flush_cache_page(vma, address, pte_pfn(entry)); pte_val(entry) &= ~shared_pte_mask; - set_pte(pte, entry); + set_pte_at(vma->vm_mm, address, pte, entry); flush_tlb_page(vma, address); ret = 1; } diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 454205b789d5..628348c9f6c5 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -26,7 +26,7 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr) unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT); const int zero = 0; - set_pte(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL)); + set_pte_ext(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL), 0); flush_tlb_kernel_page(to); asm( "mcrr p15, 0, %1, %0, c14\n" diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 465440592791..a43d2800a9cd 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -40,7 +40,7 @@ static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, - unsigned long phys_addr, pgprot_t pgprot) + unsigned long phys_addr, pgprot_t prot) { unsigned long end; @@ -53,7 +53,7 @@ remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, if (!pte_none(*pte)) goto bad; - set_pte(pte, pfn_pte(phys_addr >> PAGE_SHIFT, pgprot)); + set_pte_ext(pte, pfn_pte(phys_addr >> PAGE_SHIFT, prot), 0); address += PAGE_SIZE; phys_addr += PAGE_SIZE; pte++; diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index b7f194af20b4..f028aef9a861 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -294,12 +294,6 @@ static void __init build_mem_type_table(void) mem_types[MT_DEVICE].prot_pte |= L_PTE_BUFFERABLE; mem_types[MT_DEVICE].prot_sect |= PMD_SECT_BUFFERED; - /* - * User pages need to be mapped with the ASID - * (iow, non-global) - */ - user_pgprot |= L_PTE_ASID; - #ifdef CONFIG_SMP /* * Mark memory with the "shared" attribute for SMP systems @@ -408,7 +402,7 @@ alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pg } ptep = pte_offset_kernel(pmdp, virt); - set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot)); + set_pte_ext(ptep, pfn_pte(phys >> PAGE_SHIFT, prot), 0); } /* diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c index 20c1b0df75f2..50b9aed6000d 100644 --- a/arch/arm/mm/pgd.c +++ b/arch/arm/mm/pgd.c @@ -57,7 +57,7 @@ pgd_t *get_pgd_slow(struct mm_struct *mm) init_pmd = pmd_offset(init_pgd, 0); init_pte = pte_offset_map_nested(init_pmd, 0); - set_pte(new_pte, *init_pte); + set_pte_ext(new_pte, *init_pte, 0); pte_unmap_nested(init_pte); pte_unmap(new_pte); } diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S index 289b8e6f504d..700c04d6996e 100644 --- a/arch/arm/mm/proc-arm1020.S +++ b/arch/arm/mm/proc-arm1020.S @@ -397,7 +397,7 @@ ENTRY(cpu_arm1020_switch_mm) * Set a PTE and flush it out */ .align 5 -ENTRY(cpu_arm1020_set_pte) +ENTRY(cpu_arm1020_set_pte_ext) #ifdef CONFIG_MMU str r1, [r0], #-2048 @ linux version @@ -477,7 +477,7 @@ arm1020_processor_functions: .word cpu_arm1020_do_idle .word cpu_arm1020_dcache_clean_area .word cpu_arm1020_switch_mm - .word cpu_arm1020_set_pte + .word cpu_arm1020_set_pte_ext .size arm1020_processor_functions, . - arm1020_processor_functions .section ".rodata" diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S index bed9db6ba582..1cc206ab5eae 100644 --- a/arch/arm/mm/proc-arm1020e.S +++ b/arch/arm/mm/proc-arm1020e.S @@ -381,7 +381,7 @@ ENTRY(cpu_arm1020e_switch_mm) * Set a PTE and flush it out */ .align 5 -ENTRY(cpu_arm1020e_set_pte) +ENTRY(cpu_arm1020e_set_pte_ext) #ifdef CONFIG_MMU str r1, [r0], #-2048 @ linux version @@ -458,7 +458,7 @@ arm1020e_processor_functions: .word cpu_arm1020e_do_idle .word cpu_arm1020e_dcache_clean_area .word cpu_arm1020e_switch_mm - .word cpu_arm1020e_set_pte + .word cpu_arm1020e_set_pte_ext .size arm1020e_processor_functions, . - arm1020e_processor_functions .section ".rodata" diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S index d2a7c1b9cab9..aff0ea08e2f8 100644 --- a/arch/arm/mm/proc-arm1022.S +++ b/arch/arm/mm/proc-arm1022.S @@ -358,12 +358,12 @@ ENTRY(cpu_arm1022_switch_mm) mov pc, lr /* - * cpu_arm1022_set_pte(ptep, pte) + * cpu_arm1022_set_pte_ext(ptep, pte, ext) * * Set a PTE and flush it out */ .align 5 -ENTRY(cpu_arm1022_set_pte) +ENTRY(cpu_arm1022_set_pte_ext) #ifdef CONFIG_MMU str r1, [r0], #-2048 @ linux version @@ -441,7 +441,7 @@ arm1022_processor_functions: .word cpu_arm1022_do_idle .word cpu_arm1022_dcache_clean_area .word cpu_arm1022_switch_mm - .word cpu_arm1022_set_pte + .word cpu_arm1022_set_pte_ext .size arm1022_processor_functions, . - arm1022_processor_functions .section ".rodata" diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S index 3247ce5c0177..65e43a109085 100644 --- a/arch/arm/mm/proc-arm1026.S +++ b/arch/arm/mm/proc-arm1026.S @@ -347,12 +347,12 @@ ENTRY(cpu_arm1026_switch_mm) mov pc, lr /* - * cpu_arm1026_set_pte(ptep, pte) + * cpu_arm1026_set_pte_ext(ptep, pte, ext) * * Set a PTE and flush it out */ .align 5 -ENTRY(cpu_arm1026_set_pte) +ENTRY(cpu_arm1026_set_pte_ext) #ifdef CONFIG_MMU str r1, [r0], #-2048 @ linux version @@ -436,7 +436,7 @@ arm1026_processor_functions: .word cpu_arm1026_do_idle .word cpu_arm1026_dcache_clean_area .word cpu_arm1026_switch_mm - .word cpu_arm1026_set_pte + .word cpu_arm1026_set_pte_ext .size arm1026_processor_functions, . - arm1026_processor_functions .section .rodata diff --git a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S index ce4f9eef763c..123a7dc7a433 100644 --- a/arch/arm/mm/proc-arm6_7.S +++ b/arch/arm/mm/proc-arm6_7.S @@ -209,14 +209,14 @@ ENTRY(cpu_arm7_switch_mm) mov pc, lr /* - * Function: arm6_7_set_pte(pte_t *ptep, pte_t pte) + * Function: arm6_7_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext) * Params : r0 = Address to set * : r1 = value to set * Purpose : Set a PTE and flush it out of any WB cache */ .align 5 -ENTRY(cpu_arm6_set_pte) -ENTRY(cpu_arm7_set_pte) +ENTRY(cpu_arm6_set_pte_ext) +ENTRY(cpu_arm7_set_pte_ext) #ifdef CONFIG_MMU str r1, [r0], #-2048 @ linux version @@ -299,7 +299,7 @@ ENTRY(arm6_processor_functions) .word cpu_arm6_do_idle .word cpu_arm6_dcache_clean_area .word cpu_arm6_switch_mm - .word cpu_arm6_set_pte + .word cpu_arm6_set_pte_ext .size arm6_processor_functions, . - arm6_processor_functions /* @@ -315,7 +315,7 @@ ENTRY(arm7_processor_functions) .word cpu_arm7_do_idle .word cpu_arm7_dcache_clean_area .word cpu_arm7_switch_mm - .word cpu_arm7_set_pte + .word cpu_arm7_set_pte_ext .size arm7_processor_functions, . - arm7_processor_functions .section ".rodata" diff --git a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S index c04c194da785..dc763be43362 100644 --- a/arch/arm/mm/proc-arm720.S +++ b/arch/arm/mm/proc-arm720.S @@ -88,13 +88,13 @@ ENTRY(cpu_arm720_switch_mm) mov pc, lr /* - * Function: arm720_set_pte(pte_t *ptep, pte_t pte) + * Function: arm720_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext) * Params : r0 = Address to set * : r1 = value to set * Purpose : Set a PTE and flush it out of any WB cache */ .align 5 -ENTRY(cpu_arm720_set_pte) +ENTRY(cpu_arm720_set_pte_ext) #ifdef CONFIG_MMU str r1, [r0], #-2048 @ linux version @@ -204,7 +204,7 @@ ENTRY(arm720_processor_functions) .word cpu_arm720_do_idle .word cpu_arm720_dcache_clean_area .word cpu_arm720_switch_mm - .word cpu_arm720_set_pte + .word cpu_arm720_set_pte_ext .size arm720_processor_functions, . - arm720_processor_functions .section ".rodata" diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S index 65cbb2851bff..75c945ed6c4d 100644 --- a/arch/arm/mm/proc-arm920.S +++ b/arch/arm/mm/proc-arm920.S @@ -344,12 +344,12 @@ ENTRY(cpu_arm920_switch_mm) mov pc, lr /* - * cpu_arm920_set_pte(ptep, pte) + * cpu_arm920_set_pte(ptep, pte, ext) * * Set a PTE and flush it out */ .align 5 -ENTRY(cpu_arm920_set_pte) +ENTRY(cpu_arm920_set_pte_ext) #ifdef CONFIG_MMU str r1, [r0], #-2048 @ linux version @@ -423,7 +423,7 @@ arm920_processor_functions: .word cpu_arm920_do_idle .word cpu_arm920_dcache_clean_area .word cpu_arm920_switch_mm - .word cpu_arm920_set_pte + .word cpu_arm920_set_pte_ext .size arm920_processor_functions, . - arm920_processor_functions .section ".rodata" diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S index 52761b70d735..ffb751b877ff 100644 --- a/arch/arm/mm/proc-arm922.S +++ b/arch/arm/mm/proc-arm922.S @@ -348,12 +348,12 @@ ENTRY(cpu_arm922_switch_mm) mov pc, lr /* - * cpu_arm922_set_pte(ptep, pte) + * cpu_arm922_set_pte_ext(ptep, pte, ext) * * Set a PTE and flush it out */ .align 5 -ENTRY(cpu_arm922_set_pte) +ENTRY(cpu_arm922_set_pte_ext) #ifdef CONFIG_MMU str r1, [r0], #-2048 @ linux version @@ -427,7 +427,7 @@ arm922_processor_functions: .word cpu_arm922_do_idle .word cpu_arm922_dcache_clean_area .word cpu_arm922_switch_mm - .word cpu_arm922_set_pte + .word cpu_arm922_set_pte_ext .size arm922_processor_functions, . - arm922_processor_functions .section ".rodata" diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S index 5b74339d1588..44c2c997819f 100644 --- a/arch/arm/mm/proc-arm925.S +++ b/arch/arm/mm/proc-arm925.S @@ -391,12 +391,12 @@ ENTRY(cpu_arm925_switch_mm) mov pc, lr /* - * cpu_arm925_set_pte(ptep, pte) + * cpu_arm925_set_pte_ext(ptep, pte, ext) * * Set a PTE and flush it out */ .align 5 -ENTRY(cpu_arm925_set_pte) +ENTRY(cpu_arm925_set_pte_ext) #ifdef CONFIG_MMU str r1, [r0], #-2048 @ linux version @@ -490,7 +490,7 @@ arm925_processor_functions: .word cpu_arm925_do_idle .word cpu_arm925_dcache_clean_area .word cpu_arm925_switch_mm - .word cpu_arm925_set_pte + .word cpu_arm925_set_pte_ext .size arm925_processor_functions, . - arm925_processor_functions .section ".rodata" diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S index 080efac9d9ff..5b80b6bdd0cb 100644 --- a/arch/arm/mm/proc-arm926.S +++ b/arch/arm/mm/proc-arm926.S @@ -348,12 +348,12 @@ ENTRY(cpu_arm926_switch_mm) mov pc, lr /* - * cpu_arm926_set_pte(ptep, pte) + * cpu_arm926_set_pte_ext(ptep, pte, ext) * * Set a PTE and flush it out */ .align 5 -ENTRY(cpu_arm926_set_pte) +ENTRY(cpu_arm926_set_pte_ext) #ifdef CONFIG_MMU str r1, [r0], #-2048 @ linux version @@ -439,7 +439,7 @@ arm926_processor_functions: .word cpu_arm926_do_idle .word cpu_arm926_dcache_clean_area .word cpu_arm926_switch_mm - .word cpu_arm926_set_pte + .word cpu_arm926_set_pte_ext .size arm926_processor_functions, . - arm926_processor_functions .section ".rodata" diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S index cd7d865c9d19..6e226e12989f 100644 --- a/arch/arm/mm/proc-sa110.S +++ b/arch/arm/mm/proc-sa110.S @@ -146,12 +146,12 @@ ENTRY(cpu_sa110_switch_mm) #endif /* - * cpu_sa110_set_pte(ptep, pte) + * cpu_sa110_set_pte_ext(ptep, pte, ext) * * Set a PTE and flush it out */ .align 5 -ENTRY(cpu_sa110_set_pte) +ENTRY(cpu_sa110_set_pte_ext) #ifdef CONFIG_MMU str r1, [r0], #-2048 @ linux version @@ -222,7 +222,7 @@ ENTRY(sa110_processor_functions) .word cpu_sa110_do_idle .word cpu_sa110_dcache_clean_area .word cpu_sa110_switch_mm - .word cpu_sa110_set_pte + .word cpu_sa110_set_pte_ext .size sa110_processor_functions, . - sa110_processor_functions .section ".rodata" diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S index b776653cc31c..9afb11d089fe 100644 --- a/arch/arm/mm/proc-sa1100.S +++ b/arch/arm/mm/proc-sa1100.S @@ -159,12 +159,12 @@ ENTRY(cpu_sa1100_switch_mm) #endif /* - * cpu_sa1100_set_pte(ptep, pte) + * cpu_sa1100_set_pte_ext(ptep, pte, ext) * * Set a PTE and flush it out */ .align 5 -ENTRY(cpu_sa1100_set_pte) +ENTRY(cpu_sa1100_set_pte_ext) #ifdef CONFIG_MMU str r1, [r0], #-2048 @ linux version @@ -237,7 +237,7 @@ ENTRY(sa1100_processor_functions) .word cpu_sa1100_do_idle .word cpu_sa1100_dcache_clean_area .word cpu_sa1100_switch_mm - .word cpu_sa1100_set_pte + .word cpu_sa1100_set_pte_ext .size sa1100_processor_functions, . - sa1100_processor_functions .section ".rodata" diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c index ab143557e688..9f396b4fa0b7 100644 --- a/arch/arm/mm/proc-syms.c +++ b/arch/arm/mm/proc-syms.c @@ -17,7 +17,7 @@ #ifndef MULTI_CPU EXPORT_SYMBOL(cpu_dcache_clean_area); -EXPORT_SYMBOL(cpu_set_pte); +EXPORT_SYMBOL(cpu_set_pte_ext); #else EXPORT_SYMBOL(processor); #endif diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index 513c6c28256d..7b1843befb9c 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -103,13 +103,14 @@ ENTRY(cpu_v6_switch_mm) mov pc, lr /* - * cpu_v6_set_pte(ptep, pte) + * cpu_v6_set_pte_ext(ptep, pte, ext) * * Set a level 2 translation table entry. * * - ptep - pointer to level 2 translation table entry * (hardware version is stored at -1024 bytes) * - pte - PTE value to store + * - ext - value for extended PTE bits * * Permissions: * YUWD APX AP1 AP0 SVC User @@ -121,33 +122,34 @@ ENTRY(cpu_v6_switch_mm) * 11x0 0 1 0 r/w r/o * 1111 0 1 1 r/w r/w */ -ENTRY(cpu_v6_set_pte) +ENTRY(cpu_v6_set_pte_ext) #ifdef CONFIG_MMU str r1, [r0], #-2048 @ linux version - bic r2, r1, #0x000003f0 - bic r2, r2, #0x00000003 - orr r2, r2, #PTE_EXT_AP0 | 2 + bic r3, r1, #0x000003f0 + bic r3, r3, #0x00000003 + orr r3, r3, r2 + orr r3, r3, #PTE_EXT_AP0 | 2 tst r1, #L_PTE_WRITE tstne r1, #L_PTE_DIRTY - orreq r2, r2, #PTE_EXT_APX + orreq r3, r3, #PTE_EXT_APX tst r1, #L_PTE_USER - orrne r2, r2, #PTE_EXT_AP1 - tstne r2, #PTE_EXT_APX - bicne r2, r2, #PTE_EXT_APX | PTE_EXT_AP0 + orrne r3, r3, #PTE_EXT_AP1 + tstne r3, #PTE_EXT_APX + bicne r3, r3, #PTE_EXT_APX | PTE_EXT_AP0 tst r1, #L_PTE_YOUNG - biceq r2, r2, #PTE_EXT_APX | PTE_EXT_AP_MASK + biceq r3, r3, #PTE_EXT_APX | PTE_EXT_AP_MASK tst r1, #L_PTE_EXEC - orreq r2, r2, #PTE_EXT_XN + orreq r3, r3, #PTE_EXT_XN tst r1, #L_PTE_PRESENT - moveq r2, #0 + moveq r3, #0 - str r2, [r0] + str r3, [r0] mcr p15, 0, r0, c7, c10, 1 @ flush_pte #endif mov pc, lr @@ -233,7 +235,7 @@ ENTRY(v6_processor_functions) .word cpu_v6_do_idle .word cpu_v6_dcache_clean_area .word cpu_v6_switch_mm - .word cpu_v6_set_pte + .word cpu_v6_set_pte_ext .size v6_processor_functions, . - v6_processor_functions .type cpu_arch_name, #object diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index 1ef564d0957f..43494ae8f01a 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -357,13 +357,13 @@ ENTRY(cpu_xsc3_switch_mm) cpwait_ret lr, ip /* - * cpu_xsc3_set_pte(ptep, pte) + * cpu_xsc3_set_pte_ext(ptep, pte, ext) * * Set a PTE and flush it out * */ .align 5 -ENTRY(cpu_xsc3_set_pte) +ENTRY(cpu_xsc3_set_pte_ext) str r1, [r0], #-2048 @ linux version bic r2, r1, #0xff0 @ Keep C, B bits @@ -457,7 +457,7 @@ ENTRY(xsc3_processor_functions) .word cpu_xsc3_do_idle .word cpu_xsc3_dcache_clean_area .word cpu_xsc3_switch_mm - .word cpu_xsc3_set_pte + .word cpu_xsc3_set_pte_ext .size xsc3_processor_functions, . - xsc3_processor_functions .section ".rodata" diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index cc1004b3e511..490e11b34231 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -421,14 +421,14 @@ ENTRY(cpu_xscale_switch_mm) cpwait_ret lr, ip /* - * cpu_xscale_set_pte(ptep, pte) + * cpu_xscale_set_pte_ext(ptep, pte, ext) * * Set a PTE and flush it out * * Errata 40: must set memory to write-through for user read-only pages. */ .align 5 -ENTRY(cpu_xscale_set_pte) +ENTRY(cpu_xscale_set_pte_ext) str r1, [r0], #-2048 @ linux version bic r2, r1, #0xff0 @@ -529,7 +529,7 @@ ENTRY(xscale_processor_functions) .word cpu_xscale_do_idle .word cpu_xscale_dcache_clean_area .word cpu_xscale_switch_mm - .word cpu_xscale_set_pte + .word cpu_xscale_set_pte_ext .size xscale_processor_functions, . - xscale_processor_functions .section ".rodata" diff --git a/include/asm-arm/cpu-multi32.h b/include/asm-arm/cpu-multi32.h index 4679f63688e9..715e18a4add1 100644 --- a/include/asm-arm/cpu-multi32.h +++ b/include/asm-arm/cpu-multi32.h @@ -50,9 +50,10 @@ extern struct processor { */ void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *mm); /* - * Set a PTE + * Set a possibly extended PTE. Non-extended PTEs should + * ignore 'ext'. */ - void (*set_pte)(pte_t *ptep, pte_t pte); + void (*set_pte_ext)(pte_t *ptep, pte_t pte, unsigned int ext); } processor; #define cpu_proc_init() processor._proc_init() @@ -60,5 +61,5 @@ extern struct processor { #define cpu_reset(addr) processor.reset(addr) #define cpu_do_idle() processor._do_idle() #define cpu_dcache_clean_area(addr,sz) processor.dcache_clean_area(addr,sz) -#define cpu_set_pte(ptep, pte) processor.set_pte(ptep, pte) +#define cpu_set_pte_ext(ptep,pte,ext) processor.set_pte_ext(ptep,pte,ext) #define cpu_do_switch_mm(pgd,mm) processor.switch_mm(pgd,mm) diff --git a/include/asm-arm/cpu-single.h b/include/asm-arm/cpu-single.h index 6723e67244fa..0b120ee36091 100644 --- a/include/asm-arm/cpu-single.h +++ b/include/asm-arm/cpu-single.h @@ -28,7 +28,7 @@ #define cpu_do_idle __cpu_fn(CPU_NAME,_do_idle) #define cpu_dcache_clean_area __cpu_fn(CPU_NAME,_dcache_clean_area) #define cpu_do_switch_mm __cpu_fn(CPU_NAME,_switch_mm) -#define cpu_set_pte __cpu_fn(CPU_NAME,_set_pte) +#define cpu_set_pte_ext __cpu_fn(CPU_NAME,_set_pte_ext) #include @@ -40,5 +40,5 @@ extern void cpu_proc_fin(void); extern int cpu_do_idle(void); extern void cpu_dcache_clean_area(void *, int); extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); -extern void cpu_set_pte(pte_t *ptep, pte_t pte); +extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext); extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h index 88cd5c784ef0..b8cf2d5ec304 100644 --- a/include/asm-arm/pgtable.h +++ b/include/asm-arm/pgtable.h @@ -21,6 +21,7 @@ #include #include +#include /* * Just any arbitrary offset to the start of the vmalloc VM area: the @@ -170,7 +171,6 @@ extern void __pgd_error(const char *file, int line, unsigned long val); #define L_PTE_EXEC (1 << 6) #define L_PTE_DIRTY (1 << 7) #define L_PTE_SHARED (1 << 10) /* shared(v6), coherent(xsc3) */ -#define L_PTE_ASID (1 << 11) /* non-global (use ASID, v6) */ #ifndef __ASSEMBLY__ @@ -228,7 +228,7 @@ extern struct page *empty_zero_page; #define pfn_pte(pfn,prot) (__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))) #define pte_none(pte) (!pte_val(pte)) -#define pte_clear(mm,addr,ptep) set_pte_at((mm),(addr),(ptep), __pte(0)) +#define pte_clear(mm,addr,ptep) set_pte_ext(ptep, __pte(0), 0) #define pte_page(pte) (pfn_to_page(pte_pfn(pte))) #define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr)) #define pte_offset_map(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr)) @@ -236,8 +236,11 @@ extern struct page *empty_zero_page; #define pte_unmap(pte) do { } while (0) #define pte_unmap_nested(pte) do { } while (0) -#define set_pte(ptep, pte) cpu_set_pte(ptep,pte) -#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) +#define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext) + +#define set_pte_at(mm,addr,ptep,pteval) do { \ + set_pte_ext(ptep, pteval, (addr) >= PAGE_OFFSET ? 0 : PTE_EXT_NG); \ + } while (0) /* * The following only work if pte_present() is true. -- cgit v1.2.3-59-g8ed1b From 02828845dda5ccf921ab2557c6ca17b6e7fc70e2 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 13 Dec 2006 18:39:26 +0100 Subject: [ARM] 4016/1: prefetch macro is wrong wrt gcc's "delete-null-pointer-checks" optimization The gcc manual says: |`-fdelete-null-pointer-checks' | Use global dataflow analysis to identify and eliminate useless | checks for null pointers. The compiler assumes that dereferencing | a null pointer would have halted the program. If a pointer is | checked after it has already been dereferenced, it cannot be null. | Enabled at levels `-O2', `-O3', `-Os'. Now the problem can be seen with this test case: #include extern void bar(char *x); void foo(char *x) { prefetch(x); if (x) bar(x); } Because the constraint to the inline asm used in the prefetch() macro is a memory operand, gcc assumes that the asm code does dereference the pointer and the delete-null-pointer-checks optimization kicks in. Inspection of generated assembly for the above example shows that bar() is indeed called unconditionally without any test on the value of x. Of course in the prefetch case there is no real dereference and it cannot be assumed that a null pointer would have been caught at that point. This causes kernel oopses with constructs like hlist_for_each_entry() where the list's 'next' content is prefetched before the pointer is tested against NULL, and only when gcc feels like applying this optimization which doesn't happen all the time with more complex code. It appears that the way to prevent delete-null-pointer-checks optimization to occur in this case is to make prefetch() into a static inline function instead of a macro. At least this is what is done on x86_64 where a similar inline asm memory operand is used (I presume they would have seen the same problem if it didn't work) and resulting code for the above example confirms that. An alternative would consist of replacing the memory operand by a register operand containing the pointer, and use the addressing mode explicitly in the asm template. But that would be less optimal than an offsettable memory reference. Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- include/asm-arm/processor.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/asm-arm/processor.h b/include/asm-arm/processor.h index b442e8e2a809..1bbf16182d62 100644 --- a/include/asm-arm/processor.h +++ b/include/asm-arm/processor.h @@ -103,14 +103,14 @@ extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); #if __LINUX_ARM_ARCH__ >= 5 #define ARCH_HAS_PREFETCH -#define prefetch(ptr) \ - ({ \ - __asm__ __volatile__( \ - "pld\t%0" \ - : \ - : "o" (*(char *)(ptr)) \ - : "cc"); \ - }) +static inline void prefetch(const void *ptr) +{ + __asm__ __volatile__( + "pld\t%0" + : + : "o" (*(char *)ptr) + : "cc"); +} #define ARCH_HAS_PREFETCHW #define prefetchw(ptr) prefetch(ptr) -- cgit v1.2.3-59-g8ed1b From 47fd705287e9377acd2a4cee9aeeea02867d2e54 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 13 Dec 2006 18:33:53 +0000 Subject: [ARM] Provide a method to alter the control register i.MX needs to tweak the control register to support CPU frequency scaling. Rather than have folk blindly try and change the control register by writing to it and then wondering why it doesn't work, provide a method (which is safe for UP only, and therefore only available for UP) to achieve this. Signed-off-by: Russell King --- include/asm-arm/system.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'include') diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h index f60faccf01fa..e160aeb0138d 100644 --- a/include/asm-arm/system.h +++ b/include/asm-arm/system.h @@ -173,6 +173,26 @@ static inline void set_copro_access(unsigned int val) extern unsigned long cr_no_alignment; /* defined in entry-armv.S */ extern unsigned long cr_alignment; /* defined in entry-armv.S */ +#ifndef CONFIG_SMP +static inline void adjust_cr(unsigned long mask, unsigned long set) +{ + unsigned long flags, cr; + + mask &= ~CR_A; + + set &= mask; + + local_irq_save(flags); + + cr_no_alignment = (cr_no_alignment & ~mask) | set; + cr_alignment = (cr_alignment & ~mask) | set; + + set_cr((get_cr() & ~mask) | set); + + local_irq_restore(flags); +} +#endif + #define UDBG_UNDEFINED (1 << 0) #define UDBG_SYSCALL (1 << 1) #define UDBG_BADABORT (1 << 2) -- cgit v1.2.3-59-g8ed1b From 3c8cd0cce9ab8a25dbcf519cb0de00d2716f8379 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Wed, 6 Dec 2006 17:25:04 +0100 Subject: [ARM] 3992/1: i.MX/MX1 CPU Frequency scaling support Support to change MX1 CPU frequency at runtime. Tested on PiKRON's PiMX1 board and seems to be fully stable up to 200 MHz end even as low as 8 MHz. Signed-off-by: Pavel Pisa Signed-off-by: Russell King --- arch/arm/Kconfig | 11 +- arch/arm/mach-imx/Makefile | 2 + arch/arm/mach-imx/cpufreq.c | 287 ++++++++++++++++++++++++++++++++++++ include/asm-arm/arch-imx/imx-regs.h | 10 +- 4 files changed, 306 insertions(+), 4 deletions(-) create mode 100644 arch/arm/mach-imx/cpufreq.c (limited to 'include') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 1a59110784c6..63e7c0c582df 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -732,7 +732,7 @@ config XIP_PHYS_ADDR endmenu -if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP) +if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX ) menu "CPU Frequency scaling" @@ -759,6 +759,15 @@ config CPU_FREQ_INTEGRATOR If in doubt, say Y. +config CPU_FREQ_IMX + tristate "CPUfreq driver for i.MX CPUs" + depends on ARCH_IMX && CPU_FREQ + default n + help + This enables the CPUfreq driver for i.MX CPUs. + + If in doubt, say N. + endmenu endif diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 0b27d79f2efd..02272aa36e90 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -9,6 +9,8 @@ obj-y += irq.o time.o dma.o generic.o +obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o + # Specific board support obj-$(CONFIG_ARCH_MX1ADS) += mx1ads.o diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c new file mode 100644 index 000000000000..ac5f99895660 --- /dev/null +++ b/arch/arm/mach-imx/cpufreq.c @@ -0,0 +1,287 @@ +/* + * cpu.c: clock scaling for the iMX + * + * Copyright (C) 2000 2001, The Delft University of Technology + * Copyright (c) 2004 Sascha Hauer + * Copyright (C) 2006 Inky Lung + * Copyright (C) 2006 Pavel Pisa, PiKRON + * + * Based on SA1100 version written by: + * - Johan Pouwelse (J.A.Pouwelse@its.tudelft.nl): initial version + * - Erik Mouw (J.A.K.Mouw@its.tudelft.nl): + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*#define DEBUG*/ + +#include +#include +#include +#include +#include + +#include + +#include "generic.h" + +#ifndef __val2mfld +#define __val2mfld(mask,val) (((mask)&~((mask)<<1))*(val)&(mask)) +#endif +#ifndef __mfld2val +#define __mfld2val(mask,val) (((val)&(mask))/((mask)&~((mask)<<1))) +#endif + +#define CR_920T_CLOCK_MODE 0xC0000000 +#define CR_920T_FASTBUS_MODE 0x00000000 +#define CR_920T_ASYNC_MODE 0xC0000000 + +static u32 mpctl0_at_boot; + +static void imx_set_async_mode(void) +{ + adjust_cr(CR_920T_CLOCK_MODE, CR_920T_ASYNC_MODE); +} + +static void imx_set_fastbus_mode(void) +{ + adjust_cr(CR_920T_CLOCK_MODE, CR_920T_FASTBUS_MODE); +} + +static void imx_set_mpctl0(u32 mpctl0) +{ + unsigned long flags; + + if (mpctl0 == 0) { + local_irq_save(flags); + CSCR &= ~CSCR_MPEN; + local_irq_restore(flags); + return; + } + + local_irq_save(flags); + MPCTL0 = mpctl0; + CSCR |= CSCR_MPEN; + local_irq_restore(flags); +} + +/** + * imx_compute_mpctl - compute new PLL parameters + * @new_mpctl: pointer to location assigned by new PLL control register value + * @cur_mpctl: current PLL control register parameters + * @freq: required frequency in Hz + * @relation: is one of %CPUFREQ_RELATION_L (supremum) + * and %CPUFREQ_RELATION_H (infimum) + */ +long imx_compute_mpctl(u32 *new_mpctl, u32 cur_mpctl, unsigned long freq, int relation) +{ + u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512); + u32 mfi; + u32 mfn; + u32 mfd; + u32 pd; + unsigned long long ll; + long l; + long quot; + + /* Fdppl=2*Fref*(MFI+MFN/(MFD+1))/(PD+1) */ + /* PD=<0,15>, MFD=<1,1023>, MFI=<5,15> MFN=<0,1022> */ + + if (cur_mpctl) { + mfd = ((cur_mpctl >> 16) & 0x3ff) + 1; + pd = ((cur_mpctl >> 26) & 0xf) + 1; + } else { + pd=2; mfd=313; + } + + /* pd=2; mfd=313; mfi=8; mfn=183; */ + /* (MFI+MFN/(MFD)) = Fdppl / (2*Fref) * (PD); */ + + quot = (f_ref + (1 << 9)) >> 10; + l = (freq * pd + quot) / (2 * quot); + mfi = l >> 10; + mfn = ((l & ((1 << 10) - 1)) * mfd + (1 << 9)) >> 10; + + mfd -= 1; + pd -= 1; + + *new_mpctl = ((mfi & 0xf) << 10) | (mfn & 0x3ff) | ((mfd & 0x3ff) << 16) + | ((pd & 0xf) << 26); + + ll = 2 * (unsigned long long)f_ref * ( (mfi<<16) + (mfn<<16) / (mfd+1) ); + quot = (pd+1) * (1<<16); + ll += quot / 2; + do_div(ll, quot); + freq = ll; + + pr_debug(KERN_DEBUG "imx: new PLL parameters pd=%d mfd=%d mfi=%d mfn=%d, freq=%ld\n", + pd, mfd, mfi, mfn, freq); + + return freq; +} + + +static int imx_verify_speed(struct cpufreq_policy *policy) +{ + if (policy->cpu != 0) + return -EINVAL; + + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); + + return 0; +} + +static unsigned int imx_get_speed(unsigned int cpu) +{ + unsigned int freq; + unsigned int cr; + unsigned int cscr; + unsigned int bclk_div; + + if (cpu) + return 0; + + cscr = CSCR; + bclk_div = __mfld2val(CSCR_BCLK_DIV, cscr) + 1; + cr = get_cr(); + + if((cr & CR_920T_CLOCK_MODE) == CR_920T_FASTBUS_MODE) { + freq = imx_get_system_clk(); + freq = (freq + bclk_div/2) / bclk_div; + } else { + freq = imx_get_mcu_clk(); + if (cscr & CSCR_MPU_PRESC) + freq /= 2; + } + + freq = (freq + 500) / 1000; + + return freq; +} + +static int imx_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct cpufreq_freqs freqs; + u32 mpctl0 = 0; + u32 cscr; + unsigned long flags; + long freq; + long sysclk; + unsigned int bclk_div = 1; + + freq = target_freq * 1000; + + pr_debug(KERN_DEBUG "imx: requested frequency %ld Hz, mpctl0 at boot 0x%08x\n", + freq, mpctl0_at_boot); + + sysclk = imx_get_system_clk(); + + if (freq > sysclk + 1000000) { + freq = imx_compute_mpctl(&mpctl0, mpctl0_at_boot, freq, relation); + if (freq < 0) { + printk(KERN_WARNING "imx: target frequency %ld Hz cannot be set\n", freq); + return -EINVAL; + } + } else { + if(freq + 1000 < sysclk) { + if (relation == CPUFREQ_RELATION_L) + bclk_div = (sysclk - 1000) / freq; + else + bclk_div = (sysclk + freq + 1000) / freq; + + if(bclk_div > 16) + bclk_div = 16; + } + freq = (sysclk + bclk_div / 2) / bclk_div; + } + + freqs.old = imx_get_speed(0); + freqs.new = (freq + 500) / 1000; + freqs.cpu = 0; + freqs.flags = 0; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + local_irq_save(flags); + + imx_set_fastbus_mode(); + + imx_set_mpctl0(mpctl0); + + cscr = CSCR; + cscr &= ~CSCR_BCLK_DIV; + cscr |= __val2mfld(CSCR_BCLK_DIV, bclk_div - 1); + CSCR = cscr; + + if(mpctl0) { + CSCR |= CSCR_MPLL_RESTART; + + /* Wait until MPLL is stablized */ + while( CSCR & CSCR_MPLL_RESTART ); + + imx_set_async_mode(); + } + + local_irq_restore(flags); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + pr_debug(KERN_INFO "imx: set frequency %ld Hz, running from %s\n", + freq, mpctl0? "MPLL": "SPLL"); + + return 0; +} + +static int __init imx_cpufreq_driver_init(struct cpufreq_policy *policy) +{ + printk(KERN_INFO "i.MX cpu freq change driver v1.0\n"); + + if (policy->cpu != 0) + return -EINVAL; + + policy->cur = policy->min = policy->max = imx_get_speed(0); + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->cpuinfo.min_freq = 8000; + policy->cpuinfo.max_freq = 200000; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + return 0; +} + +static struct cpufreq_driver imx_driver = { + .flags = CPUFREQ_STICKY, + .verify = imx_verify_speed, + .target = imx_set_target, + .get = imx_get_speed, + .init = imx_cpufreq_driver_init, + .name = "imx", +}; + +static int __init imx_cpufreq_init(void) +{ + + mpctl0_at_boot = 0; + + if((CSCR & CSCR_MPEN) && + ((get_cr() & CR_920T_CLOCK_MODE) != CR_920T_FASTBUS_MODE)) + mpctl0_at_boot = MPCTL0; + + return cpufreq_register_driver(&imx_driver); +} + +arch_initcall(imx_cpufreq_init); + diff --git a/include/asm-arm/arch-imx/imx-regs.h b/include/asm-arm/arch-imx/imx-regs.h index a6912b3d8671..e56a4e247d62 100644 --- a/include/asm-arm/arch-imx/imx-regs.h +++ b/include/asm-arm/arch-imx/imx-regs.h @@ -41,7 +41,13 @@ /* PLL registers */ #define CSCR __REG(IMX_PLL_BASE) /* Clock Source Control Register */ -#define CSCR_SYSTEM_SEL (1<<16) +#define CSCR_SPLL_RESTART (1<<22) +#define CSCR_MPLL_RESTART (1<<21) +#define CSCR_SYSTEM_SEL (1<<16) +#define CSCR_BCLK_DIV (0xf<<10) +#define CSCR_MPU_PRESC (1<<15) +#define CSCR_SPEN (1<<1) +#define CSCR_MPEN (1<<0) #define MPCTL0 __REG(IMX_PLL_BASE + 0x4) /* MCU PLL Control Register 0 */ #define MPCTL1 __REG(IMX_PLL_BASE + 0x8) /* MCU PLL and System Clock Register 1 */ @@ -49,8 +55,6 @@ #define SPCTL1 __REG(IMX_PLL_BASE + 0x10) /* System PLL Control Register 1 */ #define PCDR __REG(IMX_PLL_BASE + 0x20) /* Peripheral Clock Divider Register */ -#define CSCR_MPLL_RESTART (1<<21) - /* * GPIO Module and I/O Multiplexer * x = 0..3 for reg_A, reg_B, reg_C, reg_D -- cgit v1.2.3-59-g8ed1b