From e4707dd3e9d0cb57597b6568a5e51fea5d6fca41 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 12 Mar 2009 20:11:43 +0100 Subject: [ARM] 5422/1: ARM: MMU: add a Non-cacheable Normal executable memory type This patch adds a Non-cacheable Normal ARM executable memory type, MT_MEMORY_NONCACHED. On OMAP3, this is used for rapid dynamic voltage/frequency scaling in the VDD2 voltage domain. OMAP3's SDRAM controller (SDRC) is in the VDD2 voltage domain, and its clock frequency must change along with voltage. The SDRC clock change code cannot run from SDRAM itself, since SDRAM accesses are paused during the clock change. So the current implementation of the DVFS code executes from OMAP on-chip SRAM, aka "OCM RAM." If the OCM RAM pages are marked as Cacheable, the ARM cache controller will attempt to flush dirty cache lines to the SDRC, so it can fill those lines with OCM RAM instruction code. The problem is that the SDRC is paused during DVFS, and so any SDRAM access causes the ARM MPU subsystem to hang. TI's original solution to this problem was to mark the OCM RAM sections as Strongly Ordered memory, thus preventing caching. This is overkill: since the memory is marked as non-bufferable, OCM RAM writes become needlessly slow. The idea of "Strongly Ordered SRAM" is also conceptually disturbing. Previous LAKML list discussion is here: http://www.spinics.net/lists/arm-kernel/msg54312.html This memory type MT_MEMORY_NONCACHED is used for OCM RAM by a future patch. Cc: Richard Woodruff Signed-off-by: Paul Walmsley Signed-off-by: Russell King --- arch/arm/mm/mmu.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'arch/arm/mm') diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 9b36c5cb5e9f..aa424e1da8a1 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -243,6 +243,10 @@ static struct mem_type mem_types[] = { .prot_sect = PMD_TYPE_SECT, .domain = DOMAIN_KERNEL, }, + [MT_MEMORY_NONCACHED] = { + .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, + .domain = DOMAIN_KERNEL, + }, }; const struct mem_type *get_mem_type(unsigned int type) @@ -406,9 +410,28 @@ static void __init build_mem_type_table(void) kern_pgprot |= L_PTE_SHARED; vecs_pgprot |= L_PTE_SHARED; mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; + mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S; #endif } + /* + * Non-cacheable Normal - intended for memory areas that must + * not cause dirty cache line writebacks when used + */ + if (cpu_arch >= CPU_ARCH_ARMv6) { + if (cpu_arch >= CPU_ARCH_ARMv7 && (cr & CR_TRE)) { + /* Non-cacheable Normal is XCB = 001 */ + mem_types[MT_MEMORY_NONCACHED].prot_sect |= + PMD_SECT_BUFFERED; + } else { + /* For both ARMv6 and non-TEX-remapping ARMv7 */ + mem_types[MT_MEMORY_NONCACHED].prot_sect |= + PMD_SECT_TEX(1); + } + } else { + mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_BUFFERABLE; + } + for (i = 0; i < 16; i++) { unsigned long v = pgprot_val(protection_map[i]); protection_map[i] = __pgprot(v | user_pgprot); -- cgit v1.2.3-55-g7522 From cb88214d726b337d49c1f65cbc5e5ac85837b11b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sun, 8 Feb 2009 02:00:50 +0100 Subject: [ARM] MX31/MX35: Add l2x0 cache support Signed-off-by: Sascha Hauer --- arch/arm/mach-mx3/mm.c | 27 ++++++++++++++++++++++++++- arch/arm/mm/Kconfig | 3 ++- 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'arch/arm/mm') diff --git a/arch/arm/mach-mx3/mm.c b/arch/arm/mach-mx3/mm.c index 0589b5cd33c7..44fcb6679f9a 100644 --- a/arch/arm/mach-mx3/mm.c +++ b/arch/arm/mach-mx3/mm.c @@ -22,10 +22,14 @@ #include #include -#include +#include + #include #include +#include + #include +#include /*! * @file mm.c @@ -62,3 +66,24 @@ void __init mxc_map_io(void) { iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc)); } + +#ifdef CONFIG_CACHE_L2X0 +static int mxc_init_l2x0(void) +{ + void __iomem *l2x0_base; + + l2x0_base = ioremap(L2CC_BASE_ADDR, 4096); + if (IS_ERR(l2x0_base)) { + printk(KERN_ERR "remapping L2 cache area failed with %ld\n", + PTR_ERR(l2x0_base)); + return 0; + } + + l2x0_init(l2x0_base, 0x00030024, 0x00000000); + + return 0; +} + +arch_initcall(mxc_init_l2x0); +#endif + diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index d490f3773c01..0d8581f11211 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -704,7 +704,8 @@ config CACHE_FEROCEON_L2_WRITETHROUGH config CACHE_L2X0 bool "Enable the L2x0 outer cache controller" - depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || REALVIEW_EB_A9MP + depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \ + REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31 default y select OUTER_CACHE help -- cgit v1.2.3-55-g7522 From 5f0fbf9ecaf354fa4bbf266fffdea2ea3d14a0ed Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 16 Sep 2008 13:05:53 -0400 Subject: [ARM] fixmap support This is the minimum fixmap interface expected to be implemented by architectures supporting highmem. We have a second level page table already allocated and covering 0xfff00000-0xffffffff because the exception vector page is located at 0xffff0000, and various cache tricks already use some entries above 0xffff0000. Therefore the PTEs covering 0xfff00000-0xfffeffff are free to be used. However the XScale cache flushing code already uses virtual addresses between 0xfffe0000 and 0xfffeffff. So this reserves the 0xfff00000-0xfffdffff range for fixmap stuff. The Documentation/arm/memory.txt information is updated accordingly, including the information about the actual top of DMA memory mapping region which didn't match the code. Signed-off-by: Nicolas Pitre --- Documentation/arm/memory.txt | 9 ++++++++- arch/arm/include/asm/fixmap.h | 41 +++++++++++++++++++++++++++++++++++++++++ arch/arm/mm/mm.h | 3 +-- 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 arch/arm/include/asm/fixmap.h (limited to 'arch/arm/mm') diff --git a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt index dc6045577a8b..43cb1004d35f 100644 --- a/Documentation/arm/memory.txt +++ b/Documentation/arm/memory.txt @@ -29,7 +29,14 @@ ffff0000 ffff0fff CPU vector page. CPU supports vector relocation (control register V bit.) -ffc00000 fffeffff DMA memory mapping region. Memory returned +fffe0000 fffeffff XScale cache flush area. This is used + in proc-xscale.S to flush the whole data + cache. Free for other usage on non-XScale. + +fff00000 fffdffff Fixmap mapping region. Addresses provided + by fix_to_virt() will be located here. + +ffc00000 ffefffff DMA memory mapping region. Memory returned by the dma_alloc_xxx functions will be dynamically mapped here. diff --git a/arch/arm/include/asm/fixmap.h b/arch/arm/include/asm/fixmap.h new file mode 100644 index 000000000000..bbae919bceb4 --- /dev/null +++ b/arch/arm/include/asm/fixmap.h @@ -0,0 +1,41 @@ +#ifndef _ASM_FIXMAP_H +#define _ASM_FIXMAP_H + +/* + * Nothing too fancy for now. + * + * On ARM we already have well known fixed virtual addresses imposed by + * the architecture such as the vector page which is located at 0xffff0000, + * therefore a second level page table is already allocated covering + * 0xfff00000 upwards. + * + * The cache flushing code in proc-xscale.S uses the virtual area between + * 0xfffe0000 and 0xfffeffff. + */ + +#define FIXADDR_START 0xfff00000UL +#define FIXADDR_TOP 0xfffe0000UL +#define FIXADDR_SIZE (FIXADDR_TOP - FIXADDR_START) + +#define FIX_KMAP_BEGIN 0 +#define FIX_KMAP_END (FIXADDR_SIZE >> PAGE_SHIFT) + +#define __fix_to_virt(x) (FIXADDR_START + ((x) << PAGE_SHIFT)) +#define __virt_to_fix(x) (((x) - FIXADDR_START) >> PAGE_SHIFT) + +extern void __this_fixmap_does_not_exist(void); + +static inline unsigned long fix_to_virt(const unsigned int idx) +{ + if (idx >= FIX_KMAP_END) + __this_fixmap_does_not_exist(); + return __fix_to_virt(idx); +} + +static inline unsigned int virt_to_fix(const unsigned long vaddr) +{ + BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START); + return __virt_to_fix(vaddr); +} + +#endif diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index 95bbe112965e..c4f6f05198e0 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h @@ -1,7 +1,6 @@ -/* the upper-most page table pointer */ - #ifdef CONFIG_MMU +/* the upper-most page table pointer */ extern pmd_t *top_pmd; #define TOP_PTE(x) pte_offset_kernel(top_pmd, x) -- cgit v1.2.3-55-g7522 From d73cd42893f4cdc06e6829fea2347bb92cb789d1 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 15 Sep 2008 16:44:55 -0400 Subject: [ARM] kmap support The kmap virtual area borrows a 2MB range at the top of the 16MB area below PAGE_OFFSET currently reserved for kernel modules and/or the XIP kernel. This 2MB corresponds to the range covered by 2 consecutive second-level page tables, or a single pmd entry as seen by the Linux page table abstraction. Because XIP kernels are unlikely to be seen on systems needing highmem support, there shouldn't be any shortage of VM space for modules (14 MB for modules is still way more than twice the typical usage). Because the virtual mapping of highmem pages can go away at any moment after kunmap() is called on them, we need to bypass the delayed cache flushing provided by flush_dcache_page() in that case. The atomic kmap versions are based on fixmaps, and __cpuc_flush_dcache_page() is used directly in that case. Signed-off-by: Nicolas Pitre --- arch/arm/include/asm/highmem.h | 28 ++++++++++ arch/arm/include/asm/memory.h | 13 +++-- arch/arm/mm/Makefile | 1 + arch/arm/mm/flush.c | 2 +- arch/arm/mm/highmem.c | 116 +++++++++++++++++++++++++++++++++++++++++ arch/arm/mm/mmu.c | 13 +++++ 6 files changed, 169 insertions(+), 4 deletions(-) create mode 100644 arch/arm/include/asm/highmem.h create mode 100644 arch/arm/mm/highmem.c (limited to 'arch/arm/mm') diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h new file mode 100644 index 000000000000..023d5b374544 --- /dev/null +++ b/arch/arm/include/asm/highmem.h @@ -0,0 +1,28 @@ +#ifndef _ASM_HIGHMEM_H +#define _ASM_HIGHMEM_H + +#include + +#define PKMAP_BASE (PAGE_OFFSET - PMD_SIZE) +#define LAST_PKMAP PTRS_PER_PTE +#define LAST_PKMAP_MASK (LAST_PKMAP - 1) +#define PKMAP_NR(virt) (((virt) - PKMAP_BASE) >> PAGE_SHIFT) +#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) + +#define kmap_prot PAGE_KERNEL + +#define flush_cache_kmaps() flush_cache_all() + +extern pte_t *pkmap_page_table; + +extern void *kmap_high(struct page *page); +extern void kunmap_high(struct page *page); + +extern void *kmap(struct page *page); +extern void kunmap(struct page *page); +extern void *kmap_atomic(struct page *page, enum km_type type); +extern void kunmap_atomic(void *kvaddr, enum km_type type); +extern void *kmap_atomic_pfn(unsigned long pfn, enum km_type type); +extern struct page *kmap_atomic_to_page(const void *ptr); + +#endif diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 0202a7c20e62..ae472bc376d3 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -44,13 +44,20 @@ * The module space lives between the addresses given by TASK_SIZE * and PAGE_OFFSET - it must be within 32MB of the kernel text. */ -#define MODULES_END (PAGE_OFFSET) -#define MODULES_VADDR (MODULES_END - 16*1048576) - +#define MODULES_VADDR (PAGE_OFFSET - 16*1024*1024) #if TASK_SIZE > MODULES_VADDR #error Top of user space clashes with start of module space #endif +/* + * The highmem pkmap virtual space shares the end of the module area. + */ +#ifdef CONFIG_HIGHMEM +#define MODULES_END (PAGE_OFFSET - PMD_SIZE) +#else +#define MODULES_END (PAGE_OFFSET) +#endif + /* * The XIP kernel gets mapped at the bottom of the module vm area. * Since we use sections to map it, this macro replaces the physical address diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index 480f78a3611a..185e7dc7dcf2 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_MODULES) += proc-syms.o obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o obj-$(CONFIG_DISCONTIGMEM) += discontig.o +obj-$(CONFIG_HIGHMEM) += highmem.o obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 0fa9bf388f0b..4e283481cee1 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -192,7 +192,7 @@ void flush_dcache_page(struct page *page) struct address_space *mapping = page_mapping(page); #ifndef CONFIG_SMP - if (mapping && !mapping_mapped(mapping)) + if (!PageHighMem(page) && mapping && !mapping_mapped(mapping)) set_bit(PG_dcache_dirty, &page->flags); else #endif diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c new file mode 100644 index 000000000000..a34954d9df7d --- /dev/null +++ b/arch/arm/mm/highmem.c @@ -0,0 +1,116 @@ +/* + * arch/arm/mm/highmem.c -- ARM highmem support + * + * Author: Nicolas Pitre + * Created: september 8, 2008 + * Copyright: Marvell Semiconductors Inc. + * + * 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 +#include +#include +#include +#include +#include +#include "mm.h" + +void *kmap(struct page *page) +{ + might_sleep(); + if (!PageHighMem(page)) + return page_address(page); + return kmap_high(page); +} +EXPORT_SYMBOL(kmap); + +void kunmap(struct page *page) +{ + BUG_ON(in_interrupt()); + if (!PageHighMem(page)) + return; + kunmap_high(page); +} +EXPORT_SYMBOL(kunmap); + +void *kmap_atomic(struct page *page, enum km_type type) +{ + unsigned int idx; + unsigned long vaddr; + + pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); + + idx = type + KM_TYPE_NR * smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); +#ifdef CONFIG_DEBUG_HIGHMEM + /* + * With debugging enabled, kunmap_atomic forces that entry to 0. + * Make sure it was indeed properly unmapped. + */ + BUG_ON(!pte_none(*(TOP_PTE(vaddr)))); +#endif + set_pte_ext(TOP_PTE(vaddr), mk_pte(page, kmap_prot), 0); + /* + * When debugging is off, kunmap_atomic leaves the previous mapping + * in place, so this TLB flush ensures the TLB is updated with the + * new mapping. + */ + local_flush_tlb_kernel_page(vaddr); + + return (void *)vaddr; +} +EXPORT_SYMBOL(kmap_atomic); + +void kunmap_atomic(void *kvaddr, enum km_type type) +{ + unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; + unsigned int idx = type + KM_TYPE_NR * smp_processor_id(); + + if (kvaddr >= (void *)FIXADDR_START) { + __cpuc_flush_dcache_page((void *)vaddr); +#ifdef CONFIG_DEBUG_HIGHMEM + BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx)); + set_pte_ext(TOP_PTE(vaddr), __pte(0), 0); + local_flush_tlb_kernel_page(vaddr); +#else + (void) idx; /* to kill a warning */ +#endif + } + pagefault_enable(); +} +EXPORT_SYMBOL(kunmap_atomic); + +void *kmap_atomic_pfn(unsigned long pfn, enum km_type type) +{ + unsigned int idx; + unsigned long vaddr; + + pagefault_disable(); + + idx = type + KM_TYPE_NR * smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); +#ifdef CONFIG_DEBUG_HIGHMEM + BUG_ON(!pte_none(*(TOP_PTE(vaddr)))); +#endif + set_pte_ext(TOP_PTE(vaddr), pfn_pte(pfn, kmap_prot), 0); + local_flush_tlb_kernel_page(vaddr); + + return (void *)vaddr; +} + +struct page *kmap_atomic_to_page(const void *ptr) +{ + unsigned long vaddr = (unsigned long)ptr; + pte_t *pte; + + if (vaddr < FIXADDR_START) + return virt_to_page(ptr); + + pte = TOP_PTE(vaddr); + return pte_page(*pte); +} diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index d4d082c5c2d4..4810a4c9ffce 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -895,6 +896,17 @@ static void __init devicemaps_init(struct machine_desc *mdesc) flush_cache_all(); } +static void __init kmap_init(void) +{ +#ifdef CONFIG_HIGHMEM + pmd_t *pmd = pmd_off_k(PKMAP_BASE); + pte_t *pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t)); + BUG_ON(!pmd_none(*pmd) || !pte); + __pmd_populate(pmd, __pa(pte) | _PAGE_KERNEL_TABLE); + pkmap_page_table = pte + PTRS_PER_PTE; +#endif +} + /* * paging_init() sets up the page tables, initialises the zone memory * maps, and sets up the zero page, bad page and bad page tables. @@ -908,6 +920,7 @@ void __init paging_init(struct machine_desc *mdesc) prepare_page_table(); bootmem_init(); devicemaps_init(mdesc); + kmap_init(); top_pmd = pmd_off_k(0xffff0000); -- cgit v1.2.3-55-g7522 From 3835f6cb645bdb9a58aa6e062fe1d5777f1a9748 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 17 Sep 2008 15:21:55 -0400 Subject: [ARM] mem_init(): make highmem pages available for use Signed-off-by: Nicolas Pitre --- arch/arm/mm/init.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'arch/arm/mm') diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 80fd3b69ae1f..8277802ec859 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -485,7 +486,7 @@ void __init mem_init(void) int i, node; #ifndef CONFIG_DISCONTIGMEM - max_mapnr = virt_to_page(high_memory) - mem_map; + max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map; #endif /* this will put all unused low memory onto the freelists */ @@ -504,6 +505,19 @@ void __init mem_init(void) __phys_to_pfn(__pa(swapper_pg_dir)), NULL); #endif +#ifdef CONFIG_HIGHMEM + /* set highmem page free */ + for_each_online_node(node) { + for_each_nodebank (i, &meminfo, node) { + unsigned long start = bank_pfn_start(&meminfo.bank[i]); + unsigned long end = bank_pfn_end(&meminfo.bank[i]); + if (start >= max_low_pfn + PHYS_PFN_OFFSET) + totalhigh_pages += free_area(start, end, NULL); + } + } + totalram_pages += totalhigh_pages; +#endif + /* * Since our memory may not be contiguous, calculate the * real number of pages we have in this system @@ -521,9 +535,10 @@ void __init mem_init(void) initsize = __init_end - __init_begin; printk(KERN_NOTICE "Memory: %luKB available (%dK code, " - "%dK data, %dK init)\n", + "%dK data, %dK init, %luK highmem)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), - codesize >> 10, datasize >> 10, initsize >> 10); + codesize >> 10, datasize >> 10, initsize >> 10, + (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); if (PAGE_SIZE >= 16384 && num_physpages <= 128) { extern int sysctl_overcommit_memory; -- cgit v1.2.3-55-g7522 From 43377453af83b8ff8c1c731da1508bd6b84ebfea Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 12 Mar 2009 22:52:09 -0400 Subject: [ARM] introduce dma_cache_maint_page() This is a helper to be used by the DMA mapping API to handle cache maintenance for memory identified by a page structure instead of a virtual address. Those pages may or may not be highmem pages, and when they're highmem pages, they may or may not be virtually mapped. When they're not mapped then there is no L1 cache to worry about. But even in that case the L2 cache must be processed since unmapped highmem pages can still be L2 cached. Signed-off-by: Nicolas Pitre --- arch/arm/include/asm/dma-mapping.h | 4 ++- arch/arm/include/asm/highmem.h | 3 ++ arch/arm/mm/dma-mapping.c | 72 +++++++++++++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 2 deletions(-) (limited to 'arch/arm/mm') diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 22cb14ec3438..59fa762e9c66 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -57,6 +57,8 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr) * Use the driver DMA support - see dma-mapping.h (dma_sync_*) */ extern void dma_cache_maint(const void *kaddr, size_t size, int rw); +extern void dma_cache_maint_page(struct page *page, unsigned long offset, + size_t size, int rw); /* * Return whether the given device DMA address mask can be supported @@ -316,7 +318,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, BUG_ON(!valid_dma_direction(dir)); if (!arch_is_coherent()) - dma_cache_maint(page_address(page) + offset, size, dir); + dma_cache_maint_page(page, offset, size, dir); return page_to_dma(dev, page) + offset; } diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h index 023d5b374544..7f36d00600b4 100644 --- a/arch/arm/include/asm/highmem.h +++ b/arch/arm/include/asm/highmem.h @@ -15,7 +15,10 @@ extern pte_t *pkmap_page_table; +#define ARCH_NEEDS_KMAP_HIGH_GET + extern void *kmap_high(struct page *page); +extern void *kmap_high_get(struct page *page); extern void kunmap_high(struct page *page); extern void *kmap(struct page *page); diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index f1ef5613ccd4..510c179b0ac8 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -517,6 +518,74 @@ void dma_cache_maint(const void *start, size_t size, int direction) } EXPORT_SYMBOL(dma_cache_maint); +static void dma_cache_maint_contiguous(struct page *page, unsigned long offset, + size_t size, int direction) +{ + void *vaddr; + unsigned long paddr; + void (*inner_op)(const void *, const void *); + void (*outer_op)(unsigned long, unsigned long); + + switch (direction) { + case DMA_FROM_DEVICE: /* invalidate only */ + inner_op = dmac_inv_range; + outer_op = outer_inv_range; + break; + case DMA_TO_DEVICE: /* writeback only */ + inner_op = dmac_clean_range; + outer_op = outer_clean_range; + break; + case DMA_BIDIRECTIONAL: /* writeback and invalidate */ + inner_op = dmac_flush_range; + outer_op = outer_flush_range; + break; + default: + BUG(); + } + + if (!PageHighMem(page)) { + vaddr = page_address(page) + offset; + inner_op(vaddr, vaddr + size); + } else { + vaddr = kmap_high_get(page); + if (vaddr) { + vaddr += offset; + inner_op(vaddr, vaddr + size); + kunmap_high(page); + } + } + + paddr = page_to_phys(page) + offset; + outer_op(paddr, paddr + size); +} + +void dma_cache_maint_page(struct page *page, unsigned long offset, + size_t size, int dir) +{ + /* + * A single sg entry may refer to multiple physically contiguous + * pages. But we still need to process highmem pages individually. + * If highmem is not configured then the bulk of this loop gets + * optimized out. + */ + size_t left = size; + do { + size_t len = left; + if (PageHighMem(page) && len + offset > PAGE_SIZE) { + if (offset >= PAGE_SIZE) { + page += offset / PAGE_SIZE; + offset %= PAGE_SIZE; + } + len = PAGE_SIZE - offset; + } + dma_cache_maint_contiguous(page, offset, len, dir); + offset = 0; + page++; + left -= len; + } while (left); +} +EXPORT_SYMBOL(dma_cache_maint_page); + /** * dma_map_sg - map a set of SG buffers for streaming mode DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices @@ -614,7 +683,8 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, continue; if (!arch_is_coherent()) - dma_cache_maint(sg_virt(s), s->length, dir); + dma_cache_maint_page(sg_page(s), s->offset, + s->length, dir); } } EXPORT_SYMBOL(dma_sync_sg_for_device); -- cgit v1.2.3-55-g7522 From 1bb772679ffb0ba1ff1d40d8c6b855ab029f177d Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 12 Sep 2008 16:11:51 -0400 Subject: [ARM] Feroceon: add highmem support to L2 cache handling code The choice is between looping over the physical range and performing single cache line operations, or to map highmem pages somewhere, as cache range ops are possible only on virtual addresses. Because L2 range ops are much faster, we go with the later by factoring the physical-to-virtual address conversion and use a fixmap entry for it in the HIGHMEM case. Possible future optimizations to avoid the pte setup cost: - do the pte setup for highmem pages only - determine a threshold for doing a line-by-line processing on physical addresses when the range is small Signed-off-by: Nicolas Pitre --- arch/arm/include/asm/kmap_types.h | 1 + arch/arm/mm/cache-feroceon-l2.c | 54 +++++++++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 17 deletions(-) (limited to 'arch/arm/mm') diff --git a/arch/arm/include/asm/kmap_types.h b/arch/arm/include/asm/kmap_types.h index 45def13ee17a..d16ec97ec9a9 100644 --- a/arch/arm/include/asm/kmap_types.h +++ b/arch/arm/include/asm/kmap_types.h @@ -18,6 +18,7 @@ enum km_type { KM_IRQ1, KM_SOFTIRQ0, KM_SOFTIRQ1, + KM_L2_CACHE, KM_TYPE_NR }; diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c index 80cd207cbaea..d6dd83826f8a 100644 --- a/arch/arm/mm/cache-feroceon-l2.c +++ b/arch/arm/mm/cache-feroceon-l2.c @@ -14,8 +14,12 @@ #include #include +#include +#include +#include +#include #include - +#include "mm.h" /* * Low-level cache maintenance operations. @@ -34,14 +38,36 @@ * The range operations require two successive cp15 writes, in * between which we don't want to be preempted. */ + +static inline unsigned long l2_start_va(unsigned long paddr) +{ +#ifdef CONFIG_HIGHMEM + /* + * Let's do our own fixmap stuff in a minimal way here. + * Because range ops can't be done on physical addresses, + * we simply install a virtual mapping for it only for the + * TLB lookup to occur, hence no need to flush the untouched + * memory mapping. This is protected with the disabling of + * interrupts by the caller. + */ + unsigned long idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id(); + unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + set_pte_ext(TOP_PTE(vaddr), pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL), 0); + local_flush_tlb_kernel_page(vaddr); + return vaddr + (paddr & ~PAGE_MASK); +#else + return __phys_to_virt(paddr); +#endif +} + static inline void l2_clean_pa(unsigned long addr) { __asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr)); } -static inline void l2_clean_mva_range(unsigned long start, unsigned long end) +static inline void l2_clean_pa_range(unsigned long start, unsigned long end) { - unsigned long flags; + unsigned long va_start, va_end, flags; /* * Make sure 'start' and 'end' reference the same page, as @@ -51,17 +77,14 @@ static inline void l2_clean_mva_range(unsigned long start, unsigned long end) BUG_ON((start ^ end) >> PAGE_SHIFT); raw_local_irq_save(flags); + va_start = l2_start_va(start); + va_end = va_start + (end - start); __asm__("mcr p15, 1, %0, c15, c9, 4\n\t" "mcr p15, 1, %1, c15, c9, 5" - : : "r" (start), "r" (end)); + : : "r" (va_start), "r" (va_end)); raw_local_irq_restore(flags); } -static inline void l2_clean_pa_range(unsigned long start, unsigned long end) -{ - l2_clean_mva_range(__phys_to_virt(start), __phys_to_virt(end)); -} - static inline void l2_clean_inv_pa(unsigned long addr) { __asm__("mcr p15, 1, %0, c15, c10, 3" : : "r" (addr)); @@ -72,9 +95,9 @@ static inline void l2_inv_pa(unsigned long addr) __asm__("mcr p15, 1, %0, c15, c11, 3" : : "r" (addr)); } -static inline void l2_inv_mva_range(unsigned long start, unsigned long end) +static inline void l2_inv_pa_range(unsigned long start, unsigned long end) { - unsigned long flags; + unsigned long va_start, va_end, flags; /* * Make sure 'start' and 'end' reference the same page, as @@ -84,17 +107,14 @@ static inline void l2_inv_mva_range(unsigned long start, unsigned long end) BUG_ON((start ^ end) >> PAGE_SHIFT); raw_local_irq_save(flags); + va_start = l2_start_va(start); + va_end = va_start + (end - start); __asm__("mcr p15, 1, %0, c15, c11, 4\n\t" "mcr p15, 1, %1, c15, c11, 5" - : : "r" (start), "r" (end)); + : : "r" (va_start), "r" (va_end)); raw_local_irq_restore(flags); } -static inline void l2_inv_pa_range(unsigned long start, unsigned long end) -{ - l2_inv_mva_range(__phys_to_virt(start), __phys_to_virt(end)); -} - /* * Linux primitives. -- cgit v1.2.3-55-g7522 From 3902a15e784e9b1efa8e6ad246489c609e0ef880 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 18 Sep 2008 22:55:47 -0400 Subject: [ARM] xsc3: add highmem support to L2 cache handling code On xsc3, L2 cache ops are possible only on virtual addresses. The code is rearranged so to have a linear progression requiring the least amount of pte setups in the highmem case. To protect the virtual mapping so created, interrupts must be disabled currently up to a page worth of address range. The interrupt disabling is done in a way to minimize the overhead within the inner loop. The alternative would consist in separate code for the highmem and non highmem compilation which is less preferable. Signed-off-by: Nicolas Pitre --- arch/arm/mm/cache-xsc3l2.c | 107 +++++++++++++++++++++++++++++++++------------ 1 file changed, 80 insertions(+), 27 deletions(-) (limited to 'arch/arm/mm') diff --git a/arch/arm/mm/cache-xsc3l2.c b/arch/arm/mm/cache-xsc3l2.c index 464de893a988..5d180cb0bd94 100644 --- a/arch/arm/mm/cache-xsc3l2.c +++ b/arch/arm/mm/cache-xsc3l2.c @@ -17,12 +17,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include -#include -#include - #include #include #include +#include +#include +#include +#include +#include "mm.h" #define CR_L2 (1 << 26) @@ -47,21 +49,11 @@ static inline void xsc3_l2_clean_mva(unsigned long addr) __asm__("mcr p15, 1, %0, c7, c11, 1" : : "r" (addr)); } -static inline void xsc3_l2_clean_pa(unsigned long addr) -{ - xsc3_l2_clean_mva(__phys_to_virt(addr)); -} - static inline void xsc3_l2_inv_mva(unsigned long addr) { __asm__("mcr p15, 1, %0, c7, c7, 1" : : "r" (addr)); } -static inline void xsc3_l2_inv_pa(unsigned long addr) -{ - xsc3_l2_inv_mva(__phys_to_virt(addr)); -} - static inline void xsc3_l2_inv_all(void) { unsigned long l2ctype, set_way; @@ -79,50 +71,103 @@ static inline void xsc3_l2_inv_all(void) dsb(); } +#ifdef CONFIG_HIGHMEM +#define l2_map_save_flags(x) raw_local_save_flags(x) +#define l2_map_restore_flags(x) raw_local_irq_restore(x) +#else +#define l2_map_save_flags(x) ((x) = 0) +#define l2_map_restore_flags(x) ((void)(x)) +#endif + +static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va, + unsigned long flags) +{ +#ifdef CONFIG_HIGHMEM + unsigned long va = prev_va & PAGE_MASK; + unsigned long pa_offset = pa << (32 - PAGE_SHIFT); + if (unlikely(pa_offset < (prev_va << (32 - PAGE_SHIFT)))) { + /* + * Switching to a new page. Because cache ops are + * using virtual addresses only, we must put a mapping + * in place for it. We also enable interrupts for a + * short while and disable them again to protect this + * mapping. + */ + unsigned long idx; + raw_local_irq_restore(flags); + idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id(); + va = __fix_to_virt(FIX_KMAP_BEGIN + idx); + raw_local_irq_restore(flags | PSR_I_BIT); + set_pte_ext(TOP_PTE(va), pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL), 0); + local_flush_tlb_kernel_page(va); + } + return va + (pa_offset >> (32 - PAGE_SHIFT)); +#else + return __phys_to_virt(pa); +#endif +} + static void xsc3_l2_inv_range(unsigned long start, unsigned long end) { + unsigned long vaddr, flags; + if (start == 0 && end == -1ul) { xsc3_l2_inv_all(); return; } + vaddr = -1; /* to force the first mapping */ + l2_map_save_flags(flags); + /* * Clean and invalidate partial first cache line. */ if (start & (CACHE_LINE_SIZE - 1)) { - xsc3_l2_clean_pa(start & ~(CACHE_LINE_SIZE - 1)); - xsc3_l2_inv_pa(start & ~(CACHE_LINE_SIZE - 1)); + vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr, flags); + xsc3_l2_clean_mva(vaddr); + xsc3_l2_inv_mva(vaddr); start = (start | (CACHE_LINE_SIZE - 1)) + 1; } /* - * Clean and invalidate partial last cache line. + * Invalidate all full cache lines between 'start' and 'end'. */ - if (start < end && (end & (CACHE_LINE_SIZE - 1))) { - xsc3_l2_clean_pa(end & ~(CACHE_LINE_SIZE - 1)); - xsc3_l2_inv_pa(end & ~(CACHE_LINE_SIZE - 1)); - end &= ~(CACHE_LINE_SIZE - 1); + while (start < (end & ~(CACHE_LINE_SIZE - 1))) { + vaddr = l2_map_va(start, vaddr, flags); + xsc3_l2_inv_mva(vaddr); + start += CACHE_LINE_SIZE; } /* - * Invalidate all full cache lines between 'start' and 'end'. + * Clean and invalidate partial last cache line. */ - while (start < end) { - xsc3_l2_inv_pa(start); - start += CACHE_LINE_SIZE; + if (start < end) { + vaddr = l2_map_va(start, vaddr, flags); + xsc3_l2_clean_mva(vaddr); + xsc3_l2_inv_mva(vaddr); } + l2_map_restore_flags(flags); + dsb(); } static void xsc3_l2_clean_range(unsigned long start, unsigned long end) { + unsigned long vaddr, flags; + + vaddr = -1; /* to force the first mapping */ + l2_map_save_flags(flags); + start &= ~(CACHE_LINE_SIZE - 1); while (start < end) { - xsc3_l2_clean_pa(start); + vaddr = l2_map_va(start, vaddr, flags); + xsc3_l2_clean_mva(vaddr); start += CACHE_LINE_SIZE; } + l2_map_restore_flags(flags); + dsb(); } @@ -148,18 +193,26 @@ static inline void xsc3_l2_flush_all(void) static void xsc3_l2_flush_range(unsigned long start, unsigned long end) { + unsigned long vaddr, flags; + if (start == 0 && end == -1ul) { xsc3_l2_flush_all(); return; } + vaddr = -1; /* to force the first mapping */ + l2_map_save_flags(flags); + start &= ~(CACHE_LINE_SIZE - 1); while (start < end) { - xsc3_l2_clean_pa(start); - xsc3_l2_inv_pa(start); + vaddr = l2_map_va(start, vaddr, flags); + xsc3_l2_clean_mva(vaddr); + xsc3_l2_inv_mva(vaddr); start += CACHE_LINE_SIZE; } + l2_map_restore_flags(flags); + dsb(); } -- cgit v1.2.3-55-g7522 From 3f973e22160257c5bda85815be5b1540d391a671 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 4 Nov 2008 00:48:42 -0500 Subject: [ARM] ignore high memory with VIPT aliasing caches VIPT aliasing caches have issues of their own which are not yet handled. Usage of discard_old_kernel_data() in copypage-v6.c is not highmem ready, kmap/fixmap stuff doesn't take account of cache colouring, etc. If/when those issues are handled then this could be reverted. Signed-off-by: Nicolas Pitre --- arch/arm/mm/mmu.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch/arm/mm') diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 4810a4c9ffce..cf504885a5fb 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -678,6 +679,10 @@ static void __init sanity_check_meminfo(void) if (meminfo.nr_banks >= NR_BANKS) { printk(KERN_CRIT "NR_BANKS too low, " "ignoring high memory\n"); + } else if (cache_is_vipt_aliasing()) { + printk(KERN_CRIT "HIGHMEM is not yet supported " + "with VIPT aliasing cache, " + "ignoring high memory\n"); } else { memmove(bank + 1, bank, (meminfo.nr_banks - i) * sizeof(*bank)); -- cgit v1.2.3-55-g7522 From 49cbe78637eb0503f45fc9b556ec08918a616534 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Tue, 20 Jan 2009 14:15:18 +0800 Subject: [ARM] pxa: add base support for Marvell's PXA168 processor line """The MarvellĀ® PXA168 processor is the first in a family of application processors targeted at mass market opportunities in computing and consumer devices. It balances high computing and multimedia performance with low power consumption to support extended battery life, and includes a wealth of integrated peripherals to reduce overall BOM cost .... """ See http://www.marvell.com/featured/pxa168.jsp for more information. 1. Marvell Mohawk core is a hybrid of xscale3 and its own ARM core, there are many enhancements like instructions for flushing the whole D-cache, and so on 2. Clock reuses Russell's common clkdev, and added the basic support for UART1/2. 3. Devices are a bit different from the 'mach-pxa' way, the platform devices are now dynamically allocated only when necessary (i.e. when pxa_register_device() is called). Description for each device are stored in an array of 'struct pxa_device_desc'. Now that: a. this array of device description is marked with __initdata and can be freed up system is fully up b. which means board code has to add all needed devices early in his initializing function c. platform specific data can now be marked as __initdata since they are allocated and copied by platform_device_add_data() 4. only the basic UART1/2/3 are added, more devices will come later. Signed-off-by: Jason Chagas Signed-off-by: Eric Miao --- arch/arm/Kconfig | 16 ++ arch/arm/Makefile | 1 + arch/arm/boot/compressed/head.S | 12 + arch/arm/include/asm/cacheflush.h | 8 + arch/arm/include/asm/proc-fns.h | 8 + arch/arm/mach-mmp/Kconfig | 27 ++ arch/arm/mach-mmp/Makefile | 12 + arch/arm/mach-mmp/Makefile.boot | 1 + arch/arm/mach-mmp/aspenite.c | 42 +++ arch/arm/mach-mmp/clock.c | 83 ++++++ arch/arm/mach-mmp/clock.h | 71 +++++ arch/arm/mach-mmp/common.c | 37 +++ arch/arm/mach-mmp/common.h | 11 + arch/arm/mach-mmp/devices.c | 69 +++++ arch/arm/mach-mmp/include/mach/addr-map.h | 34 +++ arch/arm/mach-mmp/include/mach/clkdev.h | 7 + arch/arm/mach-mmp/include/mach/cputype.h | 21 ++ arch/arm/mach-mmp/include/mach/debug-macro.S | 23 ++ arch/arm/mach-mmp/include/mach/devices.h | 27 ++ arch/arm/mach-mmp/include/mach/dma.h | 13 + arch/arm/mach-mmp/include/mach/entry-macro.S | 25 ++ arch/arm/mach-mmp/include/mach/hardware.h | 4 + arch/arm/mach-mmp/include/mach/io.h | 21 ++ arch/arm/mach-mmp/include/mach/irqs.h | 58 ++++ arch/arm/mach-mmp/include/mach/memory.h | 14 + arch/arm/mach-mmp/include/mach/pxa168.h | 23 ++ arch/arm/mach-mmp/include/mach/regs-apbc.h | 53 ++++ arch/arm/mach-mmp/include/mach/regs-apmu.h | 36 +++ arch/arm/mach-mmp/include/mach/regs-icu.h | 31 ++ arch/arm/mach-mmp/include/mach/regs-timers.h | 44 +++ arch/arm/mach-mmp/include/mach/system.h | 21 ++ arch/arm/mach-mmp/include/mach/timex.h | 9 + arch/arm/mach-mmp/include/mach/uncompress.h | 41 +++ arch/arm/mach-mmp/include/mach/vmalloc.h | 5 + arch/arm/mach-mmp/irq.c | 55 ++++ arch/arm/mach-mmp/pxa168.c | 77 +++++ arch/arm/mach-mmp/time.c | 199 +++++++++++++ arch/arm/mm/Kconfig | 15 +- arch/arm/mm/Makefile | 1 + arch/arm/mm/proc-mohawk.S | 416 +++++++++++++++++++++++++++ 40 files changed, 1669 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-mmp/Kconfig create mode 100644 arch/arm/mach-mmp/Makefile create mode 100644 arch/arm/mach-mmp/Makefile.boot create mode 100644 arch/arm/mach-mmp/aspenite.c create mode 100644 arch/arm/mach-mmp/clock.c create mode 100644 arch/arm/mach-mmp/clock.h create mode 100644 arch/arm/mach-mmp/common.c create mode 100644 arch/arm/mach-mmp/common.h create mode 100644 arch/arm/mach-mmp/devices.c create mode 100644 arch/arm/mach-mmp/include/mach/addr-map.h create mode 100644 arch/arm/mach-mmp/include/mach/clkdev.h create mode 100644 arch/arm/mach-mmp/include/mach/cputype.h create mode 100644 arch/arm/mach-mmp/include/mach/debug-macro.S create mode 100644 arch/arm/mach-mmp/include/mach/devices.h create mode 100644 arch/arm/mach-mmp/include/mach/dma.h create mode 100644 arch/arm/mach-mmp/include/mach/entry-macro.S create mode 100644 arch/arm/mach-mmp/include/mach/hardware.h create mode 100644 arch/arm/mach-mmp/include/mach/io.h create mode 100644 arch/arm/mach-mmp/include/mach/irqs.h create mode 100644 arch/arm/mach-mmp/include/mach/memory.h create mode 100644 arch/arm/mach-mmp/include/mach/pxa168.h create mode 100644 arch/arm/mach-mmp/include/mach/regs-apbc.h create mode 100644 arch/arm/mach-mmp/include/mach/regs-apmu.h create mode 100644 arch/arm/mach-mmp/include/mach/regs-icu.h create mode 100644 arch/arm/mach-mmp/include/mach/regs-timers.h create mode 100644 arch/arm/mach-mmp/include/mach/system.h create mode 100644 arch/arm/mach-mmp/include/mach/timex.h create mode 100644 arch/arm/mach-mmp/include/mach/uncompress.h create mode 100644 arch/arm/mach-mmp/include/mach/vmalloc.h create mode 100644 arch/arm/mach-mmp/irq.c create mode 100644 arch/arm/mach-mmp/pxa168.c create mode 100644 arch/arm/mach-mmp/time.c create mode 100644 arch/arm/mm/proc-mohawk.S (limited to 'arch/arm/mm') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 5ba00358e805..fdcd2d54e939 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -478,6 +478,8 @@ config ARCH_PXA select HAVE_CLK select COMMON_CLKDEV select ARCH_REQUIRE_GPIOLIB + select HAVE_CLK + select COMMON_CLKDEV select GENERIC_TIME select GENERIC_CLOCKEVENTS select TICK_ONESHOT @@ -485,6 +487,18 @@ config ARCH_PXA help Support for Intel/Marvell's PXA2xx/PXA3xx processor line. +config ARCH_MMP + bool "Marvell PXA168" + depends on MMU + select HAVE_CLK + select COMMON_CLKDEV + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select TICK_ONESHOT + select PLAT_PXA + help + Support for Marvell's PXA168 processor line. + config ARCH_RPC bool "RiscPC" select ARCH_ACORN @@ -621,6 +635,8 @@ source "arch/arm/mach-mv78xx0/Kconfig" source "arch/arm/mach-pxa/Kconfig" source "arch/arm/plat-pxa/Kconfig" +source "arch/arm/mach-mmp/Kconfig" + source "arch/arm/mach-sa1100/Kconfig" source "arch/arm/plat-omap/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 897f2830bc4d..95186ef17e17 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -109,6 +109,7 @@ ifeq ($(CONFIG_ARCH_SA1100),y) textofs-$(CONFIG_SA1111) := 0x00208000 endif machine-$(CONFIG_ARCH_PXA) := pxa + machine-$(CONFIG_ARCH_MMP) := mmp plat-$(CONFIG_PLAT_PXA) := pxa machine-$(CONFIG_ARCH_L7200) := l7200 machine-$(CONFIG_ARCH_INTEGRATOR) := integrator diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index d1b678dc120b..d14b827adcd6 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -636,6 +636,18 @@ proc_types: b __armv4_mmu_cache_off b __armv4_mmu_cache_flush + .word 0x56158000 @ PXA168 + .word 0xfffff000 + b __armv4_mmu_cache_on + b __armv4_mmu_cache_off + b __armv5tej_mmu_cache_flush + + .word 0x56056930 + .word 0xff0ffff0 @ PXA935 + b __armv4_mmu_cache_on + b __armv4_mmu_cache_off + b __armv4_mmu_cache_flush + .word 0x56050000 @ Feroceon .word 0xff0f0000 b __armv4_mmu_cache_on diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 6cbd8fdc9f1f..bfb0cb9aaa97 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -94,6 +94,14 @@ # endif #endif +#if defined(CONFIG_CPU_MOHAWK) +# ifdef _CACHE +# define MULTI_CACHE 1 +# else +# define _CACHE mohawk +# endif +#endif + #if defined(CONFIG_CPU_FEROCEON) # define MULTI_CACHE 1 #endif diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h index db80203b68e0..c6250311550b 100644 --- a/arch/arm/include/asm/proc-fns.h +++ b/arch/arm/include/asm/proc-fns.h @@ -185,6 +185,14 @@ # define CPU_NAME cpu_xsc3 # endif # endif +# ifdef CONFIG_CPU_MOHAWK +# ifdef CPU_NAME +# undef MULTI_CPU +# define MULTI_CPU +# else +# define CPU_NAME cpu_mohawk +# endif +# endif # ifdef CONFIG_CPU_FEROCEON # ifdef CPU_NAME # undef MULTI_CPU diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig new file mode 100644 index 000000000000..b52326763556 --- /dev/null +++ b/arch/arm/mach-mmp/Kconfig @@ -0,0 +1,27 @@ +if ARCH_MMP + +menu "Marvell PXA168 Implmentations" + +config MACH_ASPENITE + bool "Marvell's PXA168 Aspenite Development Board" + select CPU_PXA168 + help + Say 'Y' here if you want to support the Marvell PXA168-based + Aspenite Development Board. + +config MACH_ZYLONITE2 + bool "Marvell's PXA168 Zylonite2 Development Board" + select CPU_PXA168 + help + Say 'Y' here if you want to support the Marvell PXA168-based + Zylonite2 Development Board. + +endmenu + +config CPU_PXA168 + bool + select CPU_MOHAWK + help + Select code specific to PXA168 + +endif diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile new file mode 100644 index 000000000000..0ac7644ec99d --- /dev/null +++ b/arch/arm/mach-mmp/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for Marvell's PXA168 processors line +# + +obj-y += common.o clock.o devices.o irq.o time.o + +# SoC support +obj-$(CONFIG_CPU_PXA168) += pxa168.o + +# board support +obj-$(CONFIG_MACH_ASPENITE) += aspenite.o +obj-$(CONFIG_MACH_ZYLONITE2) += aspenite.o diff --git a/arch/arm/mach-mmp/Makefile.boot b/arch/arm/mach-mmp/Makefile.boot new file mode 100644 index 000000000000..574a4aa8321a --- /dev/null +++ b/arch/arm/mach-mmp/Makefile.boot @@ -0,0 +1 @@ + zreladdr-y := 0x00008000 diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c new file mode 100644 index 000000000000..e8caf58e004c --- /dev/null +++ b/arch/arm/mach-mmp/aspenite.c @@ -0,0 +1,42 @@ +/* + * linux/arch/arm/mach-mmp/aspenite.c + * + * Support for the Marvell PXA168-based Aspenite and Zylonite2 + * Development Platform. + * + * 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 + * publishhed by the Free Software Foundation. + */ + +#include + +#include +#include +#include + +#include "common.h" + +static void __init common_init(void) +{ +} + +MACHINE_START(ASPENITE, "PXA168-based Aspenite Development Platform") + .phys_io = APB_PHYS_BASE, + .boot_params = 0x00000100, + .io_pg_offst = (APB_VIRT_BASE >> 18) & 0xfffc, + .map_io = pxa_map_io, + .init_irq = pxa168_init_irq, + .timer = &pxa168_timer, + .init_machine = common_init, +MACHINE_END + +MACHINE_START(ZYLONITE2, "PXA168-based Zylonite2 Development Platform") + .phys_io = APB_PHYS_BASE, + .boot_params = 0x00000100, + .io_pg_offst = (APB_VIRT_BASE >> 18) & 0xfffc, + .map_io = pxa_map_io, + .init_irq = pxa168_init_irq, + .timer = &pxa168_timer, + .init_machine = common_init, +MACHINE_END diff --git a/arch/arm/mach-mmp/clock.c b/arch/arm/mach-mmp/clock.c new file mode 100644 index 000000000000..2d9cc5a7122f --- /dev/null +++ b/arch/arm/mach-mmp/clock.c @@ -0,0 +1,83 @@ +/* + * linux/arch/arm/mach-mmp/clock.c + * + * 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 +#include +#include +#include +#include +#include + +#include +#include "clock.h" + +static void apbc_clk_enable(struct clk *clk) +{ + uint32_t clk_rst; + + clk_rst = APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(clk->fnclksel); + __raw_writel(clk_rst, clk->clk_rst); +} + +static void apbc_clk_disable(struct clk *clk) +{ + __raw_writel(0, clk->clk_rst); +} + +struct clkops apbc_clk_ops = { + .enable = apbc_clk_enable, + .disable = apbc_clk_disable, +}; + +static DEFINE_SPINLOCK(clocks_lock); + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + + spin_lock_irqsave(&clocks_lock, flags); + if (clk->enabled++ == 0) + clk->ops->enable(clk); + spin_unlock_irqrestore(&clocks_lock, flags); + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + WARN_ON(clk->enabled == 0); + + spin_lock_irqsave(&clocks_lock, flags); + if (--clk->enabled == 0) + clk->ops->disable(clk); + spin_unlock_irqrestore(&clocks_lock, flags); +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + unsigned long rate; + + if (clk->ops->getrate) + rate = clk->ops->getrate(clk); + else + rate = clk->rate; + + return rate; +} +EXPORT_SYMBOL(clk_get_rate); + +void clks_register(struct clk_lookup *clks, size_t num) +{ + int i; + + for (i = 0; i < num; i++) + clkdev_add(&clks[i]); +} diff --git a/arch/arm/mach-mmp/clock.h b/arch/arm/mach-mmp/clock.h new file mode 100644 index 000000000000..ed967e78e6a8 --- /dev/null +++ b/arch/arm/mach-mmp/clock.h @@ -0,0 +1,71 @@ +/* + * linux/arch/arm/mach-mmp/clock.h + * + * 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 + +struct clkops { + void (*enable)(struct clk *); + void (*disable)(struct clk *); + unsigned long (*getrate)(struct clk *); +}; + +struct clk { + const struct clkops *ops; + + void __iomem *clk_rst; /* clock reset control register */ + int fnclksel; /* functional clock select (APBC) */ + uint32_t enable_val; /* value for clock enable (APMU) */ + unsigned long rate; + int enabled; +}; + +extern struct clkops apbc_clk_ops; + +#define APBC_CLK(_name, _reg, _fnclksel, _rate) \ +struct clk clk_##_name = { \ + .clk_rst = (void __iomem *)APBC_##_reg, \ + .fnclksel = _fnclksel, \ + .rate = _rate, \ + .ops = &apbc_clk_ops, \ +} + +#define APBC_CLK_OPS(_name, _reg, _fnclksel, _rate, _ops) \ +struct clk clk_##_name = { \ + .clk_rst = (void __iomem *)APBC_##_reg, \ + .fnclksel = _fnclksel, \ + .rate = _rate, \ + .ops = _ops, \ +} + +#define APMU_CLK(_name, _reg, _eval, _rate) \ +struct clk clk_##_name = { \ + .clk_rst = (void __iomem *)APMU_##_reg, \ + .enable_val = _eval, \ + .rate = _rate, \ + .ops = &apmu_clk_ops, \ +} + +#define APMU_CLK_OPS(_name, _reg, _eval, _rate, _ops) \ +struct clk clk_##_name = { \ + .clk_rst = (void __iomem *)APMU_##_reg, \ + .enable_val = _eval, \ + .rate = _rate, \ + .ops = _ops, \ +} + +#define INIT_CLKREG(_clk, _devname, _conname) \ + { \ + .clk = _clk, \ + .dev_id = _devname, \ + .con_id = _conname, \ + } + +extern struct clk clk_pxa168_gpio; +extern struct clk clk_pxa168_timers; + +extern void clks_register(struct clk_lookup *, size_t); diff --git a/arch/arm/mach-mmp/common.c b/arch/arm/mach-mmp/common.c new file mode 100644 index 000000000000..e1e66c18b446 --- /dev/null +++ b/arch/arm/mach-mmp/common.c @@ -0,0 +1,37 @@ +/* + * linux/arch/arm/mach-mmp/common.c + * + * Code common to PXA168 processor lines + * + * 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 +#include + +#include +#include +#include + +#include "common.h" + +static struct map_desc standard_io_desc[] __initdata = { + { + .pfn = __phys_to_pfn(APB_PHYS_BASE), + .virtual = APB_VIRT_BASE, + .length = APB_PHYS_SIZE, + .type = MT_DEVICE, + }, { + .pfn = __phys_to_pfn(AXI_PHYS_BASE), + .virtual = AXI_VIRT_BASE, + .length = AXI_PHYS_SIZE, + .type = MT_DEVICE, + }, +}; + +void __init pxa_map_io(void) +{ + iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); +} diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h new file mode 100644 index 000000000000..bf7a6a492de6 --- /dev/null +++ b/arch/arm/mach-mmp/common.h @@ -0,0 +1,11 @@ +#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) + +struct sys_timer; + +extern void timer_init(int irq); + +extern struct sys_timer pxa168_timer; +extern void __init pxa168_init_irq(void); + +extern void __init icu_init_irq(void); +extern void __init pxa_map_io(void); diff --git a/arch/arm/mach-mmp/devices.c b/arch/arm/mach-mmp/devices.c new file mode 100644 index 000000000000..191d9dea8731 --- /dev/null +++ b/arch/arm/mach-mmp/devices.c @@ -0,0 +1,69 @@ +/* + * linux/arch/arm/mach-mmp/devices.c + * + * 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 +#include +#include + +#include +#include + +int __init pxa_register_device(struct pxa_device_desc *desc, + void *data, size_t size) +{ + struct platform_device *pdev; + struct resource res[2 + MAX_RESOURCE_DMA]; + int i, ret = 0, nres = 0; + + pdev = platform_device_alloc(desc->drv_name, desc->id); + if (pdev == NULL) + return -ENOMEM; + + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + + memset(res, 0, sizeof(res)); + + if (desc->start != -1ul && desc->size > 0) { + res[nres].start = desc->start; + res[nres].end = desc->start + desc->size - 1; + res[nres].flags = IORESOURCE_MEM; + nres++; + } + + if (desc->irq != NO_IRQ) { + res[nres].start = desc->irq; + res[nres].end = desc->irq; + res[nres].flags = IORESOURCE_IRQ; + nres++; + } + + for (i = 0; i < MAX_RESOURCE_DMA; i++, nres++) { + if (desc->dma[i] == 0) + break; + + res[nres].start = desc->dma[i]; + res[nres].end = desc->dma[i]; + res[nres].flags = IORESOURCE_DMA; + } + + ret = platform_device_add_resources(pdev, res, nres); + if (ret) { + platform_device_put(pdev); + return ret; + } + + if (data && size) { + ret = platform_device_add_data(pdev, data, size); + if (ret) { + platform_device_put(pdev); + return ret; + } + } + + return platform_device_add(pdev); +} diff --git a/arch/arm/mach-mmp/include/mach/addr-map.h b/arch/arm/mach-mmp/include/mach/addr-map.h new file mode 100644 index 000000000000..3254089a644d --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/addr-map.h @@ -0,0 +1,34 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/addr-map.h + * + * Common address map definitions + * + * 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. + */ + +#ifndef __ASM_MACH_ADDR_MAP_H +#define __ASM_MACH_ADDR_MAP_H + +/* APB - Application Subsystem Peripheral Bus + * + * NOTE: the DMA controller registers are actually on the AXI fabric #1 + * slave port to AHB/APB bridge, due to its close relationship to those + * peripherals on APB, let's count it into the ABP mapping area. + */ +#define APB_PHYS_BASE 0xd4000000 +#define APB_VIRT_BASE 0xfe000000 +#define APB_PHYS_SIZE 0x00200000 + +#define AXI_PHYS_BASE 0xd4200000 +#define AXI_VIRT_BASE 0xfe200000 +#define AXI_PHYS_SIZE 0x00200000 + +/* Static Memory Controller - Chip Select 0 and 1 */ +#define SMC_CS0_PHYS_BASE 0x80000000 +#define SMC_CS0_PHYS_SIZE 0x10000000 +#define SMC_CS1_PHYS_BASE 0x90000000 +#define SMC_CS1_PHYS_SIZE 0x10000000 + +#endif /* __ASM_MACH_ADDR_MAP_H */ diff --git a/arch/arm/mach-mmp/include/mach/clkdev.h b/arch/arm/mach-mmp/include/mach/clkdev.h new file mode 100644 index 000000000000..2fb354e54e0d --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/clkdev.h @@ -0,0 +1,7 @@ +#ifndef __ASM_MACH_CLKDEV_H +#define __ASM_MACH_CLKDEV_H + +#define __clk_get(clk) ({ 1; }) +#define __clk_put(clk) do { } while (0) + +#endif /* __ASM_MACH_CLKDEV_H */ diff --git a/arch/arm/mach-mmp/include/mach/cputype.h b/arch/arm/mach-mmp/include/mach/cputype.h new file mode 100644 index 000000000000..4ceed7a50755 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/cputype.h @@ -0,0 +1,21 @@ +#ifndef __ASM_MACH_CPUTYPE_H +#define __ASM_MACH_CPUTYPE_H + +#include + +/* + * CPU Stepping OLD_ID CPU_ID CHIP_ID + * + * PXA168 A0 0x41159263 0x56158400 0x00A0A333 + */ + +#ifdef CONFIG_CPU_PXA168 +# define __cpu_is_pxa168(id) \ + ({ unsigned int _id = ((id) >> 8) & 0xff; _id == 0x84; }) +#else +# define __cpu_is_pxa168(id) (0) +#endif + +#define cpu_is_pxa168() ({ __cpu_is_pxa168(read_cpuid_id()); }) + +#endif /* __ASM_MACH_CPUTYPE_H */ diff --git a/arch/arm/mach-mmp/include/mach/debug-macro.S b/arch/arm/mach-mmp/include/mach/debug-macro.S new file mode 100644 index 000000000000..a850f87de51d --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/debug-macro.S @@ -0,0 +1,23 @@ +/* arch/arm/mach-mmp/include/mach/debug-macro.S + * + * Debugging macro include header + * + * Copied from arch/arm/mach-pxa/include/mach/debug.S + * + * 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 + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + ldreq \rx, =APB_PHYS_BASE @ physical + ldrne \rx, =APB_VIRT_BASE @ virtual + orr \rx, \rx, #0x00017000 + .endm + +#define UART_SHIFT 2 +#include diff --git a/arch/arm/mach-mmp/include/mach/devices.h b/arch/arm/mach-mmp/include/mach/devices.h new file mode 100644 index 000000000000..bc03388d5fde --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/devices.h @@ -0,0 +1,27 @@ +#include + +#define MAX_RESOURCE_DMA 2 + +/* structure for describing the on-chip devices */ +struct pxa_device_desc { + const char *dev_name; + const char *drv_name; + int id; + int irq; + unsigned long start; + unsigned long size; + int dma[MAX_RESOURCE_DMA]; +}; + +#define PXA168_DEVICE(_name, _drv, _id, _irq, _start, _size, _dma...) \ +struct pxa_device_desc pxa168_device_##_name __initdata = { \ + .dev_name = "pxa168-" #_name, \ + .drv_name = _drv, \ + .id = _id, \ + .irq = IRQ_PXA168_##_irq, \ + .start = _start, \ + .size = _size, \ + .dma = { _dma }, \ +}; + +extern int pxa_register_device(struct pxa_device_desc *, void *, size_t); diff --git a/arch/arm/mach-mmp/include/mach/dma.h b/arch/arm/mach-mmp/include/mach/dma.h new file mode 100644 index 000000000000..1d6914544da4 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/dma.h @@ -0,0 +1,13 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/dma.h + */ + +#ifndef __ASM_MACH_DMA_H +#define __ASM_MACH_DMA_H + +#include + +#define DMAC_REGS_VIRT (APB_VIRT_BASE + 0x00000) + +#include +#endif /* __ASM_MACH_DMA_H */ diff --git a/arch/arm/mach-mmp/include/mach/entry-macro.S b/arch/arm/mach-mmp/include/mach/entry-macro.S new file mode 100644 index 000000000000..6d3cd35478b5 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/entry-macro.S @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/entry-macro.S + * + * 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 + + .macro disable_fiq + .endm + + .macro arch_ret_to_user, tmp1, tmp2 + .endm + + .macro get_irqnr_preamble, base, tmp + ldr \base, =ICU_AP_IRQ_SEL_INT_NUM + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \tmp, [\base, #0] + and \irqnr, \tmp, #0x3f + tst \tmp, #(1 << 6) + .endm diff --git a/arch/arm/mach-mmp/include/mach/hardware.h b/arch/arm/mach-mmp/include/mach/hardware.h new file mode 100644 index 000000000000..99264a5ce5e4 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/hardware.h @@ -0,0 +1,4 @@ +#ifndef __ASM_MACH_HARDWARE_H +#define __ASM_MACH_HARDWARE_H + +#endif /* __ASM_MACH_HARDWARE_H */ diff --git a/arch/arm/mach-mmp/include/mach/io.h b/arch/arm/mach-mmp/include/mach/io.h new file mode 100644 index 000000000000..e7adf3d012c1 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/io.h @@ -0,0 +1,21 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/io.h + * + * 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. + */ + +#ifndef __ASM_MACH_IO_H +#define __ASM_MACH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * We don't actually have real ISA nor PCI buses, but there is so many + * drivers out there that might just work if we fake them... + */ +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#endif /* __ASM_MACH_IO_H */ diff --git a/arch/arm/mach-mmp/include/mach/irqs.h b/arch/arm/mach-mmp/include/mach/irqs.h new file mode 100644 index 000000000000..91ecb3fbca06 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/irqs.h @@ -0,0 +1,58 @@ +#ifndef __ASM_MACH_IRQS_H +#define __ASM_MACH_IRQS_H + +/* + * Interrupt numbers for PXA168 + */ +#define IRQ_PXA168_NONE (-1) +#define IRQ_PXA168_SSP3 0 +#define IRQ_PXA168_SSP2 1 +#define IRQ_PXA168_SSP1 2 +#define IRQ_PXA168_SSP0 3 +#define IRQ_PXA168_PMIC_INT 4 +#define IRQ_PXA168_RTC_INT 5 +#define IRQ_PXA168_RTC_ALARM 6 +#define IRQ_PXA168_TWSI0 7 +#define IRQ_PXA168_GPU 8 +#define IRQ_PXA168_KEYPAD 9 +#define IRQ_PXA168_ONEWIRE 12 +#define IRQ_PXA168_TIMER1 13 +#define IRQ_PXA168_TIMER2 14 +#define IRQ_PXA168_TIMER3 15 +#define IRQ_PXA168_CMU 16 +#define IRQ_PXA168_SSP4 17 +#define IRQ_PXA168_MSP_WAKEUP 19 +#define IRQ_PXA168_CF_WAKEUP 20 +#define IRQ_PXA168_XD_WAKEUP 21 +#define IRQ_PXA168_MFU 22 +#define IRQ_PXA168_MSP 23 +#define IRQ_PXA168_CF 24 +#define IRQ_PXA168_XD 25 +#define IRQ_PXA168_DDR_INT 26 +#define IRQ_PXA168_UART1 27 +#define IRQ_PXA168_UART2 28 +#define IRQ_PXA168_WDT 35 +#define IRQ_PXA168_FRQ_CHANGE 38 +#define IRQ_PXA168_SDH1 39 +#define IRQ_PXA168_SDH2 40 +#define IRQ_PXA168_LCD 41 +#define IRQ_PXA168_CI 42 +#define IRQ_PXA168_USB1 44 +#define IRQ_PXA168_NAND 45 +#define IRQ_PXA168_HIFI_DMA 46 +#define IRQ_PXA168_DMA_INT0 47 +#define IRQ_PXA168_DMA_INT1 48 +#define IRQ_PXA168_GPIOX 49 +#define IRQ_PXA168_USB2 51 +#define IRQ_PXA168_AC97 57 +#define IRQ_PXA168_TWSI1 58 +#define IRQ_PXA168_PMU 60 +#define IRQ_PXA168_SM_INT 63 + +#define IRQ_GPIO_START 64 +#define IRQ_GPIO_NUM 128 +#define IRQ_GPIO(x) (IRQ_GPIO_START + (x)) + +#define NR_IRQS (IRQ_GPIO_START + IRQ_GPIO_NUM) + +#endif /* __ASM_MACH_IRQS_H */ diff --git a/arch/arm/mach-mmp/include/mach/memory.h b/arch/arm/mach-mmp/include/mach/memory.h new file mode 100644 index 000000000000..bdb21d70714c --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/memory.h @@ -0,0 +1,14 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/memory.h + * + * 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. + */ + +#ifndef __ASM_MACH_MEMORY_H +#define __ASM_MACH_MEMORY_H + +#define PHYS_OFFSET UL(0x00000000) + +#endif /* __ASM_MACH_MEMORY_H */ diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h b/arch/arm/mach-mmp/include/mach/pxa168.h new file mode 100644 index 000000000000..ef0a8a2076e9 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/pxa168.h @@ -0,0 +1,23 @@ +#ifndef __ASM_MACH_PXA168_H +#define __ASM_MACH_PXA168_H + +#include + +extern struct pxa_device_desc pxa168_device_uart1; +extern struct pxa_device_desc pxa168_device_uart2; + +static inline int pxa168_add_uart(int id) +{ + struct pxa_device_desc *d = NULL; + + switch (id) { + case 1: d = &pxa168_device_uart1; break; + case 2: d = &pxa168_device_uart2; break; + } + + if (d == NULL) + return -EINVAL; + + return pxa_register_device(d, NULL, 0); +} +#endif /* __ASM_MACH_PXA168_H */ diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h b/arch/arm/mach-mmp/include/mach/regs-apbc.h new file mode 100644 index 000000000000..e0ffae594873 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/regs-apbc.h @@ -0,0 +1,53 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/regs-apbc.h + * + * Application Peripheral Bus Clock Unit + * + * 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. + */ + +#ifndef __ASM_MACH_REGS_APBC_H +#define __ASM_MACH_REGS_APBC_H + +#include + +#define APBC_VIRT_BASE (APB_VIRT_BASE + 0x015000) +#define APBC_REG(x) (APBC_VIRT_BASE + (x)) + +/* + * APB clock register offsets for PXA168 + */ +#define APBC_PXA168_UART1 APBC_REG(0x000) +#define APBC_PXA168_UART2 APBC_REG(0x004) +#define APBC_PXA168_GPIO APBC_REG(0x008) +#define APBC_PXA168_PWM0 APBC_REG(0x00c) +#define APBC_PXA168_PWM1 APBC_REG(0x010) +#define APBC_PXA168_SSP1 APBC_REG(0x01c) +#define APBC_PXA168_SSP2 APBC_REG(0x020) +#define APBC_PXA168_RTC APBC_REG(0x028) +#define APBC_PXA168_TWSI0 APBC_REG(0x02c) +#define APBC_PXA168_KPC APBC_REG(0x030) +#define APBC_PXA168_TIMERS APBC_REG(0x034) +#define APBC_PXA168_AIB APBC_REG(0x03c) +#define APBC_PXA168_SW_JTAG APBC_REG(0x040) +#define APBC_PXA168_ONEWIRE APBC_REG(0x048) +#define APBC_PXA168_SSP3 APBC_REG(0x04c) +#define APBC_PXA168_ASFAR APBC_REG(0x050) +#define APBC_PXA168_ASSAR APBC_REG(0x054) +#define APBC_PXA168_SSP4 APBC_REG(0x058) +#define APBC_PXA168_SSP5 APBC_REG(0x05c) +#define APBC_PXA168_TWSI1 APBC_REG(0x06c) +#define APBC_PXA168_UART3 APBC_REG(0x070) +#define APBC_PXA168_AC97 APBC_REG(0x084) + +/* Common APB clock register bit definitions */ +#define APBC_APBCLK (1 << 0) /* APB Bus Clock Enable */ +#define APBC_FNCLK (1 << 1) /* Functional Clock Enable */ +#define APBC_RST (1 << 2) /* Reset Generation */ + +/* Functional Clock Selection Mask */ +#define APBC_FNCLKSEL(x) (((x) & 0xf) << 4) + +#endif /* __ASM_MACH_REGS_APBC_H */ diff --git a/arch/arm/mach-mmp/include/mach/regs-apmu.h b/arch/arm/mach-mmp/include/mach/regs-apmu.h new file mode 100644 index 000000000000..919030514120 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/regs-apmu.h @@ -0,0 +1,36 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/regs-apmu.h + * + * Application Subsystem Power Management Unit + * + * 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. + */ + +#ifndef __ASM_MACH_REGS_APMU_H +#define __ASM_MACH_REGS_APMU_H + +#include + +#define APMU_VIRT_BASE (AXI_VIRT_BASE + 0x82800) +#define APMU_REG(x) (APMU_VIRT_BASE + (x)) + +/* Clock Reset Control */ +#define APMU_IRE APMU_REG(0x048) +#define APMU_LCD APMU_REG(0x04c) +#define APMU_CCIC APMU_REG(0x050) +#define APMU_SDH0 APMU_REG(0x054) +#define APMU_SDH1 APMU_REG(0x058) +#define APMU_USB APMU_REG(0x05c) +#define APMU_NAND APMU_REG(0x060) +#define APMU_DMA APMU_REG(0x064) +#define APMU_GEU APMU_REG(0x068) +#define APMU_BUS APMU_REG(0x06c) + +#define APMU_FNCLK_EN (1 << 4) +#define APMU_AXICLK_EN (1 << 3) +#define APMU_FNRST_DIS (1 << 1) +#define APMU_AXIRST_DIS (1 << 0) + +#endif /* __ASM_MACH_REGS_APMU_H */ diff --git a/arch/arm/mach-mmp/include/mach/regs-icu.h b/arch/arm/mach-mmp/include/mach/regs-icu.h new file mode 100644 index 000000000000..e5f08723e0cc --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/regs-icu.h @@ -0,0 +1,31 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/regs-icu.h + * + * Interrupt Control Unit + * + * 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. + */ + +#ifndef __ASM_MACH_ICU_H +#define __ASM_MACH_ICU_H + +#include + +#define ICU_VIRT_BASE (AXI_VIRT_BASE + 0x82000) +#define ICU_REG(x) (ICU_VIRT_BASE + (x)) + +#define ICU_INT_CONF(n) ICU_REG((n) << 2) +#define ICU_INT_CONF_AP_INT (1 << 6) +#define ICU_INT_CONF_CP_INT (1 << 5) +#define ICU_INT_CONF_IRQ (1 << 4) +#define ICU_INT_CONF_MASK (0xf) + +#define ICU_AP_FIQ_SEL_INT_NUM ICU_REG(0x108) /* AP FIQ Selected Interrupt */ +#define ICU_AP_IRQ_SEL_INT_NUM ICU_REG(0x10C) /* AP IRQ Selected Interrupt */ +#define ICU_AP_GBL_IRQ_MSK ICU_REG(0x114) /* AP Global Interrupt Mask */ +#define ICU_INT_STATUS_0 ICU_REG(0x128) /* Interrupt Stuats 0 */ +#define ICU_INT_STATUS_1 ICU_REG(0x12C) /* Interrupt Status 1 */ + +#endif /* __ASM_MACH_ICU_H */ diff --git a/arch/arm/mach-mmp/include/mach/regs-timers.h b/arch/arm/mach-mmp/include/mach/regs-timers.h new file mode 100644 index 000000000000..45589fec9fc7 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/regs-timers.h @@ -0,0 +1,44 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/regs-timers.h + * + * Timers Module + * + * 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. + */ + +#ifndef __ASM_MACH_REGS_TIMERS_H +#define __ASM_MACH_REGS_TIMERS_H + +#include + +#define TIMERS1_VIRT_BASE (APB_VIRT_BASE + 0x14000) +#define TIMERS2_VIRT_BASE (APB_VIRT_BASE + 0x16000) + +#define TMR_CCR (0x0000) +#define TMR_TN_MM(n, m) (0x0004 + ((n) << 3) + (((n) + (m)) << 2)) +#define TMR_CR(n) (0x0028 + ((n) << 2)) +#define TMR_SR(n) (0x0034 + ((n) << 2)) +#define TMR_IER(n) (0x0040 + ((n) << 2)) +#define TMR_PLVR(n) (0x004c + ((n) << 2)) +#define TMR_PLCR(n) (0x0058 + ((n) << 2)) +#define TMR_WMER (0x0064) +#define TMR_WMR (0x0068) +#define TMR_WVR (0x006c) +#define TMR_WSR (0x0070) +#define TMR_ICR(n) (0x0074 + ((n) << 2)) +#define TMR_WICR (0x0080) +#define TMR_CER (0x0084) +#define TMR_CMR (0x0088) +#define TMR_ILR(n) (0x008c + ((n) << 2)) +#define TMR_WCR (0x0098) +#define TMR_WFAR (0x009c) +#define TMR_WSAR (0x00A0) +#define TMR_CVWR(n) (0x00A4 + ((n) << 2)) + +#define TMR_CCR_CS_0(x) (((x) & 0x3) << 0) +#define TMR_CCR_CS_1(x) (((x) & 0x7) << 2) +#define TMR_CCR_CS_2(x) (((x) & 0x3) << 5) + +#endif /* __ASM_MACH_REGS_TIMERS_H */ diff --git a/arch/arm/mach-mmp/include/mach/system.h b/arch/arm/mach-mmp/include/mach/system.h new file mode 100644 index 000000000000..001edfefec19 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/system.h @@ -0,0 +1,21 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/system.h + * + * 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. + */ + +#ifndef __ASM_MACH_SYSTEM_H +#define __ASM_MACH_SYSTEM_H + +static inline void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + cpu_reset(0); +} +#endif /* __ASM_MACH_SYSTEM_H */ diff --git a/arch/arm/mach-mmp/include/mach/timex.h b/arch/arm/mach-mmp/include/mach/timex.h new file mode 100644 index 000000000000..6cebbd0ca8f4 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/timex.h @@ -0,0 +1,9 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/timex.h + * + * 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. + */ + +#define CLOCK_TICK_RATE 3250000 diff --git a/arch/arm/mach-mmp/include/mach/uncompress.h b/arch/arm/mach-mmp/include/mach/uncompress.h new file mode 100644 index 000000000000..c93d5fa5865c --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/uncompress.h @@ -0,0 +1,41 @@ +/* + * arch/arm/mach-mmp/include/mach/uncompress.h + * + * 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 +#include + +#define UART1_BASE (APB_PHYS_BASE + 0x36000) +#define UART2_BASE (APB_PHYS_BASE + 0x17000) +#define UART3_BASE (APB_PHYS_BASE + 0x18000) + +static inline void putc(char c) +{ + volatile unsigned long *UART = (unsigned long *)UART2_BASE; + + /* UART enabled? */ + if (!(UART[UART_IER] & UART_IER_UUE)) + return; + + while (!(UART[UART_LSR] & UART_LSR_THRE)) + barrier(); + + UART[UART_TX] = c; +} + +/* + * This does not append a newline + */ +static inline void flush(void) +{ +} + +/* + * nothing to do + */ +#define arch_decomp_setup() +#define arch_decomp_wdog() diff --git a/arch/arm/mach-mmp/include/mach/vmalloc.h b/arch/arm/mach-mmp/include/mach/vmalloc.h new file mode 100644 index 000000000000..b60ccaf9fee7 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/vmalloc.h @@ -0,0 +1,5 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/vmalloc.h + */ + +#define VMALLOC_END 0xfe000000 diff --git a/arch/arm/mach-mmp/irq.c b/arch/arm/mach-mmp/irq.c new file mode 100644 index 000000000000..52ff2f065eba --- /dev/null +++ b/arch/arm/mach-mmp/irq.c @@ -0,0 +1,55 @@ +/* + * linux/arch/arm/mach-mmp/irq.c + * + * Generic IRQ handling, GPIO IRQ demultiplexing, etc. + * + * Author: Bin Yang + * Created: Sep 30, 2008 + * Copyright: Marvell International Ltd. + * + * 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 +#include +#include + +#include + +#include "common.h" + +#define IRQ_ROUTE_TO_AP (ICU_INT_CONF_AP_INT | ICU_INT_CONF_IRQ) + +#define PRIORITY_DEFAULT 0x1 +#define PRIORITY_NONE 0x0 /* means IRQ disabled */ + +static void icu_mask_irq(unsigned int irq) +{ + __raw_writel(PRIORITY_NONE, ICU_INT_CONF(irq)); +} + +static void icu_unmask_irq(unsigned int irq) +{ + __raw_writel(IRQ_ROUTE_TO_AP | PRIORITY_DEFAULT, ICU_INT_CONF(irq)); +} + +static struct irq_chip icu_irq_chip = { + .name = "icu_irq", + .ack = icu_mask_irq, + .mask = icu_mask_irq, + .unmask = icu_unmask_irq, +}; + +void __init icu_init_irq(void) +{ + int irq; + + for (irq = 0; irq < 64; irq++) { + icu_mask_irq(irq); + set_irq_chip(irq, &icu_irq_chip); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } +} diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c new file mode 100644 index 000000000000..1935c7545117 --- /dev/null +++ b/arch/arm/mach-mmp/pxa168.c @@ -0,0 +1,77 @@ +/* + * linux/arch/arm/mach-mmp/pxa168.c + * + * Code specific to PXA168 + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "clock.h" + +void __init pxa168_init_irq(void) +{ + icu_init_irq(); +} + +/* APB peripheral clocks */ +static APBC_CLK(uart1, PXA168_UART1, 1, 14745600); +static APBC_CLK(uart2, PXA168_UART2, 1, 14745600); + +/* device and clock bindings */ +static struct clk_lookup pxa168_clkregs[] = { + INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL), + INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL), +}; + +static int __init pxa168_init(void) +{ + if (cpu_is_pxa168()) { + pxa_init_dma(IRQ_PXA168_DMA_INT0, 32); + clks_register(ARRAY_AND_SIZE(pxa168_clkregs)); + } + + return 0; +} +postcore_initcall(pxa168_init); + +/* system timer - clock enabled, 3.25MHz */ +#define TIMER_CLK_RST (APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3)) + +static void __init pxa168_timer_init(void) +{ + /* this is early, we have to initialize the CCU registers by + * ourselves instead of using clk_* API. Clock rate is defined + * by APBC_TIMERS_CLK_RST (3.25MHz) and enabled free-running + */ + __raw_writel(APBC_APBCLK | APBC_RST, APBC_PXA168_TIMERS); + + /* 3.25MHz, bus/functional clock enabled, release reset */ + __raw_writel(TIMER_CLK_RST, APBC_PXA168_TIMERS); + + timer_init(IRQ_PXA168_TIMER1); +} + +struct sys_timer pxa168_timer = { + .init = pxa168_timer_init, +}; + +/* on-chip devices */ +PXA168_DEVICE(uart1, "pxa2xx-uart", 0, UART1, 0xd4017000, 0x30, 21, 22); +PXA168_DEVICE(uart2, "pxa2xx-uart", 1, UART2, 0xd4018000, 0x30, 23, 24); diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c new file mode 100644 index 000000000000..b03a6eda7419 --- /dev/null +++ b/arch/arm/mach-mmp/time.c @@ -0,0 +1,199 @@ +/* + * linux/arch/arm/mach-mmp/time.c + * + * Support for clocksource and clockevents + * + * Copyright (C) 2008 Marvell International Ltd. + * All rights reserved. + * + * 2008-04-11: Jason Chagas + * 2008-10-08: Bin Yang + * + * The timers module actually includes three timers, each timer with upto + * three match comparators. Timer #0 is used here in free-running mode as + * the clock source, and match comparator #1 used as clock event device. + * + * 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 +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "clock.h" + +#define TIMERS_VIRT_BASE TIMERS1_VIRT_BASE + +#define MAX_DELTA (0xfffffffe) +#define MIN_DELTA (16) + +#define TCR2NS_SCALE_FACTOR 10 + +static unsigned long tcr2ns_scale; + +static void __init set_tcr2ns_scale(unsigned long tcr_rate) +{ + unsigned long long v = 1000000000ULL << TCR2NS_SCALE_FACTOR; + do_div(v, tcr_rate); + tcr2ns_scale = v; + /* + * We want an even value to automatically clear the top bit + * returned by cnt32_to_63() without an additional run time + * instruction. So if the LSB is 1 then round it up. + */ + if (tcr2ns_scale & 1) + tcr2ns_scale++; +} + +/* + * FIXME: the timer needs some delay to stablize the counter capture + */ +static inline uint32_t timer_read(void) +{ + int delay = 100; + + __raw_writel(1, TIMERS_VIRT_BASE + TMR_CVWR(0)); + + while (delay--) + cpu_relax(); + + return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(0)); +} + +unsigned long long sched_clock(void) +{ + unsigned long long v = cnt32_to_63(timer_read()); + return (v * tcr2ns_scale) >> TCR2NS_SCALE_FACTOR; +} + +static irqreturn_t timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *c = dev_id; + + /* disable and clear pending interrupt status */ + __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0)); + __raw_writel(0x1, TIMERS_VIRT_BASE + TMR_ICR(0)); + c->event_handler(c); + return IRQ_HANDLED; +} + +static int timer_set_next_event(unsigned long delta, + struct clock_event_device *dev) +{ + unsigned long flags, next; + + local_irq_save(flags); + + /* clear pending interrupt status and enable */ + __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0)); + __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_IER(0)); + + next = timer_read() + delta; + __raw_writel(next, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0)); + + local_irq_restore(flags); + return 0; +} + +static void timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *dev) +{ + unsigned long flags; + + local_irq_save(flags); + switch (mode) { + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + /* disable the matching interrupt */ + __raw_writel(0x00, TIMERS_VIRT_BASE + TMR_IER(0)); + break; + case CLOCK_EVT_MODE_RESUME: + case CLOCK_EVT_MODE_PERIODIC: + break; + } + local_irq_restore(flags); +} + +static struct clock_event_device ckevt = { + .name = "clockevent", + .features = CLOCK_EVT_FEAT_ONESHOT, + .shift = 32, + .rating = 200, + .set_next_event = timer_set_next_event, + .set_mode = timer_set_mode, +}; + +static cycle_t clksrc_read(void) +{ + return timer_read(); +} + +static struct clocksource cksrc = { + .name = "clocksource", + .shift = 20, + .rating = 200, + .read = clksrc_read, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void __init timer_config(void) +{ + uint32_t ccr = __raw_readl(TIMERS_VIRT_BASE + TMR_CCR); + uint32_t cer = __raw_readl(TIMERS_VIRT_BASE + TMR_CER); + uint32_t cmr = __raw_readl(TIMERS_VIRT_BASE + TMR_CMR); + + __raw_writel(cer & ~0x1, TIMERS_VIRT_BASE + TMR_CER); /* disable */ + + ccr &= TMR_CCR_CS_0(0x3); + __raw_writel(ccr, TIMERS_VIRT_BASE + TMR_CCR); + + /* free-running mode */ + __raw_writel(cmr | 0x01, TIMERS_VIRT_BASE + TMR_CMR); + + __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* free-running */ + __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(0)); /* clear status */ + __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0)); + + /* enable timer counter */ + __raw_writel(cer | 0x01, TIMERS_VIRT_BASE + TMR_CER); +} + +static struct irqaction timer_irq = { + .name = "timer", + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = timer_interrupt, + .dev_id = &ckevt, +}; + +void __init timer_init(int irq) +{ + timer_config(); + + set_tcr2ns_scale(CLOCK_TICK_RATE); + + ckevt.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt.shift); + ckevt.max_delta_ns = clockevent_delta2ns(MAX_DELTA, &ckevt); + ckevt.min_delta_ns = clockevent_delta2ns(MIN_DELTA, &ckevt); + ckevt.cpumask = cpumask_of(0); + + cksrc.mult = clocksource_hz2mult(CLOCK_TICK_RATE, cksrc.shift); + + setup_irq(irq, &timer_irq); + + clocksource_register(&cksrc); + clockevents_register_device(&ckevt); +} diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index d490f3773c01..64086f4f5fcc 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -340,6 +340,17 @@ config CPU_XSC3 select CPU_TLB_V4WBI if MMU select IO_36 +# Marvell PJ1 (Mohawk) +config CPU_MOHAWK + bool + select CPU_32v5 + select CPU_ABRT_EV5T + select CPU_PABRT_NOIFAR + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_TLB_V4WBI if MMU + select CPU_COPY_V4WB if MMU + # Feroceon config CPU_FEROCEON bool @@ -569,7 +580,7 @@ comment "Processor Features" config ARM_THUMB bool "Support Thumb user binaries" - depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V7 || CPU_FEROCEON + depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V7 || CPU_FEROCEON default y help Say Y if you want to include kernel support for running user space @@ -653,7 +664,7 @@ config CPU_CACHE_ROUND_ROBIN config CPU_BPREDICT_DISABLE bool "Disable branch prediction" - depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3 || CPU_V7 + depends on CPU_ARM1020 || CPU_V6 || CPU_MOHAWK || CPU_XSC3 || CPU_V7 help Say Y here to disable branch prediction. If unsure, say N. diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index 480f78a3611a..64149d9e55a5 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_CPU_SA110) += proc-sa110.o obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o +obj-$(CONFIG_CPU_MOHAWK) += proc-mohawk.o obj-$(CONFIG_CPU_FEROCEON) += proc-feroceon.o obj-$(CONFIG_CPU_V6) += proc-v6.o obj-$(CONFIG_CPU_V7) += proc-v7.o diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S new file mode 100644 index 000000000000..540f5078496b --- /dev/null +++ b/arch/arm/mm/proc-mohawk.S @@ -0,0 +1,416 @@ +/* + * linux/arch/arm/mm/proc-mohawk.S: MMU functions for Marvell PJ1 core + * + * PJ1 (codename Mohawk) is a hybrid of the xscale3 and Marvell's own core. + * + * Heavily based on proc-arm926.S and proc-xsc3.S + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "proc-macros.S" + +/* + * This is the maximum size of an area which will be flushed. If the + * area is larger than this, then we flush the whole cache. + */ +#define CACHE_DLIMIT 32768 + +/* + * The cache line size of the L1 D cache. + */ +#define CACHE_DLINESIZE 32 + +/* + * cpu_mohawk_proc_init() + */ +ENTRY(cpu_mohawk_proc_init) + mov pc, lr + +/* + * cpu_mohawk_proc_fin() + */ +ENTRY(cpu_mohawk_proc_fin) + stmfd sp!, {lr} + mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE + msr cpsr_c, ip + bl mohawk_flush_kern_cache_all + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1800 @ ...iz........... + bic r0, r0, #0x0006 @ .............ca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + ldmfd sp!, {pc} + +/* + * cpu_mohawk_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + * + * (same as arm926) + */ + .align 5 +ENTRY(cpu_mohawk_reset) + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mrc p15, 0, ip, c1, c0, 0 @ ctrl register + bic ip, ip, #0x0007 @ .............cam + bic ip, ip, #0x1100 @ ...i...s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 + +/* + * cpu_mohawk_do_idle() + * + * Called with IRQs disabled + */ + .align 5 +ENTRY(cpu_mohawk_do_idle) + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt + mov pc, lr + +/* + * flush_user_cache_all() + * + * Clean and invalidate all cache entries in a particular + * address space. + */ +ENTRY(mohawk_flush_user_cache_all) + /* FALLTHROUGH */ + +/* + * flush_kern_cache_all() + * + * Clean and invalidate the entire cache. + */ +ENTRY(mohawk_flush_kern_cache_all) + mov r2, #VM_EXEC + mov ip, #0 +__flush_whole_cache: + mcr p15, 0, ip, c7, c14, 0 @ clean & invalidate all D cache + tst r2, #VM_EXEC + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcrne p15, 0, ip, c7, c10, 0 @ drain write buffer + mov pc, lr + +/* + * flush_user_cache_range(start, end, flags) + * + * Clean and invalidate a range of cache entries in the + * specified address range. + * + * - start - start address (inclusive) + * - end - end address (exclusive) + * - flags - vm_flags describing address space + * + * (same as arm926) + */ +ENTRY(mohawk_flush_user_cache_range) + mov ip, #0 + sub r3, r1, r0 @ calculate total size + cmp r3, #CACHE_DLIMIT + bgt __flush_whole_cache +1: tst r2, #VM_EXEC + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #CACHE_DLINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + blo 1b + tst r2, #VM_EXEC + mcrne p15, 0, ip, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * coherent_kern_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start, end. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(mohawk_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start, end. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + * + * (same as arm926) + */ +ENTRY(mohawk_coherent_user_range) + bic r0, r0, #CACHE_DLINESIZE - 1 +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + blo 1b + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * flush_kern_dcache_page(void *page) + * + * Ensure no D cache aliasing occurs, either with itself or + * the I cache + * + * - addr - page aligned address + */ +ENTRY(mohawk_flush_kern_dcache_page) + add r1, r0, #PAGE_SZ +1: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + blo 1b + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * dma_inv_range(start, end) + * + * Invalidate (discard) the specified virtual address range. + * May not write back any entries. If 'start' or 'end' + * are not cache line aligned, those lines must be written + * back. + * + * - start - virtual start address + * - end - virtual end address + * + * (same as v4wb) + */ +ENTRY(mohawk_dma_inv_range) + tst r0, #CACHE_DLINESIZE - 1 + mcrne p15, 0, r0, c7, c10, 1 @ clean D entry + tst r1, #CACHE_DLINESIZE - 1 + mcrne p15, 0, r1, c7, c10, 1 @ clean D entry + bic r0, r0, #CACHE_DLINESIZE - 1 +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + blo 1b + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * dma_clean_range(start, end) + * + * Clean the specified virtual address range. + * + * - start - virtual start address + * - end - virtual end address + * + * (same as v4wb) + */ +ENTRY(mohawk_dma_clean_range) + bic r0, r0, #CACHE_DLINESIZE - 1 +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + blo 1b + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * dma_flush_range(start, end) + * + * Clean and invalidate the specified virtual address range. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(mohawk_dma_flush_range) + bic r0, r0, #CACHE_DLINESIZE - 1 +1: + mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + blo 1b + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +ENTRY(mohawk_cache_fns) + .long mohawk_flush_kern_cache_all + .long mohawk_flush_user_cache_all + .long mohawk_flush_user_cache_range + .long mohawk_coherent_kern_range + .long mohawk_coherent_user_range + .long mohawk_flush_kern_dcache_page + .long mohawk_dma_inv_range + .long mohawk_dma_clean_range + .long mohawk_dma_flush_range + +ENTRY(cpu_mohawk_dcache_clean_area) +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #CACHE_DLINESIZE + subs r1, r1, #CACHE_DLINESIZE + bhi 1b + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_mohawk_switch_mm(pgd) + * + * Set the translation base pointer to be as described by pgd. + * + * pgd: new page tables + */ + .align 5 +ENTRY(cpu_mohawk_switch_mm) + mov ip, #0 + mcr p15, 0, ip, c7, c14, 0 @ clean & invalidate all D cache + mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + orr r0, r0, #0x18 @ cache the page table in L2 + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr + +/* + * cpu_mohawk_set_pte_ext(ptep, pte, ext) + * + * Set a PTE and flush it out + */ + .align 5 +ENTRY(cpu_mohawk_set_pte_ext) + armv3_set_pte_ext + mov r0, r0 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + + __INIT + + .type __mohawk_setup, #function +__mohawk_setup: + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ invalidate I,D caches + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs + orr r4, r4, #0x18 @ cache the page table in L2 + mcr p15, 0, r4, c2, c0, 0 @ load page table pointer + + mov r0, #0 @ don't allow CP access + mcr p15, 0, r0, c15, c1, 0 @ write CP access register + + adr r5, mohawk_crval + ldmia r5, {r5, r6} + mrc p15, 0, r0, c1, c0 @ get control register + bic r0, r0, r5 + orr r0, r0, r6 + mov pc, lr + + .size __mohawk_setup, . - __mohawk_setup + + /* + * R + * .RVI ZFRS BLDP WCAM + * .011 1001 ..00 0101 + * + */ + .type mohawk_crval, #object +mohawk_crval: + crval clear=0x00007f3f, mmuset=0x00003905, ucset=0x00001134 + + __INITDATA + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type mohawk_processor_functions, #object +mohawk_processor_functions: + .word v5t_early_abort + .word pabort_noifar + .word cpu_mohawk_proc_init + .word cpu_mohawk_proc_fin + .word cpu_mohawk_reset + .word cpu_mohawk_do_idle + .word cpu_mohawk_dcache_clean_area + .word cpu_mohawk_switch_mm + .word cpu_mohawk_set_pte_ext + .size mohawk_processor_functions, . - mohawk_processor_functions + + .section ".rodata" + + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5te" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_mohawk_name, #object +cpu_mohawk_name: + .asciz "Marvell 88SV331x" + .size cpu_mohawk_name, . - cpu_mohawk_name + + .align + + .section ".proc.info.init", #alloc, #execinstr + + .type __88sv331x_proc_info,#object +__88sv331x_proc_info: + .long 0x56158000 @ Marvell 88SV331x (MOHAWK) + .long 0xfffff000 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __mohawk_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_mohawk_name + .long mohawk_processor_functions + .long v4wbi_tlb_fns + .long v4wb_user_fns + .long mohawk_cache_fns + .size __88sv331x_proc_info, . - __88sv331x_proc_info -- cgit v1.2.3-55-g7522 From 28853ac8fe5221de74a14f1182d7b2b383dfd85c Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Wed, 25 Mar 2009 13:10:01 +0200 Subject: ARM: Add support for FA526 v2 Adds support for Faraday FA526 core. This core is used at least by: Cortina Systems Gemini and Centroid family Cavium Networks ECONA family Grain Media GM8120 Pixelplus ImageARM Prolific PL-1029 Faraday IP evaluation boards v2: - move TLB_BTB to separate patch - update copyrights Signed-off-by: Paulius Zaleckas --- arch/arm/Makefile | 1 + arch/arm/boot/compressed/head.S | 26 ++++ arch/arm/include/asm/cacheflush.h | 8 ++ arch/arm/include/asm/page.h | 8 ++ arch/arm/include/asm/proc-fns.h | 8 ++ arch/arm/include/asm/system.h | 6 + arch/arm/include/asm/tlbflush.h | 19 +++ arch/arm/mm/Kconfig | 35 +++++- arch/arm/mm/Makefile | 4 + arch/arm/mm/cache-fa.S | 220 +++++++++++++++++++++++++++++++++ arch/arm/mm/copypage-fa.c | 86 +++++++++++++ arch/arm/mm/proc-fa526.S | 248 ++++++++++++++++++++++++++++++++++++++ arch/arm/mm/tlb-fa.S | 75 ++++++++++++ 13 files changed, 742 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mm/cache-fa.S create mode 100644 arch/arm/mm/copypage-fa.c create mode 100644 arch/arm/mm/proc-fa526.S create mode 100644 arch/arm/mm/tlb-fa.S (limited to 'arch/arm/mm') diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 24e0f0187697..d29f9260fb1c 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -72,6 +72,7 @@ tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_ARM922T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_ARM925T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi +tune-$(CONFIG_CPU_FA526) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 tune-$(CONFIG_CPU_XSCALE) :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 77d614232d81..def02483286a 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -459,6 +459,20 @@ __armv7_mmu_cache_on: mcr p15, 0, r0, c7, c5, 4 @ ISB mov pc, r12 +__fa526_cache_on: + mov r12, lr + bl __setup_mmu + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 @ Invalidate whole cache + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mcr p15, 0, r0, c8, c7, 0 @ flush UTLB + mrc p15, 0, r0, c1, c0, 0 @ read control reg + orr r0, r0, #0x1000 @ I-cache enable + bl __common_mmu_cache_on + mov r0, #0 + mcr p15, 0, r0, c8, c7, 0 @ flush UTLB + mov pc, r12 + __arm6_mmu_cache_on: mov r12, lr bl __setup_mmu @@ -636,6 +650,12 @@ proc_types: b __armv4_mmu_cache_off b __armv5tej_mmu_cache_flush + .word 0x66015261 @ FA526 + .word 0xff01fff1 + b __fa526_cache_on + b __armv4_mmu_cache_off + b __fa526_cache_flush + @ These match on the architecture ID .word 0x00020000 @ ARMv4T @@ -775,6 +795,12 @@ __armv4_mpu_cache_flush: mcr p15, 0, ip, c7, c10, 4 @ drain WB mov pc, lr +__fa526_cache_flush: + mov r1, #0 + mcr p15, 0, r1, c7, c14, 0 @ clean and invalidate D cache + mcr p15, 0, r1, c7, c5, 0 @ flush I cache + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr __armv6_mmu_cache_flush: mov r1, #0 diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 6cbd8fdc9f1f..a6b8b90ed57f 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -46,6 +46,14 @@ # define MULTI_CACHE 1 #endif +#if defined(CONFIG_CPU_FA526) +# ifdef _CACHE +# define MULTI_CACHE 1 +# else +# define _CACHE fa +# endif +#endif + #if defined(CONFIG_CPU_ARM926T) # ifdef _CACHE # define MULTI_CACHE 1 diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h index f341c9dbd662..e6eb8a67b807 100644 --- a/arch/arm/include/asm/page.h +++ b/arch/arm/include/asm/page.h @@ -76,6 +76,14 @@ # endif #endif +#ifdef CONFIG_CPU_COPY_FA +# ifdef _USER +# define MULTI_USER 1 +# else +# define _USER fa +# endif +#endif + #ifdef CONFIG_CPU_SA1100 # ifdef _USER # define MULTI_USER 1 diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h index db80203b68e0..00949281d3ee 100644 --- a/arch/arm/include/asm/proc-fns.h +++ b/arch/arm/include/asm/proc-fns.h @@ -89,6 +89,14 @@ # define CPU_NAME cpu_arm922 # endif # endif +# ifdef CONFIG_CPU_FA526 +# ifdef CPU_NAME +# undef MULTI_CPU +# define MULTI_CPU +# else +# define CPU_NAME cpu_fa526 +# endif +# endif # ifdef CONFIG_CPU_ARM925T # ifdef CPU_NAME # undef MULTI_CPU diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 811be55f338e..d6a4dad99c9b 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -125,6 +125,12 @@ extern unsigned int user_debug; : : "r" (0) : "memory") #define dmb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \ : : "r" (0) : "memory") +#elif defined(CONFIG_CPU_FA526) +#define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \ + : : "r" (0) : "memory") +#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \ + : : "r" (0) : "memory") +#define dmb() __asm__ __volatile__ ("" : : : "memory") #else #define isb() __asm__ __volatile__ ("" : : : "memory") #define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \ diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index ffedd2494eab..a62218013c78 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h @@ -54,6 +54,7 @@ * v4wb - ARMv4 with write buffer without I TLB flush entry instruction * v4wbi - ARMv4 with write buffer with I TLB flush entry instruction * fr - Feroceon (v4wbi with non-outer-cacheable page table walks) + * fa - Faraday (v4 with write buffer with UTLB and branch target buffer (BTB)) * v6wbi - ARMv6 with write buffer with I TLB flush entry instruction * v7wbi - identical to v6wbi */ @@ -90,6 +91,22 @@ # define v4_always_flags (-1UL) #endif +#define fa_tlb_flags (TLB_WB | TLB_BTB | TLB_DCLEAN | \ + TLB_V4_U_FULL | TLB_V4_U_PAGE) + +#ifdef CONFIG_CPU_TLB_FA +# define fa_possible_flags fa_tlb_flags +# define fa_always_flags fa_tlb_flags +# ifdef _TLB +# define MULTI_TLB 1 +# else +# define _TLB fa +# endif +#else +# define fa_possible_flags 0 +# define fa_always_flags (-1UL) +#endif + #define v4wbi_tlb_flags (TLB_WB | TLB_DCLEAN | \ TLB_V4_I_FULL | TLB_V4_D_FULL | \ TLB_V4_I_PAGE | TLB_V4_D_PAGE) @@ -268,6 +285,7 @@ extern struct cpu_tlb_fns cpu_tlb; v4wbi_possible_flags | \ fr_possible_flags | \ v4wb_possible_flags | \ + fa_possible_flags | \ v6wbi_possible_flags | \ v7wbi_possible_flags) @@ -276,6 +294,7 @@ extern struct cpu_tlb_fns cpu_tlb; v4wbi_always_flags & \ fr_always_flags & \ v4wb_always_flags & \ + fa_always_flags & \ v6wbi_always_flags & \ v7wbi_always_flags) diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index d490f3773c01..bc3331863d9d 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -186,6 +186,24 @@ config CPU_ARM926T Say Y if you want support for the ARM926T processor. Otherwise, say N. +# FA526 +config CPU_FA526 + bool + select CPU_32v4 + select CPU_ABRT_EV4 + select CPU_PABRT_NOIFAR + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_CACHE_FA + select CPU_COPY_FA if MMU + select CPU_TLB_FA if MMU + help + The FA526 is a version of the ARMv4 compatible processor with + Branch Target Buffer, Unified TLB and cache line size 16. + + Say Y if you want support for the FA526 processor. + Otherwise, say N. + # ARM940T config CPU_ARM940T bool "Support ARM940T processor" if ARCH_INTEGRATOR @@ -484,6 +502,9 @@ config CPU_CACHE_VIVT config CPU_CACHE_VIPT bool +config CPU_CACHE_FA + bool + if MMU # The copy-page model config CPU_COPY_V3 @@ -498,6 +519,9 @@ config CPU_COPY_V4WB config CPU_COPY_FEROCEON bool +config CPU_COPY_FA + bool + config CPU_COPY_V6 bool @@ -528,6 +552,13 @@ config CPU_TLB_FEROCEON help Feroceon TLB (v4wbi with non-outer-cachable page table walks). +config CPU_TLB_FA + bool + help + Faraday ARM FA526 architecture, unified TLB with writeback cache + and invalidate instruction cache entry. Branch target buffer is + also supported. + config CPU_TLB_V6 bool @@ -638,7 +669,7 @@ config CPU_DCACHE_SIZE config CPU_DCACHE_WRITETHROUGH bool "Force write through D-cache" - depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020) && !CPU_DCACHE_DISABLE + depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_FA526) && !CPU_DCACHE_DISABLE default y if CPU_ARM925T help Say Y here to use the data cache in writethrough mode. Unless you @@ -653,7 +684,7 @@ config CPU_CACHE_ROUND_ROBIN config CPU_BPREDICT_DISABLE bool "Disable branch prediction" - depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3 || CPU_V7 + depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3 || CPU_V7 || CPU_FA526 help Say Y here to disable branch prediction. If unsure, say N. diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index 480f78a3611a..40f941c2245c 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_CPU_CACHE_V4WT) += cache-v4wt.o obj-$(CONFIG_CPU_CACHE_V4WB) += cache-v4wb.o obj-$(CONFIG_CPU_CACHE_V6) += cache-v6.o obj-$(CONFIG_CPU_CACHE_V7) += cache-v7.o +obj-$(CONFIG_CPU_CACHE_FA) += cache-fa.o obj-$(CONFIG_CPU_COPY_V3) += copypage-v3.o obj-$(CONFIG_CPU_COPY_V4WT) += copypage-v4wt.o @@ -41,6 +42,7 @@ obj-$(CONFIG_CPU_COPY_V6) += copypage-v6.o context.o obj-$(CONFIG_CPU_SA1100) += copypage-v4mc.o obj-$(CONFIG_CPU_XSCALE) += copypage-xscale.o obj-$(CONFIG_CPU_XSC3) += copypage-xsc3.o +obj-$(CONFIG_CPU_COPY_FA) += copypage-fa.o obj-$(CONFIG_CPU_TLB_V3) += tlb-v3.o obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o @@ -49,6 +51,7 @@ obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o obj-$(CONFIG_CPU_TLB_FEROCEON) += tlb-v4wbi.o # reuse v4wbi TLB functions obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o obj-$(CONFIG_CPU_TLB_V7) += tlb-v7.o +obj-$(CONFIG_CPU_TLB_FA) += tlb-fa.o obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o @@ -62,6 +65,7 @@ obj-$(CONFIG_CPU_ARM925T) += proc-arm925.o obj-$(CONFIG_CPU_ARM926T) += proc-arm926.o obj-$(CONFIG_CPU_ARM940T) += proc-arm940.o obj-$(CONFIG_CPU_ARM946E) += proc-arm946.o +obj-$(CONFIG_CPU_FA526) += proc-fa526.o obj-$(CONFIG_CPU_ARM1020) += proc-arm1020.o obj-$(CONFIG_CPU_ARM1020E) += proc-arm1020e.o obj-$(CONFIG_CPU_ARM1022) += proc-arm1022.o diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S new file mode 100644 index 000000000000..b63a8f7b95cf --- /dev/null +++ b/arch/arm/mm/cache-fa.S @@ -0,0 +1,220 @@ +/* + * linux/arch/arm/mm/cache-fa.S + * + * Copyright (C) 2005 Faraday Corp. + * Copyright (C) 2008-2009 Paulius Zaleckas + * + * Based on cache-v4wb.S: + * Copyright (C) 1997-2002 Russell king + * + * 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. + * + * Processors: FA520 FA526 FA626 + */ +#include +#include +#include +#include + +#include "proc-macros.S" + +/* + * The size of one data cache line. + */ +#define CACHE_DLINESIZE 16 + +/* + * The total size of the data cache. + */ +#ifdef CONFIG_ARCH_GEMINI +#define CACHE_DSIZE 8192 +#else +#define CACHE_DSIZE 16384 +#endif + +/* FIXME: put optimal value here. Current one is just estimation */ +#define CACHE_DLIMIT (CACHE_DSIZE * 2) + +/* + * flush_user_cache_all() + * + * Clean and invalidate all cache entries in a particular address + * space. + */ +ENTRY(fa_flush_user_cache_all) + /* FALLTHROUGH */ +/* + * flush_kern_cache_all() + * + * Clean and invalidate the entire cache. + */ +ENTRY(fa_flush_kern_cache_all) + mov ip, #0 + mov r2, #VM_EXEC +__flush_whole_cache: + mcr p15, 0, ip, c7, c14, 0 @ clean/invalidate D cache + tst r2, #VM_EXEC + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcrne p15, 0, ip, c7, c5, 6 @ invalidate BTB + mcrne p15, 0, ip, c7, c10, 4 @ drain write buffer + mcrne p15, 0, ip, c7, c5, 4 @ prefetch flush + mov pc, lr + +/* + * flush_user_cache_range(start, end, flags) + * + * Invalidate a range of cache entries in the specified + * address space. + * + * - start - start address (inclusive, page aligned) + * - end - end address (exclusive, page aligned) + * - flags - vma_area_struct flags describing address space + */ +ENTRY(fa_flush_user_cache_range) + mov ip, #0 + sub r3, r1, r0 @ calculate total size + cmp r3, #CACHE_DLIMIT @ total size >= limit? + bhs __flush_whole_cache @ flush whole D cache + +1: tst r2, #VM_EXEC + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I line + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + blo 1b + tst r2, #VM_EXEC + mcrne p15, 0, ip, c7, c5, 6 @ invalidate BTB + mcrne p15, 0, ip, c7, c10, 4 @ data write barrier + mcrne p15, 0, ip, c7, c5, 4 @ prefetch flush + mov pc, lr + +/* + * coherent_kern_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(fa_coherent_kern_range) + /* fall through */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(fa_coherent_user_range) + bic r0, r0, #CACHE_DLINESIZE - 1 +1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + blo 1b + mov r0, #0 + mcr p15, 0, r0, c7, c5, 6 @ invalidate BTB + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mcr p15, 0, r0, c7, c5, 4 @ prefetch flush + mov pc, lr + +/* + * flush_kern_dcache_page(kaddr) + * + * Ensure that the data held in the page kaddr is written back + * to the page in question. + * + * - kaddr - kernel address (guaranteed to be page aligned) + */ +ENTRY(fa_flush_kern_dcache_page) + add r1, r0, #PAGE_SZ +1: mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + blo 1b + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mov pc, lr + +/* + * dma_inv_range(start, end) + * + * Invalidate (discard) the specified virtual address range. + * May not write back any entries. If 'start' or 'end' + * are not cache line aligned, those lines must be written + * back. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(fa_dma_inv_range) + tst r0, #CACHE_DLINESIZE - 1 + bic r0, r0, #CACHE_DLINESIZE - 1 + mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D entry + tst r1, #CACHE_DLINESIZE - 1 + bic r1, r1, #CACHE_DLINESIZE - 1 + mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D entry +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + blo 1b + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mov pc, lr + +/* + * dma_clean_range(start, end) + * + * Clean (write back) the specified virtual address range. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(fa_dma_clean_range) + bic r0, r0, #CACHE_DLINESIZE - 1 +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + blo 1b + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mov pc, lr + +/* + * dma_flush_range(start,end) + * - start - virtual start address of region + * - end - virtual end address of region + */ +ENTRY(fa_dma_flush_range) + bic r0, r0, #CACHE_DLINESIZE - 1 +1: mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + blo 1b + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mov pc, lr + + __INITDATA + + .type fa_cache_fns, #object +ENTRY(fa_cache_fns) + .long fa_flush_kern_cache_all + .long fa_flush_user_cache_all + .long fa_flush_user_cache_range + .long fa_coherent_kern_range + .long fa_coherent_user_range + .long fa_flush_kern_dcache_page + .long fa_dma_inv_range + .long fa_dma_clean_range + .long fa_dma_flush_range + .size fa_cache_fns, . - fa_cache_fns diff --git a/arch/arm/mm/copypage-fa.c b/arch/arm/mm/copypage-fa.c new file mode 100644 index 000000000000..b2a6008b0111 --- /dev/null +++ b/arch/arm/mm/copypage-fa.c @@ -0,0 +1,86 @@ +/* + * linux/arch/arm/lib/copypage-fa.S + * + * Copyright (C) 2005 Faraday Corp. + * Copyright (C) 2008-2009 Paulius Zaleckas + * + * Based on copypage-v4wb.S: + * Copyright (C) 1995-1999 Russell King + * + * 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 +#include + +/* + * Faraday optimised copy_user_page + */ +static void __naked +fa_copy_user_page(void *kto, const void *kfrom) +{ + asm("\ + stmfd sp!, {r4, lr} @ 2\n\ + mov r2, %0 @ 1\n\ +1: ldmia r1!, {r3, r4, ip, lr} @ 4\n\ + stmia r0, {r3, r4, ip, lr} @ 4\n\ + mcr p15, 0, r0, c7, c14, 1 @ 1 clean and invalidate D line\n\ + add r0, r0, #16 @ 1\n\ + ldmia r1!, {r3, r4, ip, lr} @ 4\n\ + stmia r0, {r3, r4, ip, lr} @ 4\n\ + mcr p15, 0, r0, c7, c14, 1 @ 1 clean and invalidate D line\n\ + add r0, r0, #16 @ 1\n\ + subs r2, r2, #1 @ 1\n\ + bne 1b @ 1\n\ + mcr p15, 0, r2, c7, c10, 4 @ 1 drain WB\n\ + ldmfd sp!, {r4, pc} @ 3" + : + : "I" (PAGE_SIZE / 32)); +} + +void fa_copy_user_highpage(struct page *to, struct page *from, + unsigned long vaddr) +{ + void *kto, *kfrom; + + kto = kmap_atomic(to, KM_USER0); + kfrom = kmap_atomic(from, KM_USER1); + fa_copy_user_page(kto, kfrom); + kunmap_atomic(kfrom, KM_USER1); + kunmap_atomic(kto, KM_USER0); +} + +/* + * Faraday optimised clear_user_page + * + * Same story as above. + */ +void fa_clear_user_highpage(struct page *page, unsigned long vaddr) +{ + void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + asm volatile("\ + mov r1, %2 @ 1\n\ + mov r2, #0 @ 1\n\ + mov r3, #0 @ 1\n\ + mov ip, #0 @ 1\n\ + mov lr, #0 @ 1\n\ +1: stmia %0, {r2, r3, ip, lr} @ 4\n\ + mcr p15, 0, %0, c7, c14, 1 @ 1 clean and invalidate D line\n\ + add %0, %0, #16 @ 1\n\ + stmia %0, {r2, r3, ip, lr} @ 4\n\ + mcr p15, 0, %0, c7, c14, 1 @ 1 clean and invalidate D line\n\ + add %0, %0, #16 @ 1\n\ + subs r1, r1, #1 @ 1\n\ + bne 1b @ 1\n\ + mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB" + : "=r" (ptr) + : "0" (kaddr), "I" (PAGE_SIZE / 32) + : "r1", "r2", "r3", "ip", "lr"); + kunmap_atomic(kaddr, KM_USER0); +} + +struct cpu_user_fns fa_user_fns __initdata = { + .cpu_clear_user_highpage = fa_clear_user_highpage, + .cpu_copy_user_highpage = fa_copy_user_highpage, +}; diff --git a/arch/arm/mm/proc-fa526.S b/arch/arm/mm/proc-fa526.S new file mode 100644 index 000000000000..08b8a955d5d7 --- /dev/null +++ b/arch/arm/mm/proc-fa526.S @@ -0,0 +1,248 @@ +/* + * linux/arch/arm/mm/proc-fa526.S: MMU functions for FA526 + * + * Written by : Luke Lee + * Copyright (C) 2005 Faraday Corp. + * Copyright (C) 2008-2009 Paulius Zaleckas + * + * 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. + * + * + * These are the low level assembler for performing cache and TLB + * functions on the fa526. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "proc-macros.S" + +#define CACHE_DLINESIZE 16 + + .text +/* + * cpu_fa526_proc_init() + */ +ENTRY(cpu_fa526_proc_init) + mov pc, lr + +/* + * cpu_fa526_proc_fin() + */ +ENTRY(cpu_fa526_proc_fin) + stmfd sp!, {lr} + mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE + msr cpsr_c, ip + bl fa_flush_kern_cache_all + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + nop + nop + ldmfd sp!, {pc} + +/* + * cpu_fa526_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + */ + .align 4 +ENTRY(cpu_fa526_reset) +/* TODO: Use CP8 if possible... */ + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches + mcr p15, 0, ip, c7, c10, 4 @ drain WB +#ifdef CONFIG_MMU + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs +#endif + mrc p15, 0, ip, c1, c0, 0 @ ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x1100 @ ...i...s........ + bic ip, ip, #0x0800 @ BTB off + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + nop + nop + mov pc, r0 + +/* + * cpu_fa526_do_idle() + */ + .align 4 +ENTRY(cpu_fa526_do_idle) + mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt + mov pc, lr + + +ENTRY(cpu_fa526_dcache_clean_area) +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #CACHE_DLINESIZE + subs r1, r1, #CACHE_DLINESIZE + bhi 1b + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* =============================== PageTable ============================== */ + +/* + * cpu_fa526_switch_mm(pgd) + * + * Set the translation base pointer to be as described by pgd. + * + * pgd: new page tables + */ + .align 4 +ENTRY(cpu_fa526_switch_mm) +#ifdef CONFIG_MMU + mov ip, #0 +#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache +#else + mcr p15, 0, ip, c7, c14, 0 @ clean and invalidate whole D cache +#endif + mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c5, 6 @ invalidate BTB since mm changed + mcr p15, 0, ip, c7, c10, 4 @ data write barrier + mcr p15, 0, ip, c7, c5, 4 @ prefetch flush + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, ip, c8, c7, 0 @ invalidate UTLB +#endif + mov pc, lr + +/* + * cpu_fa526_set_pte_ext(ptep, pte, ext) + * + * Set a PTE and flush it out + */ + .align 4 +ENTRY(cpu_fa526_set_pte_ext) +#ifdef CONFIG_MMU + armv3_set_pte_ext + mov r0, r0 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB +#endif + mov pc, lr + + __INIT + + .type __fa526_setup, #function +__fa526_setup: + /* On return of this routine, r0 must carry correct flags for CFG register */ + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 +#ifdef CONFIG_MMU + mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 +#endif + mcr p15, 0, r0, c7, c5, 5 @ invalidate IScratchpad RAM + + mov r0, #1 + mcr p15, 0, r0, c1, c1, 0 @ turn-on ECR + + mov r0, #0 + mcr p15, 0, r0, c7, c5, 6 @ invalidate BTB All + mcr p15, 0, r0, c7, c10, 4 @ data write barrier + mcr p15, 0, r0, c7, c5, 4 @ prefetch flush + + mov r0, #0x1f @ Domains 0, 1 = manager, 2 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + + mrc p15, 0, r0, c1, c0 @ get control register v4 + ldr r5, fa526_cr1_clear + bic r0, r0, r5 + ldr r5, fa526_cr1_set + orr r0, r0, r5 + mov pc, lr + .size __fa526_setup, . - __fa526_setup + + /* + * .RVI ZFRS BLDP WCAM + * ..11 1001 .111 1101 + * + */ + .type fa526_cr1_clear, #object + .type fa526_cr1_set, #object +fa526_cr1_clear: + .word 0x3f3f +fa526_cr1_set: + .word 0x397D + + __INITDATA + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type fa526_processor_functions, #object +fa526_processor_functions: + .word v4_early_abort + .word pabort_noifar + .word cpu_fa526_proc_init + .word cpu_fa526_proc_fin + .word cpu_fa526_reset + .word cpu_fa526_do_idle + .word cpu_fa526_dcache_clean_area + .word cpu_fa526_switch_mm + .word cpu_fa526_set_pte_ext + .size fa526_processor_functions, . - fa526_processor_functions + + .section ".rodata" + + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_fa526_name, #object +cpu_fa526_name: + .asciz "FA526" + .size cpu_fa526_name, . - cpu_fa526_name + + .align + + .section ".proc.info.init", #alloc, #execinstr + + .type __fa526_proc_info,#object +__fa526_proc_info: + .long 0x66015261 + .long 0xff01fff1 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_BIT4 | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __fa526_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF + .long cpu_fa526_name + .long fa526_processor_functions + .long fa_tlb_fns + .long fa_user_fns + .long fa_cache_fns + .size __fa526_proc_info, . - __fa526_proc_info diff --git a/arch/arm/mm/tlb-fa.S b/arch/arm/mm/tlb-fa.S new file mode 100644 index 000000000000..9694f1f6f485 --- /dev/null +++ b/arch/arm/mm/tlb-fa.S @@ -0,0 +1,75 @@ +/* + * linux/arch/arm/mm/tlb-fa.S + * + * Copyright (C) 2005 Faraday Corp. + * Copyright (C) 2008-2009 Paulius Zaleckas + * + * Based on tlb-v4wbi.S: + * Copyright (C) 1997-2002 Russell King + * + * 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. + * + * ARM architecture version 4, Faraday variation. + * This assume an unified TLBs, with a write buffer, and branch target buffer (BTB) + * + * Processors: FA520 FA526 FA626 + */ +#include +#include +#include +#include +#include "proc-macros.S" + + +/* + * flush_user_tlb_range(start, end, mm) + * + * Invalidate a range of TLB entries in the specified address space. + * + * - start - range start address + * - end - range end address + * - mm - mm_struct describing address space + */ + .align 4 +ENTRY(fa_flush_user_tlb_range) + vma_vm_mm ip, r2 + act_mm r3 @ get current->active_mm + eors r3, ip, r3 @ == mm ? + movne pc, lr @ no, we dont do anything + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + bic r0, r0, #0x0ff + bic r0, r0, #0xf00 +1: mcr p15, 0, r0, c8, c7, 1 @ invalidate UTLB entry + add r0, r0, #PAGE_SZ + cmp r0, r1 + blo 1b + mcr p15, 0, r3, c7, c5, 6 @ invalidate BTB + mcr p15, 0, r3, c7, c10, 4 @ data write barrier + mov pc, lr + + +ENTRY(fa_flush_kern_tlb_range) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + bic r0, r0, #0x0ff + bic r0, r0, #0xf00 +1: mcr p15, 0, r0, c8, c7, 1 @ invalidate UTLB entry + add r0, r0, #PAGE_SZ + cmp r0, r1 + blo 1b + mcr p15, 0, r3, c7, c5, 6 @ invalidate BTB + mcr p15, 0, r3, c7, c10, 4 @ data write barrier + mcr p15, 0, r3, c7, c5, 4 @ prefetch flush + mov pc, lr + + __INITDATA + + .type fa_tlb_fns, #object +ENTRY(fa_tlb_fns) + .long fa_flush_user_tlb_range + .long fa_flush_kern_tlb_range + .long fa_tlb_flags + .size fa_tlb_fns, . - fa_tlb_fns -- cgit v1.2.3-55-g7522 From f0bba9f934517533acbda7329be93f55d5a01c03 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Sat, 28 Mar 2009 19:18:05 +0100 Subject: [ARM] 5435/1: fix compile warning in sanity_check_meminfo() Compiling recent 2.6.29-rc kernels for ARM gives me the following warning: arch/arm/mm/mmu.c: In function 'sanity_check_meminfo': arch/arm/mm/mmu.c:697: warning: comparison between pointer and integer This is because commit 3fd9825c42c784a59b3b90bdf073f49d4bb42a8d "[ARM] 5402/1: fix a case of wrap-around in sanity_check_meminfo()" in 2.6.29-rc5-git4 added a comparison of a pointer with PAGE_OFFSET, which is an integer. Fixed by casting PAGE_OFFSET to void *. Signed-off-by: Mikael Pettersson Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/mm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mm') diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index d4d082c5c2d4..5a89e57e342d 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -694,7 +694,7 @@ static void __init sanity_check_meminfo(void) * the vmalloc area. */ if (__va(bank->start) >= VMALLOC_MIN || - __va(bank->start) < PAGE_OFFSET) { + __va(bank->start) < (void *)PAGE_OFFSET) { printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx " "(vmalloc region overlap).\n", bank->start, bank->start + bank->size - 1); -- cgit v1.2.3-55-g7522