From 1996bda2a42480c275656233e631ee0966574be4 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 21 May 2010 14:05:13 +0200 Subject: arch: Implement local64_t On 64bit, local_t is of size long, and thus we make local64_t an alias. On 32bit, we fall back to atomic64_t. (architecture can provide optimized 32-bit version) (This new facility is to be used by perf events optimizations.) Signed-off-by: Peter Zijlstra Cc: linux-arch@vger.kernel.org Cc: Andrew Morton Cc: Linus Torvalds LKML-Reference: Signed-off-by: Ingo Molnar --- arch/mips/include/asm/local64.h | 1 + 1 file changed, 1 insertion(+) create mode 100644 arch/mips/include/asm/local64.h (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/local64.h b/arch/mips/include/asm/local64.h new file mode 100644 index 00000000000..36c93b5cc23 --- /dev/null +++ b/arch/mips/include/asm/local64.h @@ -0,0 +1 @@ +#include -- cgit v1.2.3-70-g09d2 From 40cb989fcf9f0caf6a116562132c2fffed38d261 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 18 May 2010 00:38:05 +0900 Subject: MIPS: TX49xx: Define ARCH_KMALLOC_MINALIGN With SLAB, it works without ARCH_KMALLOC_MINALIGN, but with SLOB/SLUB, ARCH_KMALLOC_MINALIGN is required to ensure alignment of kmalloced buffer. Signed-off-by: Atsushi Nemoto To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1248/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-tx49xx/kmalloc.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-tx49xx/kmalloc.h b/arch/mips/include/asm/mach-tx49xx/kmalloc.h index 913ff196259..b74caf65482 100644 --- a/arch/mips/include/asm/mach-tx49xx/kmalloc.h +++ b/arch/mips/include/asm/mach-tx49xx/kmalloc.h @@ -1,8 +1,6 @@ #ifndef __ASM_MACH_TX49XX_KMALLOC_H #define __ASM_MACH_TX49XX_KMALLOC_H -/* - * All happy, no need to define ARCH_KMALLOC_MINALIGN - */ +#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES #endif /* __ASM_MACH_TX49XX_KMALLOC_H */ -- cgit v1.2.3-70-g09d2 From 6165df980801e1be7a5b65686bd52f55e0407db1 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 20 May 2010 19:15:17 +0100 Subject: MIPS: IP27: Don't include into . The include is unecessary and will when building the IP35 result in recursive header inclusion spaghetti. Signed-off-by: Ralf Baechle --- arch/mips/include/asm/sn/agent.h | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/sn/agent.h b/arch/mips/include/asm/sn/agent.h index ac4ea85c3a5..dc81114d474 100644 --- a/arch/mips/include/asm/sn/agent.h +++ b/arch/mips/include/asm/sn/agent.h @@ -11,7 +11,6 @@ #ifndef _ASM_SGI_SN_AGENT_H #define _ASM_SGI_SN_AGENT_H -#include #include #include -- cgit v1.2.3-70-g09d2 From ca36c36b7821b573fe06ce6bc34db03b557f3ce4 Mon Sep 17 00:00:00 2001 From: David VomLehn Date: Fri, 21 May 2010 11:25:36 -0700 Subject: MIPS: PowerTV: Use O(1) algorthm for phys_to_dma/dma_to_phys Replace phys_to_dma()/dma_to_phys() looping algorithm with an O(1) algorithm The approach taken is inspired by the sparse memory implementation: take a certain number of high-order bits off the address them, use this as an index into a table containing an offset to the desired address and add it to the original value. There is a table for mapping physical addresses to DMA addresses and another one for the reverse mapping. The table sizes depend on how fine-grained the mappings need to be; Coarser granularity less to smaller tables. On a processor with 32-bit physical and DMA addresses, with 4 MIB granularity, memory usage is two 2048-byte arrays. Each 32-byte cache line thus covers 64 MiB of address space. Also, renames phys_to_bus() to phys_to_dma() and bus_to_phys() to dma_to_phys() to align with kernel usage. [Ralf: Fixed silly build breakage due to stackoverflow warning caused by huge array on stack.] Signed-off-by: David VomLehn To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1257/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-powertv/dma-coherence.h | 8 +- arch/mips/include/asm/mach-powertv/ioremap.h | 165 +++++++--- arch/mips/powertv/Makefile | 3 +- arch/mips/powertv/asic/asic_devices.c | 18 +- arch/mips/powertv/ioremap.c | 136 ++++++++ arch/mips/powertv/memory.c | 341 ++++++++++++++++----- 6 files changed, 529 insertions(+), 142 deletions(-) create mode 100644 arch/mips/powertv/ioremap.c (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-powertv/dma-coherence.h b/arch/mips/include/asm/mach-powertv/dma-coherence.h index 5b8d5ebeb83..f76029c2406 100644 --- a/arch/mips/include/asm/mach-powertv/dma-coherence.h +++ b/arch/mips/include/asm/mach-powertv/dma-coherence.h @@ -65,21 +65,21 @@ static inline dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size) { if (is_kseg2(addr)) - return phys_to_bus(virt_to_phys_from_pte(addr)); + return phys_to_dma(virt_to_phys_from_pte(addr)); else - return phys_to_bus(virt_to_phys(addr)); + return phys_to_dma(virt_to_phys(addr)); } static inline dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page) { - return phys_to_bus(page_to_phys(page)); + return phys_to_dma(page_to_phys(page)); } static inline unsigned long plat_dma_addr_to_phys(struct device *dev, dma_addr_t dma_addr) { - return bus_to_phys(dma_addr); + return dma_to_phys(dma_addr); } static inline void plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr, diff --git a/arch/mips/include/asm/mach-powertv/ioremap.h b/arch/mips/include/asm/mach-powertv/ioremap.h index e6276d5146e..076f2eeaa57 100644 --- a/arch/mips/include/asm/mach-powertv/ioremap.h +++ b/arch/mips/include/asm/mach-powertv/ioremap.h @@ -10,64 +10,101 @@ #define __ASM_MACH_POWERTV_IOREMAP_H #include +#include +#include -#define LOW_MEM_BOUNDARY_PHYS 0x20000000 -#define LOW_MEM_BOUNDARY_MASK (~(LOW_MEM_BOUNDARY_PHYS - 1)) +#include +#include + +/* We're going to mess with bits, so get sizes */ +#define IOR_BPC 8 /* Bits per char */ +#define IOR_PHYS_BITS (IOR_BPC * sizeof(phys_addr_t)) +#define IOR_DMA_BITS (IOR_BPC * sizeof(dma_addr_t)) /* - * The bus addresses are different than the physical addresses that - * the processor sees by an offset. This offset varies by ASIC - * version. Define a variable to hold the offset and some macros to - * make the conversion simpler. */ -extern unsigned long phys_to_bus_offset; - -#ifdef CONFIG_HIGHMEM -#define MEM_GAP_PHYS 0x60000000 + * Define the granularity of physical/DMA mapping in terms of the number + * of bits that defines the offset within a grain. These will be the + * least significant bits of the address. The rest of a physical or DMA + * address will be used to index into an appropriate table to find the + * offset to add to the address to yield the corresponding DMA or physical + * address, respectively. + */ +#define IOR_LSBITS 22 /* Bits in a grain */ + /* - * TODO: We will use the hard code for conversion between physical and - * bus until the bootloader releases their device tree to us. + * Compute the number of most significant address bits after removing those + * used for the offset within a grain and then compute the number of table + * entries for the conversion. */ -#define phys_to_bus(x) (((x) < LOW_MEM_BOUNDARY_PHYS) ? \ - ((x) + phys_to_bus_offset) : (x)) -#define bus_to_phys(x) (((x) < MEM_GAP_PHYS_ADDR) ? \ - ((x) - phys_to_bus_offset) : (x)) -#else -#define phys_to_bus(x) ((x) + phys_to_bus_offset) -#define bus_to_phys(x) ((x) - phys_to_bus_offset) -#endif +#define IOR_PHYS_MSBITS (IOR_PHYS_BITS - IOR_LSBITS) +#define IOR_NUM_PHYS_TO_DMA ((phys_addr_t) 1 << IOR_PHYS_MSBITS) + +#define IOR_DMA_MSBITS (IOR_DMA_BITS - IOR_LSBITS) +#define IOR_NUM_DMA_TO_PHYS ((dma_addr_t) 1 << IOR_DMA_MSBITS) /* - * Determine whether the address we are given is for an ASIC device - * Params: addr Address to check - * Returns: Zero if the address is not for ASIC devices, non-zero - * if it is. + * Define data structures used as elements in the arrays for the conversion + * between physical and DMA addresses. We do some slightly fancy math to + * compute the width of the offset element of the conversion tables so + * that we can have the smallest conversion tables. Next, round up the + * sizes to the next higher power of two, i.e. the offset element will have + * 8, 16, 32, 64, etc. bits. This eliminates the need to mask off any + * bits. Finally, we compute a shift value that puts the most significant + * bits of the offset into the most significant bits of the offset element. + * This makes it more efficient on processors without barrel shifters and + * easier to see the values if the conversion table is dumped in binary. */ -static inline int asic_is_device_addr(phys_t addr) +#define _IOR_OFFSET_WIDTH(n) (1 << order_base_2(n)) +#define IOR_OFFSET_WIDTH(n) \ + (_IOR_OFFSET_WIDTH(n) < 8 ? 8 : _IOR_OFFSET_WIDTH(n)) + +#define IOR_PHYS_OFFSET_BITS IOR_OFFSET_WIDTH(IOR_PHYS_MSBITS) +#define IOR_PHYS_SHIFT (IOR_PHYS_BITS - IOR_PHYS_OFFSET_BITS) + +#define IOR_DMA_OFFSET_BITS IOR_OFFSET_WIDTH(IOR_DMA_MSBITS) +#define IOR_DMA_SHIFT (IOR_DMA_BITS - IOR_DMA_OFFSET_BITS) + +struct ior_phys_to_dma { + dma_addr_t offset:IOR_DMA_OFFSET_BITS __packed + __aligned((IOR_DMA_OFFSET_BITS / IOR_BPC)); +}; + +struct ior_dma_to_phys { + dma_addr_t offset:IOR_PHYS_OFFSET_BITS __packed + __aligned((IOR_PHYS_OFFSET_BITS / IOR_BPC)); +}; + +extern struct ior_phys_to_dma _ior_phys_to_dma[IOR_NUM_PHYS_TO_DMA]; +extern struct ior_dma_to_phys _ior_dma_to_phys[IOR_NUM_DMA_TO_PHYS]; + +static inline dma_addr_t _phys_to_dma_offset_raw(phys_addr_t phys) { - return !((phys_t)addr & (phys_t) LOW_MEM_BOUNDARY_MASK); + return (dma_addr_t)_ior_phys_to_dma[phys >> IOR_LSBITS].offset; } -/* - * Determine whether the address we are given is external RAM mappable - * into KSEG1. - * Params: addr Address to check - * Returns: Zero if the address is not for external RAM and - */ -static inline int asic_is_lowmem_ram_addr(phys_t addr) +static inline dma_addr_t _dma_to_phys_offset_raw(dma_addr_t dma) { - /* - * The RAM always starts at the following address in the processor's - * physical address space - */ - static const phys_t phys_ram_base = 0x10000000; - phys_t bus_ram_base; + return (dma_addr_t)_ior_dma_to_phys[dma >> IOR_LSBITS].offset; +} - bus_ram_base = phys_to_bus_offset + phys_ram_base; +/* These are not portable and should not be used in drivers. Drivers should + * be using ioremap() and friends to map physical addreses to virtual + * addresses and dma_map*() and friends to map virtual addresses into DMA + * addresses and back. + */ +static inline dma_addr_t phys_to_dma(phys_addr_t phys) +{ + return phys + (_phys_to_dma_offset_raw(phys) << IOR_PHYS_SHIFT); +} - return addr >= bus_ram_base && - addr < (bus_ram_base + (LOW_MEM_BOUNDARY_PHYS - phys_ram_base)); +static inline phys_addr_t dma_to_phys(dma_addr_t dma) +{ + return dma + (_dma_to_phys_offset_raw(dma) << IOR_DMA_SHIFT); } +extern void ioremap_add_map(dma_addr_t phys, phys_addr_t alias, + dma_addr_t size); + /* * Allow physical addresses to be fixed up to help peripherals located * outside the low 32-bit range -- generic pass-through version. @@ -77,10 +114,50 @@ static inline phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size) return phys_addr; } -static inline void __iomem *plat_ioremap(phys_t offset, unsigned long size, +/* + * Handle the special case of addresses the area aliased into the first + * 512 MiB of the processor's physical address space. These turn into either + * kseg0 or kseg1 addresses, depending on flags. + */ +static inline void __iomem *plat_ioremap(phys_t start, unsigned long size, unsigned long flags) { - return NULL; + phys_addr_t start_offset; + void __iomem *result = NULL; + + /* Start by checking to see whether this is an aliased address */ + start_offset = _dma_to_phys_offset_raw(start); + + /* + * If: + * o the memory is aliased into the first 512 MiB, and + * o the start and end are in the same RAM bank, and + * o we don't have a zero size or wrap around, and + * o we are supposed to create an uncached mapping, + * handle this is a kseg0 or kseg1 address + */ + if (start_offset != 0) { + phys_addr_t last; + dma_addr_t dma_to_phys_offset; + + last = start + size - 1; + dma_to_phys_offset = + _dma_to_phys_offset_raw(last) << IOR_DMA_SHIFT; + + if (dma_to_phys_offset == start_offset && + size != 0 && start <= last) { + phys_t adjusted_start; + adjusted_start = start + start_offset; + if (flags == _CACHE_UNCACHED) + result = (void __iomem *) (unsigned long) + CKSEG1ADDR(adjusted_start); + else + result = (void __iomem *) (unsigned long) + CKSEG0ADDR(adjusted_start); + } + } + + return result; } static inline int plat_iounmap(const volatile void __iomem *addr) diff --git a/arch/mips/powertv/Makefile b/arch/mips/powertv/Makefile index 0a0d73c0564..e9fe1c6efe1 100644 --- a/arch/mips/powertv/Makefile +++ b/arch/mips/powertv/Makefile @@ -23,6 +23,7 @@ # under Linux. # -obj-y += init.o memory.o reset.o time.o powertv_setup.o asic/ pci/ +obj-y += init.o ioremap.o memory.o powertv_setup.o reset.o time.o \ + asic/ pci/ EXTRA_CFLAGS += -Wall -Werror diff --git a/arch/mips/powertv/asic/asic_devices.c b/arch/mips/powertv/asic/asic_devices.c index 9ec523e4dd0..c81dd497ed7 100644 --- a/arch/mips/powertv/asic/asic_devices.c +++ b/arch/mips/powertv/asic/asic_devices.c @@ -80,8 +80,8 @@ static bool usb_configured; * Don't recommend to use it directly, it is usually used by kernel internally. * Portable code should be using interfaces such as ioremp, dma_map_single, etc. */ -unsigned long phys_to_bus_offset; -EXPORT_SYMBOL(phys_to_bus_offset); +unsigned long phys_to_dma_offset; +EXPORT_SYMBOL(phys_to_dma_offset); /* * @@ -533,10 +533,10 @@ void __init configure_platform(void) switch (asic) { case ASIC_ZEUS: - phys_to_bus_offset = 0x30000000; + phys_to_dma_offset = 0x30000000; break; case ASIC_CALLIOPE: - phys_to_bus_offset = 0x10000000; + phys_to_dma_offset = 0x10000000; break; case ASIC_CRONUSLITE: /* Fall through */ @@ -546,10 +546,10 @@ void __init configure_platform(void) * 0x2XXXXXXX. If 0x10000000 aliases into 0x60000000- * 0x6XXXXXXX, the offset should be 0x50000000, not 0x10000000. */ - phys_to_bus_offset = 0x10000000; + phys_to_dma_offset = 0x10000000; break; default: - phys_to_bus_offset = 0x00000000; + phys_to_dma_offset = 0x00000000; break; } } @@ -603,7 +603,7 @@ void __init platform_alloc_bootmem(void) int size = gp_resources[i].end - gp_resources[i].start + 1; if ((gp_resources[i].start != 0) && ((gp_resources[i].flags & IORESOURCE_MEM) != 0)) { - reserve_bootmem(bus_to_phys(gp_resources[i].start), + reserve_bootmem(dma_to_phys(gp_resources[i].start), size, 0); total += gp_resources[i].end - gp_resources[i].start + 1; @@ -627,7 +627,7 @@ void __init platform_alloc_bootmem(void) else { gp_resources[i].start = - phys_to_bus(virt_to_phys(mem)); + phys_to_dma(virt_to_phys(mem)); gp_resources[i].end = gp_resources[i].start + size - 1; total += size; @@ -691,7 +691,7 @@ static void __init pmem_setup_resource(void) if (resource && pmemaddr && pmemlen) { /* The address provided by bootloader is in kseg0. Convert to * a bus address. */ - resource->start = phys_to_bus(pmemaddr - 0x80000000); + resource->start = phys_to_dma(pmemaddr - 0x80000000); resource->end = resource->start + pmemlen - 1; pr_info("persistent memory: start=0x%x end=0x%x\n", diff --git a/arch/mips/powertv/ioremap.c b/arch/mips/powertv/ioremap.c new file mode 100644 index 00000000000..a77c6f62fe2 --- /dev/null +++ b/arch/mips/powertv/ioremap.c @@ -0,0 +1,136 @@ +/* + * ioremap.c + * + * Support for mapping between dma_addr_t values a phys_addr_t values. + * + * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: David VomLehn + * + * Description: Defines the platform resources for the SA settop. + * + * NOTE: The bootloader allocates persistent memory at an address which is + * 16 MiB below the end of the highest address in KSEG0. All fixed + * address memory reservations must avoid this region. + */ + +#include +#include + +#include + +/* + * Define the sizes of and masks for grains in physical and DMA space. The + * values are the same but the types are not. + */ +#define IOR_PHYS_GRAIN ((phys_addr_t) 1 << IOR_LSBITS) +#define IOR_PHYS_GRAIN_MASK (IOR_PHYS_GRAIN - 1) + +#define IOR_DMA_GRAIN ((dma_addr_t) 1 << IOR_LSBITS) +#define IOR_DMA_GRAIN_MASK (IOR_DMA_GRAIN - 1) + +/* + * Values that, when accessed by an index derived from a phys_addr_t and + * added to phys_addr_t value, yield a DMA address + */ +struct ior_phys_to_dma _ior_phys_to_dma[IOR_NUM_PHYS_TO_DMA]; +EXPORT_SYMBOL(_ior_phys_to_dma); + +/* + * Values that, when accessed by an index derived from a dma_addr_t and + * added to that dma_addr_t value, yield a physical address + */ +struct ior_dma_to_phys _ior_dma_to_phys[IOR_NUM_DMA_TO_PHYS]; +EXPORT_SYMBOL(_ior_dma_to_phys); + +/** + * setup_dma_to_phys - set up conversion from DMA to physical addresses + * @dma_idx: Top IOR_LSBITS bits of the DMA address, i.e. an index + * into the array _dma_to_phys. + * @delta: Value that, when added to the DMA address, will yield the + * physical address + * @s: Number of bytes in the section of memory with the given delta + * between DMA and physical addresses. + */ +static void setup_dma_to_phys(dma_addr_t dma, phys_addr_t delta, dma_addr_t s) +{ + int dma_idx, first_idx, last_idx; + phys_addr_t first, last; + + /* + * Calculate the first and last indices, rounding the first up and + * the second down. + */ + first = dma & ~IOR_DMA_GRAIN_MASK; + last = (dma + s - 1) & ~IOR_DMA_GRAIN_MASK; + first_idx = first >> IOR_LSBITS; /* Convert to indices */ + last_idx = last >> IOR_LSBITS; + + for (dma_idx = first_idx; dma_idx <= last_idx; dma_idx++) + _ior_dma_to_phys[dma_idx].offset = delta >> IOR_DMA_SHIFT; +} + +/** + * setup_phys_to_dma - set up conversion from DMA to physical addresses + * @phys_idx: Top IOR_LSBITS bits of the DMA address, i.e. an index + * into the array _phys_to_dma. + * @delta: Value that, when added to the DMA address, will yield the + * physical address + * @s: Number of bytes in the section of memory with the given delta + * between DMA and physical addresses. + */ +static void setup_phys_to_dma(phys_addr_t phys, dma_addr_t delta, phys_addr_t s) +{ + int phys_idx, first_idx, last_idx; + phys_addr_t first, last; + + /* + * Calculate the first and last indices, rounding the first up and + * the second down. + */ + first = phys & ~IOR_PHYS_GRAIN_MASK; + last = (phys + s - 1) & ~IOR_PHYS_GRAIN_MASK; + first_idx = first >> IOR_LSBITS; /* Convert to indices */ + last_idx = last >> IOR_LSBITS; + + for (phys_idx = first_idx; phys_idx <= last_idx; phys_idx++) + _ior_phys_to_dma[phys_idx].offset = delta >> IOR_PHYS_SHIFT; +} + +/** + * ioremap_add_map - add to the physical and DMA address conversion arrays + * @phys: Process's view of the address of the start of the memory chunk + * @dma: DMA address of the start of the memory chunk + * @size: Size, in bytes, of the chunk of memory + * + * NOTE: It might be obvious, but the assumption is that all @size bytes have + * the same offset between the physical address and the DMA address. + */ +void ioremap_add_map(phys_addr_t phys, phys_addr_t dma, phys_addr_t size) +{ + if (size == 0) + return; + + if ((dma & IOR_DMA_GRAIN_MASK) != 0 || + (phys & IOR_PHYS_GRAIN_MASK) != 0 || + (size & IOR_PHYS_GRAIN_MASK) != 0) + pr_crit("Memory allocation must be in chunks of 0x%x bytes\n", + IOR_PHYS_GRAIN); + + setup_dma_to_phys(dma, phys - dma, size); + setup_phys_to_dma(phys, dma - phys, size); +} diff --git a/arch/mips/powertv/memory.c b/arch/mips/powertv/memory.c index f49eb3d0358..73880ad29bc 100644 --- a/arch/mips/powertv/memory.c +++ b/arch/mips/powertv/memory.c @@ -30,28 +30,141 @@ #include #include +#include +#include #include "init.h" /* Memory constants */ #define KIBIBYTE(n) ((n) * 1024) /* Number of kibibytes */ #define MEBIBYTE(n) ((n) * KIBIBYTE(1024)) /* Number of mebibytes */ -#define DEFAULT_MEMSIZE MEBIBYTE(256) /* If no memsize provided */ -#define LOW_MEM_MAX MEBIBYTE(252) /* Max usable low mem */ -#define RES_BOOTLDR_MEMSIZE MEBIBYTE(1) /* Memory reserved for bldr */ -#define BOOT_MEM_SIZE KIBIBYTE(256) /* Memory reserved for bldr */ -#define PHYS_MEM_START 0x10000000 /* Start of physical memory */ +#define DEFAULT_MEMSIZE MEBIBYTE(128) /* If no memsize provided */ -char __initdata cmdline[COMMAND_LINE_SIZE]; +#define BLDR_SIZE KIBIBYTE(256) /* Memory reserved for bldr */ +#define RV_SIZE MEBIBYTE(4) /* Size of reset vector */ -void __init prom_meminit(void) +#define LOW_MEM_END 0x20000000 /* Highest low memory address */ +#define BLDR_ALIAS 0x10000000 /* Bootloader address */ +#define RV_PHYS 0x1fc00000 /* Reset vector address */ +#define LOW_RAM_END RV_PHYS /* End of real RAM in low mem */ + +/* + * Very low-level conversion from processor physical address to device + * DMA address for the first bank of memory. + */ +#define PHYS_TO_DMA(paddr) ((paddr) + (CONFIG_LOW_RAM_DMA - LOW_RAM_ALIAS)) + +unsigned long ptv_memsize; + +/* + * struct low_mem_reserved - Items in low memmory that are reserved + * @start: Physical address of item + * @size: Size, in bytes, of this item + * @is_aliased: True if this is RAM aliased from another location. If false, + * it is something other than aliased RAM and the RAM in the + * unaliased address is still visible outside of low memory. + */ +struct low_mem_reserved { + phys_addr_t start; + phys_addr_t size; + bool is_aliased; +}; + +/* + * Must be in ascending address order + */ +struct low_mem_reserved low_mem_reserved[] = { + {BLDR_ALIAS, BLDR_SIZE, true}, /* Bootloader RAM */ + {RV_PHYS, RV_SIZE, false}, /* Reset vector */ +}; + +/* + * struct mem_layout - layout of a piece of the system RAM + * @phys: Physical address of the start of this piece of RAM. This is the + * address at which both the processor and I/O devices see the + * RAM. + * @alias: Alias of this piece of memory in order to make it appear in + * the low memory part of the processor's address space. I/O + * devices don't see anything here. + * @size: Size, in bytes, of this piece of RAM + */ +struct mem_layout { + phys_addr_t phys; + phys_addr_t alias; + phys_addr_t size; +}; + +/* + * struct mem_layout_list - list descriptor for layouts of system RAM pieces + * @family: Specifies the family being described + * @n: Number of &struct mem_layout elements + * @layout: Pointer to the list of &mem_layout structures + */ +struct mem_layout_list { + enum family_type family; + size_t n; + struct mem_layout *layout; +}; + +static struct mem_layout f1500_layout[] = { + {0x20000000, 0x10000000, MEBIBYTE(256)}, +}; + +static struct mem_layout f4500_layout[] = { + {0x40000000, 0x10000000, MEBIBYTE(256)}, + {0x20000000, 0x20000000, MEBIBYTE(32)}, +}; + +static struct mem_layout f8500_layout[] = { + {0x40000000, 0x10000000, MEBIBYTE(256)}, + {0x20000000, 0x20000000, MEBIBYTE(32)}, + {0x30000000, 0x30000000, MEBIBYTE(32)}, +}; + +static struct mem_layout fx600_layout[] = { + {0x20000000, 0x10000000, MEBIBYTE(256)}, + {0x60000000, 0x60000000, MEBIBYTE(128)}, +}; + +static struct mem_layout_list layout_list[] = { + {FAMILY_1500, ARRAY_SIZE(f1500_layout), f1500_layout}, + {FAMILY_1500VZE, ARRAY_SIZE(f1500_layout), f1500_layout}, + {FAMILY_1500VZF, ARRAY_SIZE(f1500_layout), f1500_layout}, + {FAMILY_4500, ARRAY_SIZE(f4500_layout), f4500_layout}, + {FAMILY_8500, ARRAY_SIZE(f8500_layout), f8500_layout}, + {FAMILY_8500RNG, ARRAY_SIZE(f8500_layout), f8500_layout}, + {FAMILY_4600, ARRAY_SIZE(fx600_layout), fx600_layout}, + {FAMILY_4600VZA, ARRAY_SIZE(fx600_layout), fx600_layout}, + {FAMILY_8600, ARRAY_SIZE(fx600_layout), fx600_layout}, + {FAMILY_8600VZB, ARRAY_SIZE(fx600_layout), fx600_layout}, +}; + +/* If we can't determine the layout, use this */ +static struct mem_layout default_layout[] = { + {0x20000000, 0x10000000, MEBIBYTE(128)}, +}; + +/** + * register_non_ram - register low memory not available for RAM usage + */ +static __init void register_non_ram(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(low_mem_reserved); i++) + add_memory_region(low_mem_reserved[i].start, + low_mem_reserved[i].size, BOOT_MEM_RESERVED); +} + +/** + * get_memsize - get the size of memory as a single bank + */ +static phys_addr_t get_memsize(void) { + static char cmdline[COMMAND_LINE_SIZE] __initdata; + phys_addr_t memsize = 0; char *memsize_str; - unsigned long memsize = 0; - unsigned int physend; char *ptr; - int low_mem; - int high_mem; /* Check the command line first for a memsize directive */ strcpy(cmdline, arcs_cmdline); @@ -73,96 +186,156 @@ void __init prom_meminit(void) if (memsize == 0) { if (_prom_memsize != 0) { memsize = _prom_memsize; - pr_info("_prom_memsize = 0x%lx\n", memsize); + pr_info("_prom_memsize = 0x%x\n", memsize); /* add in memory that the bootloader doesn't * report */ - memsize += BOOT_MEM_SIZE; + memsize += BLDR_SIZE; } else { memsize = DEFAULT_MEMSIZE; pr_info("Memsize not passed by bootloader, " - "defaulting to 0x%lx\n", memsize); + "defaulting to 0x%x\n", memsize); } } } - physend = PFN_ALIGN(&_end) - 0x80000000; - if (memsize > LOW_MEM_MAX) { - low_mem = LOW_MEM_MAX; - high_mem = memsize - low_mem; - } else { - low_mem = memsize; - high_mem = 0; + return memsize; +} + +/** + * register_low_ram - register an aliased section of RAM + * @p: Alias address of memory + * @n: Number of bytes in this section of memory + * + * Returns the number of bytes registered + * + */ +static __init phys_addr_t register_low_ram(phys_addr_t p, phys_addr_t n) +{ + phys_addr_t s; + int i; + phys_addr_t orig_n; + + orig_n = n; + + BUG_ON(p + n > RV_PHYS); + + for (i = 0; n != 0 && i < ARRAY_SIZE(low_mem_reserved); i++) { + phys_addr_t start; + phys_addr_t size; + + start = low_mem_reserved[i].start; + size = low_mem_reserved[i].size; + + /* Handle memory before this low memory section */ + if (p < start) { + phys_addr_t s; + s = min(n, start - p); + add_memory_region(p, s, BOOT_MEM_RAM); + p += s; + n -= s; + } + + /* Handle the low memory section itself. If it's aliased, + * we reduce the number of byes left, but if not, the RAM + * is available elsewhere and we don't reduce the number of + * bytes remaining. */ + if (p == start) { + if (low_mem_reserved[i].is_aliased) { + s = min(n, size); + n -= s; + p += s; + } else + p += n; + } } + return orig_n - n; +} + /* - * TODO: We will use the hard code for memory configuration until - * the bootloader releases their device tree to us. + * register_ram - register real RAM + * @p: Address of memory as seen by devices + * @alias: If the memory is seen at an additional address by the processor, + * this will be the address, otherwise it is the same as @p. + * @n: Number of bytes in this section of memory */ +static __init void register_ram(phys_addr_t p, phys_addr_t alias, + phys_addr_t n) +{ /* - * Add the memory reserved for use by the bootloader to the - * memory map. - */ - add_memory_region(PHYS_MEM_START, RES_BOOTLDR_MEMSIZE, - BOOT_MEM_RESERVED); -#ifdef CONFIG_HIGHMEM_256_128 - /* - * Add memory in low for general use by the kernel and its friends - * (like drivers, applications, etc). - */ - add_memory_region(PHYS_MEM_START + RES_BOOTLDR_MEMSIZE, - LOW_MEM_MAX - RES_BOOTLDR_MEMSIZE, BOOT_MEM_RAM); - /* - * Add the memory reserved for reset vector. - */ - add_memory_region(0x1fc00000, MEBIBYTE(4), BOOT_MEM_RESERVED); - /* - * Add the memory reserved. - */ - add_memory_region(0x20000000, MEBIBYTE(1024 + 75), BOOT_MEM_RESERVED); - /* - * Add memory in high for general use by the kernel and its friends - * (like drivers, applications, etc). - * - * 75MB is reserved for devices which are using the memory in high. - */ - add_memory_region(0x60000000 + MEBIBYTE(75), MEBIBYTE(128 - 75), - BOOT_MEM_RAM); -#elif defined CONFIG_HIGHMEM_128_128 - /* - * Add memory in low for general use by the kernel and its friends - * (like drivers, applications, etc). - */ - add_memory_region(PHYS_MEM_START + RES_BOOTLDR_MEMSIZE, - MEBIBYTE(128) - RES_BOOTLDR_MEMSIZE, BOOT_MEM_RAM); - /* - * Add the memory reserved. - */ - add_memory_region(PHYS_MEM_START + MEBIBYTE(128), - MEBIBYTE(128 + 1024 + 75), BOOT_MEM_RESERVED); - /* - * Add memory in high for general use by the kernel and its friends - * (like drivers, applications, etc). - * - * 75MB is reserved for devices which are using the memory in high. - */ - add_memory_region(0x60000000 + MEBIBYTE(75), MEBIBYTE(128 - 75), - BOOT_MEM_RAM); -#else - /* Add low memory regions for either: - * - no-highmemory configuration case -OR- - * - highmemory "HIGHMEM_LOWBANK_ONLY" case - */ - /* - * Add memory for general use by the kernel and its friends - * (like drivers, applications, etc). + * If some or all of this memory has an alias, break it into the + * aliased and non-aliased portion. */ - add_memory_region(PHYS_MEM_START + RES_BOOTLDR_MEMSIZE, - low_mem - RES_BOOTLDR_MEMSIZE, BOOT_MEM_RAM); + if (p != alias) { + phys_addr_t alias_size; + phys_addr_t registered; + + alias_size = min(n, LOW_RAM_END - alias); + registered = register_low_ram(alias, alias_size); + ioremap_add_map(alias, p, n); + n -= registered; + p += registered; + } + +#ifdef CONFIG_HIGHMEM + if (n != 0) { + add_memory_region(p, n, BOOT_MEM_RAM); + ioremap_add_map(p, p, n); + } +#endif +} + +/** + * register_address_space - register things in the address space + * @memsize: Number of bytes of RAM installed + * + * Takes the given number of bytes of RAM and registers as many of the regions, + * or partial regions, as it can. So, the default configuration might have + * two regions with 256 MiB each. If the memsize passed in on the command line + * is 384 MiB, it will register the first region with 256 MiB and the second + * with 128 MiB. + */ +static __init void register_address_space(phys_addr_t memsize) +{ + int i; + phys_addr_t size; + size_t n; + struct mem_layout *layout; + enum family_type family; + /* - * Add the memory reserved for reset vector. + * Register all of the things that aren't available to the kernel as + * memory. */ - add_memory_region(0x1fc00000, MEBIBYTE(4), BOOT_MEM_RESERVED); -#endif + register_non_ram(); + + /* Find the appropriate memory description */ + family = platform_get_family(); + + for (i = 0; i < ARRAY_SIZE(layout_list); i++) { + if (layout_list[i].family == family) + break; + } + + if (i == ARRAY_SIZE(layout_list)) { + n = ARRAY_SIZE(default_layout); + layout = default_layout; + } else { + n = layout_list[i].n; + layout = layout_list[i].layout; + } + + for (i = 0; memsize != 0 && i < n; i++) { + size = min(memsize, layout[i].size); + register_ram(layout[i].phys, layout[i].alias, size); + memsize -= size; + } +} + +void __init prom_meminit(void) +{ + ptv_memsize = get_memsize(); + register_address_space(ptv_memsize); } void __init prom_free_prom_memory(void) -- cgit v1.2.3-70-g09d2 From 339e658b88108d4bc7daf61736df494dcf4a43e4 Mon Sep 17 00:00:00 2001 From: David VomLehn Date: Fri, 21 May 2010 11:25:59 -0700 Subject: MIPS: PowerTV: Correct ASIC device register names and locations Correct ASIC device register names and addresses for USB devices. Signed-off-by: David VomLehn To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1258/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-powertv/asic_reg_map.h | 2 +- arch/mips/powertv/asic/asic-calliope.c | 2 +- arch/mips/powertv/asic/asic-cronus.c | 4 ++-- arch/mips/powertv/asic/asic-zeus.c | 2 +- arch/mips/powertv/asic/asic_devices.c | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-powertv/asic_reg_map.h b/arch/mips/include/asm/mach-powertv/asic_reg_map.h index 6f26cb09828..20348e817b0 100644 --- a/arch/mips/include/asm/mach-powertv/asic_reg_map.h +++ b/arch/mips/include/asm/mach-powertv/asic_reg_map.h @@ -64,7 +64,7 @@ REGISTER_MAP_ELEMENT(int_level_0_1) REGISTER_MAP_ELEMENT(int_level_0_0) REGISTER_MAP_ELEMENT(int_docsis_en) REGISTER_MAP_ELEMENT(mips_pll_setup) -REGISTER_MAP_ELEMENT(usb_fs) +REGISTER_MAP_ELEMENT(fs432x4b4_usb_ctl) REGISTER_MAP_ELEMENT(test_bus) REGISTER_MAP_ELEMENT(crt_spare) REGISTER_MAP_ELEMENT(usb2_ohci_int_mask) diff --git a/arch/mips/powertv/asic/asic-calliope.c b/arch/mips/powertv/asic/asic-calliope.c index 1ae6623444b..0a170e0ffea 100644 --- a/arch/mips/powertv/asic/asic-calliope.c +++ b/arch/mips/powertv/asic/asic-calliope.c @@ -77,7 +77,7 @@ const struct register_map calliope_register_map __initdata = { .int_docsis_en = {.phys = CALLIOPE_ADDR(0xA028F4)}, .mips_pll_setup = {.phys = CALLIOPE_ADDR(0x980000)}, - .usb_fs = {.phys = CALLIOPE_ADDR(0x980030)}, + .fs432x4b4_usb_ctl = {.phys = CALLIOPE_ADDR(0x980030)}, .test_bus = {.phys = CALLIOPE_ADDR(0x9800CC)}, .crt_spare = {.phys = CALLIOPE_ADDR(0x9800d4)}, .usb2_ohci_int_mask = {.phys = CALLIOPE_ADDR(0x9A000c)}, diff --git a/arch/mips/powertv/asic/asic-cronus.c b/arch/mips/powertv/asic/asic-cronus.c index 5bb64bfb508..bbc0c122be5 100644 --- a/arch/mips/powertv/asic/asic-cronus.c +++ b/arch/mips/powertv/asic/asic-cronus.c @@ -77,13 +77,13 @@ const struct register_map cronus_register_map __initdata = { .int_docsis_en = {.phys = CRONUS_ADDR(0x2A28F4)}, .mips_pll_setup = {.phys = CRONUS_ADDR(0x1C0000)}, - .usb_fs = {.phys = CRONUS_ADDR(0x1C0018)}, + .fs432x4b4_usb_ctl = {.phys = CRONUS_ADDR(0x1C0028)}, .test_bus = {.phys = CRONUS_ADDR(0x1C00CC)}, .crt_spare = {.phys = CRONUS_ADDR(0x1c00d4)}, .usb2_ohci_int_mask = {.phys = CRONUS_ADDR(0x20000C)}, .usb2_strap = {.phys = CRONUS_ADDR(0x200014)}, .ehci_hcapbase = {.phys = CRONUS_ADDR(0x21FE00)}, - .ohci_hc_revision = {.phys = CRONUS_ADDR(0x1E0000)}, + .ohci_hc_revision = {.phys = CRONUS_ADDR(0x21fc00)}, .bcm1_bs_lmi_steer = {.phys = CRONUS_ADDR(0x2E0008)}, .usb2_control = {.phys = CRONUS_ADDR(0x2E004C)}, .usb2_stbus_obc = {.phys = CRONUS_ADDR(0x21FF00)}, diff --git a/arch/mips/powertv/asic/asic-zeus.c b/arch/mips/powertv/asic/asic-zeus.c index 095cbe10ebb..4a05bb09647 100644 --- a/arch/mips/powertv/asic/asic-zeus.c +++ b/arch/mips/powertv/asic/asic-zeus.c @@ -77,7 +77,7 @@ const struct register_map zeus_register_map __initdata = { .int_docsis_en = {.phys = ZEUS_ADDR(0x2828F4)}, .mips_pll_setup = {.phys = ZEUS_ADDR(0x1a0000)}, - .usb_fs = {.phys = ZEUS_ADDR(0x1a0018)}, + .fs432x4b4_usb_ctl = {.phys = ZEUS_ADDR(0x1a0018)}, .test_bus = {.phys = ZEUS_ADDR(0x1a0238)}, .crt_spare = {.phys = ZEUS_ADDR(0x1a0090)}, .usb2_ohci_int_mask = {.phys = ZEUS_ADDR(0x1e000c)}, diff --git a/arch/mips/powertv/asic/asic_devices.c b/arch/mips/powertv/asic/asic_devices.c index c81dd497ed7..006285c3064 100644 --- a/arch/mips/powertv/asic/asic_devices.c +++ b/arch/mips/powertv/asic/asic_devices.c @@ -180,9 +180,9 @@ static void __init fs_update(int pe, int md, int sdiv, int disable_div_by_3) val = ((sdiv << 29) | (md << 24) | (pe<<8) | (sout<<3) | (byp<<2) | (nsb<<1) | (disable_div_by_3<<5)); - asic_write(val, usb_fs); - asic_write(val | (en_prg<<4), usb_fs); - asic_write(val | (en_prg<<4) | pwr, usb_fs); + asic_write(val, fs432x4b4_usb_ctl); + asic_write(val | (en_prg<<4), fs432x4b4_usb_ctl); + asic_write(val | (en_prg<<4) | pwr, fs432x4b4_usb_ctl); } /* -- cgit v1.2.3-70-g09d2 From 4483b159168d3db41458925512523e44d0d49cd4 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 5 Aug 2010 13:25:59 +0100 Subject: MIPS: Provide more elevant interface cu2_notifier for CP2 extensions. Signed-off-by: Ralf Baechle Signed-off-by: David Daney Patchwork: https://patchwork.linux-mips.org/patch/1504/ --- arch/mips/cavium-octeon/cpu.c | 6 +----- arch/mips/include/asm/cop2.h | 12 ++++++++++++ arch/mips/kernel/traps.c | 7 +------ 3 files changed, 14 insertions(+), 11 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/cavium-octeon/cpu.c b/arch/mips/cavium-octeon/cpu.c index b6df5387e85..c664c8cc2b4 100644 --- a/arch/mips/cavium-octeon/cpu.c +++ b/arch/mips/cavium-octeon/cpu.c @@ -41,12 +41,8 @@ static int cnmips_cu2_call(struct notifier_block *nfb, unsigned long action, return NOTIFY_OK; /* Let default notifier send signals */ } -static struct notifier_block cnmips_cu2_notifier = { - .notifier_call = cnmips_cu2_call, -}; - static int cnmips_cu2_setup(void) { - return register_cu2_notifier(&cnmips_cu2_notifier); + return cu2_notifier(cnmips_cu2_call, 0); } early_initcall(cnmips_cu2_setup); diff --git a/arch/mips/include/asm/cop2.h b/arch/mips/include/asm/cop2.h index 6b04c98b7fa..2cb2f0c2c4f 100644 --- a/arch/mips/include/asm/cop2.h +++ b/arch/mips/include/asm/cop2.h @@ -9,6 +9,8 @@ #ifndef __ASM_COP2_H #define __ASM_COP2_H +#include + enum cu2_ops { CU2_EXCEPTION, CU2_LWC2_OP, @@ -20,4 +22,14 @@ enum cu2_ops { extern int register_cu2_notifier(struct notifier_block *nb); extern int cu2_notifier_call_chain(unsigned long val, void *v); +#define cu2_notifier(fn, pri) \ +({ \ + static struct notifier_block fn##_nb __cpuinitdata = { \ + .notifier_call = fn, \ + .priority = pri \ + }; \ + \ + register_cu2_notifier(&fn##_nb); \ +}) + #endif /* __ASM_COP2_H */ diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 852780868fb..1515b673179 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -907,11 +907,6 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action, return NOTIFY_OK; } -static struct notifier_block default_cu2_notifier = { - .notifier_call = default_cu2_call, - .priority = 0x80000000, /* Run last */ -}; - asmlinkage void do_cpu(struct pt_regs *regs) { unsigned int __user *epc; @@ -1734,5 +1729,5 @@ void __init trap_init(void) sort_extable(__start___dbe_table, __stop___dbe_table); - register_cu2_notifier(&default_cu2_notifier); + cu2_notifier(default_cu2_call, 0x80000000); /* Run last */ } -- cgit v1.2.3-70-g09d2 From 3f441ee1cc150623aa64ddb1333d57eca78fdac2 Mon Sep 17 00:00:00 2001 From: Christoph Egger Date: Wed, 9 Jun 2010 13:21:30 +0200 Subject: MIPS: Remove dead CONFIG_MTD_PB1550_BOOT, CONFIG_MTD_PB1550_USER CONFIG_MTD_PB1550_BOOT, CONFIG_MTD_PB1550_USER doesn't exist in Kconfig, therefore removing all references for it from the source code. Signed-off-by: Christoph Egger To: Manuel Lauss , To: linux-mips@linux-mips.org To: linux-kernel@vger.kernel.org Cc: vamos@i4.informatik.uni-erlangen.de Patchwork: https://patchwork.linux-mips.org/patch/1370/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-pb1x00/pb1550.h | 8 -------- 1 file changed, 8 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-pb1x00/pb1550.h b/arch/mips/include/asm/mach-pb1x00/pb1550.h index 58796410bd6..fc4d766641c 100644 --- a/arch/mips/include/asm/mach-pb1x00/pb1550.h +++ b/arch/mips/include/asm/mach-pb1x00/pb1550.h @@ -40,14 +40,6 @@ #define SMBUS_PSC_BASE PSC2_BASE_ADDR #define I2S_PSC_BASE PSC3_BASE_ADDR -#if defined(CONFIG_MTD_PB1550_BOOT) && defined(CONFIG_MTD_PB1550_USER) -#define PB1550_BOTH_BANKS -#elif defined(CONFIG_MTD_PB1550_BOOT) && !defined(CONFIG_MTD_PB1550_USER) -#define PB1550_BOOT_ONLY -#elif !defined(CONFIG_MTD_PB1550_BOOT) && defined(CONFIG_MTD_PB1550_USER) -#define PB1550_USER_ONLY -#endif - /* * Timing values as described in databook, * ns value stripped of * lower 2 bits. -- cgit v1.2.3-70-g09d2 From e6a033c1cac98be10634e7f82fe0269c8adaf3e5 Mon Sep 17 00:00:00 2001 From: Christoph Egger Date: Wed, 9 Jun 2010 13:23:27 +0200 Subject: MIPS: MSP71xx: Remove dead CONFIG_MTD_PMC_MSP_RAMROOT CONFIG_MTD_PMC_MSP_RAMROOT doesn't exist in Kconfig, therefore removing all references for it from the source code. Signed-off-by: Christoph Egger To: Ralf Baechle , Yoichi Yuasa , linux-mips@linux-mips.org, linux-kernel@vger.kernel.org Cc: vamos@i4.informatik.uni-erlangen.de Acked-by: Shane McDonald Patchwork: https://patchwork.linux-mips.org/patch/1375/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pmc-sierra/msp71xx/msp_prom.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/pmc-sierra/msp71xx/msp_prom.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_prom.h index 54ef1a96d7c..786d82daf8d 100644 --- a/arch/mips/include/asm/pmc-sierra/msp71xx/msp_prom.h +++ b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_prom.h @@ -124,10 +124,6 @@ extern void prom_meminit(void); extern void prom_fixup_mem_map(unsigned long start_mem, unsigned long end_mem); -#ifdef CONFIG_MTD_PMC_MSP_RAMROOT -extern bool get_ramroot(void **start, unsigned long *size); -#endif - extern int get_ethernet_addr(char *ethaddr_name, char *ethernet_addr); extern unsigned long get_deviceid(void); extern char identify_enet(unsigned long interface_num); -- cgit v1.2.3-70-g09d2 From 417a5eb02ce8e5fbaf3d97d8dacc813b0a273ec3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 5 Aug 2010 13:26:01 +0100 Subject: MIPS: Update comment for cpu_has_clo_clz Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cpu-features.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index ac73cede3a0..ca400f7c3f5 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -159,7 +159,8 @@ /* * MIPS32, MIPS64, VR5500, IDT32332, IDT32334 and maybe a few other - * pre-MIPS32/MIPS53 processors have CLO, CLZ. For 64-bit kernels + * pre-MIPS32/MIPS53 processors have CLO, CLZ. The IDT RC64574 is 64-bit and + * has CLO and CLZ but not DCLO nor DCLZ. For 64-bit kernels * cpu_has_clo_clz also indicates the availability of DCLO and DCLZ. */ # ifndef cpu_has_clo_clz -- cgit v1.2.3-70-g09d2 From 1a403d1d2e549bc7d280001503867321572717f6 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 25 Jun 2010 16:46:07 -0700 Subject: MIPS: Create and use asm/arch_hweight.h Some MIPS ISA processor varients can do hweight operations efficiently. Split arch_hweight.h into a seperate file, and implement the operations with __builtin_popcount{,ll} if supported. Signed-off-by: David Daney To: linux-mips@linux-mips.org Cc: David Daney Patchwork: https://patchwork.linux-mips.org/patch/1430/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/arch_hweight.h | 38 ++++++++++++++++++++++++++++++++++++ arch/mips/include/asm/bitops.h | 5 ++++- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 arch/mips/include/asm/arch_hweight.h (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/arch_hweight.h b/arch/mips/include/asm/arch_hweight.h new file mode 100644 index 00000000000..712a7445ee9 --- /dev/null +++ b/arch/mips/include/asm/arch_hweight.h @@ -0,0 +1,38 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ +#ifndef _ASM_ARCH_HWEIGHT_H +#define _ASM_ARCH_HWEIGHT_H + +#ifdef ARCH_HAS_USABLE_BUILTIN_POPCOUNT + +#include + +static inline unsigned int __arch_hweight32(unsigned int w) +{ + return __builtin_popcount(w); +} + +static inline unsigned int __arch_hweight16(unsigned int w) +{ + return __builtin_popcount(w & 0xffff); +} + +static inline unsigned int __arch_hweight8(unsigned int w) +{ + return __builtin_popcount(w & 0xff); +} + +static inline unsigned long __arch_hweight64(__u64 w) +{ + return __builtin_popcountll(w); +} + +#else +#include +#endif + +#endif /* _ASM_ARCH_HWEIGHT_H */ diff --git a/arch/mips/include/asm/bitops.h b/arch/mips/include/asm/bitops.h index 9255cfbee45..b0ce7ca2851 100644 --- a/arch/mips/include/asm/bitops.h +++ b/arch/mips/include/asm/bitops.h @@ -700,7 +700,10 @@ static inline int ffs(int word) #ifdef __KERNEL__ #include -#include + +#include +#include + #include #include #include -- cgit v1.2.3-70-g09d2 From 1d1929c7662d5da3badcf0df2ca5c9b2dc15db97 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 25 Jun 2010 16:46:08 -0700 Subject: MIPS: Octeon: Define ARCH_HAS_USABLE_BUILTIN_POPCOUNT for OCTEON. OCTEON implements __builtin_popcount with a single instruction, so lets use it. Signed-off-by: David Daney To: linux-mips@linux-mips.org Cc: David Daney Patchwork: https://patchwork.linux-mips.org/patch/1431/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h index bbf05404239..2a7ea90fee2 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h @@ -77,6 +77,14 @@ static inline int read_current_timer(unsigned long *result) return 0; } +#ifdef __OCTEON__ +/* + * All gcc versions that have OCTEON support define __OCTEON__ and have the + * __builtin_popcount support. + */ +#define ARCH_HAS_USABLE_BUILTIN_POPCOUNT 1 +#endif + static inline int octeon_has_saa(void) { int id; -- cgit v1.2.3-70-g09d2 From eebacda40f2f9818c92f61b2228c7888e1f4926c Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Thu, 17 Jun 2010 20:35:58 +0900 Subject: MIPS: EMMA2RH: Remove useless CPU_IRQ_BASE For historical reasons, we used to put MIPS CPU IRQs behind SoC-specific IRQs in the queue, and have been using CPU_IRQ_BASE as MIPS_CPU_IRQ_BASE. In recent years, however, we've brought it back to normal order, and now CPU_IRQ_BASE just redefines the generic MIPS_CPU_IRQ_BASE. At the same time, NUM_CPU_IRQ is also removed as useless. Signed-off-by: Shinya Kuribayashi To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1387/ Signed-off-by: Ralf Baechle --- arch/mips/emma/markeins/irq.c | 8 ++++---- arch/mips/include/asm/emma/emma2rh.h | 4 +--- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/emma/markeins/irq.c b/arch/mips/emma/markeins/irq.c index 9504b7ee0b7..1d1c806056c 100644 --- a/arch/mips/emma/markeins/irq.c +++ b/arch/mips/emma/markeins/irq.c @@ -301,7 +301,7 @@ void __init arch_init_irq(void) /* setup cascade interrupts */ setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_SW_CASCADE, &irq_cascade); setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_GPIO_CASCADE, &irq_cascade); - setup_irq(CPU_IRQ_BASE + CPU_EMMA2RH_CASCADE, &irq_cascade); + setup_irq(MIPS_CPU_IRQ_BASE + CPU_EMMA2RH_CASCADE, &irq_cascade); } asmlinkage void plat_irq_dispatch(void) @@ -309,13 +309,13 @@ asmlinkage void plat_irq_dispatch(void) unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; if (pending & STATUSF_IP7) - do_IRQ(CPU_IRQ_BASE + 7); + do_IRQ(MIPS_CPU_IRQ_BASE + 7); else if (pending & STATUSF_IP2) emma2rh_irq_dispatch(); else if (pending & STATUSF_IP1) - do_IRQ(CPU_IRQ_BASE + 1); + do_IRQ(MIPS_CPU_IRQ_BASE + 1); else if (pending & STATUSF_IP0) - do_IRQ(CPU_IRQ_BASE + 0); + do_IRQ(MIPS_CPU_IRQ_BASE + 0); else spurious_interrupt(); } diff --git a/arch/mips/include/asm/emma/emma2rh.h b/arch/mips/include/asm/emma/emma2rh.h index 2afb2fe11b3..fcc0064d6a8 100644 --- a/arch/mips/include/asm/emma/emma2rh.h +++ b/arch/mips/include/asm/emma/emma2rh.h @@ -99,12 +99,10 @@ #define EMMA2RH_PCI_CONFIG_BASE EMMA2RH_PCI_IO_BASE #define EMMA2RH_PCI_CONFIG_SIZE EMMA2RH_PCI_IO_SIZE -#define NUM_CPU_IRQ 8 #define NUM_EMMA2RH_IRQ 96 #define CPU_EMMA2RH_CASCADE 2 -#define CPU_IRQ_BASE MIPS_CPU_IRQ_BASE -#define EMMA2RH_IRQ_BASE (CPU_IRQ_BASE + NUM_CPU_IRQ) +#define EMMA2RH_IRQ_BASE (MIPS_CPU_IRQ_BASE + 8) /* * emma2rh irq defs -- cgit v1.2.3-70-g09d2 From 9e6f39698ac66e08017114a51600bf633becd011 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Thu, 17 Jun 2010 20:36:13 +0900 Subject: MIPS: EMMA2RH: Remove EMMA2RH_CPU_CASCADE Although all EMMAxxx SoCs can support IP2 and IP3 hardware interrupts, current EMMA2RH plat_irq_dispatch() supports IP2 only. We can make it configurable in the future, but for the time being, would like to make things explicitly allcated to IP2 in accordance with plat_irq_dispatch(). Signed-off-by: Shinya Kuribayashi To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1388/ Signed-off-by: Ralf Baechle --- arch/mips/emma/markeins/irq.c | 2 +- arch/mips/include/asm/emma/emma2rh.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/emma/markeins/irq.c b/arch/mips/emma/markeins/irq.c index 1d1c806056c..3a96799eb65 100644 --- a/arch/mips/emma/markeins/irq.c +++ b/arch/mips/emma/markeins/irq.c @@ -301,7 +301,7 @@ void __init arch_init_irq(void) /* setup cascade interrupts */ setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_SW_CASCADE, &irq_cascade); setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_GPIO_CASCADE, &irq_cascade); - setup_irq(MIPS_CPU_IRQ_BASE + CPU_EMMA2RH_CASCADE, &irq_cascade); + setup_irq(MIPS_CPU_IRQ_BASE + 2, &irq_cascade); } asmlinkage void plat_irq_dispatch(void) diff --git a/arch/mips/include/asm/emma/emma2rh.h b/arch/mips/include/asm/emma/emma2rh.h index fcc0064d6a8..95d0b7e683c 100644 --- a/arch/mips/include/asm/emma/emma2rh.h +++ b/arch/mips/include/asm/emma/emma2rh.h @@ -101,7 +101,6 @@ #define NUM_EMMA2RH_IRQ 96 -#define CPU_EMMA2RH_CASCADE 2 #define EMMA2RH_IRQ_BASE (MIPS_CPU_IRQ_BASE + 8) /* -- cgit v1.2.3-70-g09d2 From 4040703fffbb6b120253b2fe69f743466af69778 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Thu, 17 Jun 2010 20:36:32 +0900 Subject: MIPS: EMMA2RH: Replace EMMA2RH_IRQ_INTxx with EMMA2RH_IRQ_INT(n) Don't duplicate worthless lines. Signed-off-by: Shinya Kuribayashi To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1389/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/emma/emma2rh.h | 79 ++++------------------------------- arch/mips/include/asm/emma/markeins.h | 4 +- 2 files changed, 10 insertions(+), 73 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/emma/emma2rh.h b/arch/mips/include/asm/emma/emma2rh.h index 95d0b7e683c..c1449d20ef0 100644 --- a/arch/mips/include/asm/emma/emma2rh.h +++ b/arch/mips/include/asm/emma/emma2rh.h @@ -107,77 +107,14 @@ * emma2rh irq defs */ -#define EMMA2RH_IRQ_INT0 (0 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT1 (1 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT2 (2 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT3 (3 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT4 (4 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT5 (5 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT6 (6 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT7 (7 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT8 (8 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT9 (9 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT10 (10 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT11 (11 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT12 (12 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT13 (13 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT14 (14 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT15 (15 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT16 (16 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT17 (17 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT18 (18 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT19 (19 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT20 (20 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT21 (21 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT22 (22 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT23 (23 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT24 (24 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT25 (25 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT26 (26 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT27 (27 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT28 (28 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT29 (29 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT30 (30 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT31 (31 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT32 (32 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT33 (33 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT34 (34 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT35 (35 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT36 (36 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT37 (37 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT38 (38 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT39 (39 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT40 (40 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT41 (41 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT42 (42 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT43 (43 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT44 (44 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT45 (45 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT46 (46 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT47 (47 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT48 (48 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT49 (49 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT50 (50 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT51 (51 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT52 (52 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT53 (53 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT54 (54 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT55 (55 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT56 (56 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT57 (57 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT58 (58 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT59 (59 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT60 (60 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT61 (61 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT62 (62 + EMMA2RH_IRQ_BASE) -#define EMMA2RH_IRQ_INT63 (63 + EMMA2RH_IRQ_BASE) - -#define EMMA2RH_IRQ_PFUR0 EMMA2RH_IRQ_INT49 -#define EMMA2RH_IRQ_PFUR1 EMMA2RH_IRQ_INT50 -#define EMMA2RH_IRQ_PFUR2 EMMA2RH_IRQ_INT51 -#define EMMA2RH_IRQ_PIIC0 EMMA2RH_IRQ_INT56 -#define EMMA2RH_IRQ_PIIC1 EMMA2RH_IRQ_INT57 -#define EMMA2RH_IRQ_PIIC2 EMMA2RH_IRQ_INT58 +#define EMMA2RH_IRQ_INT(n) (EMMA2RH_IRQ_BASE + (n)) + +#define EMMA2RH_IRQ_PFUR0 EMMA2RH_IRQ_INT(49) +#define EMMA2RH_IRQ_PFUR1 EMMA2RH_IRQ_INT(50) +#define EMMA2RH_IRQ_PFUR2 EMMA2RH_IRQ_INT(51) +#define EMMA2RH_IRQ_PIIC0 EMMA2RH_IRQ_INT(56) +#define EMMA2RH_IRQ_PIIC1 EMMA2RH_IRQ_INT(57) +#define EMMA2RH_IRQ_PIIC2 EMMA2RH_IRQ_INT(58) /* * EMMA2RH Register Access diff --git a/arch/mips/include/asm/emma/markeins.h b/arch/mips/include/asm/emma/markeins.h index 2618bf23024..507f125f98f 100644 --- a/arch/mips/include/asm/emma/markeins.h +++ b/arch/mips/include/asm/emma/markeins.h @@ -25,8 +25,8 @@ #define NUM_EMMA2RH_IRQ_SW 32 #define NUM_EMMA2RH_IRQ_GPIO 32 -#define EMMA2RH_SW_CASCADE (EMMA2RH_IRQ_INT7 - EMMA2RH_IRQ_INT0) -#define EMMA2RH_GPIO_CASCADE (EMMA2RH_IRQ_INT46 - EMMA2RH_IRQ_INT0) +#define EMMA2RH_SW_CASCADE (EMMA2RH_IRQ_INT(7) - EMMA2RH_IRQ_INT(0)) +#define EMMA2RH_GPIO_CASCADE (EMMA2RH_IRQ_INT(46) - EMMA2RH_IRQ_INT(0)) #define EMMA2RH_SW_IRQ_BASE (EMMA2RH_IRQ_BASE + NUM_EMMA2RH_IRQ) #define EMMA2RH_GPIO_IRQ_BASE (EMMA2RH_SW_IRQ_BASE + NUM_EMMA2RH_IRQ_SW) -- cgit v1.2.3-70-g09d2 From 1f1f4e7dbc0c0312e9e7fe3cadd07340ea62070f Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Thu, 17 Jun 2010 20:37:13 +0900 Subject: MIPS: EMMA2RH: Replace EMMA2RH_SW_IRQ_INTxx with EMMA2RH_SW_IRQ(n) Don't duplicate worthless lines. Signed-off-by: Shinya Kuribayashi To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1390/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/emma/markeins.h | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/emma/markeins.h b/arch/mips/include/asm/emma/markeins.h index 507f125f98f..bf2d229c2da 100644 --- a/arch/mips/include/asm/emma/markeins.h +++ b/arch/mips/include/asm/emma/markeins.h @@ -31,38 +31,7 @@ #define EMMA2RH_SW_IRQ_BASE (EMMA2RH_IRQ_BASE + NUM_EMMA2RH_IRQ) #define EMMA2RH_GPIO_IRQ_BASE (EMMA2RH_SW_IRQ_BASE + NUM_EMMA2RH_IRQ_SW) -#define EMMA2RH_SW_IRQ_INT0 (0+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT1 (1+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT2 (2+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT3 (3+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT4 (4+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT5 (5+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT6 (6+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT7 (7+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT8 (8+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT9 (9+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT10 (10+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT11 (11+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT12 (12+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT13 (13+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT14 (14+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT15 (15+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT16 (16+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT17 (17+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT18 (18+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT19 (19+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT20 (20+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT21 (21+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT22 (22+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT23 (23+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT24 (24+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT25 (25+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT26 (26+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT27 (27+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT28 (28+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT29 (29+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT30 (30+EMMA2RH_SW_IRQ_BASE) -#define EMMA2RH_SW_IRQ_INT31 (31+EMMA2RH_SW_IRQ_BASE) +#define EMMA2RH_SW_IRQ_INT(n) (EMMA2RH_SW_IRQ_BASE + (n)) #define MARKEINS_PCI_IRQ_INTA EMMA2RH_GPIO_IRQ_BASE+15 #define MARKEINS_PCI_IRQ_INTB EMMA2RH_GPIO_IRQ_BASE+16 -- cgit v1.2.3-70-g09d2 From 1091458d09e1a0788268578001f279250d2c0844 Mon Sep 17 00:00:00 2001 From: David Daney Date: Mon, 19 Jul 2010 13:14:56 -0700 Subject: MIPS: Randomize mmap if randomize_va_space is set Fairly straight forward: For 32-bit address spaces randomize within a 16MB space, for 64-bit within a 256MB space. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1480/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/processor.h | 11 +++++++++++ arch/mips/kernel/syscall.c | 21 ++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 5d33b727acf..24d91f8618f 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -33,6 +33,11 @@ extern void (*cpu_wait)(void); extern unsigned int vced_count, vcei_count; +/* + * MIPS does have an arch_pick_mmap_layout() + */ +#define HAVE_ARCH_PICK_MMAP_LAYOUT 1 + /* * A special page (the vdso) is mapped into all processes at the very * top of the virtual memory space. @@ -52,6 +57,9 @@ extern unsigned int vced_count, vcei_count; * space during mmap's. */ #define TASK_UNMAPPED_BASE ((TASK_SIZE / 3) & ~(PAGE_SIZE)) + +#define TASK_IS_32BIT_ADDR 1 + #endif #ifdef CONFIG_64BIT @@ -77,6 +85,9 @@ extern unsigned int vced_count, vcei_count; PAGE_ALIGN(TASK_SIZE32 / 3) : PAGE_ALIGN(TASK_SIZE / 3)) #define TASK_SIZE_OF(tsk) \ (test_tsk_thread_flag(tsk, TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE) + +#define TASK_IS_32BIT_ADDR test_thread_flag(TIF_32BIT_ADDR) + #endif #ifdef __KERNEL__ diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index dd81b0f8751..9824a829f61 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -116,7 +117,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, (!vmm || addr + len <= vmm->vm_start)) return addr; } - addr = TASK_UNMAPPED_BASE; + addr = current->mm->mmap_base; if (do_color_align) addr = COLOUR_ALIGN(addr, pgoff); else @@ -134,6 +135,24 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, } } +void arch_pick_mmap_layout(struct mm_struct *mm) +{ + unsigned long random_factor = 0UL; + + if (current->flags & PF_RANDOMIZE) { + random_factor = get_random_int(); + random_factor = random_factor << PAGE_SHIFT; + if (TASK_IS_32BIT_ADDR) + random_factor &= 0xfffffful; + else + random_factor &= 0xffffffful; + } + + mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; + mm->get_unmapped_area = arch_get_unmapped_area; + mm->unmap_area = arch_unmap_area; +} + SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len, unsigned long, prot, unsigned long, flags, unsigned long, fd, off_t, offset) -- cgit v1.2.3-70-g09d2 From 652b14aa84961fa391184ccbaf559a537d33b28c Mon Sep 17 00:00:00 2001 From: David Daney Date: Mon, 19 Jul 2010 13:14:57 -0700 Subject: MIPS: Enable heap randomization. Based somewhat on the PPC implementation. 32-bit processes have the heap randomized in an 8MB space, 256MB for 64-bit processes. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1479/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/elf.h | 5 +++++ arch/mips/kernel/syscall.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index ea77a42c5f8..fd1d39eb743 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -372,4 +372,9 @@ extern const char *__elf_platform; struct linux_binprm; extern int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp); + +struct mm_struct; +extern unsigned long arch_randomize_brk(struct mm_struct *mm); +#define arch_randomize_brk arch_randomize_brk + #endif /* _ASM_ELF_H */ diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 9824a829f61..58bab2ef257 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -153,6 +154,33 @@ void arch_pick_mmap_layout(struct mm_struct *mm) mm->unmap_area = arch_unmap_area; } +static inline unsigned long brk_rnd(void) +{ + unsigned long rnd = get_random_int(); + + rnd = rnd << PAGE_SHIFT; + /* 8MB for 32bit, 256MB for 64bit */ + if (TASK_IS_32BIT_ADDR) + rnd = rnd & 0x7ffffful; + else + rnd = rnd & 0xffffffful; + + return rnd; +} + +unsigned long arch_randomize_brk(struct mm_struct *mm) +{ + unsigned long base = mm->brk; + unsigned long ret; + + ret = PAGE_ALIGN(base + brk_rnd()); + + if (ret < mm->brk) + return mm->brk; + + return ret; +} + SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len, unsigned long, prot, unsigned long, flags, unsigned long, fd, off_t, offset) -- cgit v1.2.3-70-g09d2 From 745aef5df1e2277ee9e34d86491084c0d6106338 Mon Sep 17 00:00:00 2001 From: Ricardo Mendoza Date: Mon, 19 Jul 2010 05:00:00 +0100 Subject: MIPS: RM7000: Add support for tertiary cache Add support for the external T-cache interface. Allow for platform independent size probing from 512KB to 8MB in powers of two. Signed-off-by: Ricardo Mendoza To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1477/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cacheops.h | 2 + arch/mips/mm/sc-rm7k.c | 151 +++++++++++++++++++++++++++++++++------ 2 files changed, 130 insertions(+), 23 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/cacheops.h b/arch/mips/include/asm/cacheops.h index 256ad2cc6eb..8f99c11ab66 100644 --- a/arch/mips/include/asm/cacheops.h +++ b/arch/mips/include/asm/cacheops.h @@ -62,6 +62,8 @@ * RM7000-specific cacheops */ #define Page_Invalidate_T 0x16 +#define Index_Store_Tag_T 0x0a +#define Index_Load_Tag_T 0x06 /* * R10000-specific cacheops diff --git a/arch/mips/mm/sc-rm7k.c b/arch/mips/mm/sc-rm7k.c index 53634398a56..1ef75cd80a0 100644 --- a/arch/mips/mm/sc-rm7k.c +++ b/arch/mips/mm/sc-rm7k.c @@ -16,6 +16,7 @@ #include #include #include +#include #include /* for run_uncached() */ /* Primary cache parameters. */ @@ -25,11 +26,15 @@ /* Secondary cache parameters. */ #define scache_size (256*1024) /* Fixed to 256KiB on RM7000 */ +/* Tertiary cache parameters */ +#define tc_lsize 32 + extern unsigned long icache_way_size, dcache_way_size; +unsigned long tcache_size; #include -static int rm7k_tcache_enabled; +static int rm7k_tcache_init; /* * Writeback and invalidate the primary cache dcache before DMA. @@ -46,7 +51,7 @@ static void rm7k_sc_wback_inv(unsigned long addr, unsigned long size) blast_scache_range(addr, addr + size); - if (!rm7k_tcache_enabled) + if (!rm7k_tcache_init) return; a = addr & ~(tc_pagesize - 1); @@ -70,7 +75,7 @@ static void rm7k_sc_inv(unsigned long addr, unsigned long size) blast_inv_scache_range(addr, addr + size); - if (!rm7k_tcache_enabled) + if (!rm7k_tcache_init) return; a = addr & ~(tc_pagesize - 1); @@ -83,6 +88,45 @@ static void rm7k_sc_inv(unsigned long addr, unsigned long size) } } +static void blast_rm7k_tcache(void) +{ + unsigned long start = CKSEG0ADDR(0); + unsigned long end = start + tcache_size; + + write_c0_taglo(0); + + while (start < end) { + cache_op(Page_Invalidate_T, start); + start += tc_pagesize; + } +} + +/* + * This function is executed in uncached address space. + */ +static __cpuinit void __rm7k_tc_enable(void) +{ + int i; + + set_c0_config(RM7K_CONF_TE); + + write_c0_taglo(0); + write_c0_taghi(0); + + for (i = 0; i < tcache_size; i += tc_lsize) + cache_op(Index_Store_Tag_T, CKSEG0ADDR(i)); +} + +static __cpuinit void rm7k_tc_enable(void) +{ + if (read_c0_config() & RM7K_CONF_TE) + return; + + BUG_ON(tcache_size == 0); + + run_uncached(__rm7k_tc_enable); +} + /* * This function is executed in uncached address space. */ @@ -104,13 +148,29 @@ static __cpuinit void rm7k_sc_enable(void) if (read_c0_config() & RM7K_CONF_SE) return; - printk(KERN_INFO "Enabling secondary cache...\n"); + pr_info("Enabling secondary cache...\n"); run_uncached(__rm7k_sc_enable); + + if (rm7k_tcache_init) + rm7k_tc_enable(); +} + +static void rm7k_tc_disable(void) +{ + unsigned long flags; + + local_irq_save(flags); + blast_rm7k_tcache(); + clear_c0_config(RM7K_CONF_TE); + local_irq_save(flags); } static void rm7k_sc_disable(void) { clear_c0_config(RM7K_CONF_SE); + + if (rm7k_tcache_init) + rm7k_tc_disable(); } static struct bcache_ops rm7k_sc_ops = { @@ -120,6 +180,52 @@ static struct bcache_ops rm7k_sc_ops = { .bc_inv = rm7k_sc_inv }; +/* + * This is a probing function like the one found in c-r4k.c, we look for the + * wrap around point with different addresses. + */ +static __cpuinit void __probe_tcache(void) +{ + unsigned long flags, addr, begin, end, pow2; + + begin = (unsigned long) &_stext; + begin &= ~((8 * 1024 * 1024) - 1); + end = begin + (8 * 1024 * 1024); + + local_irq_save(flags); + + set_c0_config(RM7K_CONF_TE); + + /* Fill size-multiple lines with a valid tag */ + pow2 = (256 * 1024); + for (addr = begin; addr <= end; addr = (begin + pow2)) { + unsigned long *p = (unsigned long *) addr; + __asm__ __volatile__("nop" : : "r" (*p)); + pow2 <<= 1; + } + + /* Load first line with a 0 tag, to check after */ + write_c0_taglo(0); + write_c0_taghi(0); + cache_op(Index_Store_Tag_T, begin); + + /* Look for the wrap-around */ + pow2 = (512 * 1024); + for (addr = begin + (512 * 1024); addr <= end; addr = begin + pow2) { + cache_op(Index_Load_Tag_T, addr); + if (!read_c0_taglo()) + break; + pow2 <<= 1; + } + + addr -= begin; + tcache_size = addr; + + clear_c0_config(RM7K_CONF_TE); + + local_irq_restore(flags); +} + void __cpuinit rm7k_sc_init(void) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -139,27 +245,26 @@ void __cpuinit rm7k_sc_init(void) if (!(config & RM7K_CONF_SE)) rm7k_sc_enable(); + bcops = &rm7k_sc_ops; + /* * While we're at it let's deal with the tertiary cache. */ - if (!(config & RM7K_CONF_TC)) { - - /* - * We can't enable the L3 cache yet. There may be board-specific - * magic necessary to turn it on, and blindly asking the CPU to - * start using it would may give cache errors. - * - * Also, board-specific knowledge may allow us to use the - * CACHE Flash_Invalidate_T instruction if the tag RAM supports - * it, and may specify the size of the L3 cache so we don't have - * to probe it. - */ - printk(KERN_INFO "Tertiary cache present, %s enabled\n", - (config & RM7K_CONF_TE) ? "already" : "not (yet)"); - - if ((config & RM7K_CONF_TE)) - rm7k_tcache_enabled = 1; - } - bcops = &rm7k_sc_ops; + rm7k_tcache_init = 0; + tcache_size = 0; + + if (config & RM7K_CONF_TC) + return; + + /* + * No efficient way to ask the hardware for the size of the tcache, + * so must probe for it. + */ + run_uncached(__probe_tcache); + rm7k_tc_enable(); + rm7k_tcache_init = 1; + c->tcache.linesz = tc_lsize; + c->tcache.ways = 1; + pr_info("Tertiary cache size %ldK.\n", (tcache_size >> 10)); } -- cgit v1.2.3-70-g09d2 From 42a4f17dc356689075263d7c2bd68456676fa62e Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Thu, 15 Jul 2010 21:45:04 +0200 Subject: MIPS: Alchemy: remove SOC_AU1X00 in favor of MIPS_ALCHEMY Remove the CONFIG_SOC_AU1X00 Kconfig symbol since its job can also be done by MACH_ALCHEMY, now renamed to MIPS_ALCHEMY. Signed-off-by: Manuel Lauss To: Linux-MIPS Patchwork: https://patchwork.linux-mips.org/patch/1461/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 11 ++++++++++- arch/mips/alchemy/Kconfig | 19 +------------------ arch/mips/alchemy/Platform | 4 ++-- arch/mips/boot/compressed/Makefile | 2 +- arch/mips/configs/db1000_defconfig | 3 +-- arch/mips/configs/db1100_defconfig | 3 +-- arch/mips/configs/db1200_defconfig | 3 +-- arch/mips/configs/db1500_defconfig | 3 +-- arch/mips/configs/db1550_defconfig | 3 +-- arch/mips/configs/mtx1_defconfig | 3 +-- arch/mips/configs/pb1100_defconfig | 3 +-- arch/mips/configs/pb1200_defconfig | 3 +-- arch/mips/configs/pb1500_defconfig | 3 +-- arch/mips/configs/pb1550_defconfig | 3 +-- arch/mips/include/asm/hazards.h | 4 ++-- drivers/net/Kconfig | 2 +- drivers/pcmcia/Kconfig | 4 ++-- drivers/rtc/Kconfig | 2 +- drivers/serial/Kconfig | 2 +- drivers/usb/Kconfig | 2 +- drivers/usb/host/ohci-hcd.c | 2 +- 21 files changed, 33 insertions(+), 51 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b81a6b20d25..0dd164999a9 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -23,8 +23,17 @@ choice prompt "System type" default SGI_IP22 -config MACH_ALCHEMY +config MIPS_ALCHEMY bool "Alchemy processor based machines" + select 64BIT_PHYS_ADDR + select CEVT_R4K_LIB + select CSRC_R4K_LIB + select IRQ_CPU + select SYS_HAS_CPU_MIPS32_R1 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_APM_EMULATION + select GENERIC_GPIO + select ARCH_WANT_OPTIONAL_GPIOLIB select SYS_SUPPORTS_ZBOOT config AR7 diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig index df3b1a7eb15..1179c4d4cf1 100644 --- a/arch/mips/alchemy/Kconfig +++ b/arch/mips/alchemy/Kconfig @@ -11,7 +11,7 @@ config ALCHEMY_GPIO_INDIRECT choice prompt "Machine type" - depends on MACH_ALCHEMY + depends on MIPS_ALCHEMY default MIPS_DB1000 config MIPS_MTX1 @@ -132,37 +132,20 @@ endchoice config SOC_AU1000 bool - select SOC_AU1X00 select ALCHEMY_GPIOINT_AU1000 config SOC_AU1100 bool - select SOC_AU1X00 select ALCHEMY_GPIOINT_AU1000 config SOC_AU1500 bool - select SOC_AU1X00 select ALCHEMY_GPIOINT_AU1000 config SOC_AU1550 bool - select SOC_AU1X00 select ALCHEMY_GPIOINT_AU1000 config SOC_AU1200 bool - select SOC_AU1X00 select ALCHEMY_GPIOINT_AU1000 - -config SOC_AU1X00 - bool - select 64BIT_PHYS_ADDR - select CEVT_R4K_LIB - select CSRC_R4K_LIB - select IRQ_CPU - select SYS_HAS_CPU_MIPS32_R1 - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_APM_EMULATION - select GENERIC_GPIO - select ARCH_WANT_OPTIONAL_GPIOLIB diff --git a/arch/mips/alchemy/Platform b/arch/mips/alchemy/Platform index 495cc9a2a3b..0bf2b09f310 100644 --- a/arch/mips/alchemy/Platform +++ b/arch/mips/alchemy/Platform @@ -1,7 +1,7 @@ # # Core Alchemy code # -platform-$(CONFIG_MACH_ALCHEMY) += alchemy/common/ +platform-$(CONFIG_MIPS_ALCHEMY) += alchemy/common/ # @@ -106,4 +106,4 @@ load-$(CONFIG_MIPS_XXS1500) += 0xffffffff80100000 # compiler picks the board one. If they don't, it will make sure # the alchemy generic gpio header is picked up. -cflags-$(CONFIG_MACH_ALCHEMY) += -I$(srctree)/arch/mips/include/asm/mach-au1x00 +cflags-$(CONFIG_MIPS_ALCHEMY) += -I$(srctree)/arch/mips/include/asm/mach-au1x00 diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index 74a52d79934..edc48adf884 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -40,7 +40,7 @@ vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/dbg.o ifdef CONFIG_DEBUG_ZBOOT vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o -vmlinuzobjs-$(CONFIG_MACH_ALCHEMY) += $(obj)/uart-alchemy.o +vmlinuzobjs-$(CONFIG_MIPS_ALCHEMY) += $(obj)/uart-alchemy.o endif targets += vmlinux.bin diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig index f66d406aadc..3a9ec6ccd40 100644 --- a/arch/mips/configs/db1000_defconfig +++ b/arch/mips/configs/db1000_defconfig @@ -8,7 +8,7 @@ CONFIG_MIPS=y # # Machine selection # -CONFIG_MACH_ALCHEMY=y +CONFIG_MIPS_ALCHEMY=y # CONFIG_AR7 is not set # CONFIG_BCM47XX is not set # CONFIG_BCM63XX is not set @@ -64,7 +64,6 @@ CONFIG_MIPS_DB1000=y # CONFIG_MIPS_PB1550 is not set # CONFIG_MIPS_XXS1500 is not set CONFIG_SOC_AU1000=y -CONFIG_SOC_AU1X00=y CONFIG_LOONGSON_UART_BASE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig index abb9a5805ad..4589b84301f 100644 --- a/arch/mips/configs/db1100_defconfig +++ b/arch/mips/configs/db1100_defconfig @@ -8,7 +8,7 @@ CONFIG_MIPS=y # # Machine selection # -CONFIG_MACH_ALCHEMY=y +CONFIG_MIPS_ALCHEMY=y # CONFIG_AR7 is not set # CONFIG_BCM47XX is not set # CONFIG_BCM63XX is not set @@ -64,7 +64,6 @@ CONFIG_MIPS_DB1100=y # CONFIG_MIPS_PB1550 is not set # CONFIG_MIPS_XXS1500 is not set CONFIG_SOC_AU1100=y -CONFIG_SOC_AU1X00=y CONFIG_LOONGSON_UART_BASE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig index 991c20adf47..9950f2aabd3 100644 --- a/arch/mips/configs/db1200_defconfig +++ b/arch/mips/configs/db1200_defconfig @@ -8,7 +8,7 @@ CONFIG_MIPS=y # # Machine selection # -CONFIG_MACH_ALCHEMY=y +CONFIG_MIPS_ALCHEMY=y # CONFIG_AR7 is not set # CONFIG_BCM47XX is not set # CONFIG_BCM63XX is not set @@ -64,7 +64,6 @@ CONFIG_MIPS_DB1200=y # CONFIG_MIPS_PB1550 is not set # CONFIG_MIPS_XXS1500 is not set CONFIG_SOC_AU1200=y -CONFIG_SOC_AU1X00=y CONFIG_LOONGSON_UART_BASE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig index 5424c9167bf..346ae631d1e 100644 --- a/arch/mips/configs/db1500_defconfig +++ b/arch/mips/configs/db1500_defconfig @@ -8,7 +8,7 @@ CONFIG_MIPS=y # # Machine selection # -CONFIG_MACH_ALCHEMY=y +CONFIG_MIPS_ALCHEMY=y # CONFIG_AR7 is not set # CONFIG_BCM47XX is not set # CONFIG_BCM63XX is not set @@ -64,7 +64,6 @@ CONFIG_MIPS_DB1500=y # CONFIG_MIPS_PB1550 is not set # CONFIG_MIPS_XXS1500 is not set CONFIG_SOC_AU1500=y -CONFIG_SOC_AU1X00=y CONFIG_LOONGSON_UART_BASE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig index 949b6dcf634..10eafb942af 100644 --- a/arch/mips/configs/db1550_defconfig +++ b/arch/mips/configs/db1550_defconfig @@ -8,7 +8,7 @@ CONFIG_MIPS=y # # Machine selection # -CONFIG_MACH_ALCHEMY=y +CONFIG_MIPS_ALCHEMY=y # CONFIG_AR7 is not set # CONFIG_BCM47XX is not set # CONFIG_BCM63XX is not set @@ -64,7 +64,6 @@ CONFIG_MIPS_DB1550=y # CONFIG_MIPS_PB1550 is not set # CONFIG_MIPS_XXS1500 is not set CONFIG_SOC_AU1550=y -CONFIG_SOC_AU1X00=y CONFIG_LOONGSON_UART_BASE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index cff8f4c0e57..10d20aa731d 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -8,7 +8,7 @@ CONFIG_MIPS=y # # Machine selection # -CONFIG_MACH_ALCHEMY=y +CONFIG_MIPS_ALCHEMY=y # CONFIG_AR7 is not set # CONFIG_BCM47XX is not set # CONFIG_BCM63XX is not set @@ -64,7 +64,6 @@ CONFIG_MIPS_MTX1=y # CONFIG_MIPS_PB1550 is not set # CONFIG_MIPS_XXS1500 is not set CONFIG_SOC_AU1500=y -CONFIG_SOC_AU1X00=y CONFIG_LOONGSON_UART_BASE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig index 97382b698b9..778f726af8e 100644 --- a/arch/mips/configs/pb1100_defconfig +++ b/arch/mips/configs/pb1100_defconfig @@ -8,7 +8,7 @@ CONFIG_MIPS=y # # Machine selection # -CONFIG_MACH_ALCHEMY=y +CONFIG_MIPS_ALCHEMY=y # CONFIG_AR7 is not set # CONFIG_BCM47XX is not set # CONFIG_BCM63XX is not set @@ -64,7 +64,6 @@ CONFIG_MIPS_PB1100=y # CONFIG_MIPS_PB1550 is not set # CONFIG_MIPS_XXS1500 is not set CONFIG_SOC_AU1100=y -CONFIG_SOC_AU1X00=y CONFIG_LOONGSON_UART_BASE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set diff --git a/arch/mips/configs/pb1200_defconfig b/arch/mips/configs/pb1200_defconfig index e9ad77320f1..0f908c69211 100644 --- a/arch/mips/configs/pb1200_defconfig +++ b/arch/mips/configs/pb1200_defconfig @@ -8,7 +8,7 @@ CONFIG_MIPS=y # # Machine selection # -CONFIG_MACH_ALCHEMY=y +CONFIG_MIPS_ALCHEMY=y # CONFIG_AR7 is not set # CONFIG_BCM47XX is not set # CONFIG_BCM63XX is not set @@ -64,7 +64,6 @@ CONFIG_MIPS_PB1200=y # CONFIG_MIPS_PB1550 is not set # CONFIG_MIPS_XXS1500 is not set CONFIG_SOC_AU1200=y -CONFIG_SOC_AU1X00=y CONFIG_LOONGSON_UART_BASE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig index 7497d3306b9..1c5fe6f06c0 100644 --- a/arch/mips/configs/pb1500_defconfig +++ b/arch/mips/configs/pb1500_defconfig @@ -8,7 +8,7 @@ CONFIG_MIPS=y # # Machine selection # -CONFIG_MACH_ALCHEMY=y +CONFIG_MIPS_ALCHEMY=y # CONFIG_AR7 is not set # CONFIG_BCM47XX is not set # CONFIG_BCM63XX is not set @@ -64,7 +64,6 @@ CONFIG_MIPS_PB1500=y # CONFIG_MIPS_PB1550 is not set # CONFIG_MIPS_XXS1500 is not set CONFIG_SOC_AU1500=y -CONFIG_SOC_AU1X00=y CONFIG_LOONGSON_UART_BASE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig index aa526f53cb1..49494b01138 100644 --- a/arch/mips/configs/pb1550_defconfig +++ b/arch/mips/configs/pb1550_defconfig @@ -8,7 +8,7 @@ CONFIG_MIPS=y # # Machine selection # -CONFIG_MACH_ALCHEMY=y +CONFIG_MIPS_ALCHEMY=y # CONFIG_AR7 is not set # CONFIG_BCM47XX is not set # CONFIG_BCM63XX is not set @@ -64,7 +64,6 @@ CONFIG_ALCHEMY_GPIOINT_AU1000=y CONFIG_MIPS_PB1550=y # CONFIG_MIPS_XXS1500 is not set CONFIG_SOC_AU1550=y -CONFIG_SOC_AU1X00=y CONFIG_LOONGSON_UART_BASE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set diff --git a/arch/mips/include/asm/hazards.h b/arch/mips/include/asm/hazards.h index 0eaf77ffbc4..4e332165d7b 100644 --- a/arch/mips/include/asm/hazards.h +++ b/arch/mips/include/asm/hazards.h @@ -87,7 +87,7 @@ do { \ : "=r" (tmp)); \ } while (0) -#elif defined(CONFIG_CPU_MIPSR1) && !defined(CONFIG_MACH_ALCHEMY) +#elif defined(CONFIG_CPU_MIPSR1) && !defined(CONFIG_MIPS_ALCHEMY) /* * These are slightly complicated by the fact that we guarantee R1 kernels to @@ -138,7 +138,7 @@ do { \ __instruction_hazard(); \ } while (0) -#elif defined(CONFIG_MACH_ALCHEMY) || defined(CONFIG_CPU_CAVIUM_OCTEON) || \ +#elif defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_CPU_CAVIUM_OCTEON) || \ defined(CONFIG_CPU_LOONGSON2) || defined(CONFIG_CPU_R10000) || \ defined(CONFIG_CPU_R5500) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ce2fcdd4ab9..adead30a056 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -484,7 +484,7 @@ config XTENSA_XT2000_SONIC config MIPS_AU1X00_ENET tristate "MIPS AU1000 Ethernet support" - depends on SOC_AU1X00 + depends on MIPS_ALCHEMY select PHYLIB select CRC32 help diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index d0f5ad30607..c988514eb55 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -157,11 +157,11 @@ config PCMCIA_M8XX config PCMCIA_AU1X00 tristate "Au1x00 pcmcia support" - depends on SOC_AU1X00 && PCMCIA + depends on MIPS_ALCHEMY && PCMCIA config PCMCIA_ALCHEMY_DEVBOARD tristate "Alchemy Db/Pb1xxx PCMCIA socket services" - depends on SOC_AU1X00 && PCMCIA + depends on MIPS_ALCHEMY && PCMCIA select 64BIT_PHYS_ADDR help Enable this driver of you want PCMCIA support on your Alchemy diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 10ba12c8c5e..9d6952e92e7 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -774,7 +774,7 @@ config RTC_DRV_AT91SAM9_GPBR config RTC_DRV_AU1XXX tristate "Au1xxx Counter0 RTC support" - depends on SOC_AU1X00 + depends on MIPS_ALCHEMY help This is a driver for the Au1xxx on-chip Counter0 (Time-Of-Year counter) to be used as a RTC. diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 8b23165bc5d..1acc7b3c437 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -260,7 +260,7 @@ config SERIAL_8250_ACORN config SERIAL_8250_AU1X00 bool "Au1x00 serial port support" - depends on SERIAL_8250 != n && SOC_AU1X00 + depends on SERIAL_8250 != n && MIPS_ALCHEMY help If you have an Au1x00 SOC based board and want to use the serial port, say Y to this option. The driver can handle up to 4 serial ports, diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 6a58cb1330c..c2ddab1fcf5 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -45,7 +45,7 @@ config USB_ARCH_HAS_OHCI default y if STB03xxx default y if PPC_MPC52xx # MIPS: - default y if SOC_AU1X00 + default y if MIPS_ALCHEMY # SH: default y if CPU_SUBTYPE_SH7720 default y if CPU_SUBTYPE_SH7721 diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index fc576557d8a..ba6b0a5f547 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1031,7 +1031,7 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_hcd_ep93xx_driver #endif -#ifdef CONFIG_SOC_AU1X00 +#ifdef CONFIG_MIPS_ALCHEMY #include "ohci-au1xxx.c" #define PLATFORM_DRIVER ohci_hcd_au1xxx_driver #endif -- cgit v1.2.3-70-g09d2 From f66736532a6bc593a2d7cda68835a79c23836f1b Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Wed, 21 Jul 2010 14:30:50 +0200 Subject: MIPS: au1000_eth: Get ethernet address from platform_data au1000_eth uses firmware calls to get a valid MAC address, and changes it depending on platform device id. This patch moves this logic out of the driver into the platform device registration part, where boards with supported chips can use whatever firmware interface they need; the default implementation maintains compatibility with existing, YAMON-based firmware. Tested-by: Wolfgang Grandegger Acked-by: Florian Fainelli Signed-off-by: Manuel Lauss To: Linux-MIPS Cc: netdev@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1481/ Acked-by: David S. Miller Signed-off-by: Ralf Baechle --- arch/mips/alchemy/common/platform.c | 15 ++++++++++++- arch/mips/include/asm/mach-au1x00/au1xxx_eth.h | 1 + drivers/net/au1000_eth.c | 31 ++++++-------------------- 3 files changed, 22 insertions(+), 25 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c index c233d64a0d6..1dc55ee2681 100644 --- a/arch/mips/alchemy/common/platform.c +++ b/arch/mips/alchemy/common/platform.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -21,6 +22,8 @@ #include #include +#include + #define PORT(_base, _irq) \ { \ .mapbase = _base, \ @@ -434,17 +437,27 @@ static int __init au1xxx_platform_init(void) { unsigned int uartclk = get_au1x00_uart_baud_base() * 16; int err, i; + unsigned char ethaddr[6]; /* Fill up uartclk. */ for (i = 0; au1x00_uart_data[i].flags; i++) au1x00_uart_data[i].uartclk = uartclk; + /* use firmware-provided mac addr if available and necessary */ + i = prom_get_ethernet_addr(ethaddr); + if (!i && !is_valid_ether_addr(au1xxx_eth0_platform_data.mac)) + memcpy(au1xxx_eth0_platform_data.mac, ethaddr, 6); + err = platform_add_devices(au1xxx_platform_devices, ARRAY_SIZE(au1xxx_platform_devices)); #ifndef CONFIG_SOC_AU1100 + ethaddr[5] += 1; /* next addr for 2nd MAC */ + if (!i && !is_valid_ether_addr(au1xxx_eth1_platform_data.mac)) + memcpy(au1xxx_eth1_platform_data.mac, ethaddr, 6); + /* Register second MAC if enabled in pinfunc */ if (!err && !(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2)) - platform_device_register(&au1xxx_eth1_device); + err = platform_device_register(&au1xxx_eth1_device); #endif return err; diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_eth.h b/arch/mips/include/asm/mach-au1x00/au1xxx_eth.h index bae9b758fcd..49dc8d9db18 100644 --- a/arch/mips/include/asm/mach-au1x00/au1xxx_eth.h +++ b/arch/mips/include/asm/mach-au1x00/au1xxx_eth.h @@ -9,6 +9,7 @@ struct au1000_eth_platform_data { int phy_addr; int phy_busid; int phy_irq; + char mac[6]; }; void __init au1xxx_override_eth_cfg(unsigned port, diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index ece6128bef1..17e7e27eb22 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -104,14 +104,6 @@ MODULE_VERSION(DRV_VERSION); * complete immediately. */ -/* These addresses are only used if yamon doesn't tell us what - * the mac address is, and the mac address is not passed on the - * command line. - */ -static unsigned char au1000_mac_addr[6] __devinitdata = { - 0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00 -}; - struct au1000_private *au_macs[NUM_ETH_INTERFACES]; /* @@ -1002,7 +994,6 @@ static int __devinit au1000_probe(struct platform_device *pdev) db_dest_t *pDB, *pDBfree; int irq, i, err = 0; struct resource *base, *macen; - char ethaddr[6]; base = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!base) { @@ -1079,24 +1070,13 @@ static int __devinit au1000_probe(struct platform_device *pdev) } aup->mac_id = pdev->id; - if (pdev->id == 0) { - if (prom_get_ethernet_addr(ethaddr) == 0) - memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr)); - else { - netdev_info(dev, "No MAC address found\n"); - /* Use the hard coded MAC addresses */ - } - + if (pdev->id == 0) au1000_setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR); - } else if (pdev->id == 1) + else if (pdev->id == 1) au1000_setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR); - /* - * Assign to the Ethernet ports two consecutive MAC addresses - * to match those that are printed on their stickers - */ - memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr)); - dev->dev_addr[5] += pdev->id; + /* set a random MAC now in case platform_data doesn't provide one */ + random_ether_addr(dev->dev_addr); *aup->enable = 0; aup->mac_enabled = 0; @@ -1106,6 +1086,9 @@ static int __devinit au1000_probe(struct platform_device *pdev) dev_info(&pdev->dev, "no platform_data passed, PHY search on MAC0\n"); aup->phy1_search_mac0 = 1; } else { + if (is_valid_ether_addr(pd->mac)) + memcpy(dev->dev_addr, pd->mac, 6); + aup->phy_static_config = pd->phy_static_config; aup->phy_search_highest_addr = pd->phy_search_highest_addr; aup->phy1_search_mac0 = pd->phy1_search_mac0; -- cgit v1.2.3-70-g09d2 From a5decf700be1123c2da6bdab5099bce072c55cc2 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 23 Jul 2010 10:43:48 -0700 Subject: MIPS: Octeon: Get rid of a bunch of MSI IRQ number definitions. MSI IRQ numbers are allocated dynamically, so there is no reason to have all these static definitions. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1487/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-cavium-octeon/irq.h | 66 +------------------------- arch/mips/pci/msi-octeon.c | 4 +- 2 files changed, 4 insertions(+), 66 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-cavium-octeon/irq.h b/arch/mips/include/asm/mach-cavium-octeon/irq.h index d32220fbf4f..783dae74722 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/irq.h +++ b/arch/mips/include/asm/mach-cavium-octeon/irq.h @@ -172,71 +172,9 @@ #ifdef CONFIG_PCI_MSI /* 152 - 215 represent the MSI interrupts 0-63 */ #define OCTEON_IRQ_MSI_BIT0 152 -#define OCTEON_IRQ_MSI_BIT1 153 -#define OCTEON_IRQ_MSI_BIT2 154 -#define OCTEON_IRQ_MSI_BIT3 155 -#define OCTEON_IRQ_MSI_BIT4 156 -#define OCTEON_IRQ_MSI_BIT5 157 -#define OCTEON_IRQ_MSI_BIT6 158 -#define OCTEON_IRQ_MSI_BIT7 159 -#define OCTEON_IRQ_MSI_BIT8 160 -#define OCTEON_IRQ_MSI_BIT9 161 -#define OCTEON_IRQ_MSI_BIT10 162 -#define OCTEON_IRQ_MSI_BIT11 163 -#define OCTEON_IRQ_MSI_BIT12 164 -#define OCTEON_IRQ_MSI_BIT13 165 -#define OCTEON_IRQ_MSI_BIT14 166 -#define OCTEON_IRQ_MSI_BIT15 167 -#define OCTEON_IRQ_MSI_BIT16 168 -#define OCTEON_IRQ_MSI_BIT17 169 -#define OCTEON_IRQ_MSI_BIT18 170 -#define OCTEON_IRQ_MSI_BIT19 171 -#define OCTEON_IRQ_MSI_BIT20 172 -#define OCTEON_IRQ_MSI_BIT21 173 -#define OCTEON_IRQ_MSI_BIT22 174 -#define OCTEON_IRQ_MSI_BIT23 175 -#define OCTEON_IRQ_MSI_BIT24 176 -#define OCTEON_IRQ_MSI_BIT25 177 -#define OCTEON_IRQ_MSI_BIT26 178 -#define OCTEON_IRQ_MSI_BIT27 179 -#define OCTEON_IRQ_MSI_BIT28 180 -#define OCTEON_IRQ_MSI_BIT29 181 -#define OCTEON_IRQ_MSI_BIT30 182 -#define OCTEON_IRQ_MSI_BIT31 183 -#define OCTEON_IRQ_MSI_BIT32 184 -#define OCTEON_IRQ_MSI_BIT33 185 -#define OCTEON_IRQ_MSI_BIT34 186 -#define OCTEON_IRQ_MSI_BIT35 187 -#define OCTEON_IRQ_MSI_BIT36 188 -#define OCTEON_IRQ_MSI_BIT37 189 -#define OCTEON_IRQ_MSI_BIT38 190 -#define OCTEON_IRQ_MSI_BIT39 191 -#define OCTEON_IRQ_MSI_BIT40 192 -#define OCTEON_IRQ_MSI_BIT41 193 -#define OCTEON_IRQ_MSI_BIT42 194 -#define OCTEON_IRQ_MSI_BIT43 195 -#define OCTEON_IRQ_MSI_BIT44 196 -#define OCTEON_IRQ_MSI_BIT45 197 -#define OCTEON_IRQ_MSI_BIT46 198 -#define OCTEON_IRQ_MSI_BIT47 199 -#define OCTEON_IRQ_MSI_BIT48 200 -#define OCTEON_IRQ_MSI_BIT49 201 -#define OCTEON_IRQ_MSI_BIT50 202 -#define OCTEON_IRQ_MSI_BIT51 203 -#define OCTEON_IRQ_MSI_BIT52 204 -#define OCTEON_IRQ_MSI_BIT53 205 -#define OCTEON_IRQ_MSI_BIT54 206 -#define OCTEON_IRQ_MSI_BIT55 207 -#define OCTEON_IRQ_MSI_BIT56 208 -#define OCTEON_IRQ_MSI_BIT57 209 -#define OCTEON_IRQ_MSI_BIT58 210 -#define OCTEON_IRQ_MSI_BIT59 211 -#define OCTEON_IRQ_MSI_BIT60 212 -#define OCTEON_IRQ_MSI_BIT61 213 -#define OCTEON_IRQ_MSI_BIT62 214 -#define OCTEON_IRQ_MSI_BIT63 215 +#define OCTEON_IRQ_MSI_LAST (OCTEON_IRQ_MSI_BIT0 + 63) -#define OCTEON_IRQ_LAST 216 +#define OCTEON_IRQ_LAST (OCTEON_IRQ_MSI_LAST + 1) #else #define OCTEON_IRQ_LAST 152 #endif diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c index 1e31526f0e5..5ce1a6a6494 100644 --- a/arch/mips/pci/msi-octeon.c +++ b/arch/mips/pci/msi-octeon.c @@ -181,7 +181,7 @@ void arch_teardown_msi_irq(unsigned int irq) int number_irqs; uint64_t bitmask; - if ((irq < OCTEON_IRQ_MSI_BIT0) || (irq > OCTEON_IRQ_MSI_BIT63)) + if ((irq < OCTEON_IRQ_MSI_BIT0) || (irq > OCTEON_IRQ_MSI_LAST)) panic("arch_teardown_msi_irq: Attempted to teardown illegal " "MSI interrupt (%d)", irq); irq -= OCTEON_IRQ_MSI_BIT0; @@ -337,7 +337,7 @@ static int __init octeon_msi_initialize(void) { int irq; - for (irq = OCTEON_IRQ_MSI_BIT0; irq <= OCTEON_IRQ_MSI_BIT63; irq++) { + for (irq = OCTEON_IRQ_MSI_BIT0; irq <= OCTEON_IRQ_MSI_LAST; irq++) { set_irq_chip_and_handler(irq, &octeon_irq_chip_msi, handle_percpu_irq); } -- cgit v1.2.3-70-g09d2 From babba4f11379fb3804de802a3d0bc6b96c59d547 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 23 Jul 2010 10:57:51 -0700 Subject: MIPS: Octeon: HOTPLUG_CPU fixes. * Rename camel-case InitTLBStart_addr to octeon_bootloader_entry_addr. * Convert calls to cvmx_read64_uint32(), to simple pointer dereferences. * Set proper ebase. * Don't confuse coreid and cpu numbers. * Try to maintain consistent bootloader coremask. * Update the signature and boot_init_vector of supported bootloaders. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1491/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/octeon_boot.h | 16 +++-- arch/mips/cavium-octeon/smp.c | 125 +++++++++++++++------------------- arch/mips/include/asm/octeon/octeon.h | 2 + 3 files changed, 65 insertions(+), 78 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/cavium-octeon/octeon_boot.h b/arch/mips/cavium-octeon/octeon_boot.h index 0f7f84accf9..428864b2ba4 100644 --- a/arch/mips/cavium-octeon/octeon_boot.h +++ b/arch/mips/cavium-octeon/octeon_boot.h @@ -23,14 +23,16 @@ #include struct boot_init_vector { - uint32_t stack_addr; - uint32_t code_addr; + /* First stage address - in ram instead of flash */ + uint64_t code_addr; + /* Setup code for application, NOT application entry point */ uint32_t app_start_func_addr; + /* k0 is used for global data - needs to be passed to other cores */ uint32_t k0_val; - uint32_t flags; - uint32_t boot_info_addr; + /* Address of boot info block structure */ + uint64_t boot_info_addr; + uint32_t flags; /* flags */ uint32_t pad; - uint32_t pad2; }; /* similar to bootloader's linux_app_boot_info but without global data */ @@ -40,7 +42,7 @@ struct linux_app_boot_info { uint32_t avail_coremask; uint32_t pci_console_active; uint32_t icache_prefetch_disable; - uint32_t InitTLBStart_addr; + uint64_t InitTLBStart_addr; uint32_t start_app_addr; uint32_t cur_exception_base; uint32_t no_mark_private_data; @@ -58,7 +60,7 @@ struct linux_app_boot_info { #define LINUX_APP_BOOT_BLOCK_NAME "linux-app-boot" -#define LABI_SIGNATURE 0xAABBCCDD +#define LABI_SIGNATURE 0xAABBCC01 /* from uboot-headers/octeon_mem_map.h */ #define EXCEPTION_BASE_INCR (4 * 1024) diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index ceb76496e6a..391cefe556b 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -27,7 +27,8 @@ volatile unsigned long octeon_processor_sp; volatile unsigned long octeon_processor_gp; #ifdef CONFIG_HOTPLUG_CPU -static unsigned int InitTLBStart_addr; +uint64_t octeon_bootloader_entry_addr; +EXPORT_SYMBOL(octeon_bootloader_entry_addr); #endif static irqreturn_t mailbox_interrupt(int irq, void *dev_id) @@ -80,20 +81,13 @@ static inline void octeon_send_ipi_mask(const struct cpumask *mask, static void octeon_smp_hotplug_setup(void) { #ifdef CONFIG_HOTPLUG_CPU - uint32_t labi_signature; - - labi_signature = - cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, - LABI_ADDR_IN_BOOTLOADER + - offsetof(struct linux_app_boot_info, - labi_signature))); - if (labi_signature != LABI_SIGNATURE) - pr_err("The bootloader version on this board is incorrect\n"); - InitTLBStart_addr = - cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, - LABI_ADDR_IN_BOOTLOADER + - offsetof(struct linux_app_boot_info, - InitTLBStart_addr))); + struct linux_app_boot_info *labi; + + labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER); + if (labi->labi_signature != LABI_SIGNATURE) + panic("The bootloader version on this board is incorrect."); + + octeon_bootloader_entry_addr = labi->InitTLBStart_addr; #endif } @@ -181,18 +175,21 @@ static void octeon_init_secondary(void) { const int coreid = cvmx_get_core_num(); union cvmx_ciu_intx_sum0 interrupt_enable; + unsigned int sr; #ifdef CONFIG_HOTPLUG_CPU - unsigned int cur_exception_base; - - cur_exception_base = cvmx_read64_uint32( - CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, - LABI_ADDR_IN_BOOTLOADER + - offsetof(struct linux_app_boot_info, - cur_exception_base))); - /* cur_exception_base is incremented in bootloader after setting */ - write_c0_ebase((unsigned int)(cur_exception_base - EXCEPTION_BASE_INCR)); + struct linux_app_boot_info *labi; + + labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER); + + if (labi->labi_signature != LABI_SIGNATURE) + panic("The bootloader version on this board is incorrect."); #endif + + sr = set_c0_status(ST0_BEV); + write_c0_ebase((u32)ebase); + write_c0_status(sr); + octeon_check_cpu_bist(); octeon_init_cvmcount(); /* @@ -299,8 +296,8 @@ static int octeon_cpu_disable(void) static void octeon_cpu_die(unsigned int cpu) { int coreid = cpu_logical_map(cpu); - uint32_t avail_coremask; - struct cvmx_bootmem_named_block_desc *block_desc; + uint32_t mask, new_mask; + const struct cvmx_bootmem_named_block_desc *block_desc; while (per_cpu(cpu_state, cpu) != CPU_DEAD) cpu_relax(); @@ -309,52 +306,40 @@ static void octeon_cpu_die(unsigned int cpu) * This is a bit complicated strategics of getting/settig available * cores mask, copied from bootloader */ + + mask = 1 << coreid; /* LINUX_APP_BOOT_BLOCK is initialized in bootoct binary */ block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME); if (!block_desc) { - avail_coremask = - cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, - LABI_ADDR_IN_BOOTLOADER + - offsetof - (struct linux_app_boot_info, - avail_coremask))); - } else { /* alternative, already initialized */ - avail_coremask = - cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, - block_desc->base_addr + - AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK)); - } + struct linux_app_boot_info *labi; - avail_coremask |= 1 << coreid; + labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER); - /* Setting avail_coremask for bootoct binary */ - if (!block_desc) { - cvmx_write64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, - LABI_ADDR_IN_BOOTLOADER + - offsetof(struct linux_app_boot_info, - avail_coremask)), - avail_coremask); - } else { - cvmx_write64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, - block_desc->base_addr + - AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK), - avail_coremask); + labi->avail_coremask |= mask; + new_mask = labi->avail_coremask; + } else { /* alternative, already initialized */ + uint32_t *p = (uint32_t *)PHYS_TO_XKSEG_CACHED(block_desc->base_addr + + AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK); + *p |= mask; + new_mask = *p; } - pr_info("Reset core %d. Available Coremask = %x\n", coreid, - avail_coremask); + pr_info("Reset core %d. Available Coremask = 0x%x \n", coreid, new_mask); + mb(); cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid); cvmx_write_csr(CVMX_CIU_PP_RST, 0); } void play_dead(void) { - int coreid = cvmx_get_core_num(); + int cpu = cpu_number_map(cvmx_get_core_num()); idle_task_exit(); octeon_processor_boot = 0xff; - per_cpu(cpu_state, coreid) = CPU_DEAD; + per_cpu(cpu_state, cpu) = CPU_DEAD; + + mb(); while (1) /* core will be reset here */ ; @@ -367,29 +352,27 @@ static void start_after_reset(void) kernel_entry(0, 0, 0); /* set a2 = 0 for secondary core */ } -int octeon_update_boot_vector(unsigned int cpu) +static int octeon_update_boot_vector(unsigned int cpu) { int coreid = cpu_logical_map(cpu); - unsigned int avail_coremask; - struct cvmx_bootmem_named_block_desc *block_desc; + uint32_t avail_coremask; + const struct cvmx_bootmem_named_block_desc *block_desc; struct boot_init_vector *boot_vect = - (struct boot_init_vector *) cvmx_phys_to_ptr(0x0 + - BOOTLOADER_BOOT_VECTOR); + (struct boot_init_vector *)PHYS_TO_XKSEG_CACHED(BOOTLOADER_BOOT_VECTOR); block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME); if (!block_desc) { - avail_coremask = - cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, - LABI_ADDR_IN_BOOTLOADER + - offsetof(struct linux_app_boot_info, - avail_coremask))); + struct linux_app_boot_info *labi; + + labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER); + + avail_coremask = labi->avail_coremask; + labi->avail_coremask &= ~(1 << coreid); } else { /* alternative, already initialized */ - avail_coremask = - cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, - block_desc->base_addr + - AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK)); + avail_coremask = *(uint32_t *)PHYS_TO_XKSEG_CACHED( + block_desc->base_addr + AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK); } if (!(avail_coremask & (1 << coreid))) { @@ -400,9 +383,9 @@ int octeon_update_boot_vector(unsigned int cpu) boot_vect[coreid].app_start_func_addr = (uint32_t) (unsigned long) start_after_reset; - boot_vect[coreid].code_addr = InitTLBStart_addr; + boot_vect[coreid].code_addr = octeon_bootloader_entry_addr; - CVMX_SYNC; + mb(); cvmx_write_csr(CVMX_CIU_NMI, (1 << coreid) & avail_coremask); diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h index ca6214b5ccb..c29debe7a8a 100644 --- a/arch/mips/include/asm/octeon/octeon.h +++ b/arch/mips/include/asm/octeon/octeon.h @@ -253,4 +253,6 @@ static inline uint32_t octeon_npi_read32(uint64_t address) extern struct cvmx_bootinfo *octeon_bootinfo; +extern uint64_t octeon_bootloader_entry_addr; + #endif /* __ASM_OCTEON_OCTEON_H */ -- cgit v1.2.3-70-g09d2 From 83ccf69d8f118306e90af703f32109edb6c1e4a1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 17 Jul 2010 11:07:51 +0000 Subject: MIPS: JZ4740: Add base support for Ingenic JZ4740 System-on-a-Chip Adds a new cpu type for the JZ4740 to the Linux MIPS architecture code. It also adds the iomem addresses for the different components found on a JZ4740 SoC. Signed-off-by: Lars-Peter Clausen Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1464/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/bootinfo.h | 6 +++ arch/mips/include/asm/cpu.h | 9 +++- arch/mips/include/asm/mach-jz4740/base.h | 26 +++++++++++ .../asm/mach-jz4740/cpu-feature-overrides.h | 51 ++++++++++++++++++++++ arch/mips/include/asm/mach-jz4740/war.h | 25 +++++++++++ arch/mips/kernel/cpu-probe.c | 20 +++++++++ arch/mips/mm/tlbex.c | 5 +++ 7 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 arch/mips/include/asm/mach-jz4740/base.h create mode 100644 arch/mips/include/asm/mach-jz4740/cpu-feature-overrides.h create mode 100644 arch/mips/include/asm/mach-jz4740/war.h (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h index 09eee09780f..15a8ef0707c 100644 --- a/arch/mips/include/asm/bootinfo.h +++ b/arch/mips/include/asm/bootinfo.h @@ -71,6 +71,12 @@ #define MACH_LEMOTE_LL2F 7 #define MACH_LOONGSON_END 8 +/* + * Valid machtype for group INGENIC + */ +#define MACH_INGENIC_JZ4730 0 /* JZ4730 SOC */ +#define MACH_INGENIC_JZ4740 1 /* JZ4740 SOC */ + extern char *system_type; const char *get_system_type(void); diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index a5acda41694..b201a8f5b12 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -34,7 +34,7 @@ #define PRID_COMP_LSI 0x080000 #define PRID_COMP_LEXRA 0x0b0000 #define PRID_COMP_CAVIUM 0x0d0000 - +#define PRID_COMP_INGENIC 0xd00000 /* * Assigned values for the product ID register. In order to detect a @@ -132,6 +132,12 @@ #define PRID_IMP_CAVIUM_CN50XX 0x0600 #define PRID_IMP_CAVIUM_CN52XX 0x0700 +/* + * These are the PRID's for when 23:16 == PRID_COMP_INGENIC + */ + +#define PRID_IMP_JZRISC 0x0200 + /* * Definitions for 7:0 on legacy processors */ @@ -219,6 +225,7 @@ enum cpu_type_enum { CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K, CPU_ALCHEMY, CPU_PR4450, CPU_BCM3302, CPU_BCM4710, CPU_BCM6338, CPU_BCM6345, CPU_BCM6348, CPU_BCM6358, + CPU_JZRISC, /* * MIPS64 class processors diff --git a/arch/mips/include/asm/mach-jz4740/base.h b/arch/mips/include/asm/mach-jz4740/base.h new file mode 100644 index 00000000000..f3731860545 --- /dev/null +++ b/arch/mips/include/asm/mach-jz4740/base.h @@ -0,0 +1,26 @@ +#ifndef __ASM_MACH_JZ4740_BASE_H__ +#define __ASM_MACH_JZ4740_BASE_H__ + +#define JZ4740_CPM_BASE_ADDR 0x10000000 +#define JZ4740_INTC_BASE_ADDR 0x10001000 +#define JZ4740_WDT_BASE_ADDR 0x10002000 +#define JZ4740_TCU_BASE_ADDR 0x10002010 +#define JZ4740_RTC_BASE_ADDR 0x10003000 +#define JZ4740_GPIO_BASE_ADDR 0x10010000 +#define JZ4740_AIC_BASE_ADDR 0x10020000 +#define JZ4740_MSC_BASE_ADDR 0x10021000 +#define JZ4740_UART0_BASE_ADDR 0x10030000 +#define JZ4740_UART1_BASE_ADDR 0x10031000 +#define JZ4740_I2C_BASE_ADDR 0x10042000 +#define JZ4740_SSI_BASE_ADDR 0x10043000 +#define JZ4740_SADC_BASE_ADDR 0x10070000 +#define JZ4740_EMC_BASE_ADDR 0x13010000 +#define JZ4740_DMAC_BASE_ADDR 0x13020000 +#define JZ4740_UHC_BASE_ADDR 0x13030000 +#define JZ4740_UDC_BASE_ADDR 0x13040000 +#define JZ4740_LCD_BASE_ADDR 0x13050000 +#define JZ4740_SLCD_BASE_ADDR 0x13050000 +#define JZ4740_CIM_BASE_ADDR 0x13060000 +#define JZ4740_IPU_BASE_ADDR 0x13080000 + +#endif diff --git a/arch/mips/include/asm/mach-jz4740/cpu-feature-overrides.h b/arch/mips/include/asm/mach-jz4740/cpu-feature-overrides.h new file mode 100644 index 00000000000..d12e5c6477b --- /dev/null +++ b/arch/mips/include/asm/mach-jz4740/cpu-feature-overrides.h @@ -0,0 +1,51 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ +#ifndef __ASM_MACH_JZ4740_CPU_FEATURE_OVERRIDES_H +#define __ASM_MACH_JZ4740_CPU_FEATURE_OVERRIDES_H + +#define cpu_has_tlb 1 +#define cpu_has_4kex 1 +#define cpu_has_3k_cache 0 +#define cpu_has_4k_cache 1 +#define cpu_has_tx39_cache 0 +#define cpu_has_fpu 0 +#define cpu_has_32fpr 0 +#define cpu_has_counter 0 +#define cpu_has_watch 1 +#define cpu_has_divec 1 +#define cpu_has_vce 0 +#define cpu_has_cache_cdex_p 0 +#define cpu_has_cache_cdex_s 0 +#define cpu_has_prefetch 1 +#define cpu_has_mcheck 1 +#define cpu_has_ejtag 1 +#define cpu_has_llsc 1 +#define cpu_has_mips16 0 +#define cpu_has_mdmx 0 +#define cpu_has_mips3d 0 +#define cpu_has_smartmips 0 +#define kernel_uses_llsc 1 +#define cpu_has_vtag_icache 1 +#define cpu_has_dc_aliases 0 +#define cpu_has_ic_fills_f_dc 0 +#define cpu_has_pindexed_dcache 0 +#define cpu_has_mips32r1 1 +#define cpu_has_mips32r2 0 +#define cpu_has_mips64r1 0 +#define cpu_has_mips64r2 0 +#define cpu_has_dsp 0 +#define cpu_has_mipsmt 0 +#define cpu_has_userlocal 0 +#define cpu_has_nofpuex 0 +#define cpu_has_64bits 0 +#define cpu_has_64bit_zero_reg 0 +#define cpu_has_inclusive_pcaches 0 + +#define cpu_dcache_line_size() 32 +#define cpu_icache_line_size() 32 + +#endif diff --git a/arch/mips/include/asm/mach-jz4740/war.h b/arch/mips/include/asm/mach-jz4740/war.h new file mode 100644 index 00000000000..3a5bc17e28f --- /dev/null +++ b/arch/mips/include/asm/mach-jz4740/war.h @@ -0,0 +1,25 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H +#define __ASM_MIPS_MACH_JZ4740_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */ diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 3562b854f2c..9b6633171a1 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -187,6 +187,7 @@ void __init check_wait(void) case CPU_BCM6358: case CPU_CAVIUM_OCTEON: case CPU_CAVIUM_OCTEON_PLUS: + case CPU_JZRISC: cpu_wait = r4k_wait; break; @@ -956,6 +957,22 @@ platform: } } +static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) +{ + decode_configs(c); + /* JZRISC does not implement the CP0 counter. */ + c->options &= ~MIPS_CPU_COUNTER; + switch (c->processor_id & 0xff00) { + case PRID_IMP_JZRISC: + c->cputype = CPU_JZRISC; + __cpu_name[cpu] = "Ingenic JZRISC"; + break; + default: + panic("Unknown Ingenic Processor ID!"); + break; + } +} + const char *__cpu_name[NR_CPUS]; const char *__elf_platform; @@ -994,6 +1011,9 @@ __cpuinit void cpu_probe(void) case PRID_COMP_CAVIUM: cpu_probe_cavium(c, cpu); break; + case PRID_COMP_INGENIC: + cpu_probe_ingenic(c, cpu); + break; } BUG_ON(!__cpu_name[cpu]); diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 86f004dc835..4510e61883e 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -409,6 +409,11 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l, tlbw(p); break; + case CPU_JZRISC: + tlbw(p); + uasm_i_nop(p); + break; + default: panic("No TLB refill handler yet (CPU type: %d)", current_cpu_data.cputype); -- cgit v1.2.3-70-g09d2 From 570a0bb82f0b5c2c6324153010e72c3f0c26a7a3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 17 Jul 2010 11:10:00 +0000 Subject: MIPS: JZ4740: Add clock API support. Add support for managing the clocks found on JZ4740 SoC through the Linux clock API. Signed-off-by: Lars-Peter Clausen Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1466/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-jz4740/clock.h | 28 + arch/mips/jz4740/clock-debugfs.c | 109 ++++ arch/mips/jz4740/clock.c | 924 ++++++++++++++++++++++++++++++ arch/mips/jz4740/clock.h | 76 +++ 4 files changed, 1137 insertions(+) create mode 100644 arch/mips/include/asm/mach-jz4740/clock.h create mode 100644 arch/mips/jz4740/clock-debugfs.c create mode 100644 arch/mips/jz4740/clock.c create mode 100644 arch/mips/jz4740/clock.h (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-jz4740/clock.h b/arch/mips/include/asm/mach-jz4740/clock.h new file mode 100644 index 00000000000..1b7408dd0e2 --- /dev/null +++ b/arch/mips/include/asm/mach-jz4740/clock.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __ASM_JZ4740_CLOCK_H__ +#define __ASM_JZ4740_CLOCK_H__ + +enum jz4740_wait_mode { + JZ4740_WAIT_MODE_IDLE, + JZ4740_WAIT_MODE_SLEEP, +}; + +void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode); + +void jz4740_clock_udc_enable_auto_suspend(void); +void jz4740_clock_udc_disable_auto_suspend(void); + +#endif diff --git a/arch/mips/jz4740/clock-debugfs.c b/arch/mips/jz4740/clock-debugfs.c new file mode 100644 index 00000000000..330a0f2bf17 --- /dev/null +++ b/arch/mips/jz4740/clock-debugfs.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * JZ4740 SoC clock support debugfs entries + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include "clock.h" + +static struct dentry *jz4740_clock_debugfs; + +static int jz4740_clock_debugfs_show_enabled(void *data, uint64_t *value) +{ + struct clk *clk = data; + *value = clk_is_enabled(clk); + + return 0; +} + +static int jz4740_clock_debugfs_set_enabled(void *data, uint64_t value) +{ + struct clk *clk = data; + + if (value) + return clk_enable(clk); + else + clk_disable(clk); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(jz4740_clock_debugfs_ops_enabled, + jz4740_clock_debugfs_show_enabled, + jz4740_clock_debugfs_set_enabled, + "%llu\n"); + +static int jz4740_clock_debugfs_show_rate(void *data, uint64_t *value) +{ + struct clk *clk = data; + *value = clk_get_rate(clk); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(jz4740_clock_debugfs_ops_rate, + jz4740_clock_debugfs_show_rate, + NULL, + "%llu\n"); + +void jz4740_clock_debugfs_add_clk(struct clk *clk) +{ + if (!jz4740_clock_debugfs) + return; + + clk->debugfs_entry = debugfs_create_dir(clk->name, jz4740_clock_debugfs); + debugfs_create_file("rate", S_IWUGO | S_IRUGO, clk->debugfs_entry, clk, + &jz4740_clock_debugfs_ops_rate); + debugfs_create_file("enabled", S_IRUGO, clk->debugfs_entry, clk, + &jz4740_clock_debugfs_ops_enabled); + + if (clk->parent) { + char parent_path[100]; + snprintf(parent_path, 100, "../%s", clk->parent->name); + clk->debugfs_parent_entry = debugfs_create_symlink("parent", + clk->debugfs_entry, + parent_path); + } +} + +/* TODO: Locking */ +void jz4740_clock_debugfs_update_parent(struct clk *clk) +{ + if (clk->debugfs_parent_entry) + debugfs_remove(clk->debugfs_parent_entry); + + if (clk->parent) { + char parent_path[100]; + snprintf(parent_path, 100, "../%s", clk->parent->name); + clk->debugfs_parent_entry = debugfs_create_symlink("parent", + clk->debugfs_entry, + parent_path); + } else { + clk->debugfs_parent_entry = NULL; + } +} + +void jz4740_clock_debugfs_init(void) +{ + jz4740_clock_debugfs = debugfs_create_dir("jz4740-clock", NULL); + if (IS_ERR(jz4740_clock_debugfs)) + jz4740_clock_debugfs = NULL; +} diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c new file mode 100644 index 00000000000..118a8a5562d --- /dev/null +++ b/arch/mips/jz4740/clock.c @@ -0,0 +1,924 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * JZ4740 SoC clock support + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "clock.h" + +#define JZ_REG_CLOCK_CTRL 0x00 +#define JZ_REG_CLOCK_LOW_POWER 0x04 +#define JZ_REG_CLOCK_PLL 0x10 +#define JZ_REG_CLOCK_GATE 0x20 +#define JZ_REG_CLOCK_SLEEP_CTRL 0x24 +#define JZ_REG_CLOCK_I2S 0x60 +#define JZ_REG_CLOCK_LCD 0x64 +#define JZ_REG_CLOCK_MMC 0x68 +#define JZ_REG_CLOCK_UHC 0x6C +#define JZ_REG_CLOCK_SPI 0x74 + +#define JZ_CLOCK_CTRL_I2S_SRC_PLL BIT(31) +#define JZ_CLOCK_CTRL_KO_ENABLE BIT(30) +#define JZ_CLOCK_CTRL_UDC_SRC_PLL BIT(29) +#define JZ_CLOCK_CTRL_UDIV_MASK 0x1f800000 +#define JZ_CLOCK_CTRL_CHANGE_ENABLE BIT(22) +#define JZ_CLOCK_CTRL_PLL_HALF BIT(21) +#define JZ_CLOCK_CTRL_LDIV_MASK 0x001f0000 +#define JZ_CLOCK_CTRL_UDIV_OFFSET 23 +#define JZ_CLOCK_CTRL_LDIV_OFFSET 16 +#define JZ_CLOCK_CTRL_MDIV_OFFSET 12 +#define JZ_CLOCK_CTRL_PDIV_OFFSET 8 +#define JZ_CLOCK_CTRL_HDIV_OFFSET 4 +#define JZ_CLOCK_CTRL_CDIV_OFFSET 0 + +#define JZ_CLOCK_GATE_UART0 BIT(0) +#define JZ_CLOCK_GATE_TCU BIT(1) +#define JZ_CLOCK_GATE_RTC BIT(2) +#define JZ_CLOCK_GATE_I2C BIT(3) +#define JZ_CLOCK_GATE_SPI BIT(4) +#define JZ_CLOCK_GATE_AIC BIT(5) +#define JZ_CLOCK_GATE_I2S BIT(6) +#define JZ_CLOCK_GATE_MMC BIT(7) +#define JZ_CLOCK_GATE_ADC BIT(8) +#define JZ_CLOCK_GATE_CIM BIT(9) +#define JZ_CLOCK_GATE_LCD BIT(10) +#define JZ_CLOCK_GATE_UDC BIT(11) +#define JZ_CLOCK_GATE_DMAC BIT(12) +#define JZ_CLOCK_GATE_IPU BIT(13) +#define JZ_CLOCK_GATE_UHC BIT(14) +#define JZ_CLOCK_GATE_UART1 BIT(15) + +#define JZ_CLOCK_I2S_DIV_MASK 0x01ff + +#define JZ_CLOCK_LCD_DIV_MASK 0x01ff + +#define JZ_CLOCK_MMC_DIV_MASK 0x001f + +#define JZ_CLOCK_UHC_DIV_MASK 0x000f + +#define JZ_CLOCK_SPI_SRC_PLL BIT(31) +#define JZ_CLOCK_SPI_DIV_MASK 0x000f + +#define JZ_CLOCK_PLL_M_MASK 0x01ff +#define JZ_CLOCK_PLL_N_MASK 0x001f +#define JZ_CLOCK_PLL_OD_MASK 0x0003 +#define JZ_CLOCK_PLL_STABLE BIT(10) +#define JZ_CLOCK_PLL_BYPASS BIT(9) +#define JZ_CLOCK_PLL_ENABLED BIT(8) +#define JZ_CLOCK_PLL_STABLIZE_MASK 0x000f +#define JZ_CLOCK_PLL_M_OFFSET 23 +#define JZ_CLOCK_PLL_N_OFFSET 18 +#define JZ_CLOCK_PLL_OD_OFFSET 16 + +#define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2) +#define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0) + +#define JZ_CLOCK_SLEEP_CTRL_SUSPEND_UHC BIT(7) +#define JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC BIT(6) + +static void __iomem *jz_clock_base; +static spinlock_t jz_clock_lock; +static LIST_HEAD(jz_clocks); + +struct main_clk { + struct clk clk; + uint32_t div_offset; +}; + +struct divided_clk { + struct clk clk; + uint32_t reg; + uint32_t mask; +}; + +struct static_clk { + struct clk clk; + unsigned long rate; +}; + +static uint32_t jz_clk_reg_read(int reg) +{ + return readl(jz_clock_base + reg); +} + +static void jz_clk_reg_write_mask(int reg, uint32_t val, uint32_t mask) +{ + uint32_t val2; + + spin_lock(&jz_clock_lock); + val2 = readl(jz_clock_base + reg); + val2 &= ~mask; + val2 |= val; + writel(val2, jz_clock_base + reg); + spin_unlock(&jz_clock_lock); +} + +static void jz_clk_reg_set_bits(int reg, uint32_t mask) +{ + uint32_t val; + + spin_lock(&jz_clock_lock); + val = readl(jz_clock_base + reg); + val |= mask; + writel(val, jz_clock_base + reg); + spin_unlock(&jz_clock_lock); +} + +static void jz_clk_reg_clear_bits(int reg, uint32_t mask) +{ + uint32_t val; + + spin_lock(&jz_clock_lock); + val = readl(jz_clock_base + reg); + val &= ~mask; + writel(val, jz_clock_base + reg); + spin_unlock(&jz_clock_lock); +} + +static int jz_clk_enable_gating(struct clk *clk) +{ + if (clk->gate_bit == JZ4740_CLK_NOT_GATED) + return -EINVAL; + + jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, clk->gate_bit); + return 0; +} + +static int jz_clk_disable_gating(struct clk *clk) +{ + if (clk->gate_bit == JZ4740_CLK_NOT_GATED) + return -EINVAL; + + jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, clk->gate_bit); + return 0; +} + +static int jz_clk_is_enabled_gating(struct clk *clk) +{ + if (clk->gate_bit == JZ4740_CLK_NOT_GATED) + return 1; + + return !(jz_clk_reg_read(JZ_REG_CLOCK_GATE) & clk->gate_bit); +} + +static unsigned long jz_clk_static_get_rate(struct clk *clk) +{ + return ((struct static_clk *)clk)->rate; +} + +static int jz_clk_ko_enable(struct clk *clk) +{ + jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE); + return 0; +} + +static int jz_clk_ko_disable(struct clk *clk) +{ + jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE); + return 0; +} + +static int jz_clk_ko_is_enabled(struct clk *clk) +{ + return !!(jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_KO_ENABLE); +} + +static const int pllno[] = {1, 2, 2, 4}; + +static unsigned long jz_clk_pll_get_rate(struct clk *clk) +{ + uint32_t val; + int m; + int n; + int od; + + val = jz_clk_reg_read(JZ_REG_CLOCK_PLL); + + if (val & JZ_CLOCK_PLL_BYPASS) + return clk_get_rate(clk->parent); + + m = ((val >> 23) & 0x1ff) + 2; + n = ((val >> 18) & 0x1f) + 2; + od = (val >> 16) & 0x3; + + return ((clk_get_rate(clk->parent) / n) * m) / pllno[od]; +} + +static unsigned long jz_clk_pll_half_get_rate(struct clk *clk) +{ + uint32_t reg; + + reg = jz_clk_reg_read(JZ_REG_CLOCK_CTRL); + if (reg & JZ_CLOCK_CTRL_PLL_HALF) + return jz_clk_pll_get_rate(clk->parent); + return jz_clk_pll_get_rate(clk->parent) >> 1; +} + +static const int jz_clk_main_divs[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + +static unsigned long jz_clk_main_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = jz_clk_pll_get_rate(clk->parent); + int div; + + div = parent_rate / rate; + if (div > 32) + return parent_rate / 32; + else if (div < 1) + return parent_rate; + + div &= (0x3 << (ffs(div) - 1)); + + return parent_rate / div; +} + +static unsigned long jz_clk_main_get_rate(struct clk *clk) +{ + struct main_clk *mclk = (struct main_clk *)clk; + uint32_t div; + + div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL); + + div >>= mclk->div_offset; + div &= 0xf; + + if (div >= ARRAY_SIZE(jz_clk_main_divs)) + div = ARRAY_SIZE(jz_clk_main_divs) - 1; + + return jz_clk_pll_get_rate(clk->parent) / jz_clk_main_divs[div]; +} + +static int jz_clk_main_set_rate(struct clk *clk, unsigned long rate) +{ + struct main_clk *mclk = (struct main_clk *)clk; + int i; + int div; + unsigned long parent_rate = jz_clk_pll_get_rate(clk->parent); + + rate = jz_clk_main_round_rate(clk, rate); + + div = parent_rate / rate; + + i = (ffs(div) - 1) << 1; + if (i > 0 && !(div & BIT(i-1))) + i -= 1; + + jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, i << mclk->div_offset, + 0xf << mclk->div_offset); + + return 0; +} + +static struct clk_ops jz_clk_static_ops = { + .get_rate = jz_clk_static_get_rate, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, + .is_enabled = jz_clk_is_enabled_gating, +}; + +static struct static_clk jz_clk_ext = { + .clk = { + .name = "ext", + .gate_bit = JZ4740_CLK_NOT_GATED, + .ops = &jz_clk_static_ops, + }, +}; + +static struct clk_ops jz_clk_pll_ops = { + .get_rate = jz_clk_pll_get_rate, +}; + +static struct clk jz_clk_pll = { + .name = "pll", + .parent = &jz_clk_ext.clk, + .ops = &jz_clk_pll_ops, +}; + +static struct clk_ops jz_clk_pll_half_ops = { + .get_rate = jz_clk_pll_half_get_rate, +}; + +static struct clk jz_clk_pll_half = { + .name = "pll half", + .parent = &jz_clk_pll, + .ops = &jz_clk_pll_half_ops, +}; + +static const struct clk_ops jz_clk_main_ops = { + .get_rate = jz_clk_main_get_rate, + .set_rate = jz_clk_main_set_rate, + .round_rate = jz_clk_main_round_rate, +}; + +static struct main_clk jz_clk_cpu = { + .clk = { + .name = "cclk", + .parent = &jz_clk_pll, + .ops = &jz_clk_main_ops, + }, + .div_offset = JZ_CLOCK_CTRL_CDIV_OFFSET, +}; + +static struct main_clk jz_clk_memory = { + .clk = { + .name = "mclk", + .parent = &jz_clk_pll, + .ops = &jz_clk_main_ops, + }, + .div_offset = JZ_CLOCK_CTRL_MDIV_OFFSET, +}; + +static struct main_clk jz_clk_high_speed_peripheral = { + .clk = { + .name = "hclk", + .parent = &jz_clk_pll, + .ops = &jz_clk_main_ops, + }, + .div_offset = JZ_CLOCK_CTRL_HDIV_OFFSET, +}; + + +static struct main_clk jz_clk_low_speed_peripheral = { + .clk = { + .name = "pclk", + .parent = &jz_clk_pll, + .ops = &jz_clk_main_ops, + }, + .div_offset = JZ_CLOCK_CTRL_PDIV_OFFSET, +}; + +static const struct clk_ops jz_clk_ko_ops = { + .enable = jz_clk_ko_enable, + .disable = jz_clk_ko_disable, + .is_enabled = jz_clk_ko_is_enabled, +}; + +static struct clk jz_clk_ko = { + .name = "cko", + .parent = &jz_clk_memory.clk, + .ops = &jz_clk_ko_ops, +}; + +static int jz_clk_spi_set_parent(struct clk *clk, struct clk *parent) +{ + if (parent == &jz_clk_pll) + jz_clk_reg_set_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI); + else if (parent == &jz_clk_ext.clk) + jz_clk_reg_clear_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI); + else + return -EINVAL; + + clk->parent = parent; + + return 0; +} + +static int jz_clk_i2s_set_parent(struct clk *clk, struct clk *parent) +{ + if (parent == &jz_clk_pll_half) + jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL); + else if (parent == &jz_clk_ext.clk) + jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL); + else + return -EINVAL; + + clk->parent = parent; + + return 0; +} + +static int jz_clk_udc_enable(struct clk *clk) +{ + jz_clk_reg_set_bits(JZ_REG_CLOCK_SLEEP_CTRL, + JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC); + + return 0; +} + +static int jz_clk_udc_disable(struct clk *clk) +{ + jz_clk_reg_clear_bits(JZ_REG_CLOCK_SLEEP_CTRL, + JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC); + + return 0; +} + +static int jz_clk_udc_is_enabled(struct clk *clk) +{ + return !!(jz_clk_reg_read(JZ_REG_CLOCK_SLEEP_CTRL) & + JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC); +} + +static int jz_clk_udc_set_parent(struct clk *clk, struct clk *parent) +{ + if (parent == &jz_clk_pll_half) + jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL); + else if (parent == &jz_clk_ext.clk) + jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL); + else + return -EINVAL; + + clk->parent = parent; + + return 0; +} + +static int jz_clk_udc_set_rate(struct clk *clk, unsigned long rate) +{ + int div; + + if (clk->parent == &jz_clk_ext.clk) + return -EINVAL; + + div = clk_get_rate(clk->parent) / rate - 1; + + if (div < 0) + div = 0; + else if (div > 63) + div = 63; + + jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_UDIV_OFFSET, + JZ_CLOCK_CTRL_UDIV_MASK); + return 0; +} + +static unsigned long jz_clk_udc_get_rate(struct clk *clk) +{ + int div; + + if (clk->parent == &jz_clk_ext.clk) + return clk_get_rate(clk->parent); + + div = (jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_UDIV_MASK); + div >>= JZ_CLOCK_CTRL_UDIV_OFFSET; + div += 1; + + return clk_get_rate(clk->parent) / div; +} + +static unsigned long jz_clk_divided_get_rate(struct clk *clk) +{ + struct divided_clk *dclk = (struct divided_clk *)clk; + int div; + + if (clk->parent == &jz_clk_ext.clk) + return clk_get_rate(clk->parent); + + div = (jz_clk_reg_read(dclk->reg) & dclk->mask) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int jz_clk_divided_set_rate(struct clk *clk, unsigned long rate) +{ + struct divided_clk *dclk = (struct divided_clk *)clk; + int div; + + if (clk->parent == &jz_clk_ext.clk) + return -EINVAL; + + div = clk_get_rate(clk->parent) / rate - 1; + + if (div < 0) + div = 0; + else if (div > dclk->mask) + div = dclk->mask; + + jz_clk_reg_write_mask(dclk->reg, div, dclk->mask); + + return 0; +} + +static unsigned long jz_clk_ldclk_round_rate(struct clk *clk, unsigned long rate) +{ + int div; + unsigned long parent_rate = jz_clk_pll_half_get_rate(clk->parent); + + if (rate > 150000000) + return 150000000; + + div = parent_rate / rate; + if (div < 1) + div = 1; + else if (div > 32) + div = 32; + + return parent_rate / div; +} + +static int jz_clk_ldclk_set_rate(struct clk *clk, unsigned long rate) +{ + int div; + + if (rate > 150000000) + return -EINVAL; + + div = jz_clk_pll_half_get_rate(clk->parent) / rate - 1; + if (div < 0) + div = 0; + else if (div > 31) + div = 31; + + jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_LDIV_OFFSET, + JZ_CLOCK_CTRL_LDIV_MASK); + + return 0; +} + +static unsigned long jz_clk_ldclk_get_rate(struct clk *clk) +{ + int div; + + div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_LDIV_MASK; + div >>= JZ_CLOCK_CTRL_LDIV_OFFSET; + + return jz_clk_pll_half_get_rate(clk->parent) / (div + 1); +} + +static const struct clk_ops jz_clk_ops_ld = { + .set_rate = jz_clk_ldclk_set_rate, + .get_rate = jz_clk_ldclk_get_rate, + .round_rate = jz_clk_ldclk_round_rate, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, + .is_enabled = jz_clk_is_enabled_gating, +}; + +static struct clk jz_clk_ld = { + .name = "lcd", + .gate_bit = JZ_CLOCK_GATE_LCD, + .parent = &jz_clk_pll_half, + .ops = &jz_clk_ops_ld, +}; + +static const struct clk_ops jz_clk_i2s_ops = { + .set_rate = jz_clk_divided_set_rate, + .get_rate = jz_clk_divided_get_rate, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, + .is_enabled = jz_clk_is_enabled_gating, + .set_parent = jz_clk_i2s_set_parent, +}; + +static const struct clk_ops jz_clk_spi_ops = { + .set_rate = jz_clk_divided_set_rate, + .get_rate = jz_clk_divided_get_rate, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, + .is_enabled = jz_clk_is_enabled_gating, + .set_parent = jz_clk_spi_set_parent, +}; + +static const struct clk_ops jz_clk_divided_ops = { + .set_rate = jz_clk_divided_set_rate, + .get_rate = jz_clk_divided_get_rate, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, + .is_enabled = jz_clk_is_enabled_gating, +}; + +static struct divided_clk jz4740_clock_divided_clks[] = { + [0] = { + .clk = { + .name = "i2s", + .parent = &jz_clk_ext.clk, + .gate_bit = JZ_CLOCK_GATE_I2S, + .ops = &jz_clk_i2s_ops, + }, + .reg = JZ_REG_CLOCK_I2S, + .mask = JZ_CLOCK_I2S_DIV_MASK, + }, + [1] = { + .clk = { + .name = "spi", + .parent = &jz_clk_ext.clk, + .gate_bit = JZ_CLOCK_GATE_SPI, + .ops = &jz_clk_spi_ops, + }, + .reg = JZ_REG_CLOCK_SPI, + .mask = JZ_CLOCK_SPI_DIV_MASK, + }, + [2] = { + .clk = { + .name = "lcd_pclk", + .parent = &jz_clk_pll_half, + .gate_bit = JZ4740_CLK_NOT_GATED, + .ops = &jz_clk_divided_ops, + }, + .reg = JZ_REG_CLOCK_LCD, + .mask = JZ_CLOCK_LCD_DIV_MASK, + }, + [3] = { + .clk = { + .name = "mmc", + .parent = &jz_clk_pll_half, + .gate_bit = JZ_CLOCK_GATE_MMC, + .ops = &jz_clk_divided_ops, + }, + .reg = JZ_REG_CLOCK_MMC, + .mask = JZ_CLOCK_MMC_DIV_MASK, + }, + [4] = { + .clk = { + .name = "uhc", + .parent = &jz_clk_pll_half, + .gate_bit = JZ_CLOCK_GATE_UHC, + .ops = &jz_clk_divided_ops, + }, + .reg = JZ_REG_CLOCK_UHC, + .mask = JZ_CLOCK_UHC_DIV_MASK, + }, +}; + +static const struct clk_ops jz_clk_udc_ops = { + .set_parent = jz_clk_udc_set_parent, + .set_rate = jz_clk_udc_set_rate, + .get_rate = jz_clk_udc_get_rate, + .enable = jz_clk_udc_enable, + .disable = jz_clk_udc_disable, + .is_enabled = jz_clk_udc_is_enabled, +}; + +static const struct clk_ops jz_clk_simple_ops = { + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, + .is_enabled = jz_clk_is_enabled_gating, +}; + +static struct clk jz4740_clock_simple_clks[] = { + [0] = { + .name = "udc", + .parent = &jz_clk_ext.clk, + .ops = &jz_clk_udc_ops, + }, + [1] = { + .name = "uart0", + .parent = &jz_clk_ext.clk, + .gate_bit = JZ_CLOCK_GATE_UART0, + .ops = &jz_clk_simple_ops, + }, + [2] = { + .name = "uart1", + .parent = &jz_clk_ext.clk, + .gate_bit = JZ_CLOCK_GATE_UART1, + .ops = &jz_clk_simple_ops, + }, + [3] = { + .name = "dma", + .parent = &jz_clk_high_speed_peripheral.clk, + .gate_bit = JZ_CLOCK_GATE_UART0, + .ops = &jz_clk_simple_ops, + }, + [4] = { + .name = "ipu", + .parent = &jz_clk_high_speed_peripheral.clk, + .gate_bit = JZ_CLOCK_GATE_IPU, + .ops = &jz_clk_simple_ops, + }, + [5] = { + .name = "adc", + .parent = &jz_clk_ext.clk, + .gate_bit = JZ_CLOCK_GATE_ADC, + .ops = &jz_clk_simple_ops, + }, + [6] = { + .name = "i2c", + .parent = &jz_clk_ext.clk, + .gate_bit = JZ_CLOCK_GATE_I2C, + .ops = &jz_clk_simple_ops, + }, + [7] = { + .name = "aic", + .parent = &jz_clk_ext.clk, + .gate_bit = JZ_CLOCK_GATE_AIC, + .ops = &jz_clk_simple_ops, + }, +}; + +static struct static_clk jz_clk_rtc = { + .clk = { + .name = "rtc", + .gate_bit = JZ_CLOCK_GATE_RTC, + .ops = &jz_clk_static_ops, + }, + .rate = 32768, +}; + +int clk_enable(struct clk *clk) +{ + if (!clk->ops->enable) + return -EINVAL; + + return clk->ops->enable(clk); +} +EXPORT_SYMBOL_GPL(clk_enable); + +void clk_disable(struct clk *clk) +{ + if (clk->ops->disable) + clk->ops->disable(clk); +} +EXPORT_SYMBOL_GPL(clk_disable); + +int clk_is_enabled(struct clk *clk) +{ + if (clk->ops->is_enabled) + return clk->ops->is_enabled(clk); + + return 1; +} + +unsigned long clk_get_rate(struct clk *clk) +{ + if (clk->ops->get_rate) + return clk->ops->get_rate(clk); + if (clk->parent) + return clk_get_rate(clk->parent); + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(clk_get_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + if (!clk->ops->set_rate) + return -EINVAL; + return clk->ops->set_rate(clk, rate); +} +EXPORT_SYMBOL_GPL(clk_set_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (clk->ops->round_rate) + return clk->ops->round_rate(clk, rate); + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(clk_round_rate); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + int ret; + int enabled; + + if (!clk->ops->set_parent) + return -EINVAL; + + enabled = clk_is_enabled(clk); + if (enabled) + clk_disable(clk); + ret = clk->ops->set_parent(clk, parent); + if (enabled) + clk_enable(clk); + + jz4740_clock_debugfs_update_parent(clk); + + return ret; +} +EXPORT_SYMBOL_GPL(clk_set_parent); + +struct clk *clk_get(struct device *dev, const char *name) +{ + struct clk *clk; + + list_for_each_entry(clk, &jz_clocks, list) { + if (strcmp(clk->name, name) == 0) + return clk; + } + return ERR_PTR(-ENXIO); +} +EXPORT_SYMBOL_GPL(clk_get); + +void clk_put(struct clk *clk) +{ +} +EXPORT_SYMBOL_GPL(clk_put); + +static inline void clk_add(struct clk *clk) +{ + list_add_tail(&clk->list, &jz_clocks); + + jz4740_clock_debugfs_add_clk(clk); +} + +static void clk_register_clks(void) +{ + size_t i; + + clk_add(&jz_clk_ext.clk); + clk_add(&jz_clk_pll); + clk_add(&jz_clk_pll_half); + clk_add(&jz_clk_cpu.clk); + clk_add(&jz_clk_high_speed_peripheral.clk); + clk_add(&jz_clk_low_speed_peripheral.clk); + clk_add(&jz_clk_ko); + clk_add(&jz_clk_ld); + clk_add(&jz_clk_rtc.clk); + + for (i = 0; i < ARRAY_SIZE(jz4740_clock_divided_clks); ++i) + clk_add(&jz4740_clock_divided_clks[i].clk); + + for (i = 0; i < ARRAY_SIZE(jz4740_clock_simple_clks); ++i) + clk_add(&jz4740_clock_simple_clks[i]); +} + +void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode) +{ + switch (mode) { + case JZ4740_WAIT_MODE_IDLE: + jz_clk_reg_clear_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP); + break; + case JZ4740_WAIT_MODE_SLEEP: + jz_clk_reg_set_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP); + break; + } +} + +void jz4740_clock_udc_disable_auto_suspend(void) +{ + jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC); +} +EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend); + +void jz4740_clock_udc_enable_auto_suspend(void) +{ + jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC); +} +EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend); + +void jz4740_clock_suspend(void) +{ + jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, + JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0); + + jz_clk_reg_clear_bits(JZ_REG_CLOCK_PLL, JZ_CLOCK_PLL_ENABLED); +} + +void jz4740_clock_resume(void) +{ + uint32_t pll; + + jz_clk_reg_set_bits(JZ_REG_CLOCK_PLL, JZ_CLOCK_PLL_ENABLED); + + do { + pll = jz_clk_reg_read(JZ_REG_CLOCK_PLL); + } while (!(pll & JZ_CLOCK_PLL_STABLE)); + + jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, + JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0); +} + +static int jz4740_clock_init(void) +{ + uint32_t val; + + jz_clock_base = ioremap(JZ4740_CPM_BASE_ADDR, 0x100); + if (!jz_clock_base) + return -EBUSY; + + spin_lock_init(&jz_clock_lock); + + jz_clk_ext.rate = jz4740_clock_bdata.ext_rate; + jz_clk_rtc.rate = jz4740_clock_bdata.rtc_rate; + + val = jz_clk_reg_read(JZ_REG_CLOCK_SPI); + + if (val & JZ_CLOCK_SPI_SRC_PLL) + jz4740_clock_divided_clks[1].clk.parent = &jz_clk_pll_half; + + val = jz_clk_reg_read(JZ_REG_CLOCK_CTRL); + + if (val & JZ_CLOCK_CTRL_I2S_SRC_PLL) + jz4740_clock_divided_clks[0].clk.parent = &jz_clk_pll_half; + + if (val & JZ_CLOCK_CTRL_UDC_SRC_PLL) + jz4740_clock_simple_clks[0].parent = &jz_clk_pll_half; + + jz4740_clock_debugfs_init(); + + clk_register_clks(); + + return 0; +} +arch_initcall(jz4740_clock_init); diff --git a/arch/mips/jz4740/clock.h b/arch/mips/jz4740/clock.h new file mode 100644 index 00000000000..5d07499d746 --- /dev/null +++ b/arch/mips/jz4740/clock.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * JZ4740 SoC clock support + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __MIPS_JZ4740_CLOCK_H__ +#define __MIPS_JZ4740_CLOCK_H__ + +#include + +struct jz4740_clock_board_data { + unsigned long ext_rate; + unsigned long rtc_rate; +}; + +extern struct jz4740_clock_board_data jz4740_clock_bdata; + +void jz4740_clock_suspend(void); +void jz4740_clock_resume(void); + +struct clk; + +struct clk_ops { + unsigned long (*get_rate)(struct clk *clk); + unsigned long (*round_rate)(struct clk *clk, unsigned long rate); + int (*set_rate)(struct clk *clk, unsigned long rate); + int (*enable)(struct clk *clk); + int (*disable)(struct clk *clk); + int (*is_enabled)(struct clk *clk); + + int (*set_parent)(struct clk *clk, struct clk *parent); + +}; + +struct clk { + const char *name; + struct clk *parent; + + uint32_t gate_bit; + + const struct clk_ops *ops; + + struct list_head list; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_entry; + struct dentry *debugfs_parent_entry; +#endif + +}; + +#define JZ4740_CLK_NOT_GATED ((uint32_t)-1) + +int clk_is_enabled(struct clk *clk); + +#ifdef CONFIG_DEBUG_FS +void jz4740_clock_debugfs_init(void); +void jz4740_clock_debugfs_add_clk(struct clk *clk); +void jz4740_clock_debugfs_update_parent(struct clk *clk); +#else +static inline void jz4740_clock_debugfs_init(void) {}; +static inline void jz4740_clock_debugfs_add_clk(struct clk *clk) {}; +static inline void jz4740_clock_debugfs_update_parent(struct clk *clk) {}; +#endif + +#endif -- cgit v1.2.3-70-g09d2 From 9869848d12601cdddf097a36aebe0b10dc5d177b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 17 Jul 2010 11:08:43 +0000 Subject: MIPS: JZ4740: Add IRQ handler code Add support for IRQ handling on a JZ4740 SoC. Signed-off-by: Lars-Peter Clausen Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1465/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-jz4740/irq.h | 57 +++++++++++ arch/mips/jz4740/irq.c | 167 ++++++++++++++++++++++++++++++++ arch/mips/jz4740/irq.h | 21 ++++ 3 files changed, 245 insertions(+) create mode 100644 arch/mips/include/asm/mach-jz4740/irq.h create mode 100644 arch/mips/jz4740/irq.c create mode 100644 arch/mips/jz4740/irq.h (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-jz4740/irq.h b/arch/mips/include/asm/mach-jz4740/irq.h new file mode 100644 index 00000000000..a865c983c70 --- /dev/null +++ b/arch/mips/include/asm/mach-jz4740/irq.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen + * JZ4740 IRQ definitions + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __ASM_MACH_JZ4740_IRQ_H__ +#define __ASM_MACH_JZ4740_IRQ_H__ + +#define MIPS_CPU_IRQ_BASE 0 +#define JZ4740_IRQ_BASE 8 + +/* 1st-level interrupts */ +#define JZ4740_IRQ(x) (JZ4740_IRQ_BASE + (x)) +#define JZ4740_IRQ_I2C JZ4740_IRQ(1) +#define JZ4740_IRQ_UHC JZ4740_IRQ(3) +#define JZ4740_IRQ_UART1 JZ4740_IRQ(8) +#define JZ4740_IRQ_UART0 JZ4740_IRQ(9) +#define JZ4740_IRQ_SADC JZ4740_IRQ(12) +#define JZ4740_IRQ_MSC JZ4740_IRQ(14) +#define JZ4740_IRQ_RTC JZ4740_IRQ(15) +#define JZ4740_IRQ_SSI JZ4740_IRQ(16) +#define JZ4740_IRQ_CIM JZ4740_IRQ(17) +#define JZ4740_IRQ_AIC JZ4740_IRQ(18) +#define JZ4740_IRQ_ETH JZ4740_IRQ(19) +#define JZ4740_IRQ_DMAC JZ4740_IRQ(20) +#define JZ4740_IRQ_TCU2 JZ4740_IRQ(21) +#define JZ4740_IRQ_TCU1 JZ4740_IRQ(22) +#define JZ4740_IRQ_TCU0 JZ4740_IRQ(23) +#define JZ4740_IRQ_UDC JZ4740_IRQ(24) +#define JZ4740_IRQ_GPIO3 JZ4740_IRQ(25) +#define JZ4740_IRQ_GPIO2 JZ4740_IRQ(26) +#define JZ4740_IRQ_GPIO1 JZ4740_IRQ(27) +#define JZ4740_IRQ_GPIO0 JZ4740_IRQ(28) +#define JZ4740_IRQ_IPU JZ4740_IRQ(29) +#define JZ4740_IRQ_LCD JZ4740_IRQ(30) + +/* 2nd-level interrupts */ +#define JZ4740_IRQ_DMA(x) (JZ4740_IRQ(32) + (X)) + +#define JZ4740_IRQ_INTC_GPIO(x) (JZ4740_IRQ_GPIO0 - (x)) +#define JZ4740_IRQ_GPIO(x) (JZ4740_IRQ(48) + (x)) + +#define JZ4740_IRQ_ADC_BASE JZ4740_IRQ(176) + +#define NR_IRQS (JZ4740_IRQ_ADC_BASE + 6) + +#endif diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c new file mode 100644 index 00000000000..7d33ff83580 --- /dev/null +++ b/arch/mips/jz4740/irq.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen + * JZ4740 platform IRQ support + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +static void __iomem *jz_intc_base; +static uint32_t jz_intc_wakeup; +static uint32_t jz_intc_saved; + +#define JZ_REG_INTC_STATUS 0x00 +#define JZ_REG_INTC_MASK 0x04 +#define JZ_REG_INTC_SET_MASK 0x08 +#define JZ_REG_INTC_CLEAR_MASK 0x0c +#define JZ_REG_INTC_PENDING 0x10 + +#define IRQ_BIT(x) BIT((x) - JZ4740_IRQ_BASE) + +static void intc_irq_unmask(unsigned int irq) +{ + writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_CLEAR_MASK); +} + +static void intc_irq_mask(unsigned int irq) +{ + writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_SET_MASK); +} + +static int intc_irq_set_wake(unsigned int irq, unsigned int on) +{ + if (on) + jz_intc_wakeup |= IRQ_BIT(irq); + else + jz_intc_wakeup &= ~IRQ_BIT(irq); + + return 0; +} + +static struct irq_chip intc_irq_type = { + .name = "INTC", + .mask = intc_irq_mask, + .mask_ack = intc_irq_mask, + .unmask = intc_irq_unmask, + .set_wake = intc_irq_set_wake, +}; + +static irqreturn_t jz4740_cascade(int irq, void *data) +{ + uint32_t irq_reg; + + irq_reg = readl(jz_intc_base + JZ_REG_INTC_PENDING); + + if (irq_reg) + generic_handle_irq(__fls(irq_reg) + JZ4740_IRQ_BASE); + + return IRQ_HANDLED; +} + +static struct irqaction jz4740_cascade_action = { + .handler = jz4740_cascade, + .name = "JZ4740 cascade interrupt", +}; + +void __init arch_init_irq(void) +{ + int i; + mips_cpu_irq_init(); + + jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14); + + for (i = JZ4740_IRQ_BASE; i < JZ4740_IRQ_BASE + 32; i++) { + intc_irq_mask(i); + set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq); + } + + setup_irq(2, &jz4740_cascade_action); +} + +asmlinkage void plat_irq_dispatch(void) +{ + unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; + if (pending & STATUSF_IP2) + do_IRQ(2); + else if (pending & STATUSF_IP3) + do_IRQ(3); + else + spurious_interrupt(); +} + +void jz4740_intc_suspend(void) +{ + jz_intc_saved = readl(jz_intc_base + JZ_REG_INTC_MASK); + writel(~jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_SET_MASK); + writel(jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_CLEAR_MASK); +} + +void jz4740_intc_resume(void) +{ + writel(~jz_intc_saved, jz_intc_base + JZ_REG_INTC_CLEAR_MASK); + writel(jz_intc_saved, jz_intc_base + JZ_REG_INTC_SET_MASK); +} + +#ifdef CONFIG_DEBUG_FS + +static inline void intc_seq_reg(struct seq_file *s, const char *name, + unsigned int reg) +{ + seq_printf(s, "%s:\t\t%08x\n", name, readl(jz_intc_base + reg)); +} + +static int intc_regs_show(struct seq_file *s, void *unused) +{ + intc_seq_reg(s, "Status", JZ_REG_INTC_STATUS); + intc_seq_reg(s, "Mask", JZ_REG_INTC_MASK); + intc_seq_reg(s, "Pending", JZ_REG_INTC_PENDING); + + return 0; +} + +static int intc_regs_open(struct inode *inode, struct file *file) +{ + return single_open(file, intc_regs_show, NULL); +} + +static const struct file_operations intc_regs_operations = { + .open = intc_regs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init intc_debugfs_init(void) +{ + (void) debugfs_create_file("jz_regs_intc", S_IFREG | S_IRUGO, + NULL, NULL, &intc_regs_operations); + return 0; +} +subsys_initcall(intc_debugfs_init); + +#endif diff --git a/arch/mips/jz4740/irq.h b/arch/mips/jz4740/irq.h new file mode 100644 index 00000000000..56b5eadd1fa --- /dev/null +++ b/arch/mips/jz4740/irq.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __MIPS_JZ4740_IRQ_H__ +#define __MIPS_JZ4740_IRQ_H__ + +extern void jz4740_intc_suspend(void); +extern void jz4740_intc_resume(void); + +#endif -- cgit v1.2.3-70-g09d2 From 544a7324198972716d486e04e77bc2622e12245b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 19 Jun 2010 04:08:09 +0000 Subject: MIPS: JZ4740: Add timer support Add support for the timer/counter unit on a JZ4740 SoC. This code is used as a common base for the JZ4740 clocksource/clockevent implementation and PWM support. Signed-off-by: Lars-Peter Clausen Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1396/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-jz4740/timer.h | 22 +++++ arch/mips/jz4740/timer.c | 48 +++++++++++ arch/mips/jz4740/timer.h | 136 ++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 arch/mips/include/asm/mach-jz4740/timer.h create mode 100644 arch/mips/jz4740/timer.c create mode 100644 arch/mips/jz4740/timer.h (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-jz4740/timer.h b/arch/mips/include/asm/mach-jz4740/timer.h new file mode 100644 index 00000000000..9baa03ce748 --- /dev/null +++ b/arch/mips/include/asm/mach-jz4740/timer.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * JZ4740 platform timer support + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __ASM_MACH_JZ4740_TIMER +#define __ASM_MACH_JZ4740_TIMER + +void jz4740_timer_enable_watchdog(void); +void jz4740_timer_disable_watchdog(void); + +#endif diff --git a/arch/mips/jz4740/timer.c b/arch/mips/jz4740/timer.c new file mode 100644 index 00000000000..b2c01512905 --- /dev/null +++ b/arch/mips/jz4740/timer.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * JZ4740 platform timer support + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include + +#include "timer.h" + +#include + +void __iomem *jz4740_timer_base; + +void jz4740_timer_enable_watchdog(void) +{ + writel(BIT(16), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR); +} + +void jz4740_timer_disable_watchdog(void) +{ + writel(BIT(16), jz4740_timer_base + JZ_REG_TIMER_STOP_SET); +} + +void __init jz4740_timer_init(void) +{ + jz4740_timer_base = ioremap(JZ4740_TCU_BASE_ADDR, 0x100); + + if (!jz4740_timer_base) + panic("Failed to ioremap timer registers"); + + /* Disable all timer clocks except for those used as system timers */ + writel(0x000100fc, jz4740_timer_base + JZ_REG_TIMER_STOP_SET); + + /* Timer irqs are unmasked by default, mask them */ + writel(0x00ff00ff, jz4740_timer_base + JZ_REG_TIMER_MASK_SET); +} diff --git a/arch/mips/jz4740/timer.h b/arch/mips/jz4740/timer.h new file mode 100644 index 00000000000..fca3994f2e6 --- /dev/null +++ b/arch/mips/jz4740/timer.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * JZ4740 platform timer support + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __MIPS_JZ4740_TIMER_H__ +#define __MIPS_JZ4740_TIMER_H__ + +#include +#include + +#define JZ_REG_TIMER_STOP 0x0C +#define JZ_REG_TIMER_STOP_SET 0x1C +#define JZ_REG_TIMER_STOP_CLEAR 0x2C +#define JZ_REG_TIMER_ENABLE 0x00 +#define JZ_REG_TIMER_ENABLE_SET 0x04 +#define JZ_REG_TIMER_ENABLE_CLEAR 0x08 +#define JZ_REG_TIMER_FLAG 0x10 +#define JZ_REG_TIMER_FLAG_SET 0x14 +#define JZ_REG_TIMER_FLAG_CLEAR 0x18 +#define JZ_REG_TIMER_MASK 0x20 +#define JZ_REG_TIMER_MASK_SET 0x24 +#define JZ_REG_TIMER_MASK_CLEAR 0x28 + +#define JZ_REG_TIMER_DFR(x) (((x) * 0x10) + 0x30) +#define JZ_REG_TIMER_DHR(x) (((x) * 0x10) + 0x34) +#define JZ_REG_TIMER_CNT(x) (((x) * 0x10) + 0x38) +#define JZ_REG_TIMER_CTRL(x) (((x) * 0x10) + 0x3C) + +#define JZ_TIMER_IRQ_HALF(x) BIT((x) + 0x10) +#define JZ_TIMER_IRQ_FULL(x) BIT(x) + +#define JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN BIT(9) +#define JZ_TIMER_CTRL_PWM_ACTIVE_LOW BIT(8) +#define JZ_TIMER_CTRL_PWM_ENABLE BIT(7) +#define JZ_TIMER_CTRL_PRESCALE_MASK 0x1c +#define JZ_TIMER_CTRL_PRESCALE_OFFSET 0x3 +#define JZ_TIMER_CTRL_PRESCALE_1 (0 << 3) +#define JZ_TIMER_CTRL_PRESCALE_4 (1 << 3) +#define JZ_TIMER_CTRL_PRESCALE_16 (2 << 3) +#define JZ_TIMER_CTRL_PRESCALE_64 (3 << 3) +#define JZ_TIMER_CTRL_PRESCALE_256 (4 << 3) +#define JZ_TIMER_CTRL_PRESCALE_1024 (5 << 3) + +#define JZ_TIMER_CTRL_PRESCALER(x) ((x) << JZ_TIMER_CTRL_PRESCALE_OFFSET) + +#define JZ_TIMER_CTRL_SRC_EXT BIT(2) +#define JZ_TIMER_CTRL_SRC_RTC BIT(1) +#define JZ_TIMER_CTRL_SRC_PCLK BIT(0) + +extern void __iomem *jz4740_timer_base; +void __init jz4740_timer_init(void); + +static inline void jz4740_timer_stop(unsigned int timer) +{ + writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_SET); +} + +static inline void jz4740_timer_start(unsigned int timer) +{ + writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR); +} + +static inline bool jz4740_timer_is_enabled(unsigned int timer) +{ + return readb(jz4740_timer_base + JZ_REG_TIMER_ENABLE) & BIT(timer); +} + +static inline void jz4740_timer_enable(unsigned int timer) +{ + writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_SET); +} + +static inline void jz4740_timer_disable(unsigned int timer) +{ + writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_CLEAR); +} + + +static inline void jz4740_timer_set_period(unsigned int timer, uint16_t period) +{ + writew(period, jz4740_timer_base + JZ_REG_TIMER_DFR(timer)); +} + +static inline void jz4740_timer_set_duty(unsigned int timer, uint16_t duty) +{ + writew(duty, jz4740_timer_base + JZ_REG_TIMER_DHR(timer)); +} + +static inline void jz4740_timer_set_count(unsigned int timer, uint16_t count) +{ + writew(count, jz4740_timer_base + JZ_REG_TIMER_CNT(timer)); +} + +static inline uint16_t jz4740_timer_get_count(unsigned int timer) +{ + return readw(jz4740_timer_base + JZ_REG_TIMER_CNT(timer)); +} + +static inline void jz4740_timer_ack_full(unsigned int timer) +{ + writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR); +} + +static inline void jz4740_timer_irq_full_enable(unsigned int timer) +{ + writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR); + writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_CLEAR); +} + +static inline void jz4740_timer_irq_full_disable(unsigned int timer) +{ + writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_SET); +} + +static inline void jz4740_timer_set_ctrl(unsigned int timer, uint16_t ctrl) +{ + writew(ctrl, jz4740_timer_base + JZ_REG_TIMER_CTRL(timer)); +} + +static inline uint16_t jz4740_timer_get_ctrl(unsigned int timer) +{ + return readw(jz4740_timer_base + JZ_REG_TIMER_CTRL(timer)); +} + +#endif -- cgit v1.2.3-70-g09d2 From a55f4506652cbdf23fa1b5fd509d4f3cc01e1843 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 17 Jul 2010 11:11:19 +0000 Subject: MIPS: JZ4740: Add GPIO support Add gpiolib support for JZ4740 SoCs. Signed-off-by: Lars-Peter Clausen Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1467/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-jz4740/gpio.h | 398 ++++++++++++++++++++ arch/mips/jz4740/gpio.c | 604 +++++++++++++++++++++++++++++++ 2 files changed, 1002 insertions(+) create mode 100644 arch/mips/include/asm/mach-jz4740/gpio.h create mode 100644 arch/mips/jz4740/gpio.c (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-jz4740/gpio.h b/arch/mips/include/asm/mach-jz4740/gpio.h new file mode 100644 index 00000000000..7b74703745b --- /dev/null +++ b/arch/mips/include/asm/mach-jz4740/gpio.h @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * JZ4740 GPIO pin definitions + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _JZ_GPIO_H +#define _JZ_GPIO_H + +#include + +enum jz_gpio_function { + JZ_GPIO_FUNC_NONE, + JZ_GPIO_FUNC1, + JZ_GPIO_FUNC2, + JZ_GPIO_FUNC3, +}; + + +/* + Usually a driver for a SoC component has to request several gpio pins and + configure them as funcion pins. + jz_gpio_bulk_request can be used to ease this process. + Usually one would do something like: + + const static struct jz_gpio_bulk_request i2c_pins[] = { + JZ_GPIO_BULK_PIN(I2C_SDA), + JZ_GPIO_BULK_PIN(I2C_SCK), + }; + + inside the probe function: + + ret = jz_gpio_bulk_request(i2c_pins, ARRAY_SIZE(i2c_pins)); + if (ret) { + ... + + inside the remove function: + + jz_gpio_bulk_free(i2c_pins, ARRAY_SIZE(i2c_pins)); + + +*/ +struct jz_gpio_bulk_request { + int gpio; + const char *name; + enum jz_gpio_function function; +}; + +#define JZ_GPIO_BULK_PIN(pin) { \ + .gpio = JZ_GPIO_ ## pin, \ + .name = #pin, \ + .function = JZ_GPIO_FUNC_ ## pin \ +} + +int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num); +void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num); +void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num); +void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num); +void jz_gpio_enable_pullup(unsigned gpio); +void jz_gpio_disable_pullup(unsigned gpio); +int jz_gpio_set_function(int gpio, enum jz_gpio_function function); + +int jz_gpio_port_direction_input(int port, uint32_t mask); +int jz_gpio_port_direction_output(int port, uint32_t mask); +void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask); +uint32_t jz_gpio_port_get_value(int port, uint32_t mask); + +#include + +#define JZ_GPIO_PORTA(x) ((x) + 32 * 0) +#define JZ_GPIO_PORTB(x) ((x) + 32 * 1) +#define JZ_GPIO_PORTC(x) ((x) + 32 * 2) +#define JZ_GPIO_PORTD(x) ((x) + 32 * 3) + +/* Port A function pins */ +#define JZ_GPIO_MEM_DATA0 JZ_GPIO_PORTA(0) +#define JZ_GPIO_MEM_DATA1 JZ_GPIO_PORTA(1) +#define JZ_GPIO_MEM_DATA2 JZ_GPIO_PORTA(2) +#define JZ_GPIO_MEM_DATA3 JZ_GPIO_PORTA(3) +#define JZ_GPIO_MEM_DATA4 JZ_GPIO_PORTA(4) +#define JZ_GPIO_MEM_DATA5 JZ_GPIO_PORTA(5) +#define JZ_GPIO_MEM_DATA6 JZ_GPIO_PORTA(6) +#define JZ_GPIO_MEM_DATA7 JZ_GPIO_PORTA(7) +#define JZ_GPIO_MEM_DATA8 JZ_GPIO_PORTA(8) +#define JZ_GPIO_MEM_DATA9 JZ_GPIO_PORTA(9) +#define JZ_GPIO_MEM_DATA10 JZ_GPIO_PORTA(10) +#define JZ_GPIO_MEM_DATA11 JZ_GPIO_PORTA(11) +#define JZ_GPIO_MEM_DATA12 JZ_GPIO_PORTA(12) +#define JZ_GPIO_MEM_DATA13 JZ_GPIO_PORTA(13) +#define JZ_GPIO_MEM_DATA14 JZ_GPIO_PORTA(14) +#define JZ_GPIO_MEM_DATA15 JZ_GPIO_PORTA(15) +#define JZ_GPIO_MEM_DATA16 JZ_GPIO_PORTA(16) +#define JZ_GPIO_MEM_DATA17 JZ_GPIO_PORTA(17) +#define JZ_GPIO_MEM_DATA18 JZ_GPIO_PORTA(18) +#define JZ_GPIO_MEM_DATA19 JZ_GPIO_PORTA(19) +#define JZ_GPIO_MEM_DATA20 JZ_GPIO_PORTA(20) +#define JZ_GPIO_MEM_DATA21 JZ_GPIO_PORTA(21) +#define JZ_GPIO_MEM_DATA22 JZ_GPIO_PORTA(22) +#define JZ_GPIO_MEM_DATA23 JZ_GPIO_PORTA(23) +#define JZ_GPIO_MEM_DATA24 JZ_GPIO_PORTA(24) +#define JZ_GPIO_MEM_DATA25 JZ_GPIO_PORTA(25) +#define JZ_GPIO_MEM_DATA26 JZ_GPIO_PORTA(26) +#define JZ_GPIO_MEM_DATA27 JZ_GPIO_PORTA(27) +#define JZ_GPIO_MEM_DATA28 JZ_GPIO_PORTA(28) +#define JZ_GPIO_MEM_DATA29 JZ_GPIO_PORTA(29) +#define JZ_GPIO_MEM_DATA30 JZ_GPIO_PORTA(30) +#define JZ_GPIO_MEM_DATA31 JZ_GPIO_PORTA(31) + +#define JZ_GPIO_FUNC_MEM_DATA0 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA2 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA3 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA4 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA5 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA6 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA7 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA8 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA9 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA10 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA11 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA12 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA13 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA14 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA15 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA16 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA17 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA18 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA19 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA20 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA21 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA22 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA23 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA24 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA25 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA26 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA27 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA28 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA29 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA30 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA31 JZ_GPIO_FUNC1 + +/* Port B function pins */ +#define JZ_GPIO_MEM_ADDR0 JZ_GPIO_PORTB(0) +#define JZ_GPIO_MEM_ADDR1 JZ_GPIO_PORTB(1) +#define JZ_GPIO_MEM_ADDR2 JZ_GPIO_PORTB(2) +#define JZ_GPIO_MEM_ADDR3 JZ_GPIO_PORTB(3) +#define JZ_GPIO_MEM_ADDR4 JZ_GPIO_PORTB(4) +#define JZ_GPIO_MEM_ADDR5 JZ_GPIO_PORTB(5) +#define JZ_GPIO_MEM_ADDR6 JZ_GPIO_PORTB(6) +#define JZ_GPIO_MEM_ADDR7 JZ_GPIO_PORTB(7) +#define JZ_GPIO_MEM_ADDR8 JZ_GPIO_PORTB(8) +#define JZ_GPIO_MEM_ADDR9 JZ_GPIO_PORTB(9) +#define JZ_GPIO_MEM_ADDR10 JZ_GPIO_PORTB(10) +#define JZ_GPIO_MEM_ADDR11 JZ_GPIO_PORTB(11) +#define JZ_GPIO_MEM_ADDR12 JZ_GPIO_PORTB(12) +#define JZ_GPIO_MEM_ADDR13 JZ_GPIO_PORTB(13) +#define JZ_GPIO_MEM_ADDR14 JZ_GPIO_PORTB(14) +#define JZ_GPIO_MEM_ADDR15 JZ_GPIO_PORTB(15) +#define JZ_GPIO_MEM_ADDR16 JZ_GPIO_PORTB(16) +#define JZ_GPIO_LCD_CLS JZ_GPIO_PORTB(17) +#define JZ_GPIO_LCD_SPL JZ_GPIO_PORTB(18) +#define JZ_GPIO_MEM_DCS JZ_GPIO_PORTB(19) +#define JZ_GPIO_MEM_RAS JZ_GPIO_PORTB(20) +#define JZ_GPIO_MEM_CAS JZ_GPIO_PORTB(21) +#define JZ_GPIO_MEM_SDWE JZ_GPIO_PORTB(22) +#define JZ_GPIO_MEM_CKE JZ_GPIO_PORTB(23) +#define JZ_GPIO_MEM_CKO JZ_GPIO_PORTB(24) +#define JZ_GPIO_MEM_CS0 JZ_GPIO_PORTB(25) +#define JZ_GPIO_MEM_CS1 JZ_GPIO_PORTB(26) +#define JZ_GPIO_MEM_CS2 JZ_GPIO_PORTB(27) +#define JZ_GPIO_MEM_CS3 JZ_GPIO_PORTB(28) +#define JZ_GPIO_MEM_RD JZ_GPIO_PORTB(29) +#define JZ_GPIO_MEM_WR JZ_GPIO_PORTB(30) +#define JZ_GPIO_MEM_WE0 JZ_GPIO_PORTB(31) + +#define JZ_GPIO_FUNC_MEM_ADDR0 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR2 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR3 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR4 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR5 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR6 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR7 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR8 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR9 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR10 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR11 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR12 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR13 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR14 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR15 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR16 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_CLS JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_SPL JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DCS JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_RAS JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CAS JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_SDWE JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CKE JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CKO JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CS0 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CS1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CS2 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CS3 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_RD JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_WR JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_WE0 JZ_GPIO_FUNC1 + + +#define JZ_GPIO_MEM_ADDR21 JZ_GPIO_PORTB(17) +#define JZ_GPIO_MEM_ADDR22 JZ_GPIO_PORTB(18) + +#define JZ_GPIO_FUNC_MEM_ADDR21 JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_ADDR22 JZ_GPIO_FUNC2 + +/* Port C function pins */ +#define JZ_GPIO_LCD_DATA0 JZ_GPIO_PORTC(0) +#define JZ_GPIO_LCD_DATA1 JZ_GPIO_PORTC(1) +#define JZ_GPIO_LCD_DATA2 JZ_GPIO_PORTC(2) +#define JZ_GPIO_LCD_DATA3 JZ_GPIO_PORTC(3) +#define JZ_GPIO_LCD_DATA4 JZ_GPIO_PORTC(4) +#define JZ_GPIO_LCD_DATA5 JZ_GPIO_PORTC(5) +#define JZ_GPIO_LCD_DATA6 JZ_GPIO_PORTC(6) +#define JZ_GPIO_LCD_DATA7 JZ_GPIO_PORTC(7) +#define JZ_GPIO_LCD_DATA8 JZ_GPIO_PORTC(8) +#define JZ_GPIO_LCD_DATA9 JZ_GPIO_PORTC(9) +#define JZ_GPIO_LCD_DATA10 JZ_GPIO_PORTC(10) +#define JZ_GPIO_LCD_DATA11 JZ_GPIO_PORTC(11) +#define JZ_GPIO_LCD_DATA12 JZ_GPIO_PORTC(12) +#define JZ_GPIO_LCD_DATA13 JZ_GPIO_PORTC(13) +#define JZ_GPIO_LCD_DATA14 JZ_GPIO_PORTC(14) +#define JZ_GPIO_LCD_DATA15 JZ_GPIO_PORTC(15) +#define JZ_GPIO_LCD_DATA16 JZ_GPIO_PORTC(16) +#define JZ_GPIO_LCD_DATA17 JZ_GPIO_PORTC(17) +#define JZ_GPIO_LCD_PCLK JZ_GPIO_PORTC(18) +#define JZ_GPIO_LCD_HSYNC JZ_GPIO_PORTC(19) +#define JZ_GPIO_LCD_VSYNC JZ_GPIO_PORTC(20) +#define JZ_GPIO_LCD_DE JZ_GPIO_PORTC(21) +#define JZ_GPIO_LCD_PS JZ_GPIO_PORTC(22) +#define JZ_GPIO_LCD_REV JZ_GPIO_PORTC(23) +#define JZ_GPIO_MEM_WE1 JZ_GPIO_PORTC(24) +#define JZ_GPIO_MEM_WE2 JZ_GPIO_PORTC(25) +#define JZ_GPIO_MEM_WE3 JZ_GPIO_PORTC(26) +#define JZ_GPIO_MEM_WAIT JZ_GPIO_PORTC(27) +#define JZ_GPIO_MEM_FRE JZ_GPIO_PORTC(28) +#define JZ_GPIO_MEM_FWE JZ_GPIO_PORTC(29) + +#define JZ_GPIO_FUNC_LCD_DATA0 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA2 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA3 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA4 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA5 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA6 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA7 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA8 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA9 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA10 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA11 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA12 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA13 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA14 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA15 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA16 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA17 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_PCLK JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_VSYNC JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_HSYNC JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DE JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_PS JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_REV JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_WE1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_WE2 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_WE3 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_WAIT JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_FRE JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_FWE JZ_GPIO_FUNC1 + + +#define JZ_GPIO_MEM_ADDR19 JZ_GPIO_PORTB(22) +#define JZ_GPIO_MEM_ADDR20 JZ_GPIO_PORTB(23) + +#define JZ_GPIO_FUNC_MEM_ADDR19 JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_ADDR20 JZ_GPIO_FUNC2 + +/* Port D function pins */ +#define JZ_GPIO_CIM_DATA0 JZ_GPIO_PORTD(0) +#define JZ_GPIO_CIM_DATA1 JZ_GPIO_PORTD(1) +#define JZ_GPIO_CIM_DATA2 JZ_GPIO_PORTD(2) +#define JZ_GPIO_CIM_DATA3 JZ_GPIO_PORTD(3) +#define JZ_GPIO_CIM_DATA4 JZ_GPIO_PORTD(4) +#define JZ_GPIO_CIM_DATA5 JZ_GPIO_PORTD(5) +#define JZ_GPIO_CIM_DATA6 JZ_GPIO_PORTD(6) +#define JZ_GPIO_CIM_DATA7 JZ_GPIO_PORTD(7) +#define JZ_GPIO_MSC_CMD JZ_GPIO_PORTD(8) +#define JZ_GPIO_MSC_CLK JZ_GPIO_PORTD(9) +#define JZ_GPIO_MSC_DATA0 JZ_GPIO_PORTD(10) +#define JZ_GPIO_MSC_DATA1 JZ_GPIO_PORTD(11) +#define JZ_GPIO_MSC_DATA2 JZ_GPIO_PORTD(12) +#define JZ_GPIO_MSC_DATA3 JZ_GPIO_PORTD(13) +#define JZ_GPIO_CIM_MCLK JZ_GPIO_PORTD(14) +#define JZ_GPIO_CIM_PCLK JZ_GPIO_PORTD(15) +#define JZ_GPIO_CIM_VSYNC JZ_GPIO_PORTD(16) +#define JZ_GPIO_CIM_HSYNC JZ_GPIO_PORTD(17) +#define JZ_GPIO_SPI_CLK JZ_GPIO_PORTD(18) +#define JZ_GPIO_SPI_CE0 JZ_GPIO_PORTD(19) +#define JZ_GPIO_SPI_DT JZ_GPIO_PORTD(20) +#define JZ_GPIO_SPI_DR JZ_GPIO_PORTD(21) +#define JZ_GPIO_SPI_CE1 JZ_GPIO_PORTD(22) +#define JZ_GPIO_PWM0 JZ_GPIO_PORTD(23) +#define JZ_GPIO_PWM1 JZ_GPIO_PORTD(24) +#define JZ_GPIO_PWM2 JZ_GPIO_PORTD(25) +#define JZ_GPIO_PWM3 JZ_GPIO_PORTD(26) +#define JZ_GPIO_PWM4 JZ_GPIO_PORTD(27) +#define JZ_GPIO_PWM5 JZ_GPIO_PORTD(28) +#define JZ_GPIO_PWM6 JZ_GPIO_PORTD(30) +#define JZ_GPIO_PWM7 JZ_GPIO_PORTD(31) + +#define JZ_GPIO_FUNC_CIM_DATA JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_DATA0 JZ_GPIO_FUNC_CIM_DATA +#define JZ_GPIO_FUNC_CIM_DATA1 JZ_GPIO_FUNC_CIM_DATA +#define JZ_GPIO_FUNC_CIM_DATA2 JZ_GPIO_FUNC_CIM_DATA +#define JZ_GPIO_FUNC_CIM_DATA3 JZ_GPIO_FUNC_CIM_DATA +#define JZ_GPIO_FUNC_CIM_DATA4 JZ_GPIO_FUNC_CIM_DATA +#define JZ_GPIO_FUNC_CIM_DATA5 JZ_GPIO_FUNC_CIM_DATA +#define JZ_GPIO_FUNC_CIM_DATA6 JZ_GPIO_FUNC_CIM_DATA +#define JZ_GPIO_FUNC_CIM_DATA7 JZ_GPIO_FUNC_CIM_DATA +#define JZ_GPIO_FUNC_MSC_CMD JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MSC_CLK JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MSC_DATA JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MSC_DATA0 JZ_GPIO_FUNC_MSC_DATA +#define JZ_GPIO_FUNC_MSC_DATA1 JZ_GPIO_FUNC_MSC_DATA +#define JZ_GPIO_FUNC_MSC_DATA2 JZ_GPIO_FUNC_MSC_DATA +#define JZ_GPIO_FUNC_MSC_DATA3 JZ_GPIO_FUNC_MSC_DATA +#define JZ_GPIO_FUNC_CIM_MCLK JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_PCLK JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_VSYNC JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_HSYNC JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_SPI_CLK JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_SPI_CE0 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_SPI_DT JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_SPI_DR JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_SPI_CE1 JZ_GPIO_FUNC1 + +#define JZ_GPIO_FUNC_PWM JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_PWM0 JZ_GPIO_FUNC_PWM +#define JZ_GPIO_FUNC_PWM1 JZ_GPIO_FUNC_PWM +#define JZ_GPIO_FUNC_PWM2 JZ_GPIO_FUNC_PWM +#define JZ_GPIO_FUNC_PWM3 JZ_GPIO_FUNC_PWM +#define JZ_GPIO_FUNC_PWM4 JZ_GPIO_FUNC_PWM +#define JZ_GPIO_FUNC_PWM5 JZ_GPIO_FUNC_PWM +#define JZ_GPIO_FUNC_PWM6 JZ_GPIO_FUNC_PWM +#define JZ_GPIO_FUNC_PWM7 JZ_GPIO_FUNC_PWM + +#define JZ_GPIO_MEM_SCLK_RSTN JZ_GPIO_PORTD(18) +#define JZ_GPIO_MEM_BCLK JZ_GPIO_PORTD(19) +#define JZ_GPIO_MEM_SDATO JZ_GPIO_PORTD(20) +#define JZ_GPIO_MEM_SDATI JZ_GPIO_PORTD(21) +#define JZ_GPIO_MEM_SYNC JZ_GPIO_PORTD(22) +#define JZ_GPIO_I2C_SDA JZ_GPIO_PORTD(23) +#define JZ_GPIO_I2C_SCK JZ_GPIO_PORTD(24) +#define JZ_GPIO_UART0_TXD JZ_GPIO_PORTD(25) +#define JZ_GPIO_UART0_RXD JZ_GPIO_PORTD(26) +#define JZ_GPIO_MEM_ADDR17 JZ_GPIO_PORTD(27) +#define JZ_GPIO_MEM_ADDR18 JZ_GPIO_PORTD(28) +#define JZ_GPIO_UART0_CTS JZ_GPIO_PORTD(30) +#define JZ_GPIO_UART0_RTS JZ_GPIO_PORTD(31) + +#define JZ_GPIO_FUNC_MEM_SCLK_RSTN JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_BCLK JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_SDATO JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_SDATI JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_SYNC JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_I2C_SDA JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_I2C_SCK JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_UART0_TXD JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_UART0_RXD JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_ADDR17 JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_ADDR18 JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_UART0_CTS JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_UART0_RTS JZ_GPIO_FUNC2 + +#define JZ_GPIO_UART1_RXD JZ_GPIO_PORTD(30) +#define JZ_GPIO_UART1_TXD JZ_GPIO_PORTD(31) + +#define JZ_GPIO_FUNC_UART1_RXD JZ_GPIO_FUNC3 +#define JZ_GPIO_FUNC_UART1_TXD JZ_GPIO_FUNC3 + +#endif diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c new file mode 100644 index 00000000000..38f60f35156 --- /dev/null +++ b/arch/mips/jz4740/gpio.c @@ -0,0 +1,604 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen + * JZ4740 platform GPIO support + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define JZ4740_GPIO_BASE_A (32*0) +#define JZ4740_GPIO_BASE_B (32*1) +#define JZ4740_GPIO_BASE_C (32*2) +#define JZ4740_GPIO_BASE_D (32*3) + +#define JZ4740_GPIO_NUM_A 32 +#define JZ4740_GPIO_NUM_B 32 +#define JZ4740_GPIO_NUM_C 31 +#define JZ4740_GPIO_NUM_D 32 + +#define JZ4740_IRQ_GPIO_BASE_A (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_A) +#define JZ4740_IRQ_GPIO_BASE_B (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_B) +#define JZ4740_IRQ_GPIO_BASE_C (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_C) +#define JZ4740_IRQ_GPIO_BASE_D (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_D) + +#define JZ_REG_GPIO_PIN 0x00 +#define JZ_REG_GPIO_DATA 0x10 +#define JZ_REG_GPIO_DATA_SET 0x14 +#define JZ_REG_GPIO_DATA_CLEAR 0x18 +#define JZ_REG_GPIO_MASK 0x20 +#define JZ_REG_GPIO_MASK_SET 0x24 +#define JZ_REG_GPIO_MASK_CLEAR 0x28 +#define JZ_REG_GPIO_PULL 0x30 +#define JZ_REG_GPIO_PULL_SET 0x34 +#define JZ_REG_GPIO_PULL_CLEAR 0x38 +#define JZ_REG_GPIO_FUNC 0x40 +#define JZ_REG_GPIO_FUNC_SET 0x44 +#define JZ_REG_GPIO_FUNC_CLEAR 0x48 +#define JZ_REG_GPIO_SELECT 0x50 +#define JZ_REG_GPIO_SELECT_SET 0x54 +#define JZ_REG_GPIO_SELECT_CLEAR 0x58 +#define JZ_REG_GPIO_DIRECTION 0x60 +#define JZ_REG_GPIO_DIRECTION_SET 0x64 +#define JZ_REG_GPIO_DIRECTION_CLEAR 0x68 +#define JZ_REG_GPIO_TRIGGER 0x70 +#define JZ_REG_GPIO_TRIGGER_SET 0x74 +#define JZ_REG_GPIO_TRIGGER_CLEAR 0x78 +#define JZ_REG_GPIO_FLAG 0x80 +#define JZ_REG_GPIO_FLAG_CLEAR 0x14 + +#define GPIO_TO_BIT(gpio) BIT(gpio & 0x1f) +#define GPIO_TO_REG(gpio, reg) (gpio_to_jz_gpio_chip(gpio)->base + (reg)) +#define CHIP_TO_REG(chip, reg) (gpio_chip_to_jz_gpio_chip(chip)->base + (reg)) + +struct jz_gpio_chip { + unsigned int irq; + unsigned int irq_base; + uint32_t wakeup; + uint32_t suspend_mask; + uint32_t edge_trigger_both; + + void __iomem *base; + + spinlock_t lock; + + struct gpio_chip gpio_chip; + struct irq_chip irq_chip; + struct sys_device sysdev; +}; + +static struct jz_gpio_chip jz4740_gpio_chips[]; + +static inline struct jz_gpio_chip *gpio_to_jz_gpio_chip(unsigned int gpio) +{ + return &jz4740_gpio_chips[gpio >> 5]; +} + +static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *gpio_chip) +{ + return container_of(gpio_chip, struct jz_gpio_chip, gpio_chip); +} + +static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(unsigned int irq) +{ + return get_irq_chip_data(irq); +} + +static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg) +{ + writel(GPIO_TO_BIT(gpio), GPIO_TO_REG(gpio, reg)); +} + +int jz_gpio_set_function(int gpio, enum jz_gpio_function function) +{ + if (function == JZ_GPIO_FUNC_NONE) { + jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_CLEAR); + jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR); + jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR); + } else { + jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_SET); + jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR); + switch (function) { + case JZ_GPIO_FUNC1: + jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR); + break; + case JZ_GPIO_FUNC3: + jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_SET); + case JZ_GPIO_FUNC2: /* Falltrough */ + jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_SET); + break; + default: + BUG(); + break; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(jz_gpio_set_function); + +int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num) +{ + size_t i; + int ret; + + for (i = 0; i < num; ++i, ++request) { + ret = gpio_request(request->gpio, request->name); + if (ret) + goto err; + jz_gpio_set_function(request->gpio, request->function); + } + + return 0; + +err: + for (--request; i > 0; --i, --request) { + gpio_free(request->gpio); + jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE); + } + + return ret; +} +EXPORT_SYMBOL_GPL(jz_gpio_bulk_request); + +void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num) +{ + size_t i; + + for (i = 0; i < num; ++i, ++request) { + gpio_free(request->gpio); + jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE); + } + +} +EXPORT_SYMBOL_GPL(jz_gpio_bulk_free); + +void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num) +{ + size_t i; + + for (i = 0; i < num; ++i, ++request) { + jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE); + jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_DIRECTION_CLEAR); + jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_PULL_SET); + } +} +EXPORT_SYMBOL_GPL(jz_gpio_bulk_suspend); + +void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num) +{ + size_t i; + + for (i = 0; i < num; ++i, ++request) + jz_gpio_set_function(request->gpio, request->function); +} +EXPORT_SYMBOL_GPL(jz_gpio_bulk_resume); + +void jz_gpio_enable_pullup(unsigned gpio) +{ + jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_CLEAR); +} +EXPORT_SYMBOL_GPL(jz_gpio_enable_pullup); + +void jz_gpio_disable_pullup(unsigned gpio) +{ + jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_SET); +} +EXPORT_SYMBOL_GPL(jz_gpio_disable_pullup); + +static int jz_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + return !!(readl(CHIP_TO_REG(chip, JZ_REG_GPIO_PIN)) & BIT(gpio)); +} + +static void jz_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) +{ + uint32_t __iomem *reg = CHIP_TO_REG(chip, JZ_REG_GPIO_DATA_SET); + reg += !value; + writel(BIT(gpio), reg); +} + +static int jz_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, + int value) +{ + writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_SET)); + jz_gpio_set_value(chip, gpio, value); + + return 0; +} + +static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_CLEAR)); + + return 0; +} + +int jz_gpio_port_direction_input(int port, uint32_t mask) +{ + writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_CLEAR)); + + return 0; +} +EXPORT_SYMBOL(jz_gpio_port_direction_input); + +int jz_gpio_port_direction_output(int port, uint32_t mask) +{ + writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_SET)); + + return 0; +} +EXPORT_SYMBOL(jz_gpio_port_direction_output); + +void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask) +{ + writel(~value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_CLEAR)); + writel(value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_SET)); +} +EXPORT_SYMBOL(jz_gpio_port_set_value); + +uint32_t jz_gpio_port_get_value(int port, uint32_t mask) +{ + uint32_t value = readl(GPIO_TO_REG(port, JZ_REG_GPIO_PIN)); + + return value & mask; +} +EXPORT_SYMBOL(jz_gpio_port_get_value); + +int gpio_to_irq(unsigned gpio) +{ + return JZ4740_IRQ_GPIO(0) + gpio; +} +EXPORT_SYMBOL_GPL(gpio_to_irq); + +int irq_to_gpio(unsigned irq) +{ + return irq - JZ4740_IRQ_GPIO(0); +} +EXPORT_SYMBOL_GPL(irq_to_gpio); + +#define IRQ_TO_BIT(irq) BIT(irq_to_gpio(irq) & 0x1f) + +static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq) +{ + uint32_t value; + void __iomem *reg; + uint32_t mask = IRQ_TO_BIT(irq); + + if (!(chip->edge_trigger_both & mask)) + return; + + reg = chip->base; + + value = readl(chip->base + JZ_REG_GPIO_PIN); + if (value & mask) + reg += JZ_REG_GPIO_DIRECTION_CLEAR; + else + reg += JZ_REG_GPIO_DIRECTION_SET; + + writel(mask, reg); +} + +static void jz_gpio_irq_demux_handler(unsigned int irq, struct irq_desc *desc) +{ + uint32_t flag; + unsigned int gpio_irq; + unsigned int gpio_bank; + struct jz_gpio_chip *chip = get_irq_desc_data(desc); + + gpio_bank = JZ4740_IRQ_GPIO0 - irq; + + flag = readl(chip->base + JZ_REG_GPIO_FLAG); + + if (!flag) + return; + + gpio_irq = __fls(flag); + + jz_gpio_check_trigger_both(chip, irq); + + gpio_irq += (gpio_bank << 5) + JZ4740_IRQ_GPIO(0); + + generic_handle_irq(gpio_irq); +}; + +static inline void jz_gpio_set_irq_bit(unsigned int irq, unsigned int reg) +{ + struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq); + writel(IRQ_TO_BIT(irq), chip->base + reg); +} + +static void jz_gpio_irq_mask(unsigned int irq) +{ + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_MASK_SET); +}; + +static void jz_gpio_irq_unmask(unsigned int irq) +{ + struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq); + + jz_gpio_check_trigger_both(chip, irq); + + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_MASK_CLEAR); +}; + +/* TODO: Check if function is gpio */ +static unsigned int jz_gpio_irq_startup(unsigned int irq) +{ + struct irq_desc *desc = irq_to_desc(irq); + + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_SELECT_SET); + + desc->status &= ~IRQ_MASKED; + jz_gpio_irq_unmask(irq); + + return 0; +} + +static void jz_gpio_irq_shutdown(unsigned int irq) +{ + struct irq_desc *desc = irq_to_desc(irq); + + jz_gpio_irq_mask(irq); + desc->status |= IRQ_MASKED; + + /* Set direction to input */ + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR); + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_SELECT_CLEAR); +} + +static void jz_gpio_irq_ack(unsigned int irq) +{ + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_FLAG_CLEAR); +}; + +static int jz_gpio_irq_set_type(unsigned int irq, unsigned int flow_type) +{ + struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq); + struct irq_desc *desc = irq_to_desc(irq); + + jz_gpio_irq_mask(irq); + + if (flow_type == IRQ_TYPE_EDGE_BOTH) { + uint32_t value = readl(chip->base + JZ_REG_GPIO_PIN); + if (value & IRQ_TO_BIT(irq)) + flow_type = IRQ_TYPE_EDGE_FALLING; + else + flow_type = IRQ_TYPE_EDGE_RISING; + chip->edge_trigger_both |= IRQ_TO_BIT(irq); + } else { + chip->edge_trigger_both &= ~IRQ_TO_BIT(irq); + } + + switch (flow_type) { + case IRQ_TYPE_EDGE_RISING: + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_SET); + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_SET); + break; + case IRQ_TYPE_EDGE_FALLING: + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR); + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_SET); + break; + case IRQ_TYPE_LEVEL_HIGH: + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_SET); + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_CLEAR); + break; + case IRQ_TYPE_LEVEL_LOW: + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR); + jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_CLEAR); + break; + default: + return -EINVAL; + } + + if (!(desc->status & IRQ_MASKED)) + jz_gpio_irq_unmask(irq); + + return 0; +} + +static int jz_gpio_irq_set_wake(unsigned int irq, unsigned int on) +{ + struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq); + spin_lock(&chip->lock); + if (on) + chip->wakeup |= IRQ_TO_BIT(irq); + else + chip->wakeup &= ~IRQ_TO_BIT(irq); + spin_unlock(&chip->lock); + + set_irq_wake(chip->irq, on); + return 0; +} + +/* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; + +#define JZ4740_GPIO_CHIP(_bank) { \ + .irq_base = JZ4740_IRQ_GPIO_BASE_ ## _bank, \ + .gpio_chip = { \ + .label = "Bank " # _bank, \ + .owner = THIS_MODULE, \ + .set = jz_gpio_set_value, \ + .get = jz_gpio_get_value, \ + .direction_output = jz_gpio_direction_output, \ + .direction_input = jz_gpio_direction_input, \ + .base = JZ4740_GPIO_BASE_ ## _bank, \ + .ngpio = JZ4740_GPIO_NUM_ ## _bank, \ + }, \ + .irq_chip = { \ + .name = "GPIO Bank " # _bank, \ + .mask = jz_gpio_irq_mask, \ + .unmask = jz_gpio_irq_unmask, \ + .ack = jz_gpio_irq_ack, \ + .startup = jz_gpio_irq_startup, \ + .shutdown = jz_gpio_irq_shutdown, \ + .set_type = jz_gpio_irq_set_type, \ + .set_wake = jz_gpio_irq_set_wake, \ + }, \ +} + +static struct jz_gpio_chip jz4740_gpio_chips[] = { + JZ4740_GPIO_CHIP(A), + JZ4740_GPIO_CHIP(B), + JZ4740_GPIO_CHIP(C), + JZ4740_GPIO_CHIP(D), +}; + +static inline struct jz_gpio_chip *sysdev_to_chip(struct sys_device *dev) +{ + return container_of(dev, struct jz_gpio_chip, sysdev); +} + +static int jz4740_gpio_suspend(struct sys_device *dev, pm_message_t state) +{ + struct jz_gpio_chip *chip = sysdev_to_chip(dev); + + chip->suspend_mask = readl(chip->base + JZ_REG_GPIO_MASK); + writel(~(chip->wakeup), chip->base + JZ_REG_GPIO_MASK_SET); + writel(chip->wakeup, chip->base + JZ_REG_GPIO_MASK_CLEAR); + + return 0; +} + +static int jz4740_gpio_resume(struct sys_device *dev) +{ + struct jz_gpio_chip *chip = sysdev_to_chip(dev); + uint32_t mask = chip->suspend_mask; + + writel(~mask, chip->base + JZ_REG_GPIO_MASK_CLEAR); + writel(mask, chip->base + JZ_REG_GPIO_MASK_SET); + + return 0; +} + +static struct sysdev_class jz4740_gpio_sysdev_class = { + .name = "gpio", + .suspend = jz4740_gpio_suspend, + .resume = jz4740_gpio_resume, +}; + +static int jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id) +{ + int ret, irq; + + chip->sysdev.id = id; + chip->sysdev.cls = &jz4740_gpio_sysdev_class; + ret = sysdev_register(&chip->sysdev); + + if (ret) + return ret; + + spin_lock_init(&chip->lock); + + chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100); + + gpiochip_add(&chip->gpio_chip); + + chip->irq = JZ4740_IRQ_INTC_GPIO(id); + set_irq_data(chip->irq, chip); + set_irq_chained_handler(chip->irq, jz_gpio_irq_demux_handler); + + for (irq = chip->irq_base; irq < chip->irq_base + chip->gpio_chip.ngpio; ++irq) { + lockdep_set_class(&irq_desc[irq].lock, &gpio_lock_class); + set_irq_chip_data(irq, chip); + set_irq_chip_and_handler(irq, &chip->irq_chip, handle_level_irq); + } + + return 0; +} + +static int __init jz4740_gpio_init(void) +{ + unsigned int i; + int ret; + + ret = sysdev_class_register(&jz4740_gpio_sysdev_class); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i) + jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i); + + printk(KERN_INFO "JZ4740 GPIO initalized\n"); + + return 0; +} +arch_initcall(jz4740_gpio_init); + +#ifdef CONFIG_DEBUG_FS + +static inline void gpio_seq_reg(struct seq_file *s, struct jz_gpio_chip *chip, + const char *name, unsigned int reg) +{ + seq_printf(s, "\t%s: %08x\n", name, readl(chip->base + reg)); +} + +static int gpio_regs_show(struct seq_file *s, void *unused) +{ + struct jz_gpio_chip *chip = jz4740_gpio_chips; + int i; + + for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i, ++chip) { + seq_printf(s, "==GPIO %d==\n", i); + gpio_seq_reg(s, chip, "Pin", JZ_REG_GPIO_PIN); + gpio_seq_reg(s, chip, "Data", JZ_REG_GPIO_DATA); + gpio_seq_reg(s, chip, "Mask", JZ_REG_GPIO_MASK); + gpio_seq_reg(s, chip, "Pull", JZ_REG_GPIO_PULL); + gpio_seq_reg(s, chip, "Func", JZ_REG_GPIO_FUNC); + gpio_seq_reg(s, chip, "Select", JZ_REG_GPIO_SELECT); + gpio_seq_reg(s, chip, "Direction", JZ_REG_GPIO_DIRECTION); + gpio_seq_reg(s, chip, "Trigger", JZ_REG_GPIO_TRIGGER); + gpio_seq_reg(s, chip, "Flag", JZ_REG_GPIO_FLAG); + } + + return 0; +} + +static int gpio_regs_open(struct inode *inode, struct file *file) +{ + return single_open(file, gpio_regs_show, NULL); +} + +static const struct file_operations gpio_regs_operations = { + .open = gpio_regs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init gpio_debugfs_init(void) +{ + (void) debugfs_create_file("jz_regs_gpio", S_IFREG | S_IRUGO, + NULL, NULL, &gpio_regs_operations); + return 0; +} +subsys_initcall(gpio_debugfs_init); + +#endif -- cgit v1.2.3-70-g09d2 From 68fcfe7f82f46cc2d0c28128afafbd3a3ff874f8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 19 Jun 2010 04:08:14 +0000 Subject: MIPS: JZ4740: Add DMA support. Add support for DMA transfers on JZ4740 SoCs. Signed-off-by: Lars-Peter Clausen Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1401/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-jz4740/dma.h | 90 ++++++++++ arch/mips/jz4740/dma.c | 289 ++++++++++++++++++++++++++++++++ 2 files changed, 379 insertions(+) create mode 100644 arch/mips/include/asm/mach-jz4740/dma.h create mode 100644 arch/mips/jz4740/dma.c (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-jz4740/dma.h b/arch/mips/include/asm/mach-jz4740/dma.h new file mode 100644 index 00000000000..a3be1218359 --- /dev/null +++ b/arch/mips/include/asm/mach-jz4740/dma.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * JZ7420/JZ4740 DMA definitions + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __ASM_MACH_JZ4740_DMA_H__ +#define __ASM_MACH_JZ4740_DMA_H__ + +struct jz4740_dma_chan; + +enum jz4740_dma_request_type { + JZ4740_DMA_TYPE_AUTO_REQUEST = 8, + JZ4740_DMA_TYPE_UART_TRANSMIT = 20, + JZ4740_DMA_TYPE_UART_RECEIVE = 21, + JZ4740_DMA_TYPE_SPI_TRANSMIT = 22, + JZ4740_DMA_TYPE_SPI_RECEIVE = 23, + JZ4740_DMA_TYPE_AIC_TRANSMIT = 24, + JZ4740_DMA_TYPE_AIC_RECEIVE = 25, + JZ4740_DMA_TYPE_MMC_TRANSMIT = 26, + JZ4740_DMA_TYPE_MMC_RECEIVE = 27, + JZ4740_DMA_TYPE_TCU = 28, + JZ4740_DMA_TYPE_SADC = 29, + JZ4740_DMA_TYPE_SLCD = 30, +}; + +enum jz4740_dma_width { + JZ4740_DMA_WIDTH_32BIT = 0, + JZ4740_DMA_WIDTH_8BIT = 1, + JZ4740_DMA_WIDTH_16BIT = 2, +}; + +enum jz4740_dma_transfer_size { + JZ4740_DMA_TRANSFER_SIZE_4BYTE = 0, + JZ4740_DMA_TRANSFER_SIZE_1BYTE = 1, + JZ4740_DMA_TRANSFER_SIZE_2BYTE = 2, + JZ4740_DMA_TRANSFER_SIZE_16BYTE = 3, + JZ4740_DMA_TRANSFER_SIZE_32BYTE = 4, +}; + +enum jz4740_dma_flags { + JZ4740_DMA_SRC_AUTOINC = 0x2, + JZ4740_DMA_DST_AUTOINC = 0x1, +}; + +enum jz4740_dma_mode { + JZ4740_DMA_MODE_SINGLE = 0, + JZ4740_DMA_MODE_BLOCK = 1, +}; + +struct jz4740_dma_config { + enum jz4740_dma_width src_width; + enum jz4740_dma_width dst_width; + enum jz4740_dma_transfer_size transfer_size; + enum jz4740_dma_request_type request_type; + enum jz4740_dma_flags flags; + enum jz4740_dma_mode mode; +}; + +typedef void (*jz4740_dma_complete_callback_t)(struct jz4740_dma_chan *, int, void *); + +struct jz4740_dma_chan *jz4740_dma_request(void *dev, const char *name); +void jz4740_dma_free(struct jz4740_dma_chan *dma); + +void jz4740_dma_configure(struct jz4740_dma_chan *dma, + const struct jz4740_dma_config *config); + + +void jz4740_dma_enable(struct jz4740_dma_chan *dma); +void jz4740_dma_disable(struct jz4740_dma_chan *dma); + +void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src); +void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst); +void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count); + +uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma); + +void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma, + jz4740_dma_complete_callback_t cb); + +#endif /* __ASM_JZ4740_DMA_H__ */ diff --git a/arch/mips/jz4740/dma.c b/arch/mips/jz4740/dma.c new file mode 100644 index 00000000000..5ebe75a6835 --- /dev/null +++ b/arch/mips/jz4740/dma.c @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * JZ4740 SoC DMA support + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#define JZ_REG_DMA_SRC_ADDR(x) (0x00 + (x) * 0x20) +#define JZ_REG_DMA_DST_ADDR(x) (0x04 + (x) * 0x20) +#define JZ_REG_DMA_TRANSFER_COUNT(x) (0x08 + (x) * 0x20) +#define JZ_REG_DMA_REQ_TYPE(x) (0x0C + (x) * 0x20) +#define JZ_REG_DMA_STATUS_CTRL(x) (0x10 + (x) * 0x20) +#define JZ_REG_DMA_CMD(x) (0x14 + (x) * 0x20) +#define JZ_REG_DMA_DESC_ADDR(x) (0x18 + (x) * 0x20) + +#define JZ_REG_DMA_CTRL 0x300 +#define JZ_REG_DMA_IRQ 0x304 +#define JZ_REG_DMA_DOORBELL 0x308 +#define JZ_REG_DMA_DOORBELL_SET 0x30C + +#define JZ_DMA_STATUS_CTRL_NO_DESC BIT(31) +#define JZ_DMA_STATUS_CTRL_DESC_INV BIT(6) +#define JZ_DMA_STATUS_CTRL_ADDR_ERR BIT(4) +#define JZ_DMA_STATUS_CTRL_TRANSFER_DONE BIT(3) +#define JZ_DMA_STATUS_CTRL_HALT BIT(2) +#define JZ_DMA_STATUS_CTRL_COUNT_TERMINATE BIT(1) +#define JZ_DMA_STATUS_CTRL_ENABLE BIT(0) + +#define JZ_DMA_CMD_SRC_INC BIT(23) +#define JZ_DMA_CMD_DST_INC BIT(22) +#define JZ_DMA_CMD_RDIL_MASK (0xf << 16) +#define JZ_DMA_CMD_SRC_WIDTH_MASK (0x3 << 14) +#define JZ_DMA_CMD_DST_WIDTH_MASK (0x3 << 12) +#define JZ_DMA_CMD_INTERVAL_LENGTH_MASK (0x7 << 8) +#define JZ_DMA_CMD_BLOCK_MODE BIT(7) +#define JZ_DMA_CMD_DESC_VALID BIT(4) +#define JZ_DMA_CMD_DESC_VALID_MODE BIT(3) +#define JZ_DMA_CMD_VALID_IRQ_ENABLE BIT(2) +#define JZ_DMA_CMD_TRANSFER_IRQ_ENABLE BIT(1) +#define JZ_DMA_CMD_LINK_ENABLE BIT(0) + +#define JZ_DMA_CMD_FLAGS_OFFSET 22 +#define JZ_DMA_CMD_RDIL_OFFSET 16 +#define JZ_DMA_CMD_SRC_WIDTH_OFFSET 14 +#define JZ_DMA_CMD_DST_WIDTH_OFFSET 12 +#define JZ_DMA_CMD_TRANSFER_SIZE_OFFSET 8 +#define JZ_DMA_CMD_MODE_OFFSET 7 + +#define JZ_DMA_CTRL_PRIORITY_MASK (0x3 << 8) +#define JZ_DMA_CTRL_HALT BIT(3) +#define JZ_DMA_CTRL_ADDRESS_ERROR BIT(2) +#define JZ_DMA_CTRL_ENABLE BIT(0) + + +static void __iomem *jz4740_dma_base; +static spinlock_t jz4740_dma_lock; + +static inline uint32_t jz4740_dma_read(size_t reg) +{ + return readl(jz4740_dma_base + reg); +} + +static inline void jz4740_dma_write(size_t reg, uint32_t val) +{ + writel(val, jz4740_dma_base + reg); +} + +static inline void jz4740_dma_write_mask(size_t reg, uint32_t val, uint32_t mask) +{ + uint32_t val2; + val2 = jz4740_dma_read(reg); + val2 &= ~mask; + val2 |= val; + jz4740_dma_write(reg, val2); +} + +struct jz4740_dma_chan { + unsigned int id; + void *dev; + const char *name; + + enum jz4740_dma_flags flags; + uint32_t transfer_shift; + + jz4740_dma_complete_callback_t complete_cb; + + unsigned used:1; +}; + +#define JZ4740_DMA_CHANNEL(_id) { .id = _id } + +struct jz4740_dma_chan jz4740_dma_channels[] = { + JZ4740_DMA_CHANNEL(0), + JZ4740_DMA_CHANNEL(1), + JZ4740_DMA_CHANNEL(2), + JZ4740_DMA_CHANNEL(3), + JZ4740_DMA_CHANNEL(4), + JZ4740_DMA_CHANNEL(5), +}; + +struct jz4740_dma_chan *jz4740_dma_request(void *dev, const char *name) +{ + unsigned int i; + struct jz4740_dma_chan *dma = NULL; + + spin_lock(&jz4740_dma_lock); + + for (i = 0; i < ARRAY_SIZE(jz4740_dma_channels); ++i) { + if (!jz4740_dma_channels[i].used) { + dma = &jz4740_dma_channels[i]; + dma->used = 1; + break; + } + } + + spin_unlock(&jz4740_dma_lock); + + if (!dma) + return NULL; + + dma->dev = dev; + dma->name = name; + + return dma; +} +EXPORT_SYMBOL_GPL(jz4740_dma_request); + +void jz4740_dma_configure(struct jz4740_dma_chan *dma, + const struct jz4740_dma_config *config) +{ + uint32_t cmd; + + switch (config->transfer_size) { + case JZ4740_DMA_TRANSFER_SIZE_2BYTE: + dma->transfer_shift = 1; + break; + case JZ4740_DMA_TRANSFER_SIZE_4BYTE: + dma->transfer_shift = 2; + break; + case JZ4740_DMA_TRANSFER_SIZE_16BYTE: + dma->transfer_shift = 4; + break; + case JZ4740_DMA_TRANSFER_SIZE_32BYTE: + dma->transfer_shift = 5; + break; + default: + dma->transfer_shift = 0; + break; + } + + cmd = config->flags << JZ_DMA_CMD_FLAGS_OFFSET; + cmd |= config->src_width << JZ_DMA_CMD_SRC_WIDTH_OFFSET; + cmd |= config->dst_width << JZ_DMA_CMD_DST_WIDTH_OFFSET; + cmd |= config->transfer_size << JZ_DMA_CMD_TRANSFER_SIZE_OFFSET; + cmd |= config->mode << JZ_DMA_CMD_MODE_OFFSET; + cmd |= JZ_DMA_CMD_TRANSFER_IRQ_ENABLE; + + jz4740_dma_write(JZ_REG_DMA_CMD(dma->id), cmd); + jz4740_dma_write(JZ_REG_DMA_STATUS_CTRL(dma->id), 0); + jz4740_dma_write(JZ_REG_DMA_REQ_TYPE(dma->id), config->request_type); +} +EXPORT_SYMBOL_GPL(jz4740_dma_configure); + +void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src) +{ + jz4740_dma_write(JZ_REG_DMA_SRC_ADDR(dma->id), src); +} +EXPORT_SYMBOL_GPL(jz4740_dma_set_src_addr); + +void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst) +{ + jz4740_dma_write(JZ_REG_DMA_DST_ADDR(dma->id), dst); +} +EXPORT_SYMBOL_GPL(jz4740_dma_set_dst_addr); + +void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count) +{ + count >>= dma->transfer_shift; + jz4740_dma_write(JZ_REG_DMA_TRANSFER_COUNT(dma->id), count); +} +EXPORT_SYMBOL_GPL(jz4740_dma_set_transfer_count); + +void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma, + jz4740_dma_complete_callback_t cb) +{ + dma->complete_cb = cb; +} +EXPORT_SYMBOL_GPL(jz4740_dma_set_complete_cb); + +void jz4740_dma_free(struct jz4740_dma_chan *dma) +{ + dma->dev = NULL; + dma->complete_cb = NULL; + dma->used = 0; +} +EXPORT_SYMBOL_GPL(jz4740_dma_free); + +void jz4740_dma_enable(struct jz4740_dma_chan *dma) +{ + jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), + JZ_DMA_STATUS_CTRL_NO_DESC | JZ_DMA_STATUS_CTRL_ENABLE, + JZ_DMA_STATUS_CTRL_HALT | JZ_DMA_STATUS_CTRL_NO_DESC | + JZ_DMA_STATUS_CTRL_ENABLE); + + jz4740_dma_write_mask(JZ_REG_DMA_CTRL, + JZ_DMA_CTRL_ENABLE, + JZ_DMA_CTRL_HALT | JZ_DMA_CTRL_ENABLE); +} +EXPORT_SYMBOL_GPL(jz4740_dma_enable); + +void jz4740_dma_disable(struct jz4740_dma_chan *dma) +{ + jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0, + JZ_DMA_STATUS_CTRL_ENABLE); +} +EXPORT_SYMBOL_GPL(jz4740_dma_disable); + +uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma) +{ + uint32_t residue; + residue = jz4740_dma_read(JZ_REG_DMA_TRANSFER_COUNT(dma->id)); + return residue << dma->transfer_shift; +} +EXPORT_SYMBOL_GPL(jz4740_dma_get_residue); + +static void jz4740_dma_chan_irq(struct jz4740_dma_chan *dma) +{ + uint32_t status; + + status = jz4740_dma_read(JZ_REG_DMA_STATUS_CTRL(dma->id)); + + jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0, + JZ_DMA_STATUS_CTRL_ENABLE | JZ_DMA_STATUS_CTRL_TRANSFER_DONE); + + if (dma->complete_cb) + dma->complete_cb(dma, 0, dma->dev); +} + +static irqreturn_t jz4740_dma_irq(int irq, void *dev_id) +{ + uint32_t irq_status; + unsigned int i; + + irq_status = readl(jz4740_dma_base + JZ_REG_DMA_IRQ); + + for (i = 0; i < 6; ++i) { + if (irq_status & (1 << i)) + jz4740_dma_chan_irq(&jz4740_dma_channels[i]); + } + + return IRQ_HANDLED; +} + +static int jz4740_dma_init(void) +{ + unsigned int ret; + + jz4740_dma_base = ioremap(JZ4740_DMAC_BASE_ADDR, 0x400); + + if (!jz4740_dma_base) + return -EBUSY; + + spin_lock_init(&jz4740_dma_lock); + + ret = request_irq(JZ4740_IRQ_DMAC, jz4740_dma_irq, 0, "DMA", NULL); + + if (ret) + printk(KERN_ERR "JZ4740 DMA: Failed to request irq: %d\n", ret); + + return ret; +} +arch_initcall(jz4740_dma_init); -- cgit v1.2.3-70-g09d2 From c2a529f73de56cb99ae9abcc2c8fb9fe3f2d2039 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 17 Jul 2010 11:13:29 +0000 Subject: MIPS: JZ4740: Add platform devices Add platform devices for all the JZ4740 platform drivers. Signed-off-by: Lars-Peter Clausen Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1469/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-jz4740/platform.h | 36 ++++ arch/mips/jz4740/platform.c | 291 +++++++++++++++++++++++++++ 2 files changed, 327 insertions(+) create mode 100644 arch/mips/include/asm/mach-jz4740/platform.h create mode 100644 arch/mips/jz4740/platform.c (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-jz4740/platform.h b/arch/mips/include/asm/mach-jz4740/platform.h new file mode 100644 index 00000000000..8987a76e967 --- /dev/null +++ b/arch/mips/include/asm/mach-jz4740/platform.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen + * JZ4740 platform device definitions + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef __JZ4740_PLATFORM_H +#define __JZ4740_PLATFORM_H + +#include + +extern struct platform_device jz4740_usb_ohci_device; +extern struct platform_device jz4740_udc_device; +extern struct platform_device jz4740_mmc_device; +extern struct platform_device jz4740_rtc_device; +extern struct platform_device jz4740_i2c_device; +extern struct platform_device jz4740_nand_device; +extern struct platform_device jz4740_framebuffer_device; +extern struct platform_device jz4740_i2s_device; +extern struct platform_device jz4740_pcm_device; +extern struct platform_device jz4740_codec_device; +extern struct platform_device jz4740_adc_device; + +void jz4740_serial_device_register(void); + +#endif diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c new file mode 100644 index 00000000000..95bc2b5b14f --- /dev/null +++ b/arch/mips/jz4740/platform.c @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen + * JZ4740 platform devices + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include "serial.h" +#include "clock.h" + +/* OHCI controller */ +static struct resource jz4740_usb_ohci_resources[] = { + { + .start = JZ4740_UHC_BASE_ADDR, + .end = JZ4740_UHC_BASE_ADDR + 0x1000 - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = JZ4740_IRQ_UHC, + .end = JZ4740_IRQ_UHC, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device jz4740_usb_ohci_device = { + .name = "jz4740-ohci", + .id = -1, + .dev = { + .dma_mask = &jz4740_usb_ohci_device.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(jz4740_usb_ohci_resources), + .resource = jz4740_usb_ohci_resources, +}; + +/* UDC (USB gadget controller) */ +static struct resource jz4740_usb_gdt_resources[] = { + { + .start = JZ4740_UDC_BASE_ADDR, + .end = JZ4740_UDC_BASE_ADDR + 0x1000 - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = JZ4740_IRQ_UDC, + .end = JZ4740_IRQ_UDC, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device jz4740_udc_device = { + .name = "jz-udc", + .id = -1, + .dev = { + .dma_mask = &jz4740_udc_device.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(jz4740_usb_gdt_resources), + .resource = jz4740_usb_gdt_resources, +}; + +/* MMC/SD controller */ +static struct resource jz4740_mmc_resources[] = { + { + .start = JZ4740_MSC_BASE_ADDR, + .end = JZ4740_MSC_BASE_ADDR + 0x1000 - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = JZ4740_IRQ_MSC, + .end = JZ4740_IRQ_MSC, + .flags = IORESOURCE_IRQ, + } +}; + +struct platform_device jz4740_mmc_device = { + .name = "jz4740-mmc", + .id = 0, + .dev = { + .dma_mask = &jz4740_mmc_device.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(jz4740_mmc_resources), + .resource = jz4740_mmc_resources, +}; + +/* RTC controller */ +static struct resource jz4740_rtc_resources[] = { + { + .start = JZ4740_RTC_BASE_ADDR, + .end = JZ4740_RTC_BASE_ADDR + 0x38 - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = JZ4740_IRQ_RTC, + .end = JZ4740_IRQ_RTC, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device jz4740_rtc_device = { + .name = "jz4740-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(jz4740_rtc_resources), + .resource = jz4740_rtc_resources, +}; + +/* I2C controller */ +static struct resource jz4740_i2c_resources[] = { + { + .start = JZ4740_I2C_BASE_ADDR, + .end = JZ4740_I2C_BASE_ADDR + 0x1000 - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = JZ4740_IRQ_I2C, + .end = JZ4740_IRQ_I2C, + .flags = IORESOURCE_IRQ, + } +}; + +struct platform_device jz4740_i2c_device = { + .name = "jz4740-i2c", + .id = 0, + .num_resources = ARRAY_SIZE(jz4740_i2c_resources), + .resource = jz4740_i2c_resources, +}; + +/* NAND controller */ +static struct resource jz4740_nand_resources[] = { + { + .name = "mmio", + .start = JZ4740_EMC_BASE_ADDR, + .end = JZ4740_EMC_BASE_ADDR + 0x1000 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "bank", + .start = 0x18000000, + .end = 0x180C0000 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device jz4740_nand_device = { + .name = "jz4740-nand", + .num_resources = ARRAY_SIZE(jz4740_nand_resources), + .resource = jz4740_nand_resources, +}; + +/* LCD controller */ +static struct resource jz4740_framebuffer_resources[] = { + { + .start = JZ4740_LCD_BASE_ADDR, + .end = JZ4740_LCD_BASE_ADDR + 0x1000 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device jz4740_framebuffer_device = { + .name = "jz4740-fb", + .id = -1, + .num_resources = ARRAY_SIZE(jz4740_framebuffer_resources), + .resource = jz4740_framebuffer_resources, + .dev = { + .dma_mask = &jz4740_framebuffer_device.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +/* I2S controller */ +static struct resource jz4740_i2s_resources[] = { + { + .start = JZ4740_AIC_BASE_ADDR, + .end = JZ4740_AIC_BASE_ADDR + 0x38 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device jz4740_i2s_device = { + .name = "jz4740-i2s", + .id = -1, + .num_resources = ARRAY_SIZE(jz4740_i2s_resources), + .resource = jz4740_i2s_resources, +}; + +/* PCM */ +struct platform_device jz4740_pcm_device = { + .name = "jz4740-pcm", + .id = -1, +}; + +/* Codec */ +static struct resource jz4740_codec_resources[] = { + { + .start = JZ4740_AIC_BASE_ADDR + 0x80, + .end = JZ4740_AIC_BASE_ADDR + 0x88 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device jz4740_codec_device = { + .name = "jz4740-codec", + .id = -1, + .num_resources = ARRAY_SIZE(jz4740_codec_resources), + .resource = jz4740_codec_resources, +}; + +/* ADC controller */ +static struct resource jz4740_adc_resources[] = { + { + .start = JZ4740_SADC_BASE_ADDR, + .end = JZ4740_SADC_BASE_ADDR + 0x30, + .flags = IORESOURCE_MEM, + }, + { + .start = JZ4740_IRQ_SADC, + .end = JZ4740_IRQ_SADC, + .flags = IORESOURCE_IRQ, + }, + { + .start = JZ4740_IRQ_ADC_BASE, + .end = JZ4740_IRQ_ADC_BASE, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device jz4740_adc_device = { + .name = "jz4740-adc", + .id = -1, + .num_resources = ARRAY_SIZE(jz4740_adc_resources), + .resource = jz4740_adc_resources, +}; + +/* Serial */ +#define JZ4740_UART_DATA(_id) \ + { \ + .flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE, \ + .iotype = UPIO_MEM, \ + .regshift = 2, \ + .serial_out = jz4740_serial_out, \ + .type = PORT_16550, \ + .mapbase = JZ4740_UART ## _id ## _BASE_ADDR, \ + .irq = JZ4740_IRQ_UART ## _id, \ + } + +static struct plat_serial8250_port jz4740_uart_data[] = { + JZ4740_UART_DATA(0), + JZ4740_UART_DATA(1), + {}, +}; + +static struct platform_device jz4740_uart_device = { + .name = "serial8250", + .id = 0, + .dev = { + .platform_data = jz4740_uart_data, + }, +}; + +void jz4740_serial_device_register(void) +{ + struct plat_serial8250_port *p; + + for (p = jz4740_uart_data; p->flags != 0; ++p) + p->uartclk = jz4740_clock_bdata.ext_rate; + + platform_device_register(&jz4740_uart_device); +} -- cgit v1.2.3-70-g09d2 From 7a92d54521443450b14d89c413ec2072365da5bc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 17 Jul 2010 11:14:34 +0000 Subject: FBDEV: JZ4740: Add framebuffer driver Add support for the LCD controller on JZ4740 SoCs. Signed-off-by: Lars-Peter Clausen Cc: Andrew Morton Cc: linux-fbdev@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1470/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-jz4740/jz4740_fb.h | 67 ++ drivers/video/Kconfig | 9 + drivers/video/Makefile | 1 + drivers/video/jz4740_fb.c | 847 ++++++++++++++++++++++++++ 4 files changed, 924 insertions(+) create mode 100644 arch/mips/include/asm/mach-jz4740/jz4740_fb.h create mode 100644 drivers/video/jz4740_fb.c (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_fb.h b/arch/mips/include/asm/mach-jz4740/jz4740_fb.h new file mode 100644 index 00000000000..6a50e6f7a21 --- /dev/null +++ b/arch/mips/include/asm/mach-jz4740/jz4740_fb.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __ASM_MACH_JZ4740_JZ4740_FB_H__ +#define __ASM_MACH_JZ4740_JZ4740_FB_H__ + +#include + +enum jz4740_fb_lcd_type { + JZ_LCD_TYPE_GENERIC_16_BIT = 0, + JZ_LCD_TYPE_GENERIC_18_BIT = 0 | (1 << 4), + JZ_LCD_TYPE_SPECIAL_TFT_1 = 1, + JZ_LCD_TYPE_SPECIAL_TFT_2 = 2, + JZ_LCD_TYPE_SPECIAL_TFT_3 = 3, + JZ_LCD_TYPE_NON_INTERLACED_CCIR656 = 5, + JZ_LCD_TYPE_INTERLACED_CCIR656 = 7, + JZ_LCD_TYPE_SINGLE_COLOR_STN = 8, + JZ_LCD_TYPE_SINGLE_MONOCHROME_STN = 9, + JZ_LCD_TYPE_DUAL_COLOR_STN = 10, + JZ_LCD_TYPE_DUAL_MONOCHROME_STN = 11, + JZ_LCD_TYPE_8BIT_SERIAL = 12, +}; + +#define JZ4740_FB_SPECIAL_TFT_CONFIG(start, stop) (((start) << 16) | (stop)) + +/* +* width: width of the lcd display in mm +* height: height of the lcd display in mm +* num_modes: size of modes +* modes: list of valid video modes +* bpp: bits per pixel for the lcd +* lcd_type: lcd type +*/ + +struct jz4740_fb_platform_data { + unsigned int width; + unsigned int height; + + size_t num_modes; + struct fb_videomode *modes; + + unsigned int bpp; + enum jz4740_fb_lcd_type lcd_type; + + struct { + uint32_t spl; + uint32_t cls; + uint32_t ps; + uint32_t rev; + } special_tft_config; + + unsigned pixclk_falling_edge:1; + unsigned date_enable_active_low:1; +}; + +#endif diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 3d94a147172..9e711a1d0d9 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2229,6 +2229,15 @@ config FB_BROADSHEET and could also have been called by other names when coupled with a bridge adapter. +config FB_JZ4740 + tristate "JZ4740 LCD framebuffer support" + depends on FB && MACH_JZ4740 + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + help + Framebuffer support for the JZ4740 SoC. + source "drivers/video/omap/Kconfig" source "drivers/video/omap2/Kconfig" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index ddc2af2ba45..f56a9cae215 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -131,6 +131,7 @@ obj-$(CONFIG_FB_CARMINE) += carminefb.o obj-$(CONFIG_FB_MB862XX) += mb862xx/ obj-$(CONFIG_FB_MSM) += msm/ obj-$(CONFIG_FB_NUC900) += nuc900fb.o +obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o # Platform or fallback drivers go here obj-$(CONFIG_FB_UVESA) += uvesafb.o diff --git a/drivers/video/jz4740_fb.c b/drivers/video/jz4740_fb.c new file mode 100644 index 00000000000..670ecaa0385 --- /dev/null +++ b/drivers/video/jz4740_fb.c @@ -0,0 +1,847 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen + * JZ4740 SoC LCD framebuffer driver + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#define JZ_REG_LCD_CFG 0x00 +#define JZ_REG_LCD_VSYNC 0x04 +#define JZ_REG_LCD_HSYNC 0x08 +#define JZ_REG_LCD_VAT 0x0C +#define JZ_REG_LCD_DAH 0x10 +#define JZ_REG_LCD_DAV 0x14 +#define JZ_REG_LCD_PS 0x18 +#define JZ_REG_LCD_CLS 0x1C +#define JZ_REG_LCD_SPL 0x20 +#define JZ_REG_LCD_REV 0x24 +#define JZ_REG_LCD_CTRL 0x30 +#define JZ_REG_LCD_STATE 0x34 +#define JZ_REG_LCD_IID 0x38 +#define JZ_REG_LCD_DA0 0x40 +#define JZ_REG_LCD_SA0 0x44 +#define JZ_REG_LCD_FID0 0x48 +#define JZ_REG_LCD_CMD0 0x4C +#define JZ_REG_LCD_DA1 0x50 +#define JZ_REG_LCD_SA1 0x54 +#define JZ_REG_LCD_FID1 0x58 +#define JZ_REG_LCD_CMD1 0x5C + +#define JZ_LCD_CFG_SLCD BIT(31) +#define JZ_LCD_CFG_PS_DISABLE BIT(23) +#define JZ_LCD_CFG_CLS_DISABLE BIT(22) +#define JZ_LCD_CFG_SPL_DISABLE BIT(21) +#define JZ_LCD_CFG_REV_DISABLE BIT(20) +#define JZ_LCD_CFG_HSYNCM BIT(19) +#define JZ_LCD_CFG_PCLKM BIT(18) +#define JZ_LCD_CFG_INV BIT(17) +#define JZ_LCD_CFG_SYNC_DIR BIT(16) +#define JZ_LCD_CFG_PS_POLARITY BIT(15) +#define JZ_LCD_CFG_CLS_POLARITY BIT(14) +#define JZ_LCD_CFG_SPL_POLARITY BIT(13) +#define JZ_LCD_CFG_REV_POLARITY BIT(12) +#define JZ_LCD_CFG_HSYNC_ACTIVE_LOW BIT(11) +#define JZ_LCD_CFG_PCLK_FALLING_EDGE BIT(10) +#define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9) +#define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8) +#define JZ_LCD_CFG_18_BIT BIT(7) +#define JZ_LCD_CFG_PDW (BIT(5) | BIT(4)) +#define JZ_LCD_CFG_MODE_MASK 0xf + +#define JZ_LCD_CTRL_BURST_4 (0x0 << 28) +#define JZ_LCD_CTRL_BURST_8 (0x1 << 28) +#define JZ_LCD_CTRL_BURST_16 (0x2 << 28) +#define JZ_LCD_CTRL_RGB555 BIT(27) +#define JZ_LCD_CTRL_OFUP BIT(26) +#define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24) +#define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24) +#define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24) +#define JZ_LCD_CTRL_PDD_MASK (0xff << 16) +#define JZ_LCD_CTRL_EOF_IRQ BIT(13) +#define JZ_LCD_CTRL_SOF_IRQ BIT(12) +#define JZ_LCD_CTRL_OFU_IRQ BIT(11) +#define JZ_LCD_CTRL_IFU0_IRQ BIT(10) +#define JZ_LCD_CTRL_IFU1_IRQ BIT(9) +#define JZ_LCD_CTRL_DD_IRQ BIT(8) +#define JZ_LCD_CTRL_QDD_IRQ BIT(7) +#define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6) +#define JZ_LCD_CTRL_LSB_FISRT BIT(5) +#define JZ_LCD_CTRL_DISABLE BIT(4) +#define JZ_LCD_CTRL_ENABLE BIT(3) +#define JZ_LCD_CTRL_BPP_1 0x0 +#define JZ_LCD_CTRL_BPP_2 0x1 +#define JZ_LCD_CTRL_BPP_4 0x2 +#define JZ_LCD_CTRL_BPP_8 0x3 +#define JZ_LCD_CTRL_BPP_15_16 0x4 +#define JZ_LCD_CTRL_BPP_18_24 0x5 + +#define JZ_LCD_CMD_SOF_IRQ BIT(15) +#define JZ_LCD_CMD_EOF_IRQ BIT(16) +#define JZ_LCD_CMD_ENABLE_PAL BIT(12) + +#define JZ_LCD_SYNC_MASK 0x3ff + +#define JZ_LCD_STATE_DISABLED BIT(0) + +struct jzfb_framedesc { + uint32_t next; + uint32_t addr; + uint32_t id; + uint32_t cmd; +} __packed; + +struct jzfb { + struct fb_info *fb; + struct platform_device *pdev; + void __iomem *base; + struct resource *mem; + struct jz4740_fb_platform_data *pdata; + + size_t vidmem_size; + void *vidmem; + dma_addr_t vidmem_phys; + struct jzfb_framedesc *framedesc; + dma_addr_t framedesc_phys; + + struct clk *ldclk; + struct clk *lpclk; + + unsigned is_enabled:1; + struct mutex lock; + + uint32_t pseudo_palette[16]; +}; + +static const struct fb_fix_screeninfo jzfb_fix __devinitdata = { + .id = "JZ4740 FB", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + +static const struct jz_gpio_bulk_request jz_lcd_ctrl_pins[] = { + JZ_GPIO_BULK_PIN(LCD_PCLK), + JZ_GPIO_BULK_PIN(LCD_HSYNC), + JZ_GPIO_BULK_PIN(LCD_VSYNC), + JZ_GPIO_BULK_PIN(LCD_DE), + JZ_GPIO_BULK_PIN(LCD_PS), + JZ_GPIO_BULK_PIN(LCD_REV), + JZ_GPIO_BULK_PIN(LCD_CLS), + JZ_GPIO_BULK_PIN(LCD_SPL), +}; + +static const struct jz_gpio_bulk_request jz_lcd_data_pins[] = { + JZ_GPIO_BULK_PIN(LCD_DATA0), + JZ_GPIO_BULK_PIN(LCD_DATA1), + JZ_GPIO_BULK_PIN(LCD_DATA2), + JZ_GPIO_BULK_PIN(LCD_DATA3), + JZ_GPIO_BULK_PIN(LCD_DATA4), + JZ_GPIO_BULK_PIN(LCD_DATA5), + JZ_GPIO_BULK_PIN(LCD_DATA6), + JZ_GPIO_BULK_PIN(LCD_DATA7), + JZ_GPIO_BULK_PIN(LCD_DATA8), + JZ_GPIO_BULK_PIN(LCD_DATA9), + JZ_GPIO_BULK_PIN(LCD_DATA10), + JZ_GPIO_BULK_PIN(LCD_DATA11), + JZ_GPIO_BULK_PIN(LCD_DATA12), + JZ_GPIO_BULK_PIN(LCD_DATA13), + JZ_GPIO_BULK_PIN(LCD_DATA14), + JZ_GPIO_BULK_PIN(LCD_DATA15), + JZ_GPIO_BULK_PIN(LCD_DATA16), + JZ_GPIO_BULK_PIN(LCD_DATA17), +}; + +static unsigned int jzfb_num_ctrl_pins(struct jzfb *jzfb) +{ + unsigned int num; + + switch (jzfb->pdata->lcd_type) { + case JZ_LCD_TYPE_GENERIC_16_BIT: + num = 4; + break; + case JZ_LCD_TYPE_GENERIC_18_BIT: + num = 4; + break; + case JZ_LCD_TYPE_8BIT_SERIAL: + num = 3; + break; + case JZ_LCD_TYPE_SPECIAL_TFT_1: + case JZ_LCD_TYPE_SPECIAL_TFT_2: + case JZ_LCD_TYPE_SPECIAL_TFT_3: + num = 8; + break; + default: + num = 0; + break; + } + return num; +} + +static unsigned int jzfb_num_data_pins(struct jzfb *jzfb) +{ + unsigned int num; + + switch (jzfb->pdata->lcd_type) { + case JZ_LCD_TYPE_GENERIC_16_BIT: + num = 16; + break; + case JZ_LCD_TYPE_GENERIC_18_BIT: + num = 18; + break; + case JZ_LCD_TYPE_8BIT_SERIAL: + num = 8; + break; + case JZ_LCD_TYPE_SPECIAL_TFT_1: + case JZ_LCD_TYPE_SPECIAL_TFT_2: + case JZ_LCD_TYPE_SPECIAL_TFT_3: + if (jzfb->pdata->bpp == 18) + num = 18; + else + num = 16; + break; + default: + num = 0; + break; + } + return num; +} + +/* Based on CNVT_TOHW macro from skeletonfb.c */ +static inline uint32_t jzfb_convert_color_to_hw(unsigned val, + struct fb_bitfield *bf) +{ + return (((val << bf->length) + 0x7FFF - val) >> 16) << bf->offset; +} + +static int jzfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *fb) +{ + uint32_t color; + + if (regno >= 16) + return -EINVAL; + + color = jzfb_convert_color_to_hw(red, &fb->var.red); + color |= jzfb_convert_color_to_hw(green, &fb->var.green); + color |= jzfb_convert_color_to_hw(blue, &fb->var.blue); + color |= jzfb_convert_color_to_hw(transp, &fb->var.transp); + + ((uint32_t *)(fb->pseudo_palette))[regno] = color; + + return 0; +} + +static int jzfb_get_controller_bpp(struct jzfb *jzfb) +{ + switch (jzfb->pdata->bpp) { + case 18: + case 24: + return 32; + case 15: + return 16; + default: + return jzfb->pdata->bpp; + } +} + +static struct fb_videomode *jzfb_get_mode(struct jzfb *jzfb, + struct fb_var_screeninfo *var) +{ + size_t i; + struct fb_videomode *mode = jzfb->pdata->modes; + + for (i = 0; i < jzfb->pdata->num_modes; ++i, ++mode) { + if (mode->xres == var->xres && mode->yres == var->yres) + return mode; + } + + return NULL; +} + +static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb) +{ + struct jzfb *jzfb = fb->par; + struct fb_videomode *mode; + + if (var->bits_per_pixel != jzfb_get_controller_bpp(jzfb) && + var->bits_per_pixel != jzfb->pdata->bpp) + return -EINVAL; + + mode = jzfb_get_mode(jzfb, var); + if (mode == NULL) + return -EINVAL; + + fb_videomode_to_var(var, mode); + + switch (jzfb->pdata->bpp) { + case 8: + break; + case 15: + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 6; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + break; + case 16: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + case 18: + var->red.offset = 16; + var->red.length = 6; + var->green.offset = 8; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 6; + var->bits_per_pixel = 32; + break; + case 32: + case 24: + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->bits_per_pixel = 32; + break; + default: + break; + } + + return 0; +} + +static int jzfb_set_par(struct fb_info *info) +{ + struct jzfb *jzfb = info->par; + struct jz4740_fb_platform_data *pdata = jzfb->pdata; + struct fb_var_screeninfo *var = &info->var; + struct fb_videomode *mode; + uint16_t hds, vds; + uint16_t hde, vde; + uint16_t ht, vt; + uint32_t ctrl; + uint32_t cfg; + unsigned long rate; + + mode = jzfb_get_mode(jzfb, var); + if (mode == NULL) + return -EINVAL; + + if (mode == info->mode) + return 0; + + info->mode = mode; + + hds = mode->hsync_len + mode->left_margin; + hde = hds + mode->xres; + ht = hde + mode->right_margin; + + vds = mode->vsync_len + mode->upper_margin; + vde = vds + mode->yres; + vt = vde + mode->lower_margin; + + ctrl = JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16; + + switch (pdata->bpp) { + case 1: + ctrl |= JZ_LCD_CTRL_BPP_1; + break; + case 2: + ctrl |= JZ_LCD_CTRL_BPP_2; + break; + case 4: + ctrl |= JZ_LCD_CTRL_BPP_4; + break; + case 8: + ctrl |= JZ_LCD_CTRL_BPP_8; + break; + case 15: + ctrl |= JZ_LCD_CTRL_RGB555; /* Falltrough */ + case 16: + ctrl |= JZ_LCD_CTRL_BPP_15_16; + break; + case 18: + case 24: + case 32: + ctrl |= JZ_LCD_CTRL_BPP_18_24; + break; + default: + break; + } + + cfg = pdata->lcd_type & 0xf; + + if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT)) + cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW; + + if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT)) + cfg |= JZ_LCD_CFG_VSYNC_ACTIVE_LOW; + + if (pdata->pixclk_falling_edge) + cfg |= JZ_LCD_CFG_PCLK_FALLING_EDGE; + + if (pdata->date_enable_active_low) + cfg |= JZ_LCD_CFG_DE_ACTIVE_LOW; + + if (pdata->lcd_type == JZ_LCD_TYPE_GENERIC_18_BIT) + cfg |= JZ_LCD_CFG_18_BIT; + + if (mode->pixclock) { + rate = PICOS2KHZ(mode->pixclock) * 1000; + mode->refresh = rate / vt / ht; + } else { + if (pdata->lcd_type == JZ_LCD_TYPE_8BIT_SERIAL) + rate = mode->refresh * (vt + 2 * mode->xres) * ht; + else + rate = mode->refresh * vt * ht; + + mode->pixclock = KHZ2PICOS(rate / 1000); + } + + mutex_lock(&jzfb->lock); + if (!jzfb->is_enabled) + clk_enable(jzfb->ldclk); + else + ctrl |= JZ_LCD_CTRL_ENABLE; + + switch (pdata->lcd_type) { + case JZ_LCD_TYPE_SPECIAL_TFT_1: + case JZ_LCD_TYPE_SPECIAL_TFT_2: + case JZ_LCD_TYPE_SPECIAL_TFT_3: + writel(pdata->special_tft_config.spl, jzfb->base + JZ_REG_LCD_SPL); + writel(pdata->special_tft_config.cls, jzfb->base + JZ_REG_LCD_CLS); + writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_PS); + writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_REV); + break; + default: + cfg |= JZ_LCD_CFG_PS_DISABLE; + cfg |= JZ_LCD_CFG_CLS_DISABLE; + cfg |= JZ_LCD_CFG_SPL_DISABLE; + cfg |= JZ_LCD_CFG_REV_DISABLE; + break; + } + + writel(mode->hsync_len, jzfb->base + JZ_REG_LCD_HSYNC); + writel(mode->vsync_len, jzfb->base + JZ_REG_LCD_VSYNC); + + writel((ht << 16) | vt, jzfb->base + JZ_REG_LCD_VAT); + + writel((hds << 16) | hde, jzfb->base + JZ_REG_LCD_DAH); + writel((vds << 16) | vde, jzfb->base + JZ_REG_LCD_DAV); + + writel(cfg, jzfb->base + JZ_REG_LCD_CFG); + + writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); + + if (!jzfb->is_enabled) + clk_disable(jzfb->ldclk); + + mutex_unlock(&jzfb->lock); + + clk_set_rate(jzfb->lpclk, rate); + clk_set_rate(jzfb->ldclk, rate * 3); + + return 0; +} + +static void jzfb_enable(struct jzfb *jzfb) +{ + uint32_t ctrl; + + clk_enable(jzfb->ldclk); + + jz_gpio_bulk_resume(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); + jz_gpio_bulk_resume(jz_lcd_data_pins, jzfb_num_data_pins(jzfb)); + + writel(0, jzfb->base + JZ_REG_LCD_STATE); + + writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0); + + ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL); + ctrl |= JZ_LCD_CTRL_ENABLE; + ctrl &= ~JZ_LCD_CTRL_DISABLE; + writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); +} + +static void jzfb_disable(struct jzfb *jzfb) +{ + uint32_t ctrl; + + ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL); + ctrl |= JZ_LCD_CTRL_DISABLE; + writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); + do { + ctrl = readl(jzfb->base + JZ_REG_LCD_STATE); + } while (!(ctrl & JZ_LCD_STATE_DISABLED)); + + jz_gpio_bulk_suspend(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); + jz_gpio_bulk_suspend(jz_lcd_data_pins, jzfb_num_data_pins(jzfb)); + + clk_disable(jzfb->ldclk); +} + +static int jzfb_blank(int blank_mode, struct fb_info *info) +{ + struct jzfb *jzfb = info->par; + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + mutex_lock(&jzfb->lock); + if (jzfb->is_enabled) { + mutex_unlock(&jzfb->lock); + return 0; + } + + jzfb_enable(jzfb); + jzfb->is_enabled = 1; + + mutex_unlock(&jzfb->lock); + break; + default: + mutex_lock(&jzfb->lock); + if (!jzfb->is_enabled) { + mutex_unlock(&jzfb->lock); + return 0; + } + + jzfb_disable(jzfb); + jzfb->is_enabled = 0; + + mutex_unlock(&jzfb->lock); + break; + } + + return 0; +} + +static int jzfb_alloc_devmem(struct jzfb *jzfb) +{ + int max_videosize = 0; + struct fb_videomode *mode = jzfb->pdata->modes; + void *page; + int i; + + for (i = 0; i < jzfb->pdata->num_modes; ++mode, ++i) { + if (max_videosize < mode->xres * mode->yres) + max_videosize = mode->xres * mode->yres; + } + + max_videosize *= jzfb_get_controller_bpp(jzfb) >> 3; + + jzfb->framedesc = dma_alloc_coherent(&jzfb->pdev->dev, + sizeof(*jzfb->framedesc), + &jzfb->framedesc_phys, GFP_KERNEL); + + if (!jzfb->framedesc) + return -ENOMEM; + + jzfb->vidmem_size = PAGE_ALIGN(max_videosize); + jzfb->vidmem = dma_alloc_coherent(&jzfb->pdev->dev, + jzfb->vidmem_size, + &jzfb->vidmem_phys, GFP_KERNEL); + + if (!jzfb->vidmem) + goto err_free_framedesc; + + for (page = jzfb->vidmem; + page < jzfb->vidmem + PAGE_ALIGN(jzfb->vidmem_size); + page += PAGE_SIZE) { + SetPageReserved(virt_to_page(page)); + } + + jzfb->framedesc->next = jzfb->framedesc_phys; + jzfb->framedesc->addr = jzfb->vidmem_phys; + jzfb->framedesc->id = 0xdeafbead; + jzfb->framedesc->cmd = 0; + jzfb->framedesc->cmd |= max_videosize / 4; + + return 0; + +err_free_framedesc: + dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc), + jzfb->framedesc, jzfb->framedesc_phys); + return -ENOMEM; +} + +static void jzfb_free_devmem(struct jzfb *jzfb) +{ + dma_free_coherent(&jzfb->pdev->dev, jzfb->vidmem_size, + jzfb->vidmem, jzfb->vidmem_phys); + dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc), + jzfb->framedesc, jzfb->framedesc_phys); +} + +static struct fb_ops jzfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = jzfb_check_var, + .fb_set_par = jzfb_set_par, + .fb_blank = jzfb_blank, + .fb_fillrect = sys_fillrect, + .fb_copyarea = sys_copyarea, + .fb_imageblit = sys_imageblit, + .fb_setcolreg = jzfb_setcolreg, +}; + +static int __devinit jzfb_probe(struct platform_device *pdev) +{ + int ret; + struct jzfb *jzfb; + struct fb_info *fb; + struct jz4740_fb_platform_data *pdata = pdev->dev.platform_data; + struct resource *mem; + + if (!pdata) { + dev_err(&pdev->dev, "Missing platform data\n"); + return -ENXIO; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "Failed to get register memory resource\n"); + return -ENXIO; + } + + mem = request_mem_region(mem->start, resource_size(mem), pdev->name); + if (!mem) { + dev_err(&pdev->dev, "Failed to request register memory region\n"); + return -EBUSY; + } + + fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev); + if (!fb) { + dev_err(&pdev->dev, "Failed to allocate framebuffer device\n"); + ret = -ENOMEM; + goto err_release_mem_region; + } + + fb->fbops = &jzfb_ops; + fb->flags = FBINFO_DEFAULT; + + jzfb = fb->par; + jzfb->pdev = pdev; + jzfb->pdata = pdata; + jzfb->mem = mem; + + jzfb->ldclk = clk_get(&pdev->dev, "lcd"); + if (IS_ERR(jzfb->ldclk)) { + ret = PTR_ERR(jzfb->ldclk); + dev_err(&pdev->dev, "Failed to get lcd clock: %d\n", ret); + goto err_framebuffer_release; + } + + jzfb->lpclk = clk_get(&pdev->dev, "lcd_pclk"); + if (IS_ERR(jzfb->lpclk)) { + ret = PTR_ERR(jzfb->lpclk); + dev_err(&pdev->dev, "Failed to get lcd pixel clock: %d\n", ret); + goto err_put_ldclk; + } + + jzfb->base = ioremap(mem->start, resource_size(mem)); + if (!jzfb->base) { + dev_err(&pdev->dev, "Failed to ioremap register memory region\n"); + ret = -EBUSY; + goto err_put_lpclk; + } + + platform_set_drvdata(pdev, jzfb); + + mutex_init(&jzfb->lock); + + fb_videomode_to_modelist(pdata->modes, pdata->num_modes, + &fb->modelist); + fb_videomode_to_var(&fb->var, pdata->modes); + fb->var.bits_per_pixel = pdata->bpp; + jzfb_check_var(&fb->var, fb); + + ret = jzfb_alloc_devmem(jzfb); + if (ret) { + dev_err(&pdev->dev, "Failed to allocate video memory\n"); + goto err_iounmap; + } + + fb->fix = jzfb_fix; + fb->fix.line_length = fb->var.bits_per_pixel * fb->var.xres / 8; + fb->fix.mmio_start = mem->start; + fb->fix.mmio_len = resource_size(mem); + fb->fix.smem_start = jzfb->vidmem_phys; + fb->fix.smem_len = fb->fix.line_length * fb->var.yres; + fb->screen_base = jzfb->vidmem; + fb->pseudo_palette = jzfb->pseudo_palette; + + fb_alloc_cmap(&fb->cmap, 256, 0); + + clk_enable(jzfb->ldclk); + jzfb->is_enabled = 1; + + writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0); + + fb->mode = NULL; + jzfb_set_par(fb); + + jz_gpio_bulk_request(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); + jz_gpio_bulk_request(jz_lcd_data_pins, jzfb_num_data_pins(jzfb)); + + ret = register_framebuffer(fb); + if (ret) { + dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret); + goto err_free_devmem; + } + + jzfb->fb = fb; + + return 0; + +err_free_devmem: + jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); + jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb)); + + fb_dealloc_cmap(&fb->cmap); + jzfb_free_devmem(jzfb); +err_iounmap: + iounmap(jzfb->base); +err_put_lpclk: + clk_put(jzfb->lpclk); +err_put_ldclk: + clk_put(jzfb->ldclk); +err_framebuffer_release: + framebuffer_release(fb); +err_release_mem_region: + release_mem_region(mem->start, resource_size(mem)); + return ret; +} + +static int __devexit jzfb_remove(struct platform_device *pdev) +{ + struct jzfb *jzfb = platform_get_drvdata(pdev); + + jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb); + + jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); + jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb)); + + iounmap(jzfb->base); + release_mem_region(jzfb->mem->start, resource_size(jzfb->mem)); + + fb_dealloc_cmap(&jzfb->fb->cmap); + jzfb_free_devmem(jzfb); + + platform_set_drvdata(pdev, NULL); + + clk_put(jzfb->lpclk); + clk_put(jzfb->ldclk); + + framebuffer_release(jzfb->fb); + + return 0; +} + +#ifdef CONFIG_PM + +static int jzfb_suspend(struct device *dev) +{ + struct jzfb *jzfb = dev_get_drvdata(dev); + + acquire_console_sem(); + fb_set_suspend(jzfb->fb, 1); + release_console_sem(); + + mutex_lock(&jzfb->lock); + if (jzfb->is_enabled) + jzfb_disable(jzfb); + mutex_unlock(&jzfb->lock); + + return 0; +} + +static int jzfb_resume(struct device *dev) +{ + struct jzfb *jzfb = dev_get_drvdata(dev); + clk_enable(jzfb->ldclk); + + mutex_lock(&jzfb->lock); + if (jzfb->is_enabled) + jzfb_enable(jzfb); + mutex_unlock(&jzfb->lock); + + acquire_console_sem(); + fb_set_suspend(jzfb->fb, 0); + release_console_sem(); + + return 0; +} + +static const struct dev_pm_ops jzfb_pm_ops = { + .suspend = jzfb_suspend, + .resume = jzfb_resume, + .poweroff = jzfb_suspend, + .restore = jzfb_resume, +}; + +#define JZFB_PM_OPS (&jzfb_pm_ops) + +#else +#define JZFB_PM_OPS NULL +#endif + +static struct platform_driver jzfb_driver = { + .probe = jzfb_probe, + .remove = __devexit_p(jzfb_remove), + .driver = { + .name = "jz4740-fb", + .pm = JZFB_PM_OPS, + }, +}; + +static int __init jzfb_init(void) +{ + return platform_driver_register(&jzfb_driver); +} +module_init(jzfb_init); + +static void __exit jzfb_exit(void) +{ + platform_driver_unregister(&jzfb_driver); +} +module_exit(jzfb_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("JZ4740 SoC LCD framebuffer driver"); +MODULE_ALIAS("platform:jz4740-fb"); -- cgit v1.2.3-70-g09d2 From ba01d6ec04f6d1d983101eb527caa96318fc1017 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 17 Jul 2010 11:15:29 +0000 Subject: MTD: Nand: Add JZ4740 NAND driver Add support for the NAND controller on JZ4740 SoCs. Signed-off-by: Lars-Peter Clausen Cc: David Woodhouse Cc: linux-mtd@lists.infradead.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1470/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-jz4740/jz4740_nand.h | 34 ++ drivers/mtd/nand/Kconfig | 6 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/jz4740_nand.c | 516 ++++++++++++++++++++++++ 4 files changed, 557 insertions(+) create mode 100644 arch/mips/include/asm/mach-jz4740/jz4740_nand.h create mode 100644 drivers/mtd/nand/jz4740_nand.c (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h new file mode 100644 index 00000000000..bb5b9a4e29c --- /dev/null +++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen + * JZ4740 SoC NAND controller driver + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __ASM_MACH_JZ4740_JZ4740_NAND_H__ +#define __ASM_MACH_JZ4740_JZ4740_NAND_H__ + +#include +#include + +struct jz_nand_platform_data { + int num_partitions; + struct mtd_partition *partitions; + + struct nand_ecclayout *ecc_layout; + + unsigned int busy_gpio; + + void (*ident_callback)(struct platform_device *, struct nand_chip *, + struct mtd_partition **, int *num_partitions); +}; + +#endif diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index ffc3720929f..362d177efe1 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -526,4 +526,10 @@ config MTD_NAND_NUC900 This enables the driver for the NAND Flash on evaluation board based on w90p910 / NUC9xx. +config MTD_NAND_JZ4740 + tristate "Support for JZ4740 SoC NAND controller" + depends on MACH_JZ4740 + help + Enables support for NAND Flash on JZ4740 SoC based boards. + endif # MTD_NAND diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index e8ab884ba47..ac83dcdac5d 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -46,5 +46,6 @@ obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o obj-$(CONFIG_MTD_NAND_BCM_UMI) += bcm_umi_nand.o nand_bcm_umi.o obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o obj-$(CONFIG_MTD_NAND_RICOH) += r852.o +obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o nand-objs := nand_base.o nand_bbt.o diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c new file mode 100644 index 00000000000..67343fc31bd --- /dev/null +++ b/drivers/mtd/nand/jz4740_nand.c @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen + * JZ4740 SoC NAND controller driver + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#define JZ_REG_NAND_CTRL 0x50 +#define JZ_REG_NAND_ECC_CTRL 0x100 +#define JZ_REG_NAND_DATA 0x104 +#define JZ_REG_NAND_PAR0 0x108 +#define JZ_REG_NAND_PAR1 0x10C +#define JZ_REG_NAND_PAR2 0x110 +#define JZ_REG_NAND_IRQ_STAT 0x114 +#define JZ_REG_NAND_IRQ_CTRL 0x118 +#define JZ_REG_NAND_ERR(x) (0x11C + ((x) << 2)) + +#define JZ_NAND_ECC_CTRL_PAR_READY BIT(4) +#define JZ_NAND_ECC_CTRL_ENCODING BIT(3) +#define JZ_NAND_ECC_CTRL_RS BIT(2) +#define JZ_NAND_ECC_CTRL_RESET BIT(1) +#define JZ_NAND_ECC_CTRL_ENABLE BIT(0) + +#define JZ_NAND_STATUS_ERR_COUNT (BIT(31) | BIT(30) | BIT(29)) +#define JZ_NAND_STATUS_PAD_FINISH BIT(4) +#define JZ_NAND_STATUS_DEC_FINISH BIT(3) +#define JZ_NAND_STATUS_ENC_FINISH BIT(2) +#define JZ_NAND_STATUS_UNCOR_ERROR BIT(1) +#define JZ_NAND_STATUS_ERROR BIT(0) + +#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1) +#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1) + +#define JZ_NAND_MEM_ADDR_OFFSET 0x10000 +#define JZ_NAND_MEM_CMD_OFFSET 0x08000 + +struct jz_nand { + struct mtd_info mtd; + struct nand_chip chip; + void __iomem *base; + struct resource *mem; + + void __iomem *bank_base; + struct resource *bank_mem; + + struct jz_nand_platform_data *pdata; + bool is_reading; +}; + +static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd) +{ + return container_of(mtd, struct jz_nand, mtd); +} + +static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) +{ + struct jz_nand *nand = mtd_to_jz_nand(mtd); + struct nand_chip *chip = mtd->priv; + uint32_t reg; + + if (ctrl & NAND_CTRL_CHANGE) { + BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE)); + if (ctrl & NAND_ALE) + chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_ADDR_OFFSET; + else if (ctrl & NAND_CLE) + chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_CMD_OFFSET; + else + chip->IO_ADDR_W = nand->bank_base; + + reg = readl(nand->base + JZ_REG_NAND_CTRL); + if (ctrl & NAND_NCE) + reg |= JZ_NAND_CTRL_ASSERT_CHIP(0); + else + reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0); + writel(reg, nand->base + JZ_REG_NAND_CTRL); + } + if (dat != NAND_CMD_NONE) + writeb(dat, chip->IO_ADDR_W); +} + +static int jz_nand_dev_ready(struct mtd_info *mtd) +{ + struct jz_nand *nand = mtd_to_jz_nand(mtd); + return gpio_get_value_cansleep(nand->pdata->busy_gpio); +} + +static void jz_nand_hwctl(struct mtd_info *mtd, int mode) +{ + struct jz_nand *nand = mtd_to_jz_nand(mtd); + uint32_t reg; + + writel(0, nand->base + JZ_REG_NAND_IRQ_STAT); + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); + + reg |= JZ_NAND_ECC_CTRL_RESET; + reg |= JZ_NAND_ECC_CTRL_ENABLE; + reg |= JZ_NAND_ECC_CTRL_RS; + + switch (mode) { + case NAND_ECC_READ: + reg &= ~JZ_NAND_ECC_CTRL_ENCODING; + nand->is_reading = true; + break; + case NAND_ECC_WRITE: + reg |= JZ_NAND_ECC_CTRL_ENCODING; + nand->is_reading = false; + break; + default: + break; + } + + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); +} + +static int jz_nand_calculate_ecc_rs(struct mtd_info *mtd, const uint8_t *dat, + uint8_t *ecc_code) +{ + struct jz_nand *nand = mtd_to_jz_nand(mtd); + uint32_t reg, status; + int i; + unsigned int timeout = 1000; + static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4, + 0x8b, 0xff, 0xb7, 0x6f}; + + if (nand->is_reading) + return 0; + + do { + status = readl(nand->base + JZ_REG_NAND_IRQ_STAT); + } while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout); + + if (timeout == 0) + return -1; + + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); + reg &= ~JZ_NAND_ECC_CTRL_ENABLE; + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); + + for (i = 0; i < 9; ++i) + ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i); + + /* If the written data is completly 0xff, we also want to write 0xff as + * ecc, otherwise we will get in trouble when doing subpage writes. */ + if (memcmp(ecc_code, empty_block_ecc, 9) == 0) + memset(ecc_code, 0xff, 9); + + return 0; +} + +static void jz_nand_correct_data(uint8_t *dat, int index, int mask) +{ + int offset = index & 0x7; + uint16_t data; + + index += (index >> 3); + + data = dat[index]; + data |= dat[index+1] << 8; + + mask ^= (data >> offset) & 0x1ff; + data &= ~(0x1ff << offset); + data |= (mask << offset); + + dat[index] = data & 0xff; + dat[index+1] = (data >> 8) & 0xff; +} + +static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) +{ + struct jz_nand *nand = mtd_to_jz_nand(mtd); + int i, error_count, index; + uint32_t reg, status, error; + uint32_t t; + unsigned int timeout = 1000; + + t = read_ecc[0]; + + if (t == 0xff) { + for (i = 1; i < 9; ++i) + t &= read_ecc[i]; + + t &= dat[0]; + t &= dat[nand->chip.ecc.size / 2]; + t &= dat[nand->chip.ecc.size - 1]; + + if (t == 0xff) { + for (i = 1; i < nand->chip.ecc.size - 1; ++i) + t &= dat[i]; + if (t == 0xff) + return 0; + } + } + + for (i = 0; i < 9; ++i) + writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i); + + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); + reg |= JZ_NAND_ECC_CTRL_PAR_READY; + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); + + do { + status = readl(nand->base + JZ_REG_NAND_IRQ_STAT); + } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout); + + if (timeout == 0) + return -1; + + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); + reg &= ~JZ_NAND_ECC_CTRL_ENABLE; + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); + + if (status & JZ_NAND_STATUS_ERROR) { + if (status & JZ_NAND_STATUS_UNCOR_ERROR) + return -1; + + error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29; + + for (i = 0; i < error_count; ++i) { + error = readl(nand->base + JZ_REG_NAND_ERR(i)); + index = ((error >> 16) & 0x1ff) - 1; + if (index >= 0 && index < 512) + jz_nand_correct_data(dat, index, error & 0x1ff); + } + + return error_count; + } + + return 0; +} + + +/* Copy paste of nand_read_page_hwecc_oob_first except for different eccpos + * handling. The ecc area is for 4k chips 72 bytes long and thus does not fit + * into the eccpos array. */ +static int jz_nand_read_page_hwecc_oob_first(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int page) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + unsigned int ecc_offset = chip->page_shift; + + /* Read the OOB area first */ + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + int stat; + + chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->read_buf(mtd, p, eccsize); + + stat = chip->ecc.correct(mtd, p, &chip->oob_poi[i], NULL); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + return 0; +} + +/* Copy-and-paste of nand_write_page_hwecc with different eccpos handling. */ +static void jz_nand_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + const uint8_t *p = buf; + unsigned int ecc_offset = chip->page_shift; + + for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + chip->write_buf(mtd, p, eccsize); + chip->ecc.calculate(mtd, p, &chip->oob_poi[i]); + } + + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); +} + +#ifdef CONFIG_MTD_CMDLINE_PARTS +static const char *part_probes[] = {"cmdline", NULL}; +#endif + +static int jz_nand_ioremap_resource(struct platform_device *pdev, + const char *name, struct resource **res, void __iomem **base) +{ + int ret; + + *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + if (!*res) { + dev_err(&pdev->dev, "Failed to get platform %s memory\n", name); + ret = -ENXIO; + goto err; + } + + *res = request_mem_region((*res)->start, resource_size(*res), + pdev->name); + if (!*res) { + dev_err(&pdev->dev, "Failed to request %s memory region\n", name); + ret = -EBUSY; + goto err; + } + + *base = ioremap((*res)->start, resource_size(*res)); + if (!*base) { + dev_err(&pdev->dev, "Failed to ioremap %s memory region\n", name); + ret = -EBUSY; + goto err_release_mem; + } + + return 0; + +err_release_mem: + release_mem_region((*res)->start, resource_size(*res)); +err: + *res = NULL; + *base = NULL; + return ret; +} + +static int __devinit jz_nand_probe(struct platform_device *pdev) +{ + int ret; + struct jz_nand *nand; + struct nand_chip *chip; + struct mtd_info *mtd; + struct jz_nand_platform_data *pdata = pdev->dev.platform_data; +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *partition_info; + int num_partitions = 0; +#endif + + nand = kzalloc(sizeof(*nand), GFP_KERNEL); + if (!nand) { + dev_err(&pdev->dev, "Failed to allocate device structure.\n"); + return -ENOMEM; + } + + ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base); + if (ret) + goto err_free; + ret = jz_nand_ioremap_resource(pdev, "bank", &nand->bank_mem, + &nand->bank_base); + if (ret) + goto err_iounmap_mmio; + + if (pdata && gpio_is_valid(pdata->busy_gpio)) { + ret = gpio_request(pdata->busy_gpio, "NAND busy pin"); + if (ret) { + dev_err(&pdev->dev, + "Failed to request busy gpio %d: %d\n", + pdata->busy_gpio, ret); + goto err_iounmap_mem; + } + } + + mtd = &nand->mtd; + chip = &nand->chip; + mtd->priv = chip; + mtd->owner = THIS_MODULE; + mtd->name = "jz4740-nand"; + + chip->ecc.hwctl = jz_nand_hwctl; + chip->ecc.calculate = jz_nand_calculate_ecc_rs; + chip->ecc.correct = jz_nand_correct_ecc_rs; + chip->ecc.mode = NAND_ECC_HW_OOB_FIRST; + chip->ecc.size = 512; + chip->ecc.bytes = 9; + + chip->ecc.read_page = jz_nand_read_page_hwecc_oob_first; + chip->ecc.write_page = jz_nand_write_page_hwecc; + + if (pdata) + chip->ecc.layout = pdata->ecc_layout; + + chip->chip_delay = 50; + chip->cmd_ctrl = jz_nand_cmd_ctrl; + + if (pdata && gpio_is_valid(pdata->busy_gpio)) + chip->dev_ready = jz_nand_dev_ready; + + chip->IO_ADDR_R = nand->bank_base; + chip->IO_ADDR_W = nand->bank_base; + + nand->pdata = pdata; + platform_set_drvdata(pdev, nand); + + writel(JZ_NAND_CTRL_ENABLE_CHIP(0), nand->base + JZ_REG_NAND_CTRL); + + ret = nand_scan_ident(mtd, 1, NULL); + if (ret) { + dev_err(&pdev->dev, "Failed to scan nand\n"); + goto err_gpio_free; + } + + if (pdata && pdata->ident_callback) { + pdata->ident_callback(pdev, chip, &pdata->partitions, + &pdata->num_partitions); + } + + ret = nand_scan_tail(mtd); + if (ret) { + dev_err(&pdev->dev, "Failed to scan nand\n"); + goto err_gpio_free; + } + +#ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + num_partitions = parse_mtd_partitions(mtd, part_probes, + &partition_info, 0); +#endif + if (num_partitions <= 0 && pdata) { + num_partitions = pdata->num_partitions; + partition_info = pdata->partitions; + } + + if (num_partitions > 0) + ret = add_mtd_partitions(mtd, partition_info, num_partitions); + else +#endif + ret = add_mtd_device(mtd); + + if (ret) { + dev_err(&pdev->dev, "Failed to add mtd device\n"); + goto err_nand_release; + } + + dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n"); + + return 0; + +err_nand_release: + nand_release(&nand->mtd); +err_gpio_free: + platform_set_drvdata(pdev, NULL); + gpio_free(pdata->busy_gpio); +err_iounmap_mem: + iounmap(nand->bank_base); +err_iounmap_mmio: + iounmap(nand->base); +err_free: + kfree(nand); + return ret; +} + +static int __devexit jz_nand_remove(struct platform_device *pdev) +{ + struct jz_nand *nand = platform_get_drvdata(pdev); + + nand_release(&nand->mtd); + + /* Deassert and disable all chips */ + writel(0, nand->base + JZ_REG_NAND_CTRL); + + iounmap(nand->bank_base); + release_mem_region(nand->bank_mem->start, resource_size(nand->bank_mem)); + iounmap(nand->base); + release_mem_region(nand->mem->start, resource_size(nand->mem)); + + platform_set_drvdata(pdev, NULL); + kfree(nand); + + return 0; +} + +struct platform_driver jz_nand_driver = { + .probe = jz_nand_probe, + .remove = __devexit_p(jz_nand_remove), + .driver = { + .name = "jz4740-nand", + .owner = THIS_MODULE, + }, +}; + +static int __init jz_nand_init(void) +{ + return platform_driver_register(&jz_nand_driver); +} +module_init(jz_nand_init); + +static void __exit jz_nand_exit(void) +{ + platform_driver_unregister(&jz_nand_driver); +} +module_exit(jz_nand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("NAND controller driver for JZ4740 SoC"); +MODULE_ALIAS("platform:jz4740-nand"); -- cgit v1.2.3-70-g09d2 From 61bfbdb856879cff583fe53b2ab6ae907faedee7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 15 Jul 2010 20:06:04 +0000 Subject: MMC: Add support for the controller on JZ4740 SoCs. Signed-off-by: Lars-Peter Clausen Acked-by: Matt Fleming Cc: Andrew Morton Cc: Matt Fleming Cc: linux-mmc@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1463/ Patchwork: https://patchwork.linux-mips.org/patch/1523/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-jz4740/jz4740_mmc.h | 15 + drivers/mmc/host/Kconfig | 9 + drivers/mmc/host/Makefile | 1 + drivers/mmc/host/jz4740_mmc.c | 1029 ++++++++++++++++++++++++ 4 files changed, 1054 insertions(+) create mode 100644 arch/mips/include/asm/mach-jz4740/jz4740_mmc.h create mode 100644 drivers/mmc/host/jz4740_mmc.c (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_mmc.h b/arch/mips/include/asm/mach-jz4740/jz4740_mmc.h new file mode 100644 index 00000000000..8543f432b4b --- /dev/null +++ b/arch/mips/include/asm/mach-jz4740/jz4740_mmc.h @@ -0,0 +1,15 @@ +#ifndef __LINUX_MMC_JZ4740_MMC +#define __LINUX_MMC_JZ4740_MMC + +struct jz4740_mmc_platform_data { + int gpio_power; + int gpio_card_detect; + int gpio_read_only; + unsigned card_detect_active_low:1; + unsigned read_only_active_low:1; + unsigned power_active_low:1; + + unsigned data_1bit:1; +}; + +#endif diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index f06d06e7fdf..d25e22cee4c 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -432,3 +432,12 @@ config MMC_SH_MMCIF This selects the MMC Host Interface controler (MMCIF). This driver supports MMCIF in sh7724/sh7757/sh7372. + +config MMC_JZ4740 + tristate "JZ4740 SD/Multimedia Card Interface support" + depends on MACH_JZ4740 + help + This selects support for the SD/MMC controller on Ingenic JZ4740 + SoCs. + If you have a board based on such a SoC and with a SD/MMC slot, + say Y or M here. diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index e30c2ee4889..f4e53c98d94 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_MMC_CB710) += cb710-mmc.o obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o +obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o sdhci-of-y := sdhci-of-core.o diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c new file mode 100644 index 00000000000..ad4f9870e3c --- /dev/null +++ b/drivers/mmc/host/jz4740_mmc.c @@ -0,0 +1,1029 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen + * JZ4740 SD/MMC controller driver + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define JZ_REG_MMC_STRPCL 0x00 +#define JZ_REG_MMC_STATUS 0x04 +#define JZ_REG_MMC_CLKRT 0x08 +#define JZ_REG_MMC_CMDAT 0x0C +#define JZ_REG_MMC_RESTO 0x10 +#define JZ_REG_MMC_RDTO 0x14 +#define JZ_REG_MMC_BLKLEN 0x18 +#define JZ_REG_MMC_NOB 0x1C +#define JZ_REG_MMC_SNOB 0x20 +#define JZ_REG_MMC_IMASK 0x24 +#define JZ_REG_MMC_IREG 0x28 +#define JZ_REG_MMC_CMD 0x2C +#define JZ_REG_MMC_ARG 0x30 +#define JZ_REG_MMC_RESP_FIFO 0x34 +#define JZ_REG_MMC_RXFIFO 0x38 +#define JZ_REG_MMC_TXFIFO 0x3C + +#define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7) +#define JZ_MMC_STRPCL_EXIT_TRANSFER BIT(6) +#define JZ_MMC_STRPCL_START_READWAIT BIT(5) +#define JZ_MMC_STRPCL_STOP_READWAIT BIT(4) +#define JZ_MMC_STRPCL_RESET BIT(3) +#define JZ_MMC_STRPCL_START_OP BIT(2) +#define JZ_MMC_STRPCL_CLOCK_CONTROL (BIT(1) | BIT(0)) +#define JZ_MMC_STRPCL_CLOCK_STOP BIT(0) +#define JZ_MMC_STRPCL_CLOCK_START BIT(1) + + +#define JZ_MMC_STATUS_IS_RESETTING BIT(15) +#define JZ_MMC_STATUS_SDIO_INT_ACTIVE BIT(14) +#define JZ_MMC_STATUS_PRG_DONE BIT(13) +#define JZ_MMC_STATUS_DATA_TRAN_DONE BIT(12) +#define JZ_MMC_STATUS_END_CMD_RES BIT(11) +#define JZ_MMC_STATUS_DATA_FIFO_AFULL BIT(10) +#define JZ_MMC_STATUS_IS_READWAIT BIT(9) +#define JZ_MMC_STATUS_CLK_EN BIT(8) +#define JZ_MMC_STATUS_DATA_FIFO_FULL BIT(7) +#define JZ_MMC_STATUS_DATA_FIFO_EMPTY BIT(6) +#define JZ_MMC_STATUS_CRC_RES_ERR BIT(5) +#define JZ_MMC_STATUS_CRC_READ_ERROR BIT(4) +#define JZ_MMC_STATUS_TIMEOUT_WRITE BIT(3) +#define JZ_MMC_STATUS_CRC_WRITE_ERROR BIT(2) +#define JZ_MMC_STATUS_TIMEOUT_RES BIT(1) +#define JZ_MMC_STATUS_TIMEOUT_READ BIT(0) + +#define JZ_MMC_STATUS_READ_ERROR_MASK (BIT(4) | BIT(0)) +#define JZ_MMC_STATUS_WRITE_ERROR_MASK (BIT(3) | BIT(2)) + + +#define JZ_MMC_CMDAT_IO_ABORT BIT(11) +#define JZ_MMC_CMDAT_BUS_WIDTH_4BIT BIT(10) +#define JZ_MMC_CMDAT_DMA_EN BIT(8) +#define JZ_MMC_CMDAT_INIT BIT(7) +#define JZ_MMC_CMDAT_BUSY BIT(6) +#define JZ_MMC_CMDAT_STREAM BIT(5) +#define JZ_MMC_CMDAT_WRITE BIT(4) +#define JZ_MMC_CMDAT_DATA_EN BIT(3) +#define JZ_MMC_CMDAT_RESPONSE_FORMAT (BIT(2) | BIT(1) | BIT(0)) +#define JZ_MMC_CMDAT_RSP_R1 1 +#define JZ_MMC_CMDAT_RSP_R2 2 +#define JZ_MMC_CMDAT_RSP_R3 3 + +#define JZ_MMC_IRQ_SDIO BIT(7) +#define JZ_MMC_IRQ_TXFIFO_WR_REQ BIT(6) +#define JZ_MMC_IRQ_RXFIFO_RD_REQ BIT(5) +#define JZ_MMC_IRQ_END_CMD_RES BIT(2) +#define JZ_MMC_IRQ_PRG_DONE BIT(1) +#define JZ_MMC_IRQ_DATA_TRAN_DONE BIT(0) + + +#define JZ_MMC_CLK_RATE 24000000 + +enum jz4740_mmc_state { + JZ4740_MMC_STATE_READ_RESPONSE, + JZ4740_MMC_STATE_TRANSFER_DATA, + JZ4740_MMC_STATE_SEND_STOP, + JZ4740_MMC_STATE_DONE, +}; + +struct jz4740_mmc_host { + struct mmc_host *mmc; + struct platform_device *pdev; + struct jz4740_mmc_platform_data *pdata; + struct clk *clk; + + int irq; + int card_detect_irq; + + struct resource *mem; + void __iomem *base; + struct mmc_request *req; + struct mmc_command *cmd; + + unsigned long waiting; + + uint32_t cmdat; + + uint16_t irq_mask; + + spinlock_t lock; + + struct timer_list timeout_timer; + struct sg_mapping_iter miter; + enum jz4740_mmc_state state; +}; + +static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host, + unsigned int irq, bool enabled) +{ + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + if (enabled) + host->irq_mask &= ~irq; + else + host->irq_mask |= irq; + spin_unlock_irqrestore(&host->lock, flags); + + writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK); +} + +static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host, + bool start_transfer) +{ + uint16_t val = JZ_MMC_STRPCL_CLOCK_START; + + if (start_transfer) + val |= JZ_MMC_STRPCL_START_OP; + + writew(val, host->base + JZ_REG_MMC_STRPCL); +} + +static void jz4740_mmc_clock_disable(struct jz4740_mmc_host *host) +{ + uint32_t status; + unsigned int timeout = 1000; + + writew(JZ_MMC_STRPCL_CLOCK_STOP, host->base + JZ_REG_MMC_STRPCL); + do { + status = readl(host->base + JZ_REG_MMC_STATUS); + } while (status & JZ_MMC_STATUS_CLK_EN && --timeout); +} + +static void jz4740_mmc_reset(struct jz4740_mmc_host *host) +{ + uint32_t status; + unsigned int timeout = 1000; + + writew(JZ_MMC_STRPCL_RESET, host->base + JZ_REG_MMC_STRPCL); + udelay(10); + do { + status = readl(host->base + JZ_REG_MMC_STATUS); + } while (status & JZ_MMC_STATUS_IS_RESETTING && --timeout); +} + +static void jz4740_mmc_request_done(struct jz4740_mmc_host *host) +{ + struct mmc_request *req; + + req = host->req; + host->req = NULL; + + mmc_request_done(host->mmc, req); +} + +static unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host, + unsigned int irq) +{ + unsigned int timeout = 0x800; + uint16_t status; + + do { + status = readw(host->base + JZ_REG_MMC_IREG); + } while (!(status & irq) && --timeout); + + if (timeout == 0) { + set_bit(0, &host->waiting); + mod_timer(&host->timeout_timer, jiffies + 5*HZ); + jz4740_mmc_set_irq_enabled(host, irq, true); + return true; + } + + return false; +} + +static void jz4740_mmc_transfer_check_state(struct jz4740_mmc_host *host, + struct mmc_data *data) +{ + int status; + + status = readl(host->base + JZ_REG_MMC_STATUS); + if (status & JZ_MMC_STATUS_WRITE_ERROR_MASK) { + if (status & (JZ_MMC_STATUS_TIMEOUT_WRITE)) { + host->req->cmd->error = -ETIMEDOUT; + data->error = -ETIMEDOUT; + } else { + host->req->cmd->error = -EIO; + data->error = -EIO; + } + } +} + +static bool jz4740_mmc_write_data(struct jz4740_mmc_host *host, + struct mmc_data *data) +{ + struct sg_mapping_iter *miter = &host->miter; + void __iomem *fifo_addr = host->base + JZ_REG_MMC_TXFIFO; + uint32_t *buf; + bool timeout; + size_t i, j; + + while (sg_miter_next(miter)) { + buf = miter->addr; + i = miter->length / 4; + j = i / 8; + i = i & 0x7; + while (j) { + timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); + if (unlikely(timeout)) + goto poll_timeout; + + writel(buf[0], fifo_addr); + writel(buf[1], fifo_addr); + writel(buf[2], fifo_addr); + writel(buf[3], fifo_addr); + writel(buf[4], fifo_addr); + writel(buf[5], fifo_addr); + writel(buf[6], fifo_addr); + writel(buf[7], fifo_addr); + buf += 8; + --j; + } + if (unlikely(i)) { + timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); + if (unlikely(timeout)) + goto poll_timeout; + + while (i) { + writel(*buf, fifo_addr); + ++buf; + --i; + } + } + data->bytes_xfered += miter->length; + } + sg_miter_stop(miter); + + return false; + +poll_timeout: + miter->consumed = (void *)buf - miter->addr; + data->bytes_xfered += miter->consumed; + sg_miter_stop(miter); + + return true; +} + +static bool jz4740_mmc_read_data(struct jz4740_mmc_host *host, + struct mmc_data *data) +{ + struct sg_mapping_iter *miter = &host->miter; + void __iomem *fifo_addr = host->base + JZ_REG_MMC_RXFIFO; + uint32_t *buf; + uint32_t d; + uint16_t status; + size_t i, j; + unsigned int timeout; + + while (sg_miter_next(miter)) { + buf = miter->addr; + i = miter->length; + j = i / 32; + i = i & 0x1f; + while (j) { + timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); + if (unlikely(timeout)) + goto poll_timeout; + + buf[0] = readl(fifo_addr); + buf[1] = readl(fifo_addr); + buf[2] = readl(fifo_addr); + buf[3] = readl(fifo_addr); + buf[4] = readl(fifo_addr); + buf[5] = readl(fifo_addr); + buf[6] = readl(fifo_addr); + buf[7] = readl(fifo_addr); + + buf += 8; + --j; + } + + if (unlikely(i)) { + timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); + if (unlikely(timeout)) + goto poll_timeout; + + while (i >= 4) { + *buf++ = readl(fifo_addr); + i -= 4; + } + if (unlikely(i > 0)) { + d = readl(fifo_addr); + memcpy(buf, &d, i); + } + } + data->bytes_xfered += miter->length; + + /* This can go away once MIPS implements + * flush_kernel_dcache_page */ + flush_dcache_page(miter->page); + } + sg_miter_stop(miter); + + /* For whatever reason there is sometime one word more in the fifo then + * requested */ + timeout = 1000; + status = readl(host->base + JZ_REG_MMC_STATUS); + while (!(status & JZ_MMC_STATUS_DATA_FIFO_EMPTY) && --timeout) { + d = readl(fifo_addr); + status = readl(host->base + JZ_REG_MMC_STATUS); + } + + return false; + +poll_timeout: + miter->consumed = (void *)buf - miter->addr; + data->bytes_xfered += miter->consumed; + sg_miter_stop(miter); + + return true; +} + +static void jz4740_mmc_timeout(unsigned long data) +{ + struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)data; + + if (!test_and_clear_bit(0, &host->waiting)) + return; + + jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, false); + + host->req->cmd->error = -ETIMEDOUT; + jz4740_mmc_request_done(host); +} + +static void jz4740_mmc_read_response(struct jz4740_mmc_host *host, + struct mmc_command *cmd) +{ + int i; + uint16_t tmp; + void __iomem *fifo_addr = host->base + JZ_REG_MMC_RESP_FIFO; + + if (cmd->flags & MMC_RSP_136) { + tmp = readw(fifo_addr); + for (i = 0; i < 4; ++i) { + cmd->resp[i] = tmp << 24; + tmp = readw(fifo_addr); + cmd->resp[i] |= tmp << 8; + tmp = readw(fifo_addr); + cmd->resp[i] |= tmp >> 8; + } + } else { + cmd->resp[0] = readw(fifo_addr) << 24; + cmd->resp[0] |= readw(fifo_addr) << 8; + cmd->resp[0] |= readw(fifo_addr) & 0xff; + } +} + +static void jz4740_mmc_send_command(struct jz4740_mmc_host *host, + struct mmc_command *cmd) +{ + uint32_t cmdat = host->cmdat; + + host->cmdat &= ~JZ_MMC_CMDAT_INIT; + jz4740_mmc_clock_disable(host); + + host->cmd = cmd; + + if (cmd->flags & MMC_RSP_BUSY) + cmdat |= JZ_MMC_CMDAT_BUSY; + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_R1B: + case MMC_RSP_R1: + cmdat |= JZ_MMC_CMDAT_RSP_R1; + break; + case MMC_RSP_R2: + cmdat |= JZ_MMC_CMDAT_RSP_R2; + break; + case MMC_RSP_R3: + cmdat |= JZ_MMC_CMDAT_RSP_R3; + break; + default: + break; + } + + if (cmd->data) { + cmdat |= JZ_MMC_CMDAT_DATA_EN; + if (cmd->data->flags & MMC_DATA_WRITE) + cmdat |= JZ_MMC_CMDAT_WRITE; + if (cmd->data->flags & MMC_DATA_STREAM) + cmdat |= JZ_MMC_CMDAT_STREAM; + + writew(cmd->data->blksz, host->base + JZ_REG_MMC_BLKLEN); + writew(cmd->data->blocks, host->base + JZ_REG_MMC_NOB); + } + + writeb(cmd->opcode, host->base + JZ_REG_MMC_CMD); + writel(cmd->arg, host->base + JZ_REG_MMC_ARG); + writel(cmdat, host->base + JZ_REG_MMC_CMDAT); + + jz4740_mmc_clock_enable(host, 1); +} + +static void jz_mmc_prepare_data_transfer(struct jz4740_mmc_host *host) +{ + struct mmc_command *cmd = host->req->cmd; + struct mmc_data *data = cmd->data; + int direction; + + if (data->flags & MMC_DATA_READ) + direction = SG_MITER_TO_SG; + else + direction = SG_MITER_FROM_SG; + + sg_miter_start(&host->miter, data->sg, data->sg_len, direction); +} + + +static irqreturn_t jz_mmc_irq_worker(int irq, void *devid) +{ + struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid; + struct mmc_command *cmd = host->req->cmd; + struct mmc_request *req = host->req; + bool timeout = false; + + if (cmd->error) + host->state = JZ4740_MMC_STATE_DONE; + + switch (host->state) { + case JZ4740_MMC_STATE_READ_RESPONSE: + if (cmd->flags & MMC_RSP_PRESENT) + jz4740_mmc_read_response(host, cmd); + + if (!cmd->data) + break; + + jz_mmc_prepare_data_transfer(host); + + case JZ4740_MMC_STATE_TRANSFER_DATA: + if (cmd->data->flags & MMC_DATA_READ) + timeout = jz4740_mmc_read_data(host, cmd->data); + else + timeout = jz4740_mmc_write_data(host, cmd->data); + + if (unlikely(timeout)) { + host->state = JZ4740_MMC_STATE_TRANSFER_DATA; + break; + } + + jz4740_mmc_transfer_check_state(host, cmd->data); + + timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_DATA_TRAN_DONE); + if (unlikely(timeout)) { + host->state = JZ4740_MMC_STATE_SEND_STOP; + break; + } + writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG); + + case JZ4740_MMC_STATE_SEND_STOP: + if (!req->stop) + break; + + jz4740_mmc_send_command(host, req->stop); + + timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_PRG_DONE); + if (timeout) { + host->state = JZ4740_MMC_STATE_DONE; + break; + } + case JZ4740_MMC_STATE_DONE: + break; + } + + if (!timeout) + jz4740_mmc_request_done(host); + + return IRQ_HANDLED; +} + +static irqreturn_t jz_mmc_irq(int irq, void *devid) +{ + struct jz4740_mmc_host *host = devid; + struct mmc_command *cmd = host->cmd; + uint16_t irq_reg, status, tmp; + + irq_reg = readw(host->base + JZ_REG_MMC_IREG); + + tmp = irq_reg; + irq_reg &= ~host->irq_mask; + + tmp &= ~(JZ_MMC_IRQ_TXFIFO_WR_REQ | JZ_MMC_IRQ_RXFIFO_RD_REQ | + JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE); + + if (tmp != irq_reg) + writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG); + + if (irq_reg & JZ_MMC_IRQ_SDIO) { + writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG); + mmc_signal_sdio_irq(host->mmc); + irq_reg &= ~JZ_MMC_IRQ_SDIO; + } + + if (host->req && cmd && irq_reg) { + if (test_and_clear_bit(0, &host->waiting)) { + del_timer(&host->timeout_timer); + + status = readl(host->base + JZ_REG_MMC_STATUS); + + if (status & JZ_MMC_STATUS_TIMEOUT_RES) { + cmd->error = -ETIMEDOUT; + } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) { + cmd->error = -EIO; + } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR | + JZ_MMC_STATUS_CRC_WRITE_ERROR)) { + if (cmd->data) + cmd->data->error = -EIO; + cmd->error = -EIO; + } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR | + JZ_MMC_STATUS_CRC_WRITE_ERROR)) { + if (cmd->data) + cmd->data->error = -EIO; + cmd->error = -EIO; + } + + jz4740_mmc_set_irq_enabled(host, irq_reg, false); + writew(irq_reg, host->base + JZ_REG_MMC_IREG); + + return IRQ_WAKE_THREAD; + } + } + + return IRQ_HANDLED; +} + +static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate) +{ + int div = 0; + int real_rate; + + jz4740_mmc_clock_disable(host); + clk_set_rate(host->clk, JZ_MMC_CLK_RATE); + + real_rate = clk_get_rate(host->clk); + + while (real_rate > rate && div < 7) { + ++div; + real_rate >>= 1; + } + + writew(div, host->base + JZ_REG_MMC_CLKRT); + return real_rate; +} + +static void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req) +{ + struct jz4740_mmc_host *host = mmc_priv(mmc); + + host->req = req; + + writew(0xffff, host->base + JZ_REG_MMC_IREG); + + writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG); + jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true); + + host->state = JZ4740_MMC_STATE_READ_RESPONSE; + set_bit(0, &host->waiting); + mod_timer(&host->timeout_timer, jiffies + 5*HZ); + jz4740_mmc_send_command(host, req->cmd); +} + +static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct jz4740_mmc_host *host = mmc_priv(mmc); + if (ios->clock) + jz4740_mmc_set_clock_rate(host, ios->clock); + + switch (ios->power_mode) { + case MMC_POWER_UP: + jz4740_mmc_reset(host); + if (gpio_is_valid(host->pdata->gpio_power)) + gpio_set_value(host->pdata->gpio_power, + !host->pdata->power_active_low); + host->cmdat |= JZ_MMC_CMDAT_INIT; + clk_enable(host->clk); + break; + case MMC_POWER_ON: + break; + default: + if (gpio_is_valid(host->pdata->gpio_power)) + gpio_set_value(host->pdata->gpio_power, + host->pdata->power_active_low); + clk_disable(host->clk); + break; + } + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_4BIT; + break; + case MMC_BUS_WIDTH_4: + host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_4BIT; + break; + default: + break; + } +} + +static int jz4740_mmc_get_ro(struct mmc_host *mmc) +{ + struct jz4740_mmc_host *host = mmc_priv(mmc); + if (!gpio_is_valid(host->pdata->gpio_read_only)) + return -ENOSYS; + + return gpio_get_value(host->pdata->gpio_read_only) ^ + host->pdata->read_only_active_low; +} + +static int jz4740_mmc_get_cd(struct mmc_host *mmc) +{ + struct jz4740_mmc_host *host = mmc_priv(mmc); + if (!gpio_is_valid(host->pdata->gpio_card_detect)) + return -ENOSYS; + + return gpio_get_value(host->pdata->gpio_card_detect) ^ + host->pdata->card_detect_active_low; +} + +static irqreturn_t jz4740_mmc_card_detect_irq(int irq, void *devid) +{ + struct jz4740_mmc_host *host = devid; + + mmc_detect_change(host->mmc, HZ / 2); + + return IRQ_HANDLED; +} + +static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct jz4740_mmc_host *host = mmc_priv(mmc); + jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable); +} + +static const struct mmc_host_ops jz4740_mmc_ops = { + .request = jz4740_mmc_request, + .set_ios = jz4740_mmc_set_ios, + .get_ro = jz4740_mmc_get_ro, + .get_cd = jz4740_mmc_get_cd, + .enable_sdio_irq = jz4740_mmc_enable_sdio_irq, +}; + +static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = { + JZ_GPIO_BULK_PIN(MSC_CMD), + JZ_GPIO_BULK_PIN(MSC_CLK), + JZ_GPIO_BULK_PIN(MSC_DATA0), + JZ_GPIO_BULK_PIN(MSC_DATA1), + JZ_GPIO_BULK_PIN(MSC_DATA2), + JZ_GPIO_BULK_PIN(MSC_DATA3), +}; + +static int __devinit jz4740_mmc_request_gpio(struct device *dev, int gpio, + const char *name, bool output, int value) +{ + int ret; + + if (!gpio_is_valid(gpio)) + return 0; + + ret = gpio_request(gpio, name); + if (ret) { + dev_err(dev, "Failed to request %s gpio: %d\n", name, ret); + return ret; + } + + if (output) + gpio_direction_output(gpio, value); + else + gpio_direction_input(gpio); + + return 0; +} + +static int __devinit jz4740_mmc_request_gpios(struct platform_device *pdev) +{ + int ret; + struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; + + if (!pdata) + return 0; + + ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_card_detect, + "MMC detect change", false, 0); + if (ret) + goto err; + + ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_read_only, + "MMC read only", false, 0); + if (ret) + goto err_free_gpio_card_detect; + + ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power, + "MMC read only", true, pdata->power_active_low); + if (ret) + goto err_free_gpio_read_only; + + return 0; + +err_free_gpio_read_only: + if (gpio_is_valid(pdata->gpio_read_only)) + gpio_free(pdata->gpio_read_only); +err_free_gpio_card_detect: + if (gpio_is_valid(pdata->gpio_card_detect)) + gpio_free(pdata->gpio_card_detect); +err: + return ret; +} + +static int __devinit jz4740_mmc_request_cd_irq(struct platform_device *pdev, + struct jz4740_mmc_host *host) +{ + struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; + + if (!gpio_is_valid(pdata->gpio_card_detect)) + return 0; + + host->card_detect_irq = gpio_to_irq(pdata->gpio_card_detect); + if (host->card_detect_irq < 0) { + dev_warn(&pdev->dev, "Failed to get card detect irq\n"); + return 0; + } + + return request_irq(host->card_detect_irq, jz4740_mmc_card_detect_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "MMC card detect", host); +} + +static void jz4740_mmc_free_gpios(struct platform_device *pdev) +{ + struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; + + if (!pdata) + return; + + if (gpio_is_valid(pdata->gpio_power)) + gpio_free(pdata->gpio_power); + if (gpio_is_valid(pdata->gpio_read_only)) + gpio_free(pdata->gpio_read_only); + if (gpio_is_valid(pdata->gpio_card_detect)) + gpio_free(pdata->gpio_card_detect); +} + +static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host) +{ + size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins); + if (host->pdata && host->pdata->data_1bit) + num_pins -= 3; + + return num_pins; +} + +static int __devinit jz4740_mmc_probe(struct platform_device* pdev) +{ + int ret; + struct mmc_host *mmc; + struct jz4740_mmc_host *host; + struct jz4740_mmc_platform_data *pdata; + + pdata = pdev->dev.platform_data; + + mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev); + if (!mmc) { + dev_err(&pdev->dev, "Failed to alloc mmc host structure\n"); + return -ENOMEM; + } + + host = mmc_priv(mmc); + host->pdata = pdata; + + host->irq = platform_get_irq(pdev, 0); + if (host->irq < 0) { + ret = host->irq; + dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); + goto err_free_host; + } + + host->clk = clk_get(&pdev->dev, "mmc"); + if (!host->clk) { + ret = -ENOENT; + dev_err(&pdev->dev, "Failed to get mmc clock\n"); + goto err_free_host; + } + + host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!host->mem) { + ret = -ENOENT; + dev_err(&pdev->dev, "Failed to get base platform memory\n"); + goto err_clk_put; + } + + host->mem = request_mem_region(host->mem->start, + resource_size(host->mem), pdev->name); + if (!host->mem) { + ret = -EBUSY; + dev_err(&pdev->dev, "Failed to request base memory region\n"); + goto err_clk_put; + } + + host->base = ioremap_nocache(host->mem->start, resource_size(host->mem)); + if (!host->base) { + ret = -EBUSY; + dev_err(&pdev->dev, "Failed to ioremap base memory\n"); + goto err_release_mem_region; + } + + ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); + if (ret) { + dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret); + goto err_iounmap; + } + + ret = jz4740_mmc_request_gpios(pdev); + if (ret) + goto err_gpio_bulk_free; + + mmc->ops = &jz4740_mmc_ops; + mmc->f_min = JZ_MMC_CLK_RATE / 128; + mmc->f_max = JZ_MMC_CLK_RATE; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + mmc->caps = (pdata && pdata->data_1bit) ? 0 : MMC_CAP_4_BIT_DATA; + mmc->caps |= MMC_CAP_SDIO_IRQ; + + mmc->max_blk_size = (1 << 10) - 1; + mmc->max_blk_count = (1 << 15) - 1; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + + mmc->max_phys_segs = 128; + mmc->max_hw_segs = 128; + mmc->max_seg_size = mmc->max_req_size; + + host->mmc = mmc; + host->pdev = pdev; + spin_lock_init(&host->lock); + host->irq_mask = 0xffff; + + ret = jz4740_mmc_request_cd_irq(pdev, host); + if (ret) { + dev_err(&pdev->dev, "Failed to request card detect irq\n"); + goto err_free_gpios; + } + + ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0, + dev_name(&pdev->dev), host); + if (ret) { + dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); + goto err_free_card_detect_irq; + } + + jz4740_mmc_reset(host); + jz4740_mmc_clock_disable(host); + setup_timer(&host->timeout_timer, jz4740_mmc_timeout, + (unsigned long)host); + /* It is not important when it times out, it just needs to timeout. */ + set_timer_slack(&host->timeout_timer, HZ); + + platform_set_drvdata(pdev, host); + ret = mmc_add_host(mmc); + + if (ret) { + dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret); + goto err_free_irq; + } + dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n"); + + return 0; + +err_free_irq: + free_irq(host->irq, host); +err_free_card_detect_irq: + if (host->card_detect_irq >= 0) + free_irq(host->card_detect_irq, host); +err_free_gpios: + jz4740_mmc_free_gpios(pdev); +err_gpio_bulk_free: + jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); +err_iounmap: + iounmap(host->base); +err_release_mem_region: + release_mem_region(host->mem->start, resource_size(host->mem)); +err_clk_put: + clk_put(host->clk); +err_free_host: + platform_set_drvdata(pdev, NULL); + mmc_free_host(mmc); + + return ret; +} + +static int __devexit jz4740_mmc_remove(struct platform_device *pdev) +{ + struct jz4740_mmc_host *host = platform_get_drvdata(pdev); + + del_timer_sync(&host->timeout_timer); + jz4740_mmc_set_irq_enabled(host, 0xff, false); + jz4740_mmc_reset(host); + + mmc_remove_host(host->mmc); + + free_irq(host->irq, host); + if (host->card_detect_irq >= 0) + free_irq(host->card_detect_irq, host); + + jz4740_mmc_free_gpios(pdev); + jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); + + iounmap(host->base); + release_mem_region(host->mem->start, resource_size(host->mem)); + + clk_put(host->clk); + + platform_set_drvdata(pdev, NULL); + mmc_free_host(host->mmc); + + return 0; +} + +#ifdef CONFIG_PM + +static int jz4740_mmc_suspend(struct device *dev) +{ + struct jz4740_mmc_host *host = dev_get_drvdata(dev); + + mmc_suspend_host(host->mmc); + + jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); + + return 0; +} + +static int jz4740_mmc_resume(struct device *dev) +{ + struct jz4740_mmc_host *host = dev_get_drvdata(dev); + + jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); + + mmc_resume_host(host->mmc); + + return 0; +} + +const struct dev_pm_ops jz4740_mmc_pm_ops = { + .suspend = jz4740_mmc_suspend, + .resume = jz4740_mmc_resume, + .poweroff = jz4740_mmc_suspend, + .restore = jz4740_mmc_resume, +}; + +#define JZ4740_MMC_PM_OPS (&jz4740_mmc_pm_ops) +#else +#define JZ4740_MMC_PM_OPS NULL +#endif + +static struct platform_driver jz4740_mmc_driver = { + .probe = jz4740_mmc_probe, + .remove = __devexit_p(jz4740_mmc_remove), + .driver = { + .name = "jz4740-mmc", + .owner = THIS_MODULE, + .pm = JZ4740_MMC_PM_OPS, + }, +}; + +static int __init jz4740_mmc_init(void) +{ + return platform_driver_register(&jz4740_mmc_driver); +} +module_init(jz4740_mmc_init); + +static void __exit jz4740_mmc_exit(void) +{ + platform_driver_unregister(&jz4740_mmc_driver); +} +module_exit(jz4740_mmc_exit); + +MODULE_DESCRIPTION("JZ4740 SD/MMC controller driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lars-Peter Clausen "); -- cgit v1.2.3-70-g09d2 From ca148125e6134de334b61822539d220794d8da18 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 1 Jun 2010 13:18:15 -0700 Subject: MIPS: Octeon: Implement delays with cycle counter. Power throttling make deterministic delay loops impossible. Re-implement delays using the cycle counter. This also allows us to get rid of the code that calculates loops per jiffy. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1317/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/csrc-octeon.c | 55 ++++++++++++++++++++++ arch/mips/cavium-octeon/setup.c | 4 +- .../asm/mach-cavium-octeon/cpu-feature-overrides.h | 11 ----- arch/mips/include/asm/octeon/octeon.h | 1 + 4 files changed, 58 insertions(+), 13 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/cavium-octeon/csrc-octeon.c b/arch/mips/cavium-octeon/csrc-octeon.c index 36400d23ff5..b6847c8e0dd 100644 --- a/arch/mips/cavium-octeon/csrc-octeon.c +++ b/arch/mips/cavium-octeon/csrc-octeon.c @@ -80,3 +80,58 @@ void __init plat_time_init(void) clocksource_set_clock(&clocksource_mips, mips_hpt_frequency); clocksource_register(&clocksource_mips); } + +static u64 octeon_udelay_factor; +static u64 octeon_ndelay_factor; + +void __init octeon_setup_delays(void) +{ + octeon_udelay_factor = octeon_get_clock_rate() / 1000000; + /* + * For __ndelay we divide by 2^16, so the factor is multiplied + * by the same amount. + */ + octeon_ndelay_factor = (octeon_udelay_factor * 0x10000ull) / 1000ull; + + preset_lpj = octeon_get_clock_rate() / HZ; +} + +void __udelay(unsigned long us) +{ + u64 cur, end, inc; + + cur = read_c0_cvmcount(); + + inc = us * octeon_udelay_factor; + end = cur + inc; + + while (end > cur) + cur = read_c0_cvmcount(); +} +EXPORT_SYMBOL(__udelay); + +void __ndelay(unsigned long ns) +{ + u64 cur, end, inc; + + cur = read_c0_cvmcount(); + + inc = ((ns * octeon_ndelay_factor) >> 16); + end = cur + inc; + + while (end > cur) + cur = read_c0_cvmcount(); +} +EXPORT_SYMBOL(__ndelay); + +void __delay(unsigned long loops) +{ + u64 cur, end; + + cur = read_c0_cvmcount(); + end = cur + loops; + + while (end > cur) + cur = read_c0_cvmcount(); +} +EXPORT_SYMBOL(__delay); diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index 8c81a5c5bba..7216fbd5d79 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -594,13 +594,13 @@ void __init prom_init(void) * the filesystem. Also specify the calibration delay * to avoid calculating it every time. */ - strcat(arcs_cmdline, " rw root=1f00" - " lpj=60176 slram=root,0x40000000,+1073741824"); + strcat(arcs_cmdline, " rw root=1f00 slram=root,0x40000000,+1073741824"); } mips_hpt_frequency = octeon_get_clock_rate(); octeon_init_cvmcount(); + octeon_setup_delays(); _machine_restart = octeon_restart; _machine_halt = octeon_halt; diff --git a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h index 2a7ea90fee2..b952fc7215e 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h @@ -61,22 +61,11 @@ #define kernel_uses_smartmips_rixi (cpu_data[0].cputype == CPU_CAVIUM_OCTEON_PLUS) -#define ARCH_HAS_READ_CURRENT_TIMER 1 #define ARCH_HAS_IRQ_PER_CPU 1 #define ARCH_HAS_SPINLOCK_PREFETCH 1 #define spin_lock_prefetch(x) prefetch(x) #define PREFETCH_STRIDE 128 -static inline int read_current_timer(unsigned long *result) -{ - asm volatile ("rdhwr %0,$31\n" -#ifndef CONFIG_64BIT - "\tsll %0, 0" -#endif - : "=r" (*result)); - return 0; -} - #ifdef __OCTEON__ /* * All gcc versions that have OCTEON support define __OCTEON__ and have the diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h index c29debe7a8a..917a6c413b1 100644 --- a/arch/mips/include/asm/octeon/octeon.h +++ b/arch/mips/include/asm/octeon/octeon.h @@ -50,6 +50,7 @@ extern void octeon_crypto_disable(struct octeon_cop2_state *state, extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task); extern void octeon_init_cvmcount(void); +extern void octeon_setup_delays(void); #define OCTEON_ARGV_MAX_ARGS 64 #define OCTOEN_SERIAL_LEN 20 -- cgit v1.2.3-70-g09d2 From de6d5b555c1887b5b9b59854a45ebd4805fb4b39 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 23 Jul 2010 18:41:41 -0700 Subject: MIPS: uasm: Add drotr32 and uasm_i_drotr_safe. Signed-off-by: David Daney To: linux-mips@linux-mips.org To: wim@iguana.be Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1495/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/uasm.h | 10 ++++++++++ arch/mips/mm/uasm.c | 13 ++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h index 697e40c0649..3964b2e6c7d 100644 --- a/arch/mips/include/asm/uasm.h +++ b/arch/mips/include/asm/uasm.h @@ -71,6 +71,7 @@ Ip_u2u1u3(_dsra); Ip_u2u1u3(_dsrl); Ip_u2u1u3(_dsrl32); Ip_u2u1u3(_drotr); +Ip_u2u1u3(_drotr32); Ip_u3u1u2(_dsubu); Ip_0(_eret); Ip_u1(_j); @@ -176,6 +177,15 @@ static inline void uasm_i_dsrl_safe(u32 **p, unsigned int a1, uasm_i_dsrl32(p, a1, a2, a3 - 32); } +static inline void uasm_i_drotr_safe(u32 **p, unsigned int a1, + unsigned int a2, unsigned int a3) +{ + if (a3 < 32) + uasm_i_drotr(p, a1, a2, a3); + else + uasm_i_drotr32(p, a1, a2, a3 - 32); +} + static inline void uasm_i_dsll_safe(u32 **p, unsigned int a1, unsigned int a2, unsigned int a3) { diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index 611d564fdcf..fe041d5bb41 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c @@ -62,11 +62,12 @@ enum opcode { insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, insn_bne, insn_cache, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0, insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, - insn_dsrl32, insn_drotr, insn_dsubu, insn_eret, insn_j, insn_jal, - insn_jr, insn_ld, insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, - insn_mtc0, insn_or, insn_ori, insn_pref, insn_rfe, insn_sc, insn_scd, - insn_sd, insn_sll, insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, - insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori, + insn_dsrl32, insn_drotr, insn_drotr32, insn_dsubu, insn_eret, + insn_j, insn_jal, insn_jr, insn_ld, insn_ll, insn_lld, + insn_lui, insn_lw, insn_mfc0, insn_mtc0, insn_or, insn_ori, + insn_pref, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll, + insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, insn_tlbp, + insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori, insn_dins, insn_syscall }; @@ -108,6 +109,7 @@ static struct insn insn_table[] __cpuinitdata = { { insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE }, { insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE }, { insn_drotr, M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE }, + { insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE }, { insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD }, { insn_eret, M(cop0_op, cop_op, 0, 0, 0, eret_op), 0 }, { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM }, @@ -375,6 +377,7 @@ I_u2u1u3(_dsra) I_u2u1u3(_dsrl) I_u2u1u3(_dsrl32) I_u2u1u3(_drotr) +I_u2u1u3(_drotr32) I_u3u1u2(_dsubu) I_0(_eret) I_u1(_j) -- cgit v1.2.3-70-g09d2 From 5b97c3f7ae0ad0eea1eb90d649420a1a180f2bdf Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 23 Jul 2010 18:41:42 -0700 Subject: MIPS: uasm: Add BBIT0 and BBIT1 instructions These are OCTEON specific instructions. Signed-off-by: David Daney To: linux-mips@linux-mips.org To: wim@iguana.be Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1496/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/uasm.h | 4 ++++ arch/mips/mm/uasm.c | 22 +++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h index 3964b2e6c7d..db9d449b51e 100644 --- a/arch/mips/include/asm/uasm.h +++ b/arch/mips/include/asm/uasm.h @@ -223,3 +223,7 @@ void uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1, void uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); void uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); +void uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg, + unsigned int bit, int lid); +void uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg, + unsigned int bit, int lid); diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index fe041d5bb41..636b817d390 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c @@ -68,7 +68,7 @@ enum opcode { insn_pref, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll, insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori, - insn_dins, insn_syscall + insn_dins, insn_syscall, insn_bbit0, insn_bbit1 }; struct insn { @@ -143,6 +143,8 @@ static struct insn insn_table[] __cpuinitdata = { { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE }, { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM}, + { insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, + { insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, { insn_invalid, 0, 0 } }; @@ -411,6 +413,8 @@ I_u3u1u2(_xor) I_u2u1u3(_xori) I_u2u1msbu3(_dins); I_u1(_syscall); +I_u1u2s3(_bbit0); +I_u1u2s3(_bbit1); /* Handle labels. */ void __cpuinit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid) @@ -620,3 +624,19 @@ uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) uasm_r_mips_pc16(r, *p, lid); uasm_i_bgez(p, reg, 0); } + +void __cpuinit +uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg, + unsigned int bit, int lid) +{ + uasm_r_mips_pc16(r, *p, lid); + uasm_i_bbit0(p, reg, bit, 0); +} + +void __cpuinit +uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg, + unsigned int bit, int lid) +{ + uasm_r_mips_pc16(r, *p, lid); + uasm_i_bbit1(p, reg, bit, 0); +} -- cgit v1.2.3-70-g09d2 From 22b0763a2328434ac68cca884e1b7d350ca61332 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 23 Jul 2010 18:41:43 -0700 Subject: MIPS: uasm: Add option to export uasm API. A 'select EXPORT_UASM' in Kconfig will cause the uasm to be exported for use in modules. When it is exported, all the uasm data and code cease to be __init and __initdata. Also daddiu_bug cannot be __cpuinitdata if uasm is exported. The cleanest thing is to just make it normal data. Signed-off-by: David Daney To: linux-mips@linux-mips.org To: wim@iguana.be Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1500/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 3 + arch/mips/include/asm/uasm.h | 37 +++++++----- arch/mips/kernel/cpu-bugs64.c | 2 +- arch/mips/mm/uasm.c | 131 ++++++++++++++++++++++++++---------------- 4 files changed, 110 insertions(+), 63 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 295e8c55fb3..aaca439010d 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -915,6 +915,9 @@ config CPU_LITTLE_ENDIAN endchoice +config EXPORT_UASM + bool + config SYS_SUPPORTS_APM_EMULATION bool diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h index db9d449b51e..892062d6d74 100644 --- a/arch/mips/include/asm/uasm.h +++ b/arch/mips/include/asm/uasm.h @@ -10,44 +10,55 @@ #include +#ifdef CONFIG_EXPORT_UASM +#include +#define __uasminit +#define __uasminitdata +#define UASM_EXPORT_SYMBOL(sym) EXPORT_SYMBOL(sym) +#else +#define __uasminit __cpuinit +#define __uasminitdata __cpuinitdata +#define UASM_EXPORT_SYMBOL(sym) +#endif + #define Ip_u1u2u3(op) \ -void __cpuinit \ +void __uasminit \ uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c) #define Ip_u2u1u3(op) \ -void __cpuinit \ +void __uasminit \ uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c) #define Ip_u3u1u2(op) \ -void __cpuinit \ +void __uasminit \ uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c) #define Ip_u1u2s3(op) \ -void __cpuinit \ +void __uasminit \ uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c) #define Ip_u2s3u1(op) \ -void __cpuinit \ +void __uasminit \ uasm_i##op(u32 **buf, unsigned int a, signed int b, unsigned int c) #define Ip_u2u1s3(op) \ -void __cpuinit \ +void __uasminit \ uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c) #define Ip_u2u1msbu3(op) \ -void __cpuinit \ +void __uasminit \ uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c, \ unsigned int d) #define Ip_u1u2(op) \ -void __cpuinit uasm_i##op(u32 **buf, unsigned int a, unsigned int b) +void __uasminit uasm_i##op(u32 **buf, unsigned int a, unsigned int b) #define Ip_u1s2(op) \ -void __cpuinit uasm_i##op(u32 **buf, unsigned int a, signed int b) +void __uasminit uasm_i##op(u32 **buf, unsigned int a, signed int b) -#define Ip_u1(op) void __cpuinit uasm_i##op(u32 **buf, unsigned int a) +#define Ip_u1(op) void __uasminit uasm_i##op(u32 **buf, unsigned int a) -#define Ip_0(op) void __cpuinit uasm_i##op(u32 **buf) +#define Ip_0(op) void __uasminit uasm_i##op(u32 **buf) Ip_u2u1s3(_addiu); Ip_u3u1u2(_addu); @@ -112,7 +123,7 @@ struct uasm_label { int lab; }; -void __cpuinit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid); +void __uasminit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid); #ifdef CONFIG_64BIT int uasm_in_compat_space_p(long addr); #endif @@ -122,7 +133,7 @@ void UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr); void UASM_i_LA(u32 **buf, unsigned int rs, long addr); #define UASM_L_LA(lb) \ -static inline void __cpuinit uasm_l##lb(struct uasm_label **lab, u32 *addr) \ +static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \ { \ uasm_build_label(lab, addr, label##lb); \ } diff --git a/arch/mips/kernel/cpu-bugs64.c b/arch/mips/kernel/cpu-bugs64.c index 408d0a07b3a..b8bb8ba6086 100644 --- a/arch/mips/kernel/cpu-bugs64.c +++ b/arch/mips/kernel/cpu-bugs64.c @@ -239,7 +239,7 @@ static inline void check_daddi(void) panic(bug64hit, !DADDI_WAR ? daddiwar : nowar); } -int daddiu_bug __cpuinitdata = -1; +int daddiu_bug = -1; static inline void check_daddiu(void) { diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index 636b817d390..d2647a4e012 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c @@ -86,7 +86,7 @@ struct insn { | (e) << RE_SH \ | (f) << FUNC_SH) -static struct insn insn_table[] __cpuinitdata = { +static struct insn insn_table[] __uasminitdata = { { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD }, { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD }, @@ -150,7 +150,7 @@ static struct insn insn_table[] __cpuinitdata = { #undef M -static inline __cpuinit u32 build_rs(u32 arg) +static inline __uasminit u32 build_rs(u32 arg) { if (arg & ~RS_MASK) printk(KERN_WARNING "Micro-assembler field overflow\n"); @@ -158,7 +158,7 @@ static inline __cpuinit u32 build_rs(u32 arg) return (arg & RS_MASK) << RS_SH; } -static inline __cpuinit u32 build_rt(u32 arg) +static inline __uasminit u32 build_rt(u32 arg) { if (arg & ~RT_MASK) printk(KERN_WARNING "Micro-assembler field overflow\n"); @@ -166,7 +166,7 @@ static inline __cpuinit u32 build_rt(u32 arg) return (arg & RT_MASK) << RT_SH; } -static inline __cpuinit u32 build_rd(u32 arg) +static inline __uasminit u32 build_rd(u32 arg) { if (arg & ~RD_MASK) printk(KERN_WARNING "Micro-assembler field overflow\n"); @@ -174,7 +174,7 @@ static inline __cpuinit u32 build_rd(u32 arg) return (arg & RD_MASK) << RD_SH; } -static inline __cpuinit u32 build_re(u32 arg) +static inline __uasminit u32 build_re(u32 arg) { if (arg & ~RE_MASK) printk(KERN_WARNING "Micro-assembler field overflow\n"); @@ -182,7 +182,7 @@ static inline __cpuinit u32 build_re(u32 arg) return (arg & RE_MASK) << RE_SH; } -static inline __cpuinit u32 build_simm(s32 arg) +static inline __uasminit u32 build_simm(s32 arg) { if (arg > 0x7fff || arg < -0x8000) printk(KERN_WARNING "Micro-assembler field overflow\n"); @@ -190,7 +190,7 @@ static inline __cpuinit u32 build_simm(s32 arg) return arg & 0xffff; } -static inline __cpuinit u32 build_uimm(u32 arg) +static inline __uasminit u32 build_uimm(u32 arg) { if (arg & ~IMM_MASK) printk(KERN_WARNING "Micro-assembler field overflow\n"); @@ -198,7 +198,7 @@ static inline __cpuinit u32 build_uimm(u32 arg) return arg & IMM_MASK; } -static inline __cpuinit u32 build_bimm(s32 arg) +static inline __uasminit u32 build_bimm(s32 arg) { if (arg > 0x1ffff || arg < -0x20000) printk(KERN_WARNING "Micro-assembler field overflow\n"); @@ -209,7 +209,7 @@ static inline __cpuinit u32 build_bimm(s32 arg) return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff); } -static inline __cpuinit u32 build_jimm(u32 arg) +static inline __uasminit u32 build_jimm(u32 arg) { if (arg & ~((JIMM_MASK) << 2)) printk(KERN_WARNING "Micro-assembler field overflow\n"); @@ -217,7 +217,7 @@ static inline __cpuinit u32 build_jimm(u32 arg) return (arg >> 2) & JIMM_MASK; } -static inline __cpuinit u32 build_scimm(u32 arg) +static inline __uasminit u32 build_scimm(u32 arg) { if (arg & ~SCIMM_MASK) printk(KERN_WARNING "Micro-assembler field overflow\n"); @@ -225,7 +225,7 @@ static inline __cpuinit u32 build_scimm(u32 arg) return (arg & SCIMM_MASK) << SCIMM_SH; } -static inline __cpuinit u32 build_func(u32 arg) +static inline __uasminit u32 build_func(u32 arg) { if (arg & ~FUNC_MASK) printk(KERN_WARNING "Micro-assembler field overflow\n"); @@ -233,7 +233,7 @@ static inline __cpuinit u32 build_func(u32 arg) return arg & FUNC_MASK; } -static inline __cpuinit u32 build_set(u32 arg) +static inline __uasminit u32 build_set(u32 arg) { if (arg & ~SET_MASK) printk(KERN_WARNING "Micro-assembler field overflow\n"); @@ -245,7 +245,7 @@ static inline __cpuinit u32 build_set(u32 arg) * The order of opcode arguments is implicitly left to right, * starting with RS and ending with FUNC or IMM. */ -static void __cpuinit build_insn(u32 **buf, enum opcode opc, ...) +static void __uasminit build_insn(u32 **buf, enum opcode opc, ...) { struct insn *ip = NULL; unsigned int i; @@ -295,67 +295,78 @@ static void __cpuinit build_insn(u32 **buf, enum opcode opc, ...) Ip_u1u2u3(op) \ { \ build_insn(buf, insn##op, a, b, c); \ -} +} \ +UASM_EXPORT_SYMBOL(uasm_i##op); #define I_u2u1u3(op) \ Ip_u2u1u3(op) \ { \ build_insn(buf, insn##op, b, a, c); \ -} +} \ +UASM_EXPORT_SYMBOL(uasm_i##op); #define I_u3u1u2(op) \ Ip_u3u1u2(op) \ { \ build_insn(buf, insn##op, b, c, a); \ -} +} \ +UASM_EXPORT_SYMBOL(uasm_i##op); #define I_u1u2s3(op) \ Ip_u1u2s3(op) \ { \ build_insn(buf, insn##op, a, b, c); \ -} +} \ +UASM_EXPORT_SYMBOL(uasm_i##op); #define I_u2s3u1(op) \ Ip_u2s3u1(op) \ { \ build_insn(buf, insn##op, c, a, b); \ -} +} \ +UASM_EXPORT_SYMBOL(uasm_i##op); #define I_u2u1s3(op) \ Ip_u2u1s3(op) \ { \ build_insn(buf, insn##op, b, a, c); \ -} +} \ +UASM_EXPORT_SYMBOL(uasm_i##op); #define I_u2u1msbu3(op) \ Ip_u2u1msbu3(op) \ { \ build_insn(buf, insn##op, b, a, c+d-1, c); \ -} +} \ +UASM_EXPORT_SYMBOL(uasm_i##op); #define I_u1u2(op) \ Ip_u1u2(op) \ { \ build_insn(buf, insn##op, a, b); \ -} +} \ +UASM_EXPORT_SYMBOL(uasm_i##op); #define I_u1s2(op) \ Ip_u1s2(op) \ { \ build_insn(buf, insn##op, a, b); \ -} +} \ +UASM_EXPORT_SYMBOL(uasm_i##op); #define I_u1(op) \ Ip_u1(op) \ { \ build_insn(buf, insn##op, a); \ -} +} \ +UASM_EXPORT_SYMBOL(uasm_i##op); #define I_0(op) \ Ip_0(op) \ { \ build_insn(buf, insn##op); \ -} +} \ +UASM_EXPORT_SYMBOL(uasm_i##op); I_u2u1s3(_addiu) I_u3u1u2(_addu) @@ -417,14 +428,15 @@ I_u1u2s3(_bbit0); I_u1u2s3(_bbit1); /* Handle labels. */ -void __cpuinit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid) +void __uasminit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid) { (*lab)->addr = addr; (*lab)->lab = lid; (*lab)++; } +UASM_EXPORT_SYMBOL(uasm_build_label); -int __cpuinit uasm_in_compat_space_p(long addr) +int __uasminit uasm_in_compat_space_p(long addr) { /* Is this address in 32bit compat space? */ #ifdef CONFIG_64BIT @@ -433,8 +445,9 @@ int __cpuinit uasm_in_compat_space_p(long addr) return 1; #endif } +UASM_EXPORT_SYMBOL(uasm_in_compat_space_p); -static int __cpuinit uasm_rel_highest(long val) +static int __uasminit uasm_rel_highest(long val) { #ifdef CONFIG_64BIT return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000; @@ -443,7 +456,7 @@ static int __cpuinit uasm_rel_highest(long val) #endif } -static int __cpuinit uasm_rel_higher(long val) +static int __uasminit uasm_rel_higher(long val) { #ifdef CONFIG_64BIT return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000; @@ -452,17 +465,19 @@ static int __cpuinit uasm_rel_higher(long val) #endif } -int __cpuinit uasm_rel_hi(long val) +int __uasminit uasm_rel_hi(long val) { return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000; } +UASM_EXPORT_SYMBOL(uasm_rel_hi); -int __cpuinit uasm_rel_lo(long val) +int __uasminit uasm_rel_lo(long val) { return ((val & 0xffff) ^ 0x8000) - 0x8000; } +UASM_EXPORT_SYMBOL(uasm_rel_lo); -void __cpuinit UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr) +void __uasminit UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr) { if (!uasm_in_compat_space_p(addr)) { uasm_i_lui(buf, rs, uasm_rel_highest(addr)); @@ -477,8 +492,9 @@ void __cpuinit UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr) } else uasm_i_lui(buf, rs, uasm_rel_hi(addr)); } +UASM_EXPORT_SYMBOL(UASM_i_LA_mostly); -void __cpuinit UASM_i_LA(u32 **buf, unsigned int rs, long addr) +void __uasminit UASM_i_LA(u32 **buf, unsigned int rs, long addr) { UASM_i_LA_mostly(buf, rs, addr); if (uasm_rel_lo(addr)) { @@ -488,9 +504,10 @@ void __cpuinit UASM_i_LA(u32 **buf, unsigned int rs, long addr) uasm_i_addiu(buf, rs, rs, uasm_rel_lo(addr)); } } +UASM_EXPORT_SYMBOL(UASM_i_LA); /* Handle relocations. */ -void __cpuinit +void __uasminit uasm_r_mips_pc16(struct uasm_reloc **rel, u32 *addr, int lid) { (*rel)->addr = addr; @@ -498,8 +515,9 @@ uasm_r_mips_pc16(struct uasm_reloc **rel, u32 *addr, int lid) (*rel)->lab = lid; (*rel)++; } +UASM_EXPORT_SYMBOL(uasm_r_mips_pc16); -static inline void __cpuinit +static inline void __uasminit __resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab) { long laddr = (long)lab->addr; @@ -516,7 +534,7 @@ __resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab) } } -void __cpuinit +void __uasminit uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab) { struct uasm_label *l; @@ -526,24 +544,27 @@ uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab) if (rel->lab == l->lab) __resolve_relocs(rel, l); } +UASM_EXPORT_SYMBOL(uasm_resolve_relocs); -void __cpuinit +void __uasminit uasm_move_relocs(struct uasm_reloc *rel, u32 *first, u32 *end, long off) { for (; rel->lab != UASM_LABEL_INVALID; rel++) if (rel->addr >= first && rel->addr < end) rel->addr += off; } +UASM_EXPORT_SYMBOL(uasm_move_relocs); -void __cpuinit +void __uasminit uasm_move_labels(struct uasm_label *lab, u32 *first, u32 *end, long off) { for (; lab->lab != UASM_LABEL_INVALID; lab++) if (lab->addr >= first && lab->addr < end) lab->addr += off; } +UASM_EXPORT_SYMBOL(uasm_move_labels); -void __cpuinit +void __uasminit uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab, u32 *first, u32 *end, u32 *target) { @@ -554,8 +575,9 @@ uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab, u32 *first, uasm_move_relocs(rel, first, end, off); uasm_move_labels(lab, first, end, off); } +UASM_EXPORT_SYMBOL(uasm_copy_handler); -int __cpuinit uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr) +int __uasminit uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr) { for (; rel->lab != UASM_LABEL_INVALID; rel++) { if (rel->addr == addr @@ -566,77 +588,88 @@ int __cpuinit uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr) return 0; } +UASM_EXPORT_SYMBOL(uasm_insn_has_bdelay); /* Convenience functions for labeled branches. */ -void __cpuinit +void __uasminit uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) { uasm_r_mips_pc16(r, *p, lid); uasm_i_bltz(p, reg, 0); } +UASM_EXPORT_SYMBOL(uasm_il_bltz); -void __cpuinit +void __uasminit uasm_il_b(u32 **p, struct uasm_reloc **r, int lid) { uasm_r_mips_pc16(r, *p, lid); uasm_i_b(p, 0); } +UASM_EXPORT_SYMBOL(uasm_il_b); -void __cpuinit +void __uasminit uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) { uasm_r_mips_pc16(r, *p, lid); uasm_i_beqz(p, reg, 0); } +UASM_EXPORT_SYMBOL(uasm_il_beqz); -void __cpuinit +void __uasminit uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) { uasm_r_mips_pc16(r, *p, lid); uasm_i_beqzl(p, reg, 0); } +UASM_EXPORT_SYMBOL(uasm_il_beqzl); -void __cpuinit +void __uasminit uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1, unsigned int reg2, int lid) { uasm_r_mips_pc16(r, *p, lid); uasm_i_bne(p, reg1, reg2, 0); } +UASM_EXPORT_SYMBOL(uasm_il_bne); -void __cpuinit +void __uasminit uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) { uasm_r_mips_pc16(r, *p, lid); uasm_i_bnez(p, reg, 0); } +UASM_EXPORT_SYMBOL(uasm_il_bnez); -void __cpuinit +void __uasminit uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) { uasm_r_mips_pc16(r, *p, lid); uasm_i_bgezl(p, reg, 0); } +UASM_EXPORT_SYMBOL(uasm_il_bgezl); -void __cpuinit +void __uasminit uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) { uasm_r_mips_pc16(r, *p, lid); uasm_i_bgez(p, reg, 0); } +UASM_EXPORT_SYMBOL(uasm_il_bgez); -void __cpuinit +void __uasminit uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg, unsigned int bit, int lid) { uasm_r_mips_pc16(r, *p, lid); uasm_i_bbit0(p, reg, bit, 0); } +UASM_EXPORT_SYMBOL(uasm_il_bbit0); -void __cpuinit +void __uasminit uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg, unsigned int bit, int lid) { uasm_r_mips_pc16(r, *p, lid); uasm_i_bbit1(p, reg, bit, 0); } +UASM_EXPORT_SYMBOL(uasm_il_bbit1); -- cgit v1.2.3-70-g09d2 From 96ffa02d219f50a52e0482ad85130858c61efc63 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 23 Jul 2010 18:41:46 -0700 Subject: MIPS: Define ST0_NMI in asm/mipsregs.h This is used by the forthcoming OCTEON watchdog patch. Signed-off-by: David Daney To: linux-mips@linux-mips.org To: wim@iguana.be Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1498/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mipsregs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index c6e3c93ce7c..335474c155f 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -408,6 +408,7 @@ #define STATUSB_IP15 7 #define STATUSF_IP15 (_ULCAST_(1) << 7) #define ST0_CH 0x00040000 +#define ST0_NMI 0x00080000 #define ST0_SR 0x00100000 #define ST0_TS 0x00200000 #define ST0_BEV 0x00400000 -- cgit v1.2.3-70-g09d2 From b8c7428af023c4cc37b8651e309713c1f4d9a18e Mon Sep 17 00:00:00 2001 From: Wu Zhangjin Date: Sat, 24 Jul 2010 09:22:13 +0800 Subject: MIPS: Loongson: Remove set_irq_trigger_mode() set_irq_trigger_mode() is not needed on all platforms so remove it and move the related source code to mach_init_irq(). This will allow gdium to share the common irq.c without adding an empty set_irq_trigger_mode(). Signed-off-by: Wu Zhangjin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1493/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-loongson/loongson.h | 1 - arch/mips/loongson/common/irq.c | 3 --- arch/mips/loongson/fuloong-2e/irq.c | 11 ++++------- arch/mips/loongson/lemote-2f/irq.c | 11 ++++------- 4 files changed, 8 insertions(+), 18 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h index fcdbe3a4ce1..53ee881c675 100644 --- a/arch/mips/include/asm/mach-loongson/loongson.h +++ b/arch/mips/include/asm/mach-loongson/loongson.h @@ -45,7 +45,6 @@ static inline void prom_init_uart_base(void) /* irq operation functions */ extern void bonito_irqdispatch(void); extern void __init bonito_irq_init(void); -extern void __init set_irq_trigger_mode(void); extern void __init mach_init_irq(void); extern void mach_irq_dispatch(unsigned int pending); extern int mach_i8259_irq(void); diff --git a/arch/mips/loongson/common/irq.c b/arch/mips/loongson/common/irq.c index 25a11df0348..5897471dedc 100644 --- a/arch/mips/loongson/common/irq.c +++ b/arch/mips/loongson/common/irq.c @@ -53,9 +53,6 @@ void __init arch_init_irq(void) */ clear_c0_status(ST0_IM | ST0_BEV); - /* setting irq trigger mode */ - set_irq_trigger_mode(); - /* no steer */ LOONGSON_INTSTEER = 0; diff --git a/arch/mips/loongson/fuloong-2e/irq.c b/arch/mips/loongson/fuloong-2e/irq.c index 320e9379bdd..99e08c3db3f 100644 --- a/arch/mips/loongson/fuloong-2e/irq.c +++ b/arch/mips/loongson/fuloong-2e/irq.c @@ -44,13 +44,6 @@ static struct irqaction cascade_irqaction = { .name = "cascade", }; -void __init set_irq_trigger_mode(void) -{ - /* most bonito irq should be level triggered */ - LOONGSON_INTEDGE = LOONGSON_ICU_SYSTEMERR | LOONGSON_ICU_MASTERERR | - LOONGSON_ICU_RETRYERR | LOONGSON_ICU_MBOXES; -} - void __init mach_init_irq(void) { /* init all controller @@ -59,6 +52,10 @@ void __init mach_init_irq(void) * 32-63 ------> bonito irq */ + /* most bonito irq should be level triggered */ + LOONGSON_INTEDGE = LOONGSON_ICU_SYSTEMERR | LOONGSON_ICU_MASTERERR | + LOONGSON_ICU_RETRYERR | LOONGSON_ICU_MBOXES; + /* Sets the first-level interrupt dispatcher. */ mips_cpu_irq_init(); init_i8259_irqs(); diff --git a/arch/mips/loongson/lemote-2f/irq.c b/arch/mips/loongson/lemote-2f/irq.c index 1d8b4d28a05..c6db7e7df96 100644 --- a/arch/mips/loongson/lemote-2f/irq.c +++ b/arch/mips/loongson/lemote-2f/irq.c @@ -91,13 +91,6 @@ void mach_irq_dispatch(unsigned int pending) spurious_interrupt(); } -void __init set_irq_trigger_mode(void) -{ - /* setup cs5536 as high level trigger */ - LOONGSON_INTPOL = LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1; - LOONGSON_INTEDGE &= ~(LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1); -} - static irqreturn_t ip6_action(int cpl, void *dev_id) { return IRQ_HANDLED; @@ -122,6 +115,10 @@ void __init mach_init_irq(void) * 32-63 ------> bonito irq */ + /* setup cs5536 as high level trigger */ + LOONGSON_INTPOL = LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1; + LOONGSON_INTEDGE &= ~(LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1); + /* Sets the first-level interrupt dispatcher. */ mips_cpu_irq_init(); init_i8259_irqs(); -- cgit v1.2.3-70-g09d2 From de3bc0e7ba5e89d63cb2dbac4e49a5c4b18669b5 Mon Sep 17 00:00:00 2001 From: Wu Zhangjin Date: Sat, 24 Jul 2010 09:22:14 +0800 Subject: MIPS: Loongson: Oprofile: add a new do_perfcnt_IRQ() On FuLoong-2F IP6 is shared by the performance counter overflow interrupt and the Bonito northbridge interrupt. To reduce overhead only call do_IRQ() when oprofile is enabled to reduce overhead. This patch adds an inline function do_perfcnt_IRQ() to hide the #if's , which can be shared by the other Loongson machines, i.e. gdium. Signed-off-by: Wu Zhangjin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1492/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-loongson/loongson.h | 8 ++++++++ arch/mips/loongson/fuloong-2e/irq.c | 2 +- arch/mips/loongson/lemote-2f/irq.c | 4 +--- 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h index 53ee881c675..cb6985f2430 100644 --- a/arch/mips/include/asm/mach-loongson/loongson.h +++ b/arch/mips/include/asm/mach-loongson/loongson.h @@ -62,6 +62,14 @@ extern int mach_i8259_irq(void); #define LOONGSON_IRQ_BASE 32 #define LOONGSON2_PERFCNT_IRQ (MIPS_CPU_IRQ_BASE + 6) /* cpu perf counter */ +#include +static inline void do_perfcnt_IRQ(void) +{ +#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE) + do_IRQ(LOONGSON2_PERFCNT_IRQ); +#endif +} + #define LOONGSON_FLASH_BASE 0x1c000000 #define LOONGSON_FLASH_SIZE 0x02000000 /* 32M */ #define LOONGSON_FLASH_TOP (LOONGSON_FLASH_BASE+LOONGSON_FLASH_SIZE-1) diff --git a/arch/mips/loongson/fuloong-2e/irq.c b/arch/mips/loongson/fuloong-2e/irq.c index 99e08c3db3f..d61a04222b8 100644 --- a/arch/mips/loongson/fuloong-2e/irq.c +++ b/arch/mips/loongson/fuloong-2e/irq.c @@ -30,7 +30,7 @@ asmlinkage void mach_irq_dispatch(unsigned int pending) if (pending & CAUSEF_IP7) do_IRQ(MIPS_CPU_IRQ_BASE + 7); else if (pending & CAUSEF_IP6) /* perf counter loverflow */ - do_IRQ(LOONGSON2_PERFCNT_IRQ); + do_perfcnt_IRQ(); else if (pending & CAUSEF_IP5) i8259_irqdispatch(); else if (pending & CAUSEF_IP2) diff --git a/arch/mips/loongson/lemote-2f/irq.c b/arch/mips/loongson/lemote-2f/irq.c index c6db7e7df96..71347d7030c 100644 --- a/arch/mips/loongson/lemote-2f/irq.c +++ b/arch/mips/loongson/lemote-2f/irq.c @@ -79,9 +79,7 @@ void mach_irq_dispatch(unsigned int pending) if (pending & CAUSEF_IP7) do_IRQ(LOONGSON_TIMER_IRQ); else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */ -#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE) - do_IRQ(LOONGSON2_PERFCNT_IRQ); -#endif + do_perfcnt_IRQ(); bonito_irqdispatch(); } else if (pending & CAUSEF_IP3) /* CPU UART */ do_IRQ(LOONGSON_UART_IRQ); -- cgit v1.2.3-70-g09d2 From 1aa2b2782a056b9bb0a19fae5a04624d8dcd8379 Mon Sep 17 00:00:00 2001 From: David Daney Date: Mon, 26 Jul 2010 18:14:15 -0700 Subject: MIPS: Octeon: Support 256 MSI on PCIe Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/1507/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-cavium-octeon/irq.h | 2 +- arch/mips/pci/msi-octeon.c | 294 +++++++++++++++---------- 2 files changed, 178 insertions(+), 118 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-cavium-octeon/irq.h b/arch/mips/include/asm/mach-cavium-octeon/irq.h index 783dae74722..6ddab8aef64 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/irq.h +++ b/arch/mips/include/asm/mach-cavium-octeon/irq.h @@ -172,7 +172,7 @@ #ifdef CONFIG_PCI_MSI /* 152 - 215 represent the MSI interrupts 0-63 */ #define OCTEON_IRQ_MSI_BIT0 152 -#define OCTEON_IRQ_MSI_LAST (OCTEON_IRQ_MSI_BIT0 + 63) +#define OCTEON_IRQ_MSI_LAST (OCTEON_IRQ_MSI_BIT0 + 255) #define OCTEON_IRQ_LAST (OCTEON_IRQ_MSI_LAST + 1) #else diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c index 83ceb52d6e0..7c756408b85 100644 --- a/arch/mips/pci/msi-octeon.c +++ b/arch/mips/pci/msi-octeon.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2005-2009 Cavium Networks + * Copyright (C) 2005-2009, 2010 Cavium Networks */ #include #include @@ -22,7 +22,7 @@ * Each bit in msi_free_irq_bitmask represents a MSI interrupt that is * in use. */ -static uint64_t msi_free_irq_bitmask; +static u64 msi_free_irq_bitmask[4]; /* * Each bit in msi_multiple_irq_bitmask tells that the device using @@ -30,7 +30,7 @@ static uint64_t msi_free_irq_bitmask; * is used so we can disable all of the MSI interrupts when a device * uses multiple. */ -static uint64_t msi_multiple_irq_bitmask; +static u64 msi_multiple_irq_bitmask[4]; /* * This lock controls updates to msi_free_irq_bitmask and @@ -38,6 +38,11 @@ static uint64_t msi_multiple_irq_bitmask; */ static DEFINE_SPINLOCK(msi_free_irq_bitmask_lock); +/* + * Number of MSI IRQs used. This variable is set up in + * the module init time. + */ +static int msi_irq_size; /** * Called when a driver request MSI interrupts instead of the @@ -54,12 +59,13 @@ static DEFINE_SPINLOCK(msi_free_irq_bitmask_lock); int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) { struct msi_msg msg; - uint16_t control; + u16 control; int configured_private_bits; int request_private_bits; - int irq; + int irq = 0; int irq_step; - uint64_t search_mask; + u64 search_mask; + int index; /* * Read the MSI config to figure out how many IRQs this device @@ -111,29 +117,31 @@ try_only_one: * use. */ spin_lock(&msi_free_irq_bitmask_lock); - for (irq = 0; irq < 64; irq += irq_step) { - if ((msi_free_irq_bitmask & (search_mask << irq)) == 0) { - msi_free_irq_bitmask |= search_mask << irq; - msi_multiple_irq_bitmask |= (search_mask >> 1) << irq; - break; + for (index = 0; index < msi_irq_size/64; index++) { + for (irq = 0; irq < 64; irq += irq_step) { + if ((msi_free_irq_bitmask[index] & (search_mask << irq)) == 0) { + msi_free_irq_bitmask[index] |= search_mask << irq; + msi_multiple_irq_bitmask[index] |= (search_mask >> 1) << irq; + goto msi_irq_allocated; + } } } +msi_irq_allocated: spin_unlock(&msi_free_irq_bitmask_lock); /* Make sure the search for available interrupts didn't fail */ if (irq >= 64) { if (request_private_bits) { - pr_err("arch_setup_msi_irq: Unable to find %d free " - "interrupts, trying just one", + pr_err("arch_setup_msi_irq: Unable to find %d free interrupts, trying just one", 1 << request_private_bits); request_private_bits = 0; goto try_only_one; } else - panic("arch_setup_msi_irq: Unable to find a free MSI " - "interrupt"); + panic("arch_setup_msi_irq: Unable to find a free MSI interrupt"); } /* MSI interrupts start at logical IRQ OCTEON_IRQ_MSI_BIT0 */ + irq += index*64; irq += OCTEON_IRQ_MSI_BIT0; switch (octeon_dma_bar_type) { @@ -179,12 +187,18 @@ try_only_one: void arch_teardown_msi_irq(unsigned int irq) { int number_irqs; - uint64_t bitmask; + u64 bitmask; + int index = 0; + int irq0; - if ((irq < OCTEON_IRQ_MSI_BIT0) || (irq > OCTEON_IRQ_MSI_LAST)) + if ((irq < OCTEON_IRQ_MSI_BIT0) + || (irq > msi_irq_size + OCTEON_IRQ_MSI_BIT0)) panic("arch_teardown_msi_irq: Attempted to teardown illegal " "MSI interrupt (%d)", irq); + irq -= OCTEON_IRQ_MSI_BIT0; + index = irq / 64; + irq0 = irq % 64; /* * Count the number of IRQs we need to free by looking at the @@ -192,151 +206,197 @@ void arch_teardown_msi_irq(unsigned int irq) * IRQ is also owned by this device. */ number_irqs = 0; - while ((irq+number_irqs < 64) && - (msi_multiple_irq_bitmask & (1ull << (irq + number_irqs)))) + while ((irq0 + number_irqs < 64) && + (msi_multiple_irq_bitmask[index] + & (1ull << (irq0 + number_irqs)))) number_irqs++; number_irqs++; /* Mask with one bit for each IRQ */ bitmask = (1 << number_irqs) - 1; /* Shift the mask to the correct bit location */ - bitmask <<= irq; - if ((msi_free_irq_bitmask & bitmask) != bitmask) + bitmask <<= irq0; + if ((msi_free_irq_bitmask[index] & bitmask) != bitmask) panic("arch_teardown_msi_irq: Attempted to teardown MSI " "interrupt (%d) not in use", irq); /* Checks are done, update the in use bitmask */ spin_lock(&msi_free_irq_bitmask_lock); - msi_free_irq_bitmask &= ~bitmask; - msi_multiple_irq_bitmask &= ~bitmask; + msi_free_irq_bitmask[index] &= ~bitmask; + msi_multiple_irq_bitmask[index] &= ~bitmask; spin_unlock(&msi_free_irq_bitmask_lock); } +static DEFINE_RAW_SPINLOCK(octeon_irq_msi_lock); -/* - * Called by the interrupt handling code when an MSI interrupt - * occurs. - */ -static irqreturn_t octeon_msi_interrupt(int cpl, void *dev_id) +static u64 msi_rcv_reg[4]; +static u64 mis_ena_reg[4]; + +static void octeon_irq_msi_enable_pcie(unsigned int irq) { - uint64_t msi_bits; - int irq; + u64 en; + unsigned long flags; + int msi_number = irq - OCTEON_IRQ_MSI_BIT0; + int irq_index = msi_number >> 6; + int irq_bit = msi_number & 0x3f; + + raw_spin_lock_irqsave(&octeon_irq_msi_lock, flags); + en = cvmx_read_csr(mis_ena_reg[irq_index]); + en |= 1ull << irq_bit; + cvmx_write_csr(mis_ena_reg[irq_index], en); + cvmx_read_csr(mis_ena_reg[irq_index]); + raw_spin_unlock_irqrestore(&octeon_irq_msi_lock, flags); +} - if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_PCIE) - msi_bits = cvmx_read_csr(CVMX_PEXP_NPEI_MSI_RCV0); - else - msi_bits = cvmx_read_csr(CVMX_NPI_NPI_MSI_RCV); - irq = fls64(msi_bits); - if (irq) { - irq += OCTEON_IRQ_MSI_BIT0 - 1; - if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { - /* These chips have PCIe */ - cvmx_write_csr(CVMX_PEXP_NPEI_MSI_RCV0, - 1ull << (irq - OCTEON_IRQ_MSI_BIT0)); - } else { - /* These chips have PCI */ - cvmx_write_csr(CVMX_NPI_NPI_MSI_RCV, - 1ull << (irq - OCTEON_IRQ_MSI_BIT0)); - } - if (irq_desc[irq].action) { - do_IRQ(irq); - return IRQ_HANDLED; - } else { - pr_err("Spurious MSI interrupt %d\n", irq); - } - } - return IRQ_NONE; +static void octeon_irq_msi_disable_pcie(unsigned int irq) +{ + u64 en; + unsigned long flags; + int msi_number = irq - OCTEON_IRQ_MSI_BIT0; + int irq_index = msi_number >> 6; + int irq_bit = msi_number & 0x3f; + + raw_spin_lock_irqsave(&octeon_irq_msi_lock, flags); + en = cvmx_read_csr(mis_ena_reg[irq_index]); + en &= ~(1ull << irq_bit); + cvmx_write_csr(mis_ena_reg[irq_index], en); + cvmx_read_csr(mis_ena_reg[irq_index]); + raw_spin_unlock_irqrestore(&octeon_irq_msi_lock, flags); } -static DEFINE_RAW_SPINLOCK(octeon_irq_msi_lock); +static struct irq_chip octeon_irq_chip_msi_pcie = { + .name = "MSI", + .enable = octeon_irq_msi_enable_pcie, + .disable = octeon_irq_msi_disable_pcie, +}; -static void octeon_irq_msi_enable(unsigned int irq) +static void octeon_irq_msi_enable_pci(unsigned int irq) { - if (!octeon_has_feature(OCTEON_FEATURE_PCIE)) { - /* - * Octeon PCI doesn't have the ability to mask/unmask - * MSI interrupts individually. Instead of - * masking/unmasking them in groups of 16, we simple - * assume MSI devices are well behaved. MSI - * interrupts are always enable and the ACK is assumed - * to be enough. - */ - } else { - /* These chips have PCIe. Note that we only support - * the first 64 MSI interrupts. Unfortunately all the - * MSI enables are in the same register. We use - * MSI0's lock to control access to them all. - */ - uint64_t en; - unsigned long flags; - raw_spin_lock_irqsave(&octeon_irq_msi_lock, flags); - en = cvmx_read_csr(CVMX_PEXP_NPEI_MSI_ENB0); - en |= 1ull << (irq - OCTEON_IRQ_MSI_BIT0); - cvmx_write_csr(CVMX_PEXP_NPEI_MSI_ENB0, en); - cvmx_read_csr(CVMX_PEXP_NPEI_MSI_ENB0); - raw_spin_unlock_irqrestore(&octeon_irq_msi_lock, flags); - } + /* + * Octeon PCI doesn't have the ability to mask/unmask MSI + * interrupts individually. Instead of masking/unmasking them + * in groups of 16, we simple assume MSI devices are well + * behaved. MSI interrupts are always enable and the ACK is + * assumed to be enough + */ } -static void octeon_irq_msi_disable(unsigned int irq) +static void octeon_irq_msi_disable_pci(unsigned int irq) { - if (!octeon_has_feature(OCTEON_FEATURE_PCIE)) { - /* See comment in enable */ - } else { - /* - * These chips have PCIe. Note that we only support - * the first 64 MSI interrupts. Unfortunately all the - * MSI enables are in the same register. We use - * MSI0's lock to control access to them all. - */ - uint64_t en; - unsigned long flags; - raw_spin_lock_irqsave(&octeon_irq_msi_lock, flags); - en = cvmx_read_csr(CVMX_PEXP_NPEI_MSI_ENB0); - en &= ~(1ull << (irq - OCTEON_IRQ_MSI_BIT0)); - cvmx_write_csr(CVMX_PEXP_NPEI_MSI_ENB0, en); - cvmx_read_csr(CVMX_PEXP_NPEI_MSI_ENB0); - raw_spin_unlock_irqrestore(&octeon_irq_msi_lock, flags); - } + /* See comment in enable */ } -static struct irq_chip octeon_irq_chip_msi = { +static struct irq_chip octeon_irq_chip_msi_pci = { .name = "MSI", - .enable = octeon_irq_msi_enable, - .disable = octeon_irq_msi_disable, + .enable = octeon_irq_msi_enable_pci, + .disable = octeon_irq_msi_disable_pci, }; /* - * Initializes the MSI interrupt handling code + * Called by the interrupt handling code when an MSI interrupt + * occurs. */ -static int __init octeon_msi_initialize(void) +static irqreturn_t __octeon_msi_do_interrupt(int index, u64 msi_bits) { int irq; + int bit; - for (irq = OCTEON_IRQ_MSI_BIT0; irq <= OCTEON_IRQ_MSI_LAST; irq++) { - set_irq_chip_and_handler(irq, &octeon_irq_chip_msi, handle_simple_irq); + bit = fls64(msi_bits); + if (bit) { + bit--; + /* Acknowledge it first. */ + cvmx_write_csr(msi_rcv_reg[index], 1ull << bit); + + irq = bit + OCTEON_IRQ_MSI_BIT0 + 64 * index; + do_IRQ(irq); + return IRQ_HANDLED; } + return IRQ_NONE; +} + +#define OCTEON_MSI_INT_HANDLER_X(x) \ +static irqreturn_t octeon_msi_interrupt##x(int cpl, void *dev_id) \ +{ \ + u64 msi_bits = cvmx_read_csr(msi_rcv_reg[(x)]); \ + return __octeon_msi_do_interrupt((x), msi_bits); \ +} + +/* + * Create octeon_msi_interrupt{0-3} function body + */ +OCTEON_MSI_INT_HANDLER_X(0); +OCTEON_MSI_INT_HANDLER_X(1); +OCTEON_MSI_INT_HANDLER_X(2); +OCTEON_MSI_INT_HANDLER_X(3); + +/* + * Initializes the MSI interrupt handling code + */ +int __init octeon_msi_initialize(void) +{ + int irq; + struct irq_chip *msi; + + if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_PCIE) { + msi_rcv_reg[0] = CVMX_PEXP_NPEI_MSI_RCV0; + msi_rcv_reg[1] = CVMX_PEXP_NPEI_MSI_RCV1; + msi_rcv_reg[2] = CVMX_PEXP_NPEI_MSI_RCV2; + msi_rcv_reg[3] = CVMX_PEXP_NPEI_MSI_RCV3; + mis_ena_reg[0] = CVMX_PEXP_NPEI_MSI_ENB0; + mis_ena_reg[1] = CVMX_PEXP_NPEI_MSI_ENB1; + mis_ena_reg[2] = CVMX_PEXP_NPEI_MSI_ENB2; + mis_ena_reg[3] = CVMX_PEXP_NPEI_MSI_ENB3; + msi = &octeon_irq_chip_msi_pcie; + } else { + msi_rcv_reg[0] = CVMX_NPI_NPI_MSI_RCV; +#define INVALID_GENERATE_ADE 0x8700000000000000ULL; + msi_rcv_reg[1] = INVALID_GENERATE_ADE; + msi_rcv_reg[2] = INVALID_GENERATE_ADE; + msi_rcv_reg[3] = INVALID_GENERATE_ADE; + mis_ena_reg[0] = INVALID_GENERATE_ADE; + mis_ena_reg[1] = INVALID_GENERATE_ADE; + mis_ena_reg[2] = INVALID_GENERATE_ADE; + mis_ena_reg[3] = INVALID_GENERATE_ADE; + msi = &octeon_irq_chip_msi_pci; + } + + for (irq = OCTEON_IRQ_MSI_BIT0; irq <= OCTEON_IRQ_MSI_LAST; irq++) + set_irq_chip_and_handler(irq, msi, handle_simple_irq); if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { - if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt, - 0, "MSI[0:63]", octeon_msi_interrupt)) + if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt0, + 0, "MSI[0:63]", octeon_msi_interrupt0)) panic("request_irq(OCTEON_IRQ_PCI_MSI0) failed"); + + if (request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt1, + 0, "MSI[64:127]", octeon_msi_interrupt1)) + panic("request_irq(OCTEON_IRQ_PCI_MSI1) failed"); + + if (request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt2, + 0, "MSI[127:191]", octeon_msi_interrupt2)) + panic("request_irq(OCTEON_IRQ_PCI_MSI2) failed"); + + if (request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt3, + 0, "MSI[192:255]", octeon_msi_interrupt3)) + panic("request_irq(OCTEON_IRQ_PCI_MSI3) failed"); + + msi_irq_size = 256; } else if (octeon_is_pci_host()) { - if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt, - 0, "MSI[0:15]", octeon_msi_interrupt)) + if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt0, + 0, "MSI[0:15]", octeon_msi_interrupt0)) panic("request_irq(OCTEON_IRQ_PCI_MSI0) failed"); - if (request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt, - 0, "MSI[16:31]", octeon_msi_interrupt)) + if (request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt0, + 0, "MSI[16:31]", octeon_msi_interrupt0)) panic("request_irq(OCTEON_IRQ_PCI_MSI1) failed"); - if (request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt, - 0, "MSI[32:47]", octeon_msi_interrupt)) + if (request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt0, + 0, "MSI[32:47]", octeon_msi_interrupt0)) panic("request_irq(OCTEON_IRQ_PCI_MSI2) failed"); - if (request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt, - 0, "MSI[48:63]", octeon_msi_interrupt)) + if (request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt0, + 0, "MSI[48:63]", octeon_msi_interrupt0)) panic("request_irq(OCTEON_IRQ_PCI_MSI3) failed"); - + msi_irq_size = 64; } return 0; } -- cgit v1.2.3-70-g09d2 From 52a0f00b50ea360e3cf7e3281523c6a8aafc5761 Mon Sep 17 00:00:00 2001 From: Chandrakala Chavva Date: Mon, 26 Jul 2010 18:14:16 -0700 Subject: MIPS: Octeon: Disallow MSI-X interrupt and fall back to MSI interrupts. MSI-X interrupts are not supported yet for Octeon, return error if MSI-X interrupts are requested by driver so that the driver will fall back to use MSI interrupts. Signed-off-by: Chandrakala Chavva To: linux-mips@linux-mips.org Cc: David Daney Patchwork: https://patchwork.linux-mips.org/patch/1506/ Signed-off-by: Ralf Baechle Signed-off-by: David Daney --- arch/mips/include/asm/pci.h | 5 +++++ arch/mips/pci/msi-octeon.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h index 3beea1479b4..576397c6992 100644 --- a/arch/mips/include/asm/pci.h +++ b/arch/mips/include/asm/pci.h @@ -140,6 +140,11 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) return channel ? 15 : 14; } +#ifdef CONFIG_CPU_CAVIUM_OCTEON +/* MSI arch hook for OCTEON */ +#define arch_setup_msi_irqs arch_setup_msi_irqs +#endif + extern int pci_probe_only; extern char * (*pcibios_plat_setup)(char *str); diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c index 7c756408b85..d8080499872 100644 --- a/arch/mips/pci/msi-octeon.c +++ b/arch/mips/pci/msi-octeon.c @@ -177,6 +177,34 @@ msi_irq_allocated: return 0; } +int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) +{ + struct msi_desc *entry; + int ret; + + /* + * MSI-X is not supported. + */ + if (type == PCI_CAP_ID_MSIX) + return -EINVAL; + + /* + * If an architecture wants to support multiple MSI, it needs to + * override arch_setup_msi_irqs() + */ + if (type == PCI_CAP_ID_MSI && nvec > 1) + return 1; + + list_for_each_entry(entry, &dev->msi_list, list) { + ret = arch_setup_msi_irq(dev, entry); + if (ret < 0) + return ret; + if (ret > 0) + return -ENOSPC; + } + + return 0; +} /** * Called when a device no longer needs its MSI interrupts. All -- cgit v1.2.3-70-g09d2 From ef771ad4ad59c88ffd1e313aa9e943751f83d3a2 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 3 Aug 2010 13:53:24 -0700 Subject: MIPS: kprobes: Define regs_return_value() Signed-off-by: David Daney To: linux-mips@linux-mips.org To: ananth@in.ibm.com To: anil.s.keshavamurthy@intel.com To: davem@davemloft.net To: masami.hiramatsu.pt@hitachi.com Cc: linux-kernel@vger.kernel.org, Cc: hschauhan@nulltrace.org Patchwork: https://patchwork.linux-mips.org/patch/1529/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/ptrace.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h index cdc6a46efd9..9f1b8dba2c8 100644 --- a/arch/mips/include/asm/ptrace.h +++ b/arch/mips/include/asm/ptrace.h @@ -137,6 +137,7 @@ extern int ptrace_set_watch_regs(struct task_struct *child, */ #define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER) +#define regs_return_value(_regs) ((_regs)->regs[2]) #define instruction_pointer(regs) ((regs)->cp0_epc) #define profile_pc(regs) instruction_pointer(regs) -- cgit v1.2.3-70-g09d2 From 2ea6399f553bf9a47260723b44d50f747e310218 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 3 Aug 2010 11:22:19 -0700 Subject: MIPS: Add instrunction format for BREAK and SYSCALL Signed-off-by: David Daney To: linux-mips@linux-mips.org To: ananth@in.ibm.com To: anil.s.keshavamurthy@intel.com To: davem@davemloft.net To: masami.hiramatsu.pt@hitachi.com Cc: linux-kernel@vger.kernel.org Cc: hschauhan@nulltrace.org Patchwork: https://patchwork.linux-mips.org/patch/1524/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/inst.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/inst.h b/arch/mips/include/asm/inst.h index 6489f00731c..444ff71aa0e 100644 --- a/arch/mips/include/asm/inst.h +++ b/arch/mips/include/asm/inst.h @@ -247,6 +247,12 @@ struct ma_format { /* FPU multipy and add format (MIPS IV) */ unsigned int fmt : 2; }; +struct b_format { /* BREAK and SYSCALL */ + unsigned int opcode:6; + unsigned int code:20; + unsigned int func:6; +}; + #elif defined(__MIPSEL__) struct j_format { /* Jump format */ @@ -314,6 +320,12 @@ struct ma_format { /* FPU multipy and add format (MIPS IV) */ unsigned int opcode : 6; }; +struct b_format { /* BREAK and SYSCALL */ + unsigned int func:6; + unsigned int code:20; + unsigned int opcode:6; +}; + #else /* !defined (__MIPSEB__) && !defined (__MIPSEL__) */ #error "MIPS but neither __MIPSEL__ nor __MIPSEB__?" #endif @@ -328,7 +340,8 @@ union mips_instruction { struct c_format c_format; struct r_format r_format; struct f_format f_format; - struct ma_format ma_format; + struct ma_format ma_format; + struct b_format b_format; }; /* HACHACHAHCAHC ... */ -- cgit v1.2.3-70-g09d2 From c1bf207d6ee1eb72e9c10365edbdc7c9ff7fb9b0 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 3 Aug 2010 11:22:20 -0700 Subject: MIPS: kprobe: Add support. This patch is based on previous work by Sony and Himanshu Chauhan. I have done some cleanup and implemented JProbes and KRETPROBES. The KRETPROBES part is pretty much copied verbatim from powerpc. A possible future enhance might be to factor out the common code. Signed-off-by: David Daney Cc: Himanshu Chauhan To: linux-mips@linux-mips.org To: ananth@in.ibm.com, To: anil.s.keshavamurthy@intel.com To: davem@davemloft.net To: masami.hiramatsu.pt@hitachi.com Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1525/ Patchwork: https://patchwork.linux-mips.org/patch/1530/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 2 + arch/mips/Makefile | 3 + arch/mips/include/asm/break.h | 2 + arch/mips/include/asm/kdebug.h | 3 + arch/mips/include/asm/kprobes.h | 92 +++++++ arch/mips/kernel/Makefile | 1 + arch/mips/kernel/kprobes.c | 557 ++++++++++++++++++++++++++++++++++++++++ arch/mips/kernel/traps.c | 22 +- arch/mips/mm/fault.c | 15 +- 9 files changed, 695 insertions(+), 2 deletions(-) create mode 100644 arch/mips/include/asm/kprobes.h create mode 100644 arch/mips/kernel/kprobes.c (limited to 'arch/mips/include/asm') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index aaca439010d..36642df7d5f 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -10,6 +10,8 @@ config MIPS select HAVE_DYNAMIC_FTRACE select HAVE_FTRACE_MCOUNT_RECORD select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_KPROBES + select HAVE_KRETPROBES select RTC_LIB if !MACH_LOONGSON mainmenu "Linux/MIPS Kernel Configuration" diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 9296cbf3f1f..f0d196090e9 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -259,6 +259,9 @@ endif vmlinux.32: vmlinux $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@ + +#obj-$(CONFIG_KPROBES) += kprobes.o + # # The 64-bit ELF tools are pretty broken so at this time we generate 64-bit # ELF files from 32-bit files by conversion. diff --git a/arch/mips/include/asm/break.h b/arch/mips/include/asm/break.h index 44437ed765e..9161e684cb4 100644 --- a/arch/mips/include/asm/break.h +++ b/arch/mips/include/asm/break.h @@ -30,6 +30,8 @@ #define BRK_BUG 512 /* Used by BUG() */ #define BRK_KDB 513 /* Used in KDB_ENTER() */ #define BRK_MEMU 514 /* Used by FPU emulator */ +#define BRK_KPROBE_BP 515 /* Kprobe break */ +#define BRK_KPROBE_SSTEPBP 516 /* Kprobe single step software implementation */ #define BRK_MULOVF 1023 /* Multiply overflow */ #endif /* __ASM_BREAK_H */ diff --git a/arch/mips/include/asm/kdebug.h b/arch/mips/include/asm/kdebug.h index 5bf62aafc89..6a9af5fcb5d 100644 --- a/arch/mips/include/asm/kdebug.h +++ b/arch/mips/include/asm/kdebug.h @@ -8,6 +8,9 @@ enum die_val { DIE_FP, DIE_TRAP, DIE_RI, + DIE_PAGE_FAULT, + DIE_BREAK, + DIE_SSTEPBP }; #endif /* _ASM_MIPS_KDEBUG_H */ diff --git a/arch/mips/include/asm/kprobes.h b/arch/mips/include/asm/kprobes.h new file mode 100644 index 00000000000..e6ea4d4d720 --- /dev/null +++ b/arch/mips/include/asm/kprobes.h @@ -0,0 +1,92 @@ +/* + * Kernel Probes (KProbes) + * include/asm-mips/kprobes.h + * + * Copyright 2006 Sony Corp. + * Copyright 2010 Cavium Networks + * + * 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ASM_KPROBES_H +#define _ASM_KPROBES_H + +#include +#include + +#include +#include +#include + +#define __ARCH_WANT_KPROBES_INSN_SLOT + +struct kprobe; +struct pt_regs; + +typedef union mips_instruction kprobe_opcode_t; + +#define MAX_INSN_SIZE 2 + +#define flush_insn_slot(p) \ +do { \ + flush_icache_range((unsigned long)p->addr, \ + (unsigned long)p->addr + \ + (MAX_INSN_SIZE * sizeof(kprobe_opcode_t))); \ +} while (0) + + +#define kretprobe_blacklist_size 0 + +void arch_remove_kprobe(struct kprobe *p); + +/* Architecture specific copy of original instruction*/ +struct arch_specific_insn { + /* copy of the original instruction */ + kprobe_opcode_t *insn; +}; + +struct prev_kprobe { + struct kprobe *kp; + unsigned long status; + unsigned long old_SR; + unsigned long saved_SR; + unsigned long saved_epc; +}; + +#define MAX_JPROBES_STACK_SIZE 128 +#define MAX_JPROBES_STACK_ADDR \ + (((unsigned long)current_thread_info()) + THREAD_SIZE - 32 - sizeof(struct pt_regs)) + +#define MIN_JPROBES_STACK_SIZE(ADDR) \ + ((((ADDR) + MAX_JPROBES_STACK_SIZE) > MAX_JPROBES_STACK_ADDR) \ + ? MAX_JPROBES_STACK_ADDR - (ADDR) \ + : MAX_JPROBES_STACK_SIZE) + + +/* per-cpu kprobe control block */ +struct kprobe_ctlblk { + unsigned long kprobe_status; + unsigned long kprobe_old_SR; + unsigned long kprobe_saved_SR; + unsigned long kprobe_saved_epc; + unsigned long jprobe_saved_sp; + struct pt_regs jprobe_saved_regs; + u8 jprobes_stack[MAX_JPROBES_STACK_SIZE]; + struct prev_kprobe prev_kprobe; +}; + +extern int kprobe_exceptions_notify(struct notifier_block *self, + unsigned long val, void *data); + +#endif /* _ASM_KPROBES_H */ diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index ff5ec2e0184..06f84829978 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o obj-$(CONFIG_IRQ_GIC) += irq-gic.o +obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_32BIT) += scall32-o32.o obj-$(CONFIG_64BIT) += scall64-64.o obj-$(CONFIG_MIPS32_COMPAT) += linux32.o ptrace32.o signal32.o diff --git a/arch/mips/kernel/kprobes.c b/arch/mips/kernel/kprobes.c new file mode 100644 index 00000000000..ee28683fc2a --- /dev/null +++ b/arch/mips/kernel/kprobes.c @@ -0,0 +1,557 @@ +/* + * Kernel Probes (KProbes) + * arch/mips/kernel/kprobes.c + * + * Copyright 2006 Sony Corp. + * Copyright 2010 Cavium Networks + * + * Some portions copied from the powerpc version. + * + * Copyright (C) IBM Corporation, 2002, 2004 + * + * 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; version 2 of the License. + * + * 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 + +static const union mips_instruction breakpoint_insn = { + .b_format = { + .opcode = spec_op, + .code = BRK_KPROBE_BP, + .func = break_op + } +}; + +static const union mips_instruction breakpoint2_insn = { + .b_format = { + .opcode = spec_op, + .code = BRK_KPROBE_SSTEPBP, + .func = break_op + } +}; + +DEFINE_PER_CPU(struct kprobe *, current_kprobe); +DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); + +static int __kprobes insn_has_delayslot(union mips_instruction insn) +{ + switch (insn.i_format.opcode) { + + /* + * This group contains: + * jr and jalr are in r_format format. + */ + case spec_op: + switch (insn.r_format.func) { + case jr_op: + case jalr_op: + break; + default: + goto insn_ok; + } + + /* + * This group contains: + * bltz_op, bgez_op, bltzl_op, bgezl_op, + * bltzal_op, bgezal_op, bltzall_op, bgezall_op. + */ + case bcond_op: + + /* + * These are unconditional and in j_format. + */ + case jal_op: + case j_op: + + /* + * These are conditional and in i_format. + */ + case beq_op: + case beql_op: + case bne_op: + case bnel_op: + case blez_op: + case blezl_op: + case bgtz_op: + case bgtzl_op: + + /* + * These are the FPA/cp1 branch instructions. + */ + case cop1_op: + +#ifdef CONFIG_CPU_CAVIUM_OCTEON + case lwc2_op: /* This is bbit0 on Octeon */ + case ldc2_op: /* This is bbit032 on Octeon */ + case swc2_op: /* This is bbit1 on Octeon */ + case sdc2_op: /* This is bbit132 on Octeon */ +#endif + return 1; + default: + break; + } +insn_ok: + return 0; +} + +int __kprobes arch_prepare_kprobe(struct kprobe *p) +{ + union mips_instruction insn; + union mips_instruction prev_insn; + int ret = 0; + + prev_insn = p->addr[-1]; + insn = p->addr[0]; + + if (insn_has_delayslot(insn) || insn_has_delayslot(prev_insn)) { + pr_notice("Kprobes for branch and jump instructions are not supported\n"); + ret = -EINVAL; + goto out; + } + + /* insn: must be on special executable page on mips. */ + p->ainsn.insn = get_insn_slot(); + if (!p->ainsn.insn) { + ret = -ENOMEM; + goto out; + } + + /* + * In the kprobe->ainsn.insn[] array we store the original + * instruction at index zero and a break trap instruction at + * index one. + */ + + memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t)); + p->ainsn.insn[1] = breakpoint2_insn; + p->opcode = *p->addr; + +out: + return ret; +} + +void __kprobes arch_arm_kprobe(struct kprobe *p) +{ + *p->addr = breakpoint_insn; + flush_insn_slot(p); +} + +void __kprobes arch_disarm_kprobe(struct kprobe *p) +{ + *p->addr = p->opcode; + flush_insn_slot(p); +} + +void __kprobes arch_remove_kprobe(struct kprobe *p) +{ + free_insn_slot(p->ainsn.insn, 0); +} + +static void save_previous_kprobe(struct kprobe_ctlblk *kcb) +{ + kcb->prev_kprobe.kp = kprobe_running(); + kcb->prev_kprobe.status = kcb->kprobe_status; + kcb->prev_kprobe.old_SR = kcb->kprobe_old_SR; + kcb->prev_kprobe.saved_SR = kcb->kprobe_saved_SR; + kcb->prev_kprobe.saved_epc = kcb->kprobe_saved_epc; +} + +static void restore_previous_kprobe(struct kprobe_ctlblk *kcb) +{ + __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; + kcb->kprobe_status = kcb->prev_kprobe.status; + kcb->kprobe_old_SR = kcb->prev_kprobe.old_SR; + kcb->kprobe_saved_SR = kcb->prev_kprobe.saved_SR; + kcb->kprobe_saved_epc = kcb->prev_kprobe.saved_epc; +} + +static void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) +{ + __get_cpu_var(current_kprobe) = p; + kcb->kprobe_saved_SR = kcb->kprobe_old_SR = (regs->cp0_status & ST0_IE); + kcb->kprobe_saved_epc = regs->cp0_epc; +} + +static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + regs->cp0_status &= ~ST0_IE; + + /* single step inline if the instruction is a break */ + if (p->opcode.word == breakpoint_insn.word || + p->opcode.word == breakpoint2_insn.word) + regs->cp0_epc = (unsigned long)p->addr; + else + regs->cp0_epc = (unsigned long)&p->ainsn.insn[0]; +} + +static int __kprobes kprobe_handler(struct pt_regs *regs) +{ + struct kprobe *p; + int ret = 0; + kprobe_opcode_t *addr; + struct kprobe_ctlblk *kcb; + + addr = (kprobe_opcode_t *) regs->cp0_epc; + + /* + * We don't want to be preempted for the entire + * duration of kprobe processing + */ + preempt_disable(); + kcb = get_kprobe_ctlblk(); + + /* Check we're not actually recursing */ + if (kprobe_running()) { + p = get_kprobe(addr); + if (p) { + if (kcb->kprobe_status == KPROBE_HIT_SS && + p->ainsn.insn->word == breakpoint_insn.word) { + regs->cp0_status &= ~ST0_IE; + regs->cp0_status |= kcb->kprobe_saved_SR; + goto no_kprobe; + } + /* + * We have reentered the kprobe_handler(), since + * another probe was hit while within the handler. + * We here save the original kprobes variables and + * just single step on the instruction of the new probe + * without calling any user handlers. + */ + save_previous_kprobe(kcb); + set_current_kprobe(p, regs, kcb); + kprobes_inc_nmissed_count(p); + prepare_singlestep(p, regs); + kcb->kprobe_status = KPROBE_REENTER; + return 1; + } else { + if (addr->word != breakpoint_insn.word) { + /* + * The breakpoint instruction was removed by + * another cpu right after we hit, no further + * handling of this interrupt is appropriate + */ + ret = 1; + goto no_kprobe; + } + p = __get_cpu_var(current_kprobe); + if (p->break_handler && p->break_handler(p, regs)) + goto ss_probe; + } + goto no_kprobe; + } + + p = get_kprobe(addr); + if (!p) { + if (addr->word != breakpoint_insn.word) { + /* + * The breakpoint instruction was removed right + * after we hit it. Another cpu has removed + * either a probepoint or a debugger breakpoint + * at this address. In either case, no further + * handling of this interrupt is appropriate. + */ + ret = 1; + } + /* Not one of ours: let kernel handle it */ + goto no_kprobe; + } + + set_current_kprobe(p, regs, kcb); + kcb->kprobe_status = KPROBE_HIT_ACTIVE; + + if (p->pre_handler && p->pre_handler(p, regs)) { + /* handler has already set things up, so skip ss setup */ + return 1; + } + +ss_probe: + prepare_singlestep(p, regs); + kcb->kprobe_status = KPROBE_HIT_SS; + return 1; + +no_kprobe: + preempt_enable_no_resched(); + return ret; + +} + +/* + * Called after single-stepping. p->addr is the address of the + * instruction whose first byte has been replaced by the "break 0" + * instruction. To avoid the SMP problems that can occur when we + * temporarily put back the original opcode to single-step, we + * single-stepped a copy of the instruction. The address of this + * copy is p->ainsn.insn. + * + * This function prepares to return from the post-single-step + * breakpoint trap. + */ +static void __kprobes resume_execution(struct kprobe *p, + struct pt_regs *regs, + struct kprobe_ctlblk *kcb) +{ + unsigned long orig_epc = kcb->kprobe_saved_epc; + regs->cp0_epc = orig_epc + 4; +} + +static inline int post_kprobe_handler(struct pt_regs *regs) +{ + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (!cur) + return 0; + + if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { + kcb->kprobe_status = KPROBE_HIT_SSDONE; + cur->post_handler(cur, regs, 0); + } + + resume_execution(cur, regs, kcb); + + regs->cp0_status |= kcb->kprobe_saved_SR; + + /* Restore back the original saved kprobes variables and continue. */ + if (kcb->kprobe_status == KPROBE_REENTER) { + restore_previous_kprobe(kcb); + goto out; + } + reset_current_kprobe(); +out: + preempt_enable_no_resched(); + + return 1; +} + +static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) +{ + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) + return 1; + + if (kcb->kprobe_status & KPROBE_HIT_SS) { + resume_execution(cur, regs, kcb); + regs->cp0_status |= kcb->kprobe_old_SR; + + reset_current_kprobe(); + preempt_enable_no_resched(); + } + return 0; +} + +/* + * Wrapper routine for handling exceptions. + */ +int __kprobes kprobe_exceptions_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + + struct die_args *args = (struct die_args *)data; + int ret = NOTIFY_DONE; + + switch (val) { + case DIE_BREAK: + if (kprobe_handler(args->regs)) + ret = NOTIFY_STOP; + break; + case DIE_SSTEPBP: + if (post_kprobe_handler(args->regs)) + ret = NOTIFY_STOP; + break; + + case DIE_PAGE_FAULT: + /* kprobe_running() needs smp_processor_id() */ + preempt_disable(); + + if (kprobe_running() + && kprobe_fault_handler(args->regs, args->trapnr)) + ret = NOTIFY_STOP; + preempt_enable(); + break; + default: + break; + } + return ret; +} + +int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) +{ + struct jprobe *jp = container_of(p, struct jprobe, kp); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + kcb->jprobe_saved_regs = *regs; + kcb->jprobe_saved_sp = regs->regs[29]; + + memcpy(kcb->jprobes_stack, (void *)kcb->jprobe_saved_sp, + MIN_JPROBES_STACK_SIZE(kcb->jprobe_saved_sp)); + + regs->cp0_epc = (unsigned long)(jp->entry); + + return 1; +} + +/* Defined in the inline asm below. */ +void jprobe_return_end(void); + +void __kprobes jprobe_return(void) +{ + /* Assembler quirk necessitates this '0,code' business. */ + asm volatile( + "break 0,%0\n\t" + ".globl jprobe_return_end\n" + "jprobe_return_end:\n" + : : "n" (BRK_KPROBE_BP) : "memory"); +} + +int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) +{ + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (regs->cp0_epc >= (unsigned long)jprobe_return && + regs->cp0_epc <= (unsigned long)jprobe_return_end) { + *regs = kcb->jprobe_saved_regs; + memcpy((void *)kcb->jprobe_saved_sp, kcb->jprobes_stack, + MIN_JPROBES_STACK_SIZE(kcb->jprobe_saved_sp)); + preempt_enable_no_resched(); + + return 1; + } + return 0; +} + +/* + * Function return probe trampoline: + * - init_kprobes() establishes a probepoint here + * - When the probed function returns, this probe causes the + * handlers to fire + */ +static void __used kretprobe_trampoline_holder(void) +{ + asm volatile( + ".set push\n\t" + /* Keep the assembler from reordering and placing JR here. */ + ".set noreorder\n\t" + "nop\n\t" + ".global kretprobe_trampoline\n" + "kretprobe_trampoline:\n\t" + "nop\n\t" + ".set pop" + : : : "memory"); +} + +void kretprobe_trampoline(void); + +void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, + struct pt_regs *regs) +{ + ri->ret_addr = (kprobe_opcode_t *) regs->regs[31]; + + /* Replace the return addr with trampoline addr */ + regs->regs[31] = (unsigned long)kretprobe_trampoline; +} + +/* + * Called when the probe at kretprobe trampoline is hit + */ +static int __kprobes trampoline_probe_handler(struct kprobe *p, + struct pt_regs *regs) +{ + struct kretprobe_instance *ri = NULL; + struct hlist_head *head, empty_rp; + struct hlist_node *node, *tmp; + unsigned long flags, orig_ret_address = 0; + unsigned long trampoline_address = (unsigned long)kretprobe_trampoline; + + INIT_HLIST_HEAD(&empty_rp); + kretprobe_hash_lock(current, &head, &flags); + + /* + * It is possible to have multiple instances associated with a given + * task either because an multiple functions in the call path + * have a return probe installed on them, and/or more than one return + * return probe was registered for a target function. + * + * We can handle this because: + * - instances are always inserted at the head of the list + * - when multiple return probes are registered for the same + * function, the first instance's ret_addr will point to the + * real return address, and all the rest will point to + * kretprobe_trampoline + */ + hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { + if (ri->task != current) + /* another task is sharing our hash bucket */ + continue; + + if (ri->rp && ri->rp->handler) + ri->rp->handler(ri, regs); + + orig_ret_address = (unsigned long)ri->ret_addr; + recycle_rp_inst(ri, &empty_rp); + + if (orig_ret_address != trampoline_address) + /* + * This is the real return address. Any other + * instances associated with this task are for + * other calls deeper on the call stack + */ + break; + } + + kretprobe_assert(ri, orig_ret_address, trampoline_address); + instruction_pointer(regs) = orig_ret_address; + + reset_current_kprobe(); + kretprobe_hash_unlock(current, &flags); + preempt_enable_no_resched(); + + hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { + hlist_del(&ri->hlist); + kfree(ri); + } + /* + * By returning a non-zero value, we are telling + * kprobe_handler() that we don't want the post_handler + * to run (and have re-enabled preemption) + */ + return 1; +} + +int __kprobes arch_trampoline_kprobe(struct kprobe *p) +{ + if (p->addr == (kprobe_opcode_t *)kretprobe_trampoline) + return 1; + + return 0; +} + +static struct kprobe trampoline_p = { + .addr = (kprobe_opcode_t *)kretprobe_trampoline, + .pre_handler = trampoline_probe_handler +}; + +int __init arch_init_kprobes(void) +{ + return register_kprobe(&trampoline_p); +} diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 1515b673179..4c6079f2495 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -334,7 +335,7 @@ void show_regs(struct pt_regs *regs) __show_regs((struct pt_regs *)regs); } -void show_registers(const struct pt_regs *regs) +void show_registers(struct pt_regs *regs) { const int field = 2 * sizeof(unsigned long); @@ -783,6 +784,25 @@ asmlinkage void do_bp(struct pt_regs *regs) if (bcode >= (1 << 10)) bcode >>= 10; + /* + * notify the kprobe handlers, if instruction is likely to + * pertain to them. + */ + switch (bcode) { + case BRK_KPROBE_BP: + if (notify_die(DIE_BREAK, "debug", regs, bcode, 0, 0) == NOTIFY_STOP) + return; + else + break; + case BRK_KPROBE_SSTEPBP: + if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode, 0, 0) == NOTIFY_STOP) + return; + else + break; + default: + break; + } + do_trap_or_bp(regs, bcode, "Break"); return; diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index b4aac424b2e..783ad0065fd 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -24,13 +25,14 @@ #include #include #include /* For VMALLOC_END */ +#include /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate * routines. */ -asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, +asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long write, unsigned long address) { struct vm_area_struct * vma = NULL; @@ -46,6 +48,17 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, field, regs->cp0_epc); #endif +#ifdef CONFIG_KPROBES + /* + * This is to notify the fault handler of the kprobes. The + * exception code is redundant as it is also carried in REGS, + * but we pass it anyhow. + */ + if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1, + (regs->cp0_cause >> 2) & 0x1f, SIGSEGV) == NOTIFY_STOP) + return; +#endif + info.si_code = SEGV_MAPERR; /* -- cgit v1.2.3-70-g09d2 From 7281cd22973008a782860e48ed8d85d00204168c Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 3 Aug 2010 14:57:39 -0700 Subject: MIPS: Remove unused task_struct.trap_no field. It is initialized to zero and only ever read. Remove it, and pass zero in its place. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1531/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/processor.h | 2 -- arch/mips/kernel/asm-offsets.c | 1 - arch/mips/kernel/traps.c | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 24d91f8618f..0d629bb93cb 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -229,7 +229,6 @@ struct thread_struct { unsigned long cp0_badvaddr; /* Last user fault */ unsigned long cp0_baduaddr; /* Last kernel fault accessing USEG */ unsigned long error_code; - unsigned long trap_no; unsigned long irix_trampoline; /* Wheee... */ unsigned long irix_oldctx; #ifdef CONFIG_CPU_CAVIUM_OCTEON @@ -301,7 +300,6 @@ struct thread_struct { .cp0_badvaddr = 0, \ .cp0_baduaddr = 0, \ .error_code = 0, \ - .trap_no = 0, \ .irix_trampoline = 0, \ .irix_oldctx = 0, \ /* \ diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index ca6c83218ca..6b30fb2caa6 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -126,7 +126,6 @@ void output_thread_defines(void) thread.cp0_baduaddr); OFFSET(THREAD_ECODE, task_struct, \ thread.error_code); - OFFSET(THREAD_TRAPNO, task_struct, thread.trap_no); OFFSET(THREAD_TRAMP, task_struct, \ thread.irix_trampoline); OFFSET(THREAD_OLDCTX, task_struct, \ diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 4c6079f2495..6019e9ea9a6 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -376,7 +376,7 @@ void __noreturn die(const char * str, struct pt_regs * regs) mips_mt_regdump(dvpret); #endif /* CONFIG_MIPS_MT_SMTC */ - if (notify_die(DIE_OOPS, str, regs, 0, current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) + if (notify_die(DIE_OOPS, str, regs, 0, 0, SIGSEGV) == NOTIFY_STOP) sig = 0; printk("%s[#%d]:\n", str, ++die_counter); -- cgit v1.2.3-70-g09d2 From 2b5987abaf2dd6c3934e0376b7d9f64411cdcf03 Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 4 Aug 2010 14:53:57 -0700 Subject: MIPS: Octeon: Allow more than 3.75GB of memory with PCIe We reserve the 3.75GB - 4GB region of PCIe address space for device to device transfers, making the corresponding physical memory under direct mapping unavailable for DMA. To allow for PCIe DMA to all physical memory we map this chunk of physical memory with BAR1. Because of the resulting discontinuity in the mapping function, we remove a page of memory at each end of the range so multi-page DMA buffers can never be allocated that span the range. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1535/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/dma-octeon.c | 17 ++++++++------ arch/mips/cavium-octeon/setup.c | 34 +++++++++++++++++++++++++++- arch/mips/include/asm/octeon/pci-octeon.h | 13 +++++++++++ arch/mips/pci/pcie-octeon.c | 37 ++++++++++++++++++++++++++----- 4 files changed, 87 insertions(+), 14 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/cavium-octeon/dma-octeon.c b/arch/mips/cavium-octeon/dma-octeon.c index be531ec1f20..d22b5a2d64f 100644 --- a/arch/mips/cavium-octeon/dma-octeon.c +++ b/arch/mips/cavium-octeon/dma-octeon.c @@ -99,13 +99,16 @@ dma_addr_t octeon_map_dma_mem(struct device *dev, void *ptr, size_t size) panic("dma_map_single: " "Attempt to map illegal memory address 0x%llx\n", physical); - else if ((physical + size >= - (4ull<<30) - (OCTEON_PCI_BAR1_HOLE_SIZE<<20)) - && physical < (4ull<<30)) - pr_warning("dma_map_single: Warning: " - "Mapping memory address that might " - "conflict with devices 0x%llx-0x%llx\n", - physical, physical+size-1); + else if (physical >= CVMX_PCIE_BAR1_PHYS_BASE && + physical + size < (CVMX_PCIE_BAR1_PHYS_BASE + CVMX_PCIE_BAR1_PHYS_SIZE)) { + result = physical - CVMX_PCIE_BAR1_PHYS_BASE + CVMX_PCIE_BAR1_RC_BASE; + + if (((result+size-1) & dma_mask) != result+size-1) + panic("dma_map_single: Attempt to map address 0x%llx-0x%llx, which can't be accessed according to the dma mask 0x%llx\n", + physical, physical+size-1, dma_mask); + goto done; + } + /* The 2nd 256MB is mapped at 256<<20 instead of 0x410000000 */ if ((physical >= 0x410000000ull) && physical < 0x420000000ull) result = physical - 0x400000000ull; diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index 041326e34f4..69197cb6c7e 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -32,6 +32,7 @@ #include #include +#include #ifdef CONFIG_CAVIUM_DECODE_RSL extern void cvmx_interrupt_rsl_decode(void); @@ -609,6 +610,22 @@ void __init prom_init(void) register_smp_ops(&octeon_smp_ops); } +/* Exclude a single page from the regions obtained in plat_mem_setup. */ +static __init void memory_exclude_page(u64 addr, u64 *mem, u64 *size) +{ + if (addr > *mem && addr < *mem + *size) { + u64 inc = addr - *mem; + add_memory_region(*mem, inc, BOOT_MEM_RAM); + *mem += inc; + *size -= inc; + } + + if (addr == *mem && *size > PAGE_SIZE) { + *mem += PAGE_SIZE; + *size -= PAGE_SIZE; + } +} + void __init plat_mem_setup(void) { uint64_t mem_alloc_size; @@ -659,12 +676,27 @@ void __init plat_mem_setup(void) CVMX_BOOTMEM_FLAG_NO_LOCKING); #endif if (memory >= 0) { + u64 size = mem_alloc_size; + + /* + * exclude a page at the beginning and end of + * the 256MB PCIe 'hole' so the kernel will not + * try to allocate multi-page buffers that + * span the discontinuity. + */ + memory_exclude_page(CVMX_PCIE_BAR1_PHYS_BASE, + &memory, &size); + memory_exclude_page(CVMX_PCIE_BAR1_PHYS_BASE + + CVMX_PCIE_BAR1_PHYS_SIZE, + &memory, &size); + /* * This function automatically merges address * regions next to each other if they are * received in incrementing order. */ - add_memory_region(memory, mem_alloc_size, BOOT_MEM_RAM); + if (size) + add_memory_region(memory, size, BOOT_MEM_RAM); total += mem_alloc_size; } else { break; diff --git a/arch/mips/include/asm/octeon/pci-octeon.h b/arch/mips/include/asm/octeon/pci-octeon.h index 6ac5d3e3398..ece78043acf 100644 --- a/arch/mips/include/asm/octeon/pci-octeon.h +++ b/arch/mips/include/asm/octeon/pci-octeon.h @@ -14,6 +14,19 @@ /* Some PCI cards require delays when accessing config space. */ #define PCI_CONFIG_SPACE_DELAY 10000 +/* + * The physical memory base mapped by BAR1. 256MB at the end of the + * first 4GB. + */ +#define CVMX_PCIE_BAR1_PHYS_BASE ((1ull << 32) - (1ull << 28)) +#define CVMX_PCIE_BAR1_PHYS_SIZE (1ull << 28) + +/* + * The RC base of BAR1. gen1 has a 39-bit BAR2, gen2 has 41-bit BAR2, + * place BAR1 so it is the same for both. + */ +#define CVMX_PCIE_BAR1_RC_BASE (1ull << 41) + /* * pcibios_map_irq() is defined inside pci-octeon.c. All it does is * call the Octeon specific version pointed to by this variable. This diff --git a/arch/mips/pci/pcie-octeon.c b/arch/mips/pci/pcie-octeon.c index 6aa5c542d52..861361e0c9a 100644 --- a/arch/mips/pci/pcie-octeon.c +++ b/arch/mips/pci/pcie-octeon.c @@ -402,6 +402,10 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) npei_ctl_status2.s.mps = 0; /* Max read request size = 128 bytes for best Octeon DMA performance */ npei_ctl_status2.s.mrrs = 0; + if (pcie_port) + npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */ + else + npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */ cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64); /* ECRC Generation (PCIE*_CFG070[GE,CE]) */ @@ -666,6 +670,8 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port) static int cvmx_pcie_rc_initialize(int pcie_port) { int i; + int base; + u64 addr_swizzle; union cvmx_ciu_soft_prst ciu_soft_prst; union cvmx_pescx_bist_status pescx_bist_status; union cvmx_pescx_bist_status2 pescx_bist_status2; @@ -674,6 +680,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port) union cvmx_npei_mem_access_subidx mem_access_subid; union cvmx_npei_dbg_data npei_dbg_data; union cvmx_pescx_ctl_status2 pescx_ctl_status2; + union cvmx_npei_bar1_indexx bar1_index; /* * Make sure we aren't trying to setup a target mode interface @@ -918,12 +925,30 @@ static int cvmx_pcie_rc_initialize(int pcie_port) /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */ cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0); - /* - * Disable Octeon's BAR1. It isn't needed in RC mode since - * BAR2 maps all of memory. BAR2 also maps 256MB-512MB into - * the 2nd 256MB of memory. - */ - cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), -1); + /* BAR1 follows BAR2 with a gap. */ + cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE); + + bar1_index.u32 = 0; + bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22); + bar1_index.s.ca = 1; /* Not Cached */ + bar1_index.s.end_swp = 1; /* Endian Swap mode */ + bar1_index.s.addr_v = 1; /* Valid entry */ + + base = pcie_port ? 16 : 0; + + /* Big endian swizzle for 32-bit PEXP_NCB register. */ +#ifdef __MIPSEB__ + addr_swizzle = 4; +#else + addr_swizzle = 0; +#endif + for (i = 0; i < 16; i++) { + cvmx_write64_uint32((CVMX_PEXP_NPEI_BAR1_INDEXX(base) ^ addr_swizzle), + bar1_index.u32); + base++; + /* 256MB / 16 >> 22 == 4 */ + bar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22); + } /* * Set Octeon's BAR2 to decode 0-2^39. Bar0 and Bar1 take -- cgit v1.2.3-70-g09d2 From 47a348614492987ef307aad299c09163344e4eaf Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Mon, 2 Aug 2010 23:56:22 +0200 Subject: MIPS: BCM47xx: Fix nvram_getenv return value. Nvram_getenv should behave like cfe_getenv. cfe_getenv returns 0 on success and -9 if the value was not found. If the input was wrong -8 will be returned by cfe_getenv. Change nvram_getenv to do the same. Signed-off-by: Hauke Mehrtens Cc: Waldemar Brodkorb Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1520/ Signed-off-by: Ralf Baechle --- arch/mips/bcm47xx/nvram.c | 4 ++-- arch/mips/include/asm/mach-bcm47xx/nvram.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index 06e03b222f6..e5b6615731e 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -69,7 +69,7 @@ int nvram_getenv(char *name, char *val, size_t val_len) char *var, *value, *end, *eq; if (!name) - return 1; + return NVRAM_ERR_INV_PARAM; if (!nvram_buf[0]) early_nvram_init(); @@ -89,6 +89,6 @@ int nvram_getenv(char *name, char *val, size_t val_len) return 0; } } - return 1; + return NVRAM_ERR_ENVNOTFOUND; } EXPORT_SYMBOL(nvram_getenv); diff --git a/arch/mips/include/asm/mach-bcm47xx/nvram.h b/arch/mips/include/asm/mach-bcm47xx/nvram.h index 0d8cc146f7a..c58ebd8bc15 100644 --- a/arch/mips/include/asm/mach-bcm47xx/nvram.h +++ b/arch/mips/include/asm/mach-bcm47xx/nvram.h @@ -31,6 +31,9 @@ struct nvram_header { #define NVRAM_MAX_VALUE_LEN 255 #define NVRAM_MAX_PARAM_LEN 64 +#define NVRAM_ERR_INV_PARAM -8 +#define NVRAM_ERR_ENVNOTFOUND -9 + extern int nvram_getenv(char *name, char *val, size_t val_len); #endif -- cgit v1.2.3-70-g09d2 From 51f1336d4dbd0935d873761f7f267c3f5abc9bd6 Mon Sep 17 00:00:00 2001 From: David VomLehn Date: Mon, 2 Aug 2010 11:44:00 -0700 Subject: MIPS: PowerTV: Add Gaia platform definitions. Define ASIC address, memory preallocations, and initialization code for the Gaia platform. Signed-off-by: David VomLehn To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1519/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-powertv/asic.h | 4 + arch/mips/include/asm/mach-powertv/asic_regs.h | 4 +- arch/mips/powertv/asic/Makefile | 6 +- arch/mips/powertv/asic/asic-gaia.c | 96 ++++ arch/mips/powertv/asic/asic_devices.c | 20 +- arch/mips/powertv/asic/prealloc-gaia.c | 589 +++++++++++++++++++++++++ 6 files changed, 708 insertions(+), 11 deletions(-) create mode 100644 arch/mips/powertv/asic/asic-gaia.c create mode 100644 arch/mips/powertv/asic/prealloc-gaia.c (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-powertv/asic.h b/arch/mips/include/asm/mach-powertv/asic.h index bcad43a93eb..df33d93e4f5 100644 --- a/arch/mips/include/asm/mach-powertv/asic.h +++ b/arch/mips/include/asm/mach-powertv/asic.h @@ -40,19 +40,23 @@ enum family_type { FAMILY_8600VZB, FAMILY_1500VZE, FAMILY_1500VZF, + FAMILY_8700, FAMILIES }; /* Register maps for each ASIC */ extern const struct register_map calliope_register_map; extern const struct register_map cronus_register_map; +extern const struct register_map gaia_register_map; extern const struct register_map zeus_register_map; extern struct resource dvr_cronus_resources[]; +extern struct resource dvr_gaia_resources[]; extern struct resource dvr_zeus_resources[]; extern struct resource non_dvr_calliope_resources[]; extern struct resource non_dvr_cronus_resources[]; extern struct resource non_dvr_cronuslite_resources[]; +extern struct resource non_dvr_gaia_resources[]; extern struct resource non_dvr_vz_calliope_resources[]; extern struct resource non_dvr_vze_calliope_resources[]; extern struct resource non_dvr_vzf_calliope_resources[]; diff --git a/arch/mips/include/asm/mach-powertv/asic_regs.h b/arch/mips/include/asm/mach-powertv/asic_regs.h index 1e11236c6db..2657ae6a7ec 100644 --- a/arch/mips/include/asm/mach-powertv/asic_regs.h +++ b/arch/mips/include/asm/mach-powertv/asic_regs.h @@ -27,7 +27,8 @@ enum asic_type { ASIC_CALLIOPE, ASIC_CRONUS, ASIC_CRONUSLITE, - ASICS + ASIC_GAIA, + ASICS /* Number of supported ASICs */ }; /* hardcoded values read from Chip Version registers */ @@ -37,6 +38,7 @@ enum asic_type { #define NAND_FLASH_BASE 0x03000000 #define CALLIOPE_IO_BASE 0x08000000 +#define GAIA_IO_BASE 0x09000000 #define CRONUS_IO_BASE 0x09000000 #define ZEUS_IO_BASE 0x09000000 diff --git a/arch/mips/powertv/asic/Makefile b/arch/mips/powertv/asic/Makefile index bebfdcff044..f0e95dc0ac9 100644 --- a/arch/mips/powertv/asic/Makefile +++ b/arch/mips/powertv/asic/Makefile @@ -16,8 +16,8 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # -obj-y += asic-calliope.o asic-cronus.o asic-zeus.o asic_devices.o asic_int.o \ - irq_asic.o prealloc-calliope.o prealloc-cronus.o \ - prealloc-cronuslite.o prealloc-zeus.o +obj-y += asic-calliope.o asic-cronus.o asic-gaia.o asic-zeus.o \ + asic_devices.o asic_int.o irq_asic.o prealloc-calliope.o \ + prealloc-cronus.o prealloc-cronuslite.o prealloc-gaia.o prealloc-zeus.o EXTRA_CFLAGS += -Wall -Werror diff --git a/arch/mips/powertv/asic/asic-gaia.c b/arch/mips/powertv/asic/asic-gaia.c new file mode 100644 index 00000000000..91dda682752 --- /dev/null +++ b/arch/mips/powertv/asic/asic-gaia.c @@ -0,0 +1,96 @@ +/* + * Locations of devices in the Gaia ASIC + * + * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: David VomLehn + */ + +#include +#include + +const struct register_map gaia_register_map __initdata = { + .eic_slow0_strt_add = {.phys = GAIA_IO_BASE + 0x000000}, + .eic_cfg_bits = {.phys = GAIA_IO_BASE + 0x000038}, + .eic_ready_status = {.phys = GAIA_IO_BASE + 0x00004C}, + + .chipver3 = {.phys = GAIA_IO_BASE + 0x2A0800}, + .chipver2 = {.phys = GAIA_IO_BASE + 0x2A0804}, + .chipver1 = {.phys = GAIA_IO_BASE + 0x2A0808}, + .chipver0 = {.phys = GAIA_IO_BASE + 0x2A080C}, + + /* The registers of IRBlaster */ + .uart1_intstat = {.phys = GAIA_IO_BASE + 0x2A1800}, + .uart1_inten = {.phys = GAIA_IO_BASE + 0x2A1804}, + .uart1_config1 = {.phys = GAIA_IO_BASE + 0x2A1808}, + .uart1_config2 = {.phys = GAIA_IO_BASE + 0x2A180C}, + .uart1_divisorhi = {.phys = GAIA_IO_BASE + 0x2A1810}, + .uart1_divisorlo = {.phys = GAIA_IO_BASE + 0x2A1814}, + .uart1_data = {.phys = GAIA_IO_BASE + 0x2A1818}, + .uart1_status = {.phys = GAIA_IO_BASE + 0x2A181C}, + + .int_stat_3 = {.phys = GAIA_IO_BASE + 0x2A2800}, + .int_stat_2 = {.phys = GAIA_IO_BASE + 0x2A2804}, + .int_stat_1 = {.phys = GAIA_IO_BASE + 0x2A2808}, + .int_stat_0 = {.phys = GAIA_IO_BASE + 0x2A280C}, + .int_config = {.phys = GAIA_IO_BASE + 0x2A2810}, + .int_int_scan = {.phys = GAIA_IO_BASE + 0x2A2818}, + .ien_int_3 = {.phys = GAIA_IO_BASE + 0x2A2830}, + .ien_int_2 = {.phys = GAIA_IO_BASE + 0x2A2834}, + .ien_int_1 = {.phys = GAIA_IO_BASE + 0x2A2838}, + .ien_int_0 = {.phys = GAIA_IO_BASE + 0x2A283C}, + .int_level_3_3 = {.phys = GAIA_IO_BASE + 0x2A2880}, + .int_level_3_2 = {.phys = GAIA_IO_BASE + 0x2A2884}, + .int_level_3_1 = {.phys = GAIA_IO_BASE + 0x2A2888}, + .int_level_3_0 = {.phys = GAIA_IO_BASE + 0x2A288C}, + .int_level_2_3 = {.phys = GAIA_IO_BASE + 0x2A2890}, + .int_level_2_2 = {.phys = GAIA_IO_BASE + 0x2A2894}, + .int_level_2_1 = {.phys = GAIA_IO_BASE + 0x2A2898}, + .int_level_2_0 = {.phys = GAIA_IO_BASE + 0x2A289C}, + .int_level_1_3 = {.phys = GAIA_IO_BASE + 0x2A28A0}, + .int_level_1_2 = {.phys = GAIA_IO_BASE + 0x2A28A4}, + .int_level_1_1 = {.phys = GAIA_IO_BASE + 0x2A28A8}, + .int_level_1_0 = {.phys = GAIA_IO_BASE + 0x2A28AC}, + .int_level_0_3 = {.phys = GAIA_IO_BASE + 0x2A28B0}, + .int_level_0_2 = {.phys = GAIA_IO_BASE + 0x2A28B4}, + .int_level_0_1 = {.phys = GAIA_IO_BASE + 0x2A28B8}, + .int_level_0_0 = {.phys = GAIA_IO_BASE + 0x2A28BC}, + .int_docsis_en = {.phys = GAIA_IO_BASE + 0x2A28F4}, + + .mips_pll_setup = {.phys = GAIA_IO_BASE + 0x1C0000}, + .fs432x4b4_usb_ctl = {.phys = GAIA_IO_BASE + 0x1C0024}, + .test_bus = {.phys = GAIA_IO_BASE + 0x1C00CC}, + .crt_spare = {.phys = GAIA_IO_BASE + 0x1c0108}, + .usb2_ohci_int_mask = {.phys = GAIA_IO_BASE + 0x20000C}, + .usb2_strap = {.phys = GAIA_IO_BASE + 0x200014}, + .ehci_hcapbase = {.phys = GAIA_IO_BASE + 0x21FE00}, + .ohci_hc_revision = {.phys = GAIA_IO_BASE + 0x21fc00}, + .bcm1_bs_lmi_steer = {.phys = GAIA_IO_BASE + 0x2E0004}, + .usb2_control = {.phys = GAIA_IO_BASE + 0x2E004C}, + .usb2_stbus_obc = {.phys = GAIA_IO_BASE + 0x21FF00}, + .usb2_stbus_mess_size = {.phys = GAIA_IO_BASE + 0x21FF04}, + .usb2_stbus_chunk_size = {.phys = GAIA_IO_BASE + 0x21FF08}, + + .pcie_regs = {.phys = GAIA_IO_BASE + 0x220000}, + .tim_ch = {.phys = GAIA_IO_BASE + 0x2A2C10}, + .tim_cl = {.phys = GAIA_IO_BASE + 0x2A2C14}, + .gpio_dout = {.phys = GAIA_IO_BASE + 0x2A2C20}, + .gpio_din = {.phys = GAIA_IO_BASE + 0x2A2C24}, + .gpio_dir = {.phys = GAIA_IO_BASE + 0x2A2C2C}, + .watchdog = {.phys = GAIA_IO_BASE + 0x2A2C30}, + .front_panel = {.phys = GAIA_IO_BASE + 0x2A3800}, +}; diff --git a/arch/mips/powertv/asic/asic_devices.c b/arch/mips/powertv/asic/asic_devices.c index 006285c3064..095a887df39 100644 --- a/arch/mips/powertv/asic/asic_devices.c +++ b/arch/mips/powertv/asic/asic_devices.c @@ -1,7 +1,6 @@ /* - * ASIC Device List Intialization * - * Description: Defines the platform resources for the SA settop. + * Description: Defines the platform resources for Gaia-based settops. * * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. * @@ -19,11 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * - * Author: Ken Eppinett - * David Schleef - * - * Description: Defines the platform resources for the SA settop. - * * NOTE: The bootloader allocates persistent memory at an address which is * 16 MiB below the end of the highest address in KSEG0. All fixed * address memory reservations must avoid this region. @@ -289,6 +283,9 @@ static __init noinline void platform_set_family(void) case BOOTLDRFAMILY('F', '1'): platform_family = FAMILY_1500VZF; break; + case BOOTLDRFAMILY('8', '7'): + platform_family = FAMILY_8700; + break; default: platform_family = -1; } @@ -526,6 +523,15 @@ void __init configure_platform(void) "DVR_CAPABLE\n"); break; + case FAMILY_8700: + platform_features = FFS_CAPABLE | PCIE_CAPABLE; + asic = ASIC_GAIA; + set_register_map(GAIA_IO_BASE, &gaia_register_map); + gp_resources = dvr_gaia_resources; + + pr_info("Platform: 8700 - GAIA, DVR_CAPABLE\n"); + break; + default: pr_crit("Platform: UNKNOWN PLATFORM\n"); break; diff --git a/arch/mips/powertv/asic/prealloc-gaia.c b/arch/mips/powertv/asic/prealloc-gaia.c new file mode 100644 index 00000000000..8ac8c7aeb98 --- /dev/null +++ b/arch/mips/powertv/asic/prealloc-gaia.c @@ -0,0 +1,589 @@ +/* + * Memory pre-allocations for Gaia boxes. + * + * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: David VomLehn + */ + +#include +#include + +/* + * DVR_CAPABLE GAIA RESOURCES + */ +struct resource dvr_gaia_resources[] __initdata = { + /* + * + * VIDEO1 / LX1 + * + */ + { + .name = "ST231aImage", /* Delta-Mu 1 image and ram */ + .start = 0x24000000, + .end = 0x241FFFFF, /* 2MiB */ + .flags = IORESOURCE_MEM, + }, + { + .name = "ST231aMonitor", /* 8KiB block ST231a monitor */ + .start = 0x24200000, + .end = 0x24201FFF, + .flags = IORESOURCE_MEM, + }, + { + .name = "MediaMemory1", + .start = 0x24202000, + .end = 0x25FFFFFF, /*~29.9MiB (32MiB - (2MiB + 8KiB)) */ + .flags = IORESOURCE_MEM, + }, + /* + * + * VIDEO2 / LX2 + * + */ + { + .name = "ST231bImage", /* Delta-Mu 2 image and ram */ + .start = 0x60000000, + .end = 0x601FFFFF, /* 2MiB */ + .flags = IORESOURCE_IO, + }, + { + .name = "ST231bMonitor", /* 8KiB block ST231b monitor */ + .start = 0x60200000, + .end = 0x60201FFF, + .flags = IORESOURCE_IO, + }, + { + .name = "MediaMemory2", + .start = 0x60202000, + .end = 0x61FFFFFF, /*~29.9MiB (32MiB - (2MiB + 8KiB)) */ + .flags = IORESOURCE_IO, + }, + /* + * + * Sysaudio Driver + * + * This driver requires: + * + * Arbitrary Based Buffers: + * DSP_Image_Buff - DSP code and data images (1MB) + * ADSC_CPU_PCM_Buff - ADSC CPU PCM buffer (40KB) + * ADSC_AUX_Buff - ADSC AUX buffer (16KB) + * ADSC_Main_Buff - ADSC Main buffer (16KB) + * + */ + { + .name = "DSP_Image_Buff", + .start = 0x00000000, + .end = 0x000FFFFF, + .flags = IORESOURCE_MEM, + }, + { + .name = "ADSC_CPU_PCM_Buff", + .start = 0x00000000, + .end = 0x00009FFF, + .flags = IORESOURCE_MEM, + }, + { + .name = "ADSC_AUX_Buff", + .start = 0x00000000, + .end = 0x00003FFF, + .flags = IORESOURCE_MEM, + }, + { + .name = "ADSC_Main_Buff", + .start = 0x00000000, + .end = 0x00003FFF, + .flags = IORESOURCE_MEM, + }, + /* + * + * STAVEM driver/STAPI + * + * This driver requires: + * + * Arbitrary Based Buffers: + * This memory area is used for allocating buffers for Video decoding + * purposes. Allocation/De-allocation within this buffer is managed + * by the STAVMEM driver of the STAPI. They could be Decimated + * Picture Buffers, Intermediate Buffers, as deemed necessary for + * video decoding purposes, for any video decoders on Zeus. + * + */ + { + .name = "AVMEMPartition0", + .start = 0x63580000, + .end = 0x64180000 - 1, /* 12 MB total */ + .flags = IORESOURCE_IO, + }, + /* + * + * DOCSIS Subsystem + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Docsis - + * + */ + { + .name = "Docsis", + .start = 0x62000000, + .end = 0x62700000 - 1, /* 7 MB total */ + .flags = IORESOURCE_IO, + }, + /* + * + * GHW HAL Driver + * + * This driver requires: + * + * Arbitrary Based Buffers: + * GraphicsHeap - PowerTV Graphics Heap + * + */ + { + .name = "GraphicsHeap", + .start = 0x62700000, + .end = 0x63500000 - 1, /* 14 MB total */ + .flags = IORESOURCE_IO, + }, + /* + * + * multi com buffer area + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Docsis - + * + */ + { + .name = "MulticomSHM", + .start = 0x26000000, + .end = 0x26020000 - 1, + .flags = IORESOURCE_MEM, + }, + /* + * + * DMA Ring buffer + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Docsis - + * + */ + { + .name = "BMM_Buffer", + .start = 0x00000000, + .end = 0x00280000 - 1, + .flags = IORESOURCE_MEM, + }, + /* + * + * Display bins buffer for unit0 + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Display Bins for unit0 + * + */ + { + .name = "DisplayBins0", + .start = 0x00000000, + .end = 0x00000FFF, /* 4 KB total */ + .flags = IORESOURCE_MEM, + }, + /* + * + * Display bins buffer + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Display Bins for unit1 + * + */ + { + .name = "DisplayBins1", + .start = 0x64AD4000, + .end = 0x64AD5000 - 1, /* 4 KB total */ + .flags = IORESOURCE_IO, + }, + /* + * + * ITFS + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Docsis - + * + */ + { + .name = "ITFS", + .start = 0x64180000, + /* 815,104 bytes each for 2 ITFS partitions. */ + .end = 0x6430DFFF, + .flags = IORESOURCE_IO, + }, + /* + * + * AVFS + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Docsis - + * + */ + { + .name = "AvfsDmaMem", + .start = 0x6430E000, + /* (945K * 8) = (128K *3) 5 playbacks / 3 server */ + .end = 0x64AD0000 - 1, + .flags = IORESOURCE_IO, + }, + { + .name = "AvfsFileSys", + .start = 0x64AD0000, + .end = 0x64AD1000 - 1, /* 4K */ + .flags = IORESOURCE_IO, + }, + /* + * + * Smartcard + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Read and write buffers for Internal/External cards + * + */ + { + .name = "SmartCardInfo", + .start = 0x64AD1000, + .end = 0x64AD3800 - 1, + .flags = IORESOURCE_IO, + }, + /* + * + * KAVNET + * NP Reset Vector - must be of the form xxCxxxxx + * NP Image - must be video bank 1 + * NP IPC - must be video bank 2 + */ + { + .name = "NP_Reset_Vector", + .start = 0x27c00000, + .end = 0x27c01000 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "NP_Image", + .start = 0x27020000, + .end = 0x27060000 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "NP_IPC", + .start = 0x63500000, + .end = 0x63580000 - 1, + .flags = IORESOURCE_IO, + }, + /* + * Add other resources here + */ + { }, +}; + +/* + * NON_DVR_CAPABLE GAIA RESOURCES + */ +struct resource non_dvr_gaia_resources[] __initdata = { + /* + * + * VIDEO1 / LX1 + * + */ + { + .name = "ST231aImage", /* Delta-Mu 1 image and ram */ + .start = 0x24000000, + .end = 0x241FFFFF, /* 2MiB */ + .flags = IORESOURCE_MEM, + }, + { + .name = "ST231aMonitor", /* 8KiB block ST231a monitor */ + .start = 0x24200000, + .end = 0x24201FFF, + .flags = IORESOURCE_MEM, + }, + { + .name = "MediaMemory1", + .start = 0x24202000, + .end = 0x25FFFFFF, /*~29.9MiB (32MiB - (2MiB + 8KiB)) */ + .flags = IORESOURCE_MEM, + }, + /* + * + * VIDEO2 / LX2 + * + */ + { + .name = "ST231bImage", /* Delta-Mu 2 image and ram */ + .start = 0x60000000, + .end = 0x601FFFFF, /* 2MiB */ + .flags = IORESOURCE_IO, + }, + { + .name = "ST231bMonitor", /* 8KiB block ST231b monitor */ + .start = 0x60200000, + .end = 0x60201FFF, + .flags = IORESOURCE_IO, + }, + { + .name = "MediaMemory2", + .start = 0x60202000, + .end = 0x61FFFFFF, /*~29.9MiB (32MiB - (2MiB + 8KiB)) */ + .flags = IORESOURCE_IO, + }, + /* + * + * Sysaudio Driver + * + * This driver requires: + * + * Arbitrary Based Buffers: + * DSP_Image_Buff - DSP code and data images (1MB) + * ADSC_CPU_PCM_Buff - ADSC CPU PCM buffer (40KB) + * ADSC_AUX_Buff - ADSC AUX buffer (16KB) + * ADSC_Main_Buff - ADSC Main buffer (16KB) + * + */ + { + .name = "DSP_Image_Buff", + .start = 0x00000000, + .end = 0x000FFFFF, + .flags = IORESOURCE_MEM, + }, + { + .name = "ADSC_CPU_PCM_Buff", + .start = 0x00000000, + .end = 0x00009FFF, + .flags = IORESOURCE_MEM, + }, + { + .name = "ADSC_AUX_Buff", + .start = 0x00000000, + .end = 0x00003FFF, + .flags = IORESOURCE_MEM, + }, + { + .name = "ADSC_Main_Buff", + .start = 0x00000000, + .end = 0x00003FFF, + .flags = IORESOURCE_MEM, + }, + /* + * + * STAVEM driver/STAPI + * + * This driver requires: + * + * Arbitrary Based Buffers: + * This memory area is used for allocating buffers for Video decoding + * purposes. Allocation/De-allocation within this buffer is managed + * by the STAVMEM driver of the STAPI. They could be Decimated + * Picture Buffers, Intermediate Buffers, as deemed necessary for + * video decoding purposes, for any video decoders on Zeus. + * + */ + { + .name = "AVMEMPartition0", + .start = 0x63580000, + .end = 0x64180000 - 1, /* 12 MB total */ + .flags = IORESOURCE_IO, + }, + /* + * + * DOCSIS Subsystem + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Docsis - + * + */ + { + .name = "Docsis", + .start = 0x62000000, + .end = 0x62700000 - 1, /* 7 MB total */ + .flags = IORESOURCE_IO, + }, + /* + * + * GHW HAL Driver + * + * This driver requires: + * + * Arbitrary Based Buffers: + * GraphicsHeap - PowerTV Graphics Heap + * + */ + { + .name = "GraphicsHeap", + .start = 0x62700000, + .end = 0x63500000 - 1, /* 14 MB total */ + .flags = IORESOURCE_IO, + }, + /* + * + * multi com buffer area + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Docsis - + * + */ + { + .name = "MulticomSHM", + .start = 0x26000000, + .end = 0x26020000 - 1, + .flags = IORESOURCE_MEM, + }, + /* + * + * DMA Ring buffer + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Docsis - + * + */ + { + .name = "BMM_Buffer", + .start = 0x00000000, + .end = 0x000AA000 - 1, + .flags = IORESOURCE_MEM, + }, + /* + * + * Display bins buffer for unit0 + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Display Bins for unit0 + * + */ + { + .name = "DisplayBins0", + .start = 0x00000000, + .end = 0x00000FFF, /* 4 KB total */ + .flags = IORESOURCE_MEM, + }, + /* + * + * Display bins buffer + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Display Bins for unit1 + * + */ + { + .name = "DisplayBins1", + .start = 0x64AD4000, + .end = 0x64AD5000 - 1, /* 4 KB total */ + .flags = IORESOURCE_IO, + }, + /* + * + * AVFS: player HAL memory + * + * + */ + { + .name = "AvfsDmaMem", + .start = 0x6430E000, + .end = 0x645D2C00 - 1, /* 945K * 3 for playback */ + .flags = IORESOURCE_IO, + }, + /* + * + * PMEM + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Persistent memory for diagnostics. + * + */ + { + .name = "DiagPersistentMemory", + .start = 0x00000000, + .end = 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, + /* + * + * Smartcard + * + * This driver requires: + * + * Arbitrary Based Buffers: + * Read and write buffers for Internal/External cards + * + */ + { + .name = "SmartCardInfo", + .start = 0x64AD1000, + .end = 0x64AD3800 - 1, + .flags = IORESOURCE_IO, + }, + /* + * + * KAVNET + * NP Reset Vector - must be of the form xxCxxxxx + * NP Image - must be video bank 1 + * NP IPC - must be video bank 2 + */ + { + .name = "NP_Reset_Vector", + .start = 0x27c00000, + .end = 0x27c01000 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "NP_Image", + .start = 0x27020000, + .end = 0x27060000 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "NP_IPC", + .start = 0x63500000, + .end = 0x63580000 - 1, + .flags = IORESOURCE_IO, + }, + { }, +}; -- cgit v1.2.3-70-g09d2 From 0d365753d0b7c26043fdfa97790411606fb40112 Mon Sep 17 00:00:00 2001 From: David VomLehn Date: Mon, 2 Aug 2010 18:40:58 -0700 Subject: MIPS: PowerTV: Separate PowerTV USB support from non-USB code Separate USB code into a file separate from asic/asic_devices. Separating the USB code from everything else in asic/asic_devices.c goes a long way toward reducing the use of that file as a dumping ground for everything that didn't seem to fit anywhere else. Signed-off-by: David VomLehn To: linux-mips@linux-mips.org Cc: greg@kroah.com Cc: linux-usb@vger.kernel.org Patchwork: http://patchwork.linux-mips.org/patch/1522/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-powertv/asic.h | 17 +- arch/mips/include/asm/mach-powertv/asic_regs.h | 1 + arch/mips/powertv/Makefile | 2 + arch/mips/powertv/asic/asic_devices.c | 238 +-------------- arch/mips/powertv/powertv-usb.c | 403 +++++++++++++++++++++++++ 5 files changed, 432 insertions(+), 229 deletions(-) create mode 100644 arch/mips/powertv/powertv-usb.c (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/mach-powertv/asic.h b/arch/mips/include/asm/mach-powertv/asic.h index df33d93e4f5..c7077a64b9a 100644 --- a/arch/mips/include/asm/mach-powertv/asic.h +++ b/arch/mips/include/asm/mach-powertv/asic.h @@ -20,6 +20,7 @@ #define _ASM_MACH_POWERTV_ASIC_H #include +#include #include #define DVR_CAPABLE (1<<0) @@ -71,16 +72,24 @@ extern int platform_supports_ffs(void); extern int platform_supports_pcie(void); extern int platform_supports_display(void); extern void configure_platform(void); -extern void platform_configure_usb_ehci(void); -extern void platform_unconfigure_usb_ehci(void); -extern void platform_configure_usb_ohci(void); -extern void platform_unconfigure_usb_ohci(void); /* Platform Resources */ #define ASIC_RESOURCE_GET_EXISTS 1 extern struct resource *asic_resource_get(const char *name); extern void platform_release_memory(void *baddr, int size); +/* USB configuration */ +struct usb_hcd; /* Forward reference */ +extern void platform_configure_usb_ehci(void); +extern void platform_unconfigure_usb_ehci(void); +extern void platform_configure_usb_ohci(void); +extern void platform_unconfigure_usb_ohci(void); + +/* Resource for ASIC registers */ +extern struct resource asic_resource; +extern int platform_usb_devices_init(struct platform_device **echi_dev, + struct platform_device **ohci_dev); + /* Reboot Cause */ extern void set_reboot_cause(char code, unsigned int data, unsigned int data2); extern void set_locked_reboot_cause(char code, unsigned int data, diff --git a/arch/mips/include/asm/mach-powertv/asic_regs.h b/arch/mips/include/asm/mach-powertv/asic_regs.h index 2657ae6a7ec..deecb26a077 100644 --- a/arch/mips/include/asm/mach-powertv/asic_regs.h +++ b/arch/mips/include/asm/mach-powertv/asic_regs.h @@ -101,6 +101,7 @@ static inline void register_map_virtualize(struct register_map *map) } extern struct register_map _asic_register_map; +extern unsigned long asic_phy_base; /* * Macros to interface to registers through their ioremapped address diff --git a/arch/mips/powertv/Makefile b/arch/mips/powertv/Makefile index 506c4ca9d44..baf6e9092a9 100644 --- a/arch/mips/powertv/Makefile +++ b/arch/mips/powertv/Makefile @@ -26,4 +26,6 @@ obj-y += init.o ioremap.o memory.o powertv_setup.o reset.o time.o \ asic/ pci/ +obj-$(CONFIG_USB) += powertv-usb.o + EXTRA_CFLAGS += -Wall diff --git a/arch/mips/powertv/asic/asic_devices.c b/arch/mips/powertv/asic/asic_devices.c index 095a887df39..e56fa61b399 100644 --- a/arch/mips/powertv/asic/asic_devices.c +++ b/arch/mips/powertv/asic/asic_devices.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -68,7 +67,6 @@ unsigned long asic_phy_base; unsigned long asic_base; EXPORT_SYMBOL(asic_base); /* Exported for testing */ struct resource *gp_resources; -static bool usb_configured; /* * Don't recommend to use it directly, it is usually used by kernel internally. @@ -90,102 +88,20 @@ struct resource asic_resource = { .flags = IORESOURCE_MEM, }; -/* - * - * USB Host Resource Definition - * - */ - -static struct resource ehci_resources[] = { - { - .parent = &asic_resource, - .start = 0, - .end = 0xff, - .flags = IORESOURCE_MEM, - }, - { - .start = irq_usbehci, - .end = irq_usbehci, - .flags = IORESOURCE_IRQ, - }, -}; - -static u64 ehci_dmamask = DMA_BIT_MASK(32); - -static struct platform_device ehci_device = { - .name = "powertv-ehci", - .id = 0, - .num_resources = 2, - .resource = ehci_resources, - .dev = { - .dma_mask = &ehci_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; - -static struct resource ohci_resources[] = { - { - .parent = &asic_resource, - .start = 0, - .end = 0xff, - .flags = IORESOURCE_MEM, - }, - { - .start = irq_usbohci, - .end = irq_usbohci, - .flags = IORESOURCE_IRQ, - }, -}; - -static u64 ohci_dmamask = DMA_BIT_MASK(32); - -static struct platform_device ohci_device = { - .name = "powertv-ohci", - .id = 0, - .num_resources = 2, - .resource = ohci_resources, - .dev = { - .dma_mask = &ohci_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; - -static struct platform_device *platform_devices[] = { - &ehci_device, - &ohci_device, -}; - -/* - * - * Platform Configuration and Device Initialization - * - */ -static void __init fs_update(int pe, int md, int sdiv, int disable_div_by_3) -{ - int en_prg, byp, pwr, nsb, val; - int sout; - - sout = 1; - en_prg = 1; - byp = 0; - nsb = 1; - pwr = 1; - - val = ((sdiv << 29) | (md << 24) | (pe<<8) | (sout<<3) | (byp<<2) | - (nsb<<1) | (disable_div_by_3<<5)); - - asic_write(val, fs432x4b4_usb_ctl); - asic_write(val | (en_prg<<4), fs432x4b4_usb_ctl); - asic_write(val | (en_prg<<4) | pwr, fs432x4b4_usb_ctl); -} - /* * Allow override of bootloader-specified model + * Returns zero on success, a negative errno value on failure. This parameter + * allows overriding of the bootloader-specified model. */ static char __initdata cmdline[COMMAND_LINE_SIZE]; #define FORCEFAMILY_PARAM "forcefamily" +/* + * check_forcefamily - check for, and parse, forcefamily command line parameter + * @forced_family: Pointer to two-character array in which to store the + * value of the forcedfamily parameter, if any. + */ static __init int check_forcefamily(unsigned char forced_family[2]) { const char *p; @@ -225,14 +141,10 @@ static __init int check_forcefamily(unsigned char forced_family[2]) */ static __init noinline void platform_set_family(void) { -#define BOOTLDRFAMILY(byte1, byte0) (((byte1) << 8) | (byte0)) - unsigned char forced_family[2]; unsigned short bootldr_family; - check_forcefamily(forced_family); - - if (forced_family[0] != '\0' && forced_family[1] != '\0') + if (check_forcefamily(forced_family) == 0) bootldr_family = BOOTLDRFAMILY(forced_family[0], forced_family[1]); else { @@ -297,25 +209,10 @@ unsigned int platform_get_family(void) } EXPORT_SYMBOL(platform_get_family); -/* - * \brief usb_eye_configure() for optimizing the USB eye on Calliope. - * - * \param unsigned int value saved to the register. - * - * \return none - * - */ -static void __init usb_eye_configure(unsigned int value) -{ - asic_write(asic_read(crt_spare) | value, crt_spare); -} - /* * platform_get_asic - determine the ASIC type. * - * \param none - * - * \return ASIC type; ASIC_UNKNOWN if none + * Returns the ASIC type, or ASIC_UNKNOWN if unknown * */ enum asic_type platform_get_asic(void) @@ -325,93 +222,10 @@ enum asic_type platform_get_asic(void) EXPORT_SYMBOL(platform_get_asic); /* - * platform_configure_usb - usb configuration based on platform type. - * @bcm1_usb2_ctl: value for the BCM1_USB2_CTL register, which is - * quirky - */ -static void __init platform_configure_usb(void) -{ - u32 bcm1_usb2_ctl; - - if (usb_configured) - return; - - switch (asic) { - case ASIC_ZEUS: - case ASIC_CRONUS: - case ASIC_CRONUSLITE: - fs_update(0x0000, 0x11, 0x02, 0); - bcm1_usb2_ctl = 0x803; - break; - - case ASIC_CALLIOPE: - fs_update(0x0000, 0x11, 0x02, 1); - - switch (platform_family) { - case FAMILY_1500VZE: - break; - - case FAMILY_1500VZF: - usb_eye_configure(0x003c0000); - break; - - default: - usb_eye_configure(0x00300000); - break; - } - - bcm1_usb2_ctl = 0x803; - break; - - default: - pr_err("Unknown ASIC type: %d\n", asic); - break; - } - - /* turn on USB power */ - asic_write(0, usb2_strap); - /* Enable all OHCI interrupts */ - asic_write(bcm1_usb2_ctl, usb2_control); - /* USB2_STBUS_OBC store32/load32 */ - asic_write(3, usb2_stbus_obc); - /* USB2_STBUS_MESS_SIZE 2 packets */ - asic_write(1, usb2_stbus_mess_size); - /* USB2_STBUS_CHUNK_SIZE 2 packets */ - asic_write(1, usb2_stbus_chunk_size); - - usb_configured = true; -} - -/* - * Set up the USB EHCI interface - */ -void platform_configure_usb_ehci() -{ - platform_configure_usb(); -} - -/* - * Set up the USB OHCI interface - */ -void platform_configure_usb_ohci() -{ - platform_configure_usb(); -} - -/* - * Shut the USB EHCI interface down--currently a NOP + * set_register_map - set ASIC register configuration + * @phys_base: Physical address of the base of the ASIC registers + * @map: Description of key ASIC registers */ -void platform_unconfigure_usb_ehci() -{ -} - -/* - * Shut the USB OHCI interface down--currently a NOP - */ -void platform_unconfigure_usb_ohci() -{ -} - static void __init set_register_map(unsigned long phys_base, const struct register_map *map) { @@ -560,34 +374,8 @@ void __init configure_platform(void) } } -/** - * platform_devices_init - sets up USB device resourse. - */ -static int __init platform_devices_init(void) -{ - pr_notice("%s: ----- Initializing USB resources -----\n", __func__); - - asic_resource.start = asic_phy_base; - asic_resource.end += asic_resource.start; - - ehci_resources[0].start = asic_reg_phys_addr(ehci_hcapbase); - ehci_resources[0].end += ehci_resources[0].start; - - ohci_resources[0].start = asic_reg_phys_addr(ohci_hc_revision); - ohci_resources[0].end += ohci_resources[0].start; - - set_io_port_base(0); - - platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); - - return 0; -} - -arch_initcall(platform_devices_init); - /* - * - * BOOTMEM ALLOCATION + * RESOURCE ALLOCATION * */ /* diff --git a/arch/mips/powertv/powertv-usb.c b/arch/mips/powertv/powertv-usb.c new file mode 100644 index 00000000000..6ac85cf7aa2 --- /dev/null +++ b/arch/mips/powertv/powertv-usb.c @@ -0,0 +1,403 @@ +/* + * powertv-usb.c + * + * Description: ASIC-specific USB device setup and shutdown + * + * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. + * Copyright (C) 2009 Cisco Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Ken Eppinett + * David Schleef + * + * NOTE: The bootloader allocates persistent memory at an address which is + * 16 MiB below the end of the highest address in KSEG0. All fixed + * address memory reservations must avoid this region. + */ + +#include +#include +#include +#include +#include + +/* misc_clk_ctl1 values */ +#define MCC1_30MHZ_POWERUP_SELECT (1 << 14) +#define MCC1_DIV9 (1 << 13) +#define MCC1_ETHMIPS_POWERUP_SELECT (1 << 11) +#define MCC1_USB_POWERUP_SELECT (1 << 1) +#define MCC1_CLOCK108_POWERUP_SELECT (1 << 0) + +/* Possible values for clock select */ +#define MCC1_USB_CLOCK_HIGH_Z (0 << 4) +#define MCC1_USB_CLOCK_48MHZ (1 << 4) +#define MCC1_USB_CLOCK_24MHZ (2 << 4) +#define MCC1_USB_CLOCK_6MHZ (3 << 4) + +#define MCC1_CONFIG (MCC1_30MHZ_POWERUP_SELECT | \ + MCC1_DIV9 | \ + MCC1_ETHMIPS_POWERUP_SELECT | \ + MCC1_USB_POWERUP_SELECT | \ + MCC1_CLOCK108_POWERUP_SELECT) + +/* misc_clk_ctl2 values */ +#define MCC2_GMII_GCLK_TO_PAD (1 << 31) +#define MCC2_ETHER125_0_CLOCK_SELECT (1 << 29) +#define MCC2_RMII_0_CLOCK_SELECT (1 << 28) +#define MCC2_GMII_TX0_CLOCK_SELECT (1 << 27) +#define MCC2_GMII_RX0_CLOCK_SELECT (1 << 26) +#define MCC2_ETHER125_1_CLOCK_SELECT (1 << 24) +#define MCC2_RMII_1_CLOCK_SELECT (1 << 23) +#define MCC2_GMII_TX1_CLOCK_SELECT (1 << 22) +#define MCC2_GMII_RX1_CLOCK_SELECT (1 << 21) +#define MCC2_ETHER125_2_CLOCK_SELECT (1 << 19) +#define MCC2_RMII_2_CLOCK_SELECT (1 << 18) +#define MCC2_GMII_TX2_CLOCK_SELECT (1 << 17) +#define MCC2_GMII_RX2_CLOCK_SELECT (1 << 16) + +#define ETHER_CLK_CONFIG (MCC2_GMII_GCLK_TO_PAD | \ + MCC2_ETHER125_0_CLOCK_SELECT | \ + MCC2_RMII_0_CLOCK_SELECT | \ + MCC2_GMII_TX0_CLOCK_SELECT | \ + MCC2_GMII_RX0_CLOCK_SELECT | \ + MCC2_ETHER125_1_CLOCK_SELECT | \ + MCC2_RMII_1_CLOCK_SELECT | \ + MCC2_GMII_TX1_CLOCK_SELECT | \ + MCC2_GMII_RX1_CLOCK_SELECT | \ + MCC2_ETHER125_2_CLOCK_SELECT | \ + MCC2_RMII_2_CLOCK_SELECT | \ + MCC2_GMII_TX2_CLOCK_SELECT | \ + MCC2_GMII_RX2_CLOCK_SELECT) + +/* misc_clk_ctl2 definitions for Gaia */ +#define FSX4A_REF_SELECT (1 << 16) +#define FSX4B_REF_SELECT (1 << 17) +#define FSX4C_REF_SELECT (1 << 18) +#define DDR_PLL_REF_SELECT (1 << 19) +#define MIPS_PLL_REF_SELECT (1 << 20) + +/* Definitions for the QAM frequency select register FS432X4A4_QAM_CTL */ +#define QAM_FS_SDIV_SHIFT 29 +#define QAM_FS_MD_SHIFT 24 +#define QAM_FS_MD_MASK 0x1f /* Cut down to 5 bits */ +#define QAM_FS_PE_SHIFT 8 + +#define QAM_FS_DISABLE_DIVIDE_BY_3 (1 << 5) +#define QAM_FS_ENABLE_PROGRAM (1 << 4) +#define QAM_FS_ENABLE_OUTPUT (1 << 3) +#define QAM_FS_SELECT_TEST_BYPASS (1 << 2) +#define QAM_FS_DISABLE_DIGITAL_STANDBY (1 << 1) +#define QAM_FS_CHOOSE_FS (1 << 0) + +/* Definitions for fs432x4a_ctl register */ +#define QAM_FS_NSDIV_54MHZ (1 << 2) + +/* Definitions for bcm1_usb2_ctl register */ +#define BCM1_USB2_CTL_BISTOK (1 << 11) +#define BCM1_USB2_CTL_PORT2_SHIFT_JK (1 << 7) +#define BCM1_USB2_CTL_PORT1_SHIFT_JK (1 << 6) +#define BCM1_USB2_CTL_PORT2_FAST_EDGE (1 << 5) +#define BCM1_USB2_CTL_PORT1_FAST_EDGE (1 << 4) +#define BCM1_USB2_CTL_EHCI_PRT_PWR_ACTIVE_HIGH (1 << 1) +#define BCM1_USB2_CTL_APP_PRT_OVRCUR_IN_ACTIVE_HIGH (1 << 0) + +/* Definitions for crt_spare register */ +#define CRT_SPARE_PORT2_SHIFT_JK (1 << 21) +#define CRT_SPARE_PORT1_SHIFT_JK (1 << 20) +#define CRT_SPARE_PORT2_FAST_EDGE (1 << 19) +#define CRT_SPARE_PORT1_FAST_EDGE (1 << 18) +#define CRT_SPARE_DIVIDE_BY_9_FROM_432 (1 << 17) +#define CRT_SPARE_USB_DIVIDE_BY_9 (1 << 16) + +/* Definitions for usb2_stbus_obc register */ +#define USB_STBUS_OBC_STORE32_LOAD32 0x3 + +/* Definitions for usb2_stbus_mess_size register */ +#define USB2_STBUS_MESS_SIZE_2 0x1 /* 2 packets */ + +/* Definitions for usb2_stbus_chunk_size register */ +#define USB2_STBUS_CHUNK_SIZE_2 0x1 /* 2 packets */ + +/* Definitions for usb2_strap register */ +#define USB2_STRAP_HFREQ_SELECT 0x1 + +/* + * USB Host Resource Definition + */ + +static struct resource ehci_resources[] = { + { + .parent = &asic_resource, + .start = 0, + .end = 0xff, + .flags = IORESOURCE_MEM, + }, + { + .start = irq_usbehci, + .end = irq_usbehci, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 ehci_dmamask = 0xffffffffULL; + +static struct platform_device ehci_device = { + .name = "powertv-ehci", + .id = 0, + .num_resources = 2, + .resource = ehci_resources, + .dev = { + .dma_mask = &ehci_dmamask, + .coherent_dma_mask = 0xffffffff, + }, +}; + +static struct resource ohci_resources[] = { + { + .parent = &asic_resource, + .start = 0, + .end = 0xff, + .flags = IORESOURCE_MEM, + }, + { + .start = irq_usbohci, + .end = irq_usbohci, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 ohci_dmamask = 0xffffffffULL; + +static struct platform_device ohci_device = { + .name = "powertv-ohci", + .id = 0, + .num_resources = 2, + .resource = ohci_resources, + .dev = { + .dma_mask = &ohci_dmamask, + .coherent_dma_mask = 0xffffffff, + }, +}; + +static unsigned usb_users; +static DEFINE_SPINLOCK(usb_regs_lock); + +/* + * + * fs_update - set frequency synthesizer for USB + * @pe_bits Phase tap setting + * @md_bits Coarse selector bus for algorithm of phase tap + * @sdiv_bits Output divider setting + * @disable_div_by_3 Either QAM_FS_DISABLE_DIVIDE_BY_3 or zero + * @standby Either QAM_FS_DISABLE_DIGITAL_STANDBY or zero + * + * QAM frequency selection code, which affects the frequency at which USB + * runs. The frequency is calculated as: + * 2^15 * ndiv * Fin + * Fout = ------------------------------------------------------------ + * (sdiv * (ipe * (1 + md/32) - (ipe - 2^15)*(1 + (md + 1)/32))) + * where: + * Fin 54 MHz + * ndiv QAM_FS_NSDIV_54MHZ ? 8 : 16 + * sdiv 1 << (sdiv_bits + 1) + * ipe Same as pe_bits + * md A five-bit, two's-complement integer (range [-16, 15]), which + * is the lower 5 bits of md_bits. + */ +static void fs_update(u32 pe_bits, int md_bits, u32 sdiv_bits, + u32 disable_div_by_3, u32 standby) +{ + u32 val; + + val = ((sdiv_bits << QAM_FS_SDIV_SHIFT) | + ((md_bits & QAM_FS_MD_MASK) << QAM_FS_MD_SHIFT) | + (pe_bits << QAM_FS_PE_SHIFT) | + QAM_FS_ENABLE_OUTPUT | + standby | + disable_div_by_3); + asic_write(val, fs432x4b4_usb_ctl); + asic_write(val | QAM_FS_ENABLE_PROGRAM, fs432x4b4_usb_ctl); + asic_write(val | QAM_FS_ENABLE_PROGRAM | QAM_FS_CHOOSE_FS, + fs432x4b4_usb_ctl); +} + +/* + * usb_eye_configure - for optimizing the shape USB eye waveform + * @set: Bits to set in the register + * @clear: Bits to clear in the register; each bit with a one will + * be set in the register, zero bits will not be modified + */ +static void usb_eye_configure(u32 set, u32 clear) +{ + u32 old; + + old = asic_read(crt_spare); + old |= set; + old &= ~clear; + asic_write(old, crt_spare); +} + +/* + * platform_configure_usb - usb configuration based on platform type. + */ +static void platform_configure_usb(void) +{ + u32 bcm1_usb2_ctl_value; + enum asic_type asic_type; + unsigned long flags; + + spin_lock_irqsave(&usb_regs_lock, flags); + usb_users++; + + if (usb_users != 1) { + spin_unlock_irqrestore(&usb_regs_lock, flags); + return; + } + + asic_type = platform_get_asic(); + + switch (asic_type) { + case ASIC_ZEUS: + fs_update(0x0000, -15, 0x02, 0, 0); + bcm1_usb2_ctl_value = BCM1_USB2_CTL_EHCI_PRT_PWR_ACTIVE_HIGH | + BCM1_USB2_CTL_APP_PRT_OVRCUR_IN_ACTIVE_HIGH; + break; + + case ASIC_CRONUS: + case ASIC_CRONUSLITE: + usb_eye_configure(0, CRT_SPARE_USB_DIVIDE_BY_9); + fs_update(0x8000, -14, 0x03, QAM_FS_DISABLE_DIVIDE_BY_3, + QAM_FS_DISABLE_DIGITAL_STANDBY); + bcm1_usb2_ctl_value = BCM1_USB2_CTL_EHCI_PRT_PWR_ACTIVE_HIGH | + BCM1_USB2_CTL_APP_PRT_OVRCUR_IN_ACTIVE_HIGH; + break; + + case ASIC_CALLIOPE: + fs_update(0x0000, -15, 0x02, QAM_FS_DISABLE_DIVIDE_BY_3, + QAM_FS_DISABLE_DIGITAL_STANDBY); + + switch (platform_get_family()) { + case FAMILY_1500VZE: + break; + + case FAMILY_1500VZF: + usb_eye_configure(CRT_SPARE_PORT2_SHIFT_JK | + CRT_SPARE_PORT1_SHIFT_JK | + CRT_SPARE_PORT2_FAST_EDGE | + CRT_SPARE_PORT1_FAST_EDGE, 0); + break; + + default: + usb_eye_configure(CRT_SPARE_PORT2_SHIFT_JK | + CRT_SPARE_PORT1_SHIFT_JK, 0); + break; + } + + bcm1_usb2_ctl_value = BCM1_USB2_CTL_BISTOK | + BCM1_USB2_CTL_EHCI_PRT_PWR_ACTIVE_HIGH | + BCM1_USB2_CTL_APP_PRT_OVRCUR_IN_ACTIVE_HIGH; + break; + + case ASIC_GAIA: + fs_update(0x8000, -14, 0x03, QAM_FS_DISABLE_DIVIDE_BY_3, + QAM_FS_DISABLE_DIGITAL_STANDBY); + bcm1_usb2_ctl_value = BCM1_USB2_CTL_BISTOK | + BCM1_USB2_CTL_EHCI_PRT_PWR_ACTIVE_HIGH | + BCM1_USB2_CTL_APP_PRT_OVRCUR_IN_ACTIVE_HIGH; + break; + + default: + pr_err("Unknown ASIC type: %d\n", asic_type); + bcm1_usb2_ctl_value = 0; + break; + } + + /* turn on USB power */ + asic_write(0, usb2_strap); + /* Enable all OHCI interrupts */ + asic_write(bcm1_usb2_ctl_value, usb2_control); + /* usb2_stbus_obc store32/load32 */ + asic_write(USB_STBUS_OBC_STORE32_LOAD32, usb2_stbus_obc); + /* usb2_stbus_mess_size 2 packets */ + asic_write(USB2_STBUS_MESS_SIZE_2, usb2_stbus_mess_size); + /* usb2_stbus_chunk_size 2 packets */ + asic_write(USB2_STBUS_CHUNK_SIZE_2, usb2_stbus_chunk_size); + spin_unlock_irqrestore(&usb_regs_lock, flags); +} + +static void platform_unconfigure_usb(void) +{ + unsigned long flags; + + spin_lock_irqsave(&usb_regs_lock, flags); + usb_users--; + if (usb_users == 0) + asic_write(USB2_STRAP_HFREQ_SELECT, usb2_strap); + spin_unlock_irqrestore(&usb_regs_lock, flags); +} + +/* + * Set up the USB EHCI interface + */ +void platform_configure_usb_ehci() +{ + platform_configure_usb(); +} +EXPORT_SYMBOL(platform_configure_usb_ehci); + +/* + * Set up the USB OHCI interface + */ +void platform_configure_usb_ohci() +{ + platform_configure_usb(); +} +EXPORT_SYMBOL(platform_configure_usb_ohci); + +/* + * Shut the USB EHCI interface down + */ +void platform_unconfigure_usb_ehci() +{ + platform_unconfigure_usb(); +} +EXPORT_SYMBOL(platform_unconfigure_usb_ehci); + +/* + * Shut the USB OHCI interface down + */ +void platform_unconfigure_usb_ohci() +{ + platform_unconfigure_usb(); +} +EXPORT_SYMBOL(platform_unconfigure_usb_ohci); + +/** + * platform_devices_init - sets up USB device resourse. + */ +int __init platform_usb_devices_init(struct platform_device **ehci_dev, + struct platform_device **ohci_dev) +{ + *ehci_dev = &ehci_device; + ehci_resources[0].start = asic_reg_phys_addr(ehci_hcapbase); + ehci_resources[0].end += ehci_resources[0].start; + + *ohci_dev = &ohci_device; + ohci_resources[0].start = asic_reg_phys_addr(ohci_hc_revision); + ohci_resources[0].end += ohci_resources[0].start; + + return 0; +} -- cgit v1.2.3-70-g09d2 From 0896a9becdea36b2da21709b5e73ba47ae6481ea Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 5 Aug 2010 09:22:21 -0500 Subject: kgdb,mips: Individual register get/set for mips Implement the ability to individually get and set registers for kdb and kgdb for mips. Signed-off-by: Jason Wessel Acked-by: Ralf Baechle CC: linux-mips@linux-mips.org --- arch/mips/include/asm/kgdb.h | 19 ++-- arch/mips/kernel/kgdb.c | 203 ++++++++++++++++++++++++++++++------------- 2 files changed, 154 insertions(+), 68 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/kgdb.h b/arch/mips/include/asm/kgdb.h index 19002d605ac..e6c0b0e14cc 100644 --- a/arch/mips/include/asm/kgdb.h +++ b/arch/mips/include/asm/kgdb.h @@ -8,28 +8,27 @@ #if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) || \ (_MIPS_ISA == _MIPS_ISA_MIPS32) -#define KGDB_GDB_REG_SIZE 32 +#define KGDB_GDB_REG_SIZE 32 +#define GDB_SIZEOF_REG sizeof(u32) #elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ (_MIPS_ISA == _MIPS_ISA_MIPS64) #ifdef CONFIG_32BIT -#define KGDB_GDB_REG_SIZE 32 +#define KGDB_GDB_REG_SIZE 32 +#define GDB_SIZEOF_REG sizeof(u32) #else /* CONFIG_CPU_32BIT */ -#define KGDB_GDB_REG_SIZE 64 +#define KGDB_GDB_REG_SIZE 64 +#define GDB_SIZEOF_REG sizeof(u64) #endif #else #error "Need to set KGDB_GDB_REG_SIZE for MIPS ISA" #endif /* _MIPS_ISA */ #define BUFMAX 2048 -#if (KGDB_GDB_REG_SIZE == 32) -#define NUMREGBYTES (90*sizeof(u32)) -#define NUMCRITREGBYTES (12*sizeof(u32)) -#else -#define NUMREGBYTES (90*sizeof(u64)) -#define NUMCRITREGBYTES (12*sizeof(u64)) -#endif +#define DBG_MAX_REG_NUM 72 +#define NUMREGBYTES (DBG_MAX_REG_NUM * sizeof(GDB_SIZEOF_REG)) +#define NUMCRITREGBYTES (12 * sizeof(GDB_SIZEOF_REG)) #define BREAK_INSTR_SIZE 4 #define CACHE_FLUSH_IS_SAFE 0 diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index 9b78ff6e9b8..5e76c2daa7f 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c @@ -50,6 +50,151 @@ static struct hard_trap_info { { 0, 0} /* Must be last */ }; +struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = +{ + { "zero", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) }, + { "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) }, + { "v0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) }, + { "v1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) }, + { "a0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) }, + { "a1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) }, + { "a2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) }, + { "a3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) }, + { "t0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) }, + { "t1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) }, + { "t2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) }, + { "t3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) }, + { "t4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) }, + { "t5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) }, + { "t6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) }, + { "t7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) }, + { "s0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16]) }, + { "s1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17]) }, + { "s2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18]) }, + { "s3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19]) }, + { "s4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20]) }, + { "s5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21]) }, + { "s6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22]) }, + { "s7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23]) }, + { "t8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24]) }, + { "t9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25]) }, + { "k0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26]) }, + { "k1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27]) }, + { "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28]) }, + { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29]) }, + { "s8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30]) }, + { "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31]) }, + { "sr", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_status) }, + { "lo", GDB_SIZEOF_REG, offsetof(struct pt_regs, lo) }, + { "hi", GDB_SIZEOF_REG, offsetof(struct pt_regs, hi) }, + { "bad", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_badvaddr) }, + { "cause", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_cause) }, + { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_epc) }, + { "f0", GDB_SIZEOF_REG, 0 }, + { "f1", GDB_SIZEOF_REG, 1 }, + { "f2", GDB_SIZEOF_REG, 2 }, + { "f3", GDB_SIZEOF_REG, 3 }, + { "f4", GDB_SIZEOF_REG, 4 }, + { "f5", GDB_SIZEOF_REG, 5 }, + { "f6", GDB_SIZEOF_REG, 6 }, + { "f7", GDB_SIZEOF_REG, 7 }, + { "f8", GDB_SIZEOF_REG, 8 }, + { "f9", GDB_SIZEOF_REG, 9 }, + { "f10", GDB_SIZEOF_REG, 10 }, + { "f11", GDB_SIZEOF_REG, 11 }, + { "f12", GDB_SIZEOF_REG, 12 }, + { "f13", GDB_SIZEOF_REG, 13 }, + { "f14", GDB_SIZEOF_REG, 14 }, + { "f15", GDB_SIZEOF_REG, 15 }, + { "f16", GDB_SIZEOF_REG, 16 }, + { "f17", GDB_SIZEOF_REG, 17 }, + { "f18", GDB_SIZEOF_REG, 18 }, + { "f19", GDB_SIZEOF_REG, 19 }, + { "f20", GDB_SIZEOF_REG, 20 }, + { "f21", GDB_SIZEOF_REG, 21 }, + { "f22", GDB_SIZEOF_REG, 22 }, + { "f23", GDB_SIZEOF_REG, 23 }, + { "f24", GDB_SIZEOF_REG, 24 }, + { "f25", GDB_SIZEOF_REG, 25 }, + { "f26", GDB_SIZEOF_REG, 26 }, + { "f27", GDB_SIZEOF_REG, 27 }, + { "f28", GDB_SIZEOF_REG, 28 }, + { "f29", GDB_SIZEOF_REG, 29 }, + { "f30", GDB_SIZEOF_REG, 30 }, + { "f31", GDB_SIZEOF_REG, 31 }, + { "fsr", GDB_SIZEOF_REG, 0 }, + { "fir", GDB_SIZEOF_REG, 0 }, +}; + +int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) +{ + int fp_reg; + + if (regno < 0 || regno >= DBG_MAX_REG_NUM) + return -EINVAL; + + if (dbg_reg_def[regno].offset != -1 && regno < 38) { + memcpy((void *)regs + dbg_reg_def[regno].offset, mem, + dbg_reg_def[regno].size); + } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { + /* FP registers 38 -> 69 */ + if (!(regs->cp0_status & ST0_CU1)) + return 0; + if (regno == 70) { + /* Process the fcr31/fsr (register 70) */ + memcpy((void *)¤t->thread.fpu.fcr31, mem, + dbg_reg_def[regno].size); + goto out_save; + } else if (regno == 71) { + /* Ignore the fir (register 71) */ + goto out_save; + } + fp_reg = dbg_reg_def[regno].offset; + memcpy((void *)¤t->thread.fpu.fpr[fp_reg], mem, + dbg_reg_def[regno].size); +out_save: + restore_fp(current); + } + + return 0; +} + +char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) +{ + int fp_reg; + + if (regno >= DBG_MAX_REG_NUM || regno < 0) + return NULL; + + if (dbg_reg_def[regno].offset != -1 && regno < 38) { + /* First 38 registers */ + memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, + dbg_reg_def[regno].size); + } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { + /* FP registers 38 -> 69 */ + if (!(regs->cp0_status & ST0_CU1)) + goto out; + save_fp(current); + if (regno == 70) { + /* Process the fcr31/fsr (register 70) */ + memcpy(mem, (void *)¤t->thread.fpu.fcr31, + dbg_reg_def[regno].size); + goto out; + } else if (regno == 71) { + /* Ignore the fir (register 71) */ + memset(mem, 0, dbg_reg_def[regno].size); + goto out; + } + fp_reg = dbg_reg_def[regno].offset; + memcpy(mem, (void *)¤t->thread.fpu.fpr[fp_reg], + dbg_reg_def[regno].size); + } + +out: + return dbg_reg_def[regno].name; + +} + void arch_kgdb_breakpoint(void) { __asm__ __volatile__( @@ -84,64 +229,6 @@ static int compute_signal(int tt) return SIGHUP; /* default for things we don't know about */ } -void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) -{ - int reg; - -#if (KGDB_GDB_REG_SIZE == 32) - u32 *ptr = (u32 *)gdb_regs; -#else - u64 *ptr = (u64 *)gdb_regs; -#endif - - for (reg = 0; reg < 32; reg++) - *(ptr++) = regs->regs[reg]; - - *(ptr++) = regs->cp0_status; - *(ptr++) = regs->lo; - *(ptr++) = regs->hi; - *(ptr++) = regs->cp0_badvaddr; - *(ptr++) = regs->cp0_cause; - *(ptr++) = regs->cp0_epc; - - /* FP REGS */ - if (!(current && (regs->cp0_status & ST0_CU1))) - return; - - save_fp(current); - for (reg = 0; reg < 32; reg++) - *(ptr++) = current->thread.fpu.fpr[reg]; -} - -void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) -{ - int reg; - -#if (KGDB_GDB_REG_SIZE == 32) - const u32 *ptr = (u32 *)gdb_regs; -#else - const u64 *ptr = (u64 *)gdb_regs; -#endif - - for (reg = 0; reg < 32; reg++) - regs->regs[reg] = *(ptr++); - - regs->cp0_status = *(ptr++); - regs->lo = *(ptr++); - regs->hi = *(ptr++); - regs->cp0_badvaddr = *(ptr++); - regs->cp0_cause = *(ptr++); - regs->cp0_epc = *(ptr++); - - /* FP REGS from current */ - if (!(current && (regs->cp0_status & ST0_CU1))) - return; - - for (reg = 0; reg < 32; reg++) - current->thread.fpu.fpr[reg] = *(ptr++); - restore_fp(current); -} - /* * Similar to regs_to_gdb_regs() except that process is sleeping and so * we may not be able to get all the info. -- cgit v1.2.3-70-g09d2 From 7e005f79791dcd58436c88ded4a7f5aed1b82147 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 31 May 2010 15:59:04 +0900 Subject: remove needless ISA_DMA_THRESHOLD Architectures don't need to define ISA_DMA_THRESHOLD anymore. Signed-off-by: FUJITA Tomonori Acked-by: James Bottomley Acked-by: David Howells Signed-off-by: Jens Axboe --- arch/alpha/include/asm/scatterlist.h | 2 -- arch/avr32/include/asm/scatterlist.h | 2 -- arch/blackfin/include/asm/scatterlist.h | 2 -- arch/cris/include/asm/scatterlist.h | 2 -- arch/frv/include/asm/scatterlist.h | 2 -- arch/h8300/include/asm/scatterlist.h | 2 -- arch/ia64/include/asm/scatterlist.h | 9 --------- arch/m32r/include/asm/scatterlist.h | 2 -- arch/m68k/include/asm/scatterlist.h | 3 --- arch/microblaze/include/asm/scatterlist.h | 2 -- arch/mips/include/asm/scatterlist.h | 2 -- arch/mn10300/include/asm/scatterlist.h | 2 -- arch/parisc/include/asm/scatterlist.h | 1 - arch/powerpc/include/asm/scatterlist.h | 3 --- arch/s390/include/asm/scatterlist.h | 2 -- arch/score/include/asm/scatterlist.h | 2 -- arch/sh/include/asm/scatterlist.h | 2 -- arch/sparc/include/asm/scatterlist.h | 1 - arch/x86/include/asm/scatterlist.h | 1 - arch/xtensa/include/asm/scatterlist.h | 2 -- 20 files changed, 46 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/alpha/include/asm/scatterlist.h b/arch/alpha/include/asm/scatterlist.h index 5728c52a741..017d7471c3c 100644 --- a/arch/alpha/include/asm/scatterlist.h +++ b/arch/alpha/include/asm/scatterlist.h @@ -3,6 +3,4 @@ #include -#define ISA_DMA_THRESHOLD (~0UL) - #endif /* !(_ALPHA_SCATTERLIST_H) */ diff --git a/arch/avr32/include/asm/scatterlist.h b/arch/avr32/include/asm/scatterlist.h index 06394e5ead6..a5902d9834e 100644 --- a/arch/avr32/include/asm/scatterlist.h +++ b/arch/avr32/include/asm/scatterlist.h @@ -3,6 +3,4 @@ #include -#define ISA_DMA_THRESHOLD (0xffffffff) - #endif /* __ASM_AVR32_SCATTERLIST_H */ diff --git a/arch/blackfin/include/asm/scatterlist.h b/arch/blackfin/include/asm/scatterlist.h index 64d41d34ab0..d177a158895 100644 --- a/arch/blackfin/include/asm/scatterlist.h +++ b/arch/blackfin/include/asm/scatterlist.h @@ -3,6 +3,4 @@ #include -#define ISA_DMA_THRESHOLD (0xffffffff) - #endif /* !(_BLACKFIN_SCATTERLIST_H) */ diff --git a/arch/cris/include/asm/scatterlist.h b/arch/cris/include/asm/scatterlist.h index 249a7842ff5..f11f8f40ec4 100644 --- a/arch/cris/include/asm/scatterlist.h +++ b/arch/cris/include/asm/scatterlist.h @@ -3,6 +3,4 @@ #include -#define ISA_DMA_THRESHOLD (0x1fffffff) - #endif /* !(__ASM_CRIS_SCATTERLIST_H) */ diff --git a/arch/frv/include/asm/scatterlist.h b/arch/frv/include/asm/scatterlist.h index 1614bfd7e3a..0e5eb301846 100644 --- a/arch/frv/include/asm/scatterlist.h +++ b/arch/frv/include/asm/scatterlist.h @@ -3,6 +3,4 @@ #include -#define ISA_DMA_THRESHOLD (0xffffffffUL) - #endif /* !_ASM_SCATTERLIST_H */ diff --git a/arch/h8300/include/asm/scatterlist.h b/arch/h8300/include/asm/scatterlist.h index de08a4a2cc1..82130eda0e5 100644 --- a/arch/h8300/include/asm/scatterlist.h +++ b/arch/h8300/include/asm/scatterlist.h @@ -3,6 +3,4 @@ #include -#define ISA_DMA_THRESHOLD (0xffffffff) - #endif /* !(_H8300_SCATTERLIST_H) */ diff --git a/arch/ia64/include/asm/scatterlist.h b/arch/ia64/include/asm/scatterlist.h index f299a4fb25c..08fd93bff1d 100644 --- a/arch/ia64/include/asm/scatterlist.h +++ b/arch/ia64/include/asm/scatterlist.h @@ -2,15 +2,6 @@ #define _ASM_IA64_SCATTERLIST_H #include -/* - * It used to be that ISA_DMA_THRESHOLD had something to do with the - * DMA-limits of ISA-devices. Nowadays, its only remaining use (apart - * from the aha1542.c driver, which isn't 64-bit clean anyhow) is to - * tell the block-layer (via BLK_BOUNCE_ISA) what the max. physical - * address of a page is that is allocated with GFP_DMA. On IA-64, - * that's 4GB - 1. - */ -#define ISA_DMA_THRESHOLD 0xffffffff #define ARCH_HAS_SG_CHAIN #endif /* _ASM_IA64_SCATTERLIST_H */ diff --git a/arch/m32r/include/asm/scatterlist.h b/arch/m32r/include/asm/scatterlist.h index aeeddd8dac1..7370b8b6243 100644 --- a/arch/m32r/include/asm/scatterlist.h +++ b/arch/m32r/include/asm/scatterlist.h @@ -3,6 +3,4 @@ #include -#define ISA_DMA_THRESHOLD (0x1fffffff) - #endif /* _ASM_M32R_SCATTERLIST_H */ diff --git a/arch/m68k/include/asm/scatterlist.h b/arch/m68k/include/asm/scatterlist.h index 175da06c6b9..312505452a1 100644 --- a/arch/m68k/include/asm/scatterlist.h +++ b/arch/m68k/include/asm/scatterlist.h @@ -3,7 +3,4 @@ #include -/* This is bogus and should go away. */ -#define ISA_DMA_THRESHOLD (0x00ffffff) - #endif /* !(_M68K_SCATTERLIST_H) */ diff --git a/arch/microblaze/include/asm/scatterlist.h b/arch/microblaze/include/asm/scatterlist.h index dc4a8900cc8..35d786fe93a 100644 --- a/arch/microblaze/include/asm/scatterlist.h +++ b/arch/microblaze/include/asm/scatterlist.h @@ -1,3 +1 @@ #include - -#define ISA_DMA_THRESHOLD (~0UL) diff --git a/arch/mips/include/asm/scatterlist.h b/arch/mips/include/asm/scatterlist.h index 9af65e79be3..7ee0e646d82 100644 --- a/arch/mips/include/asm/scatterlist.h +++ b/arch/mips/include/asm/scatterlist.h @@ -3,6 +3,4 @@ #include -#define ISA_DMA_THRESHOLD (0x00ffffffUL) - #endif /* __ASM_SCATTERLIST_H */ diff --git a/arch/mn10300/include/asm/scatterlist.h b/arch/mn10300/include/asm/scatterlist.h index 7bd00b9e030..7baa4006008 100644 --- a/arch/mn10300/include/asm/scatterlist.h +++ b/arch/mn10300/include/asm/scatterlist.h @@ -13,6 +13,4 @@ #include -#define ISA_DMA_THRESHOLD (0x00ffffff) - #endif /* _ASM_SCATTERLIST_H */ diff --git a/arch/parisc/include/asm/scatterlist.h b/arch/parisc/include/asm/scatterlist.h index 2c3b79b54b2..8bf1f0dd1f1 100644 --- a/arch/parisc/include/asm/scatterlist.h +++ b/arch/parisc/include/asm/scatterlist.h @@ -5,7 +5,6 @@ #include #include -#define ISA_DMA_THRESHOLD (~0UL) #define sg_virt_addr(sg) ((unsigned long)sg_virt(sg)) #endif /* _ASM_PARISC_SCATTERLIST_H */ diff --git a/arch/powerpc/include/asm/scatterlist.h b/arch/powerpc/include/asm/scatterlist.h index 34cc78fd0ef..de1f620bd5c 100644 --- a/arch/powerpc/include/asm/scatterlist.h +++ b/arch/powerpc/include/asm/scatterlist.h @@ -12,9 +12,6 @@ #include #include -#ifdef __powerpc64__ -#define ISA_DMA_THRESHOLD (~0UL) -#endif #define ARCH_HAS_SG_CHAIN #endif /* _ASM_POWERPC_SCATTERLIST_H */ diff --git a/arch/s390/include/asm/scatterlist.h b/arch/s390/include/asm/scatterlist.h index be44d94cba5..35d786fe93a 100644 --- a/arch/s390/include/asm/scatterlist.h +++ b/arch/s390/include/asm/scatterlist.h @@ -1,3 +1 @@ -#define ISA_DMA_THRESHOLD (~0UL) - #include diff --git a/arch/score/include/asm/scatterlist.h b/arch/score/include/asm/scatterlist.h index 4fa1a665821..9f533b8362c 100644 --- a/arch/score/include/asm/scatterlist.h +++ b/arch/score/include/asm/scatterlist.h @@ -1,8 +1,6 @@ #ifndef _ASM_SCORE_SCATTERLIST_H #define _ASM_SCORE_SCATTERLIST_H -#define ISA_DMA_THRESHOLD (~0UL) - #include #endif /* _ASM_SCORE_SCATTERLIST_H */ diff --git a/arch/sh/include/asm/scatterlist.h b/arch/sh/include/asm/scatterlist.h index e38d1d4c7f6..98dfc3510f1 100644 --- a/arch/sh/include/asm/scatterlist.h +++ b/arch/sh/include/asm/scatterlist.h @@ -1,8 +1,6 @@ #ifndef __ASM_SH_SCATTERLIST_H #define __ASM_SH_SCATTERLIST_H -#define ISA_DMA_THRESHOLD phys_addr_mask() - #include #endif /* __ASM_SH_SCATTERLIST_H */ diff --git a/arch/sparc/include/asm/scatterlist.h b/arch/sparc/include/asm/scatterlist.h index 433e45f05fd..92bb638313f 100644 --- a/arch/sparc/include/asm/scatterlist.h +++ b/arch/sparc/include/asm/scatterlist.h @@ -3,7 +3,6 @@ #include -#define ISA_DMA_THRESHOLD (~0UL) #define ARCH_HAS_SG_CHAIN #endif /* !(_SPARC_SCATTERLIST_H) */ diff --git a/arch/x86/include/asm/scatterlist.h b/arch/x86/include/asm/scatterlist.h index fb0b1874396..4240878b9d7 100644 --- a/arch/x86/include/asm/scatterlist.h +++ b/arch/x86/include/asm/scatterlist.h @@ -3,7 +3,6 @@ #include -#define ISA_DMA_THRESHOLD (0x00ffffff) #define ARCH_HAS_SG_CHAIN #endif /* _ASM_X86_SCATTERLIST_H */ diff --git a/arch/xtensa/include/asm/scatterlist.h b/arch/xtensa/include/asm/scatterlist.h index b1f9fdc1d5b..a0421a61d9e 100644 --- a/arch/xtensa/include/asm/scatterlist.h +++ b/arch/xtensa/include/asm/scatterlist.h @@ -13,6 +13,4 @@ #include -#define ISA_DMA_THRESHOLD (~0UL) - #endif /* _XTENSA_SCATTERLIST_H */ -- cgit v1.2.3-70-g09d2 From 365b18189789bfa1acd9939e6312b8a4b4577b28 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 7 Jul 2010 18:53:25 +0200 Subject: add f_flags to struct statfs(64) Add a flags field to help glibc implementing statvfs(3) efficiently. We copy the flag values from glibc, and add a new ST_VALID flag to denote that f_flags is implemented. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- arch/mips/include/asm/statfs.h | 12 +++++++---- arch/s390/include/asm/statfs.h | 9 +++++--- fs/statfs.c | 47 +++++++++++++++++++++++++++++++++++++++++- include/asm-generic/statfs.h | 9 +++++--- include/linux/statfs.h | 25 ++++++++++++++++++++-- 5 files changed, 89 insertions(+), 13 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/mips/include/asm/statfs.h b/arch/mips/include/asm/statfs.h index c3ddf973c1c..0f805c7a42a 100644 --- a/arch/mips/include/asm/statfs.h +++ b/arch/mips/include/asm/statfs.h @@ -33,7 +33,8 @@ struct statfs { /* Linux specials */ __kernel_fsid_t f_fsid; long f_namelen; - long f_spare[6]; + long f_flags; + long f_spare[5]; }; #if (_MIPS_SIM == _MIPS_SIM_ABI32) || (_MIPS_SIM == _MIPS_SIM_NABI32) @@ -53,7 +54,8 @@ struct statfs64 { __u64 f_bavail; __kernel_fsid_t f_fsid; __u32 f_namelen; - __u32 f_spare[6]; + __u32 f_flags; + __u32 f_spare[5]; }; #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ @@ -73,7 +75,8 @@ struct statfs64 { /* Same as struct statfs */ /* Linux specials */ __kernel_fsid_t f_fsid; long f_namelen; - long f_spare[6]; + long f_flags; + long f_spare[5]; }; struct compat_statfs64 { @@ -88,7 +91,8 @@ struct compat_statfs64 { __u64 f_bavail; __kernel_fsid_t f_fsid; __u32 f_namelen; - __u32 f_spare[6]; + __u32 f_flags; + __u32 f_spare[5]; }; #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ diff --git a/arch/s390/include/asm/statfs.h b/arch/s390/include/asm/statfs.h index 06cc70307ec..3be7fbd406c 100644 --- a/arch/s390/include/asm/statfs.h +++ b/arch/s390/include/asm/statfs.h @@ -33,7 +33,8 @@ struct statfs { __kernel_fsid_t f_fsid; int f_namelen; int f_frsize; - int f_spare[5]; + int f_flags; + int f_spare[4]; }; struct statfs64 { @@ -47,7 +48,8 @@ struct statfs64 { __kernel_fsid_t f_fsid; int f_namelen; int f_frsize; - int f_spare[5]; + int f_flags; + int f_spare[4]; }; struct compat_statfs64 { @@ -61,7 +63,8 @@ struct compat_statfs64 { __kernel_fsid_t f_fsid; __u32 f_namelen; __u32 f_frsize; - __u32 f_spare[5]; + __u32 f_flags; + __u32 f_spare[4]; }; #endif /* __s390x__ */ diff --git a/fs/statfs.c b/fs/statfs.c index 6a305709a4d..30ea8c8a996 100644 --- a/fs/statfs.c +++ b/fs/statfs.c @@ -2,11 +2,49 @@ #include #include #include +#include #include #include #include #include +static int flags_by_mnt(int mnt_flags) +{ + int flags = 0; + + if (mnt_flags & MNT_READONLY) + flags |= ST_RDONLY; + if (mnt_flags & MNT_NOSUID) + flags |= ST_NOSUID; + if (mnt_flags & MNT_NODEV) + flags |= ST_NODEV; + if (mnt_flags & MNT_NOEXEC) + flags |= ST_NOEXEC; + if (mnt_flags & MNT_NOATIME) + flags |= ST_NOATIME; + if (mnt_flags & MNT_NODIRATIME) + flags |= ST_NODIRATIME; + if (mnt_flags & MNT_RELATIME) + flags |= ST_RELATIME; + return flags; +} + +static int flags_by_sb(int s_flags) +{ + int flags = 0; + if (s_flags & MS_SYNCHRONOUS) + flags |= ST_SYNCHRONOUS; + if (s_flags & MS_MANDLOCK) + flags |= ST_MANDLOCK; + return flags; +} + +static int calculate_f_flags(struct vfsmount *mnt) +{ + return ST_VALID | flags_by_mnt(mnt->mnt_flags) | + flags_by_sb(mnt->mnt_sb->s_flags); +} + int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf) { int retval; @@ -26,7 +64,12 @@ int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf) int vfs_statfs(struct path *path, struct kstatfs *buf) { - return statfs_by_dentry(path->dentry, buf); + int error; + + error = statfs_by_dentry(path->dentry, buf); + if (!error) + buf->f_flags = calculate_f_flags(path->mnt); + return error; } EXPORT_SYMBOL(vfs_statfs); @@ -69,6 +112,7 @@ static int do_statfs_native(struct path *path, struct statfs *buf) buf->f_fsid = st.f_fsid; buf->f_namelen = st.f_namelen; buf->f_frsize = st.f_frsize; + buf->f_flags = st.f_flags; memset(buf->f_spare, 0, sizeof(buf->f_spare)); } return 0; @@ -96,6 +140,7 @@ static int do_statfs64(struct path *path, struct statfs64 *buf) buf->f_fsid = st.f_fsid; buf->f_namelen = st.f_namelen; buf->f_frsize = st.f_frsize; + buf->f_flags = st.f_flags; memset(buf->f_spare, 0, sizeof(buf->f_spare)); } return 0; diff --git a/include/asm-generic/statfs.h b/include/asm-generic/statfs.h index 3b4fb3e52f0..0fd28e028de 100644 --- a/include/asm-generic/statfs.h +++ b/include/asm-generic/statfs.h @@ -33,7 +33,8 @@ struct statfs { __kernel_fsid_t f_fsid; __statfs_word f_namelen; __statfs_word f_frsize; - __statfs_word f_spare[5]; + __statfs_word f_flags; + __statfs_word f_spare[4]; }; /* @@ -55,7 +56,8 @@ struct statfs64 { __kernel_fsid_t f_fsid; __statfs_word f_namelen; __statfs_word f_frsize; - __statfs_word f_spare[5]; + __statfs_word f_flags; + __statfs_word f_spare[4]; } ARCH_PACK_STATFS64; /* @@ -77,7 +79,8 @@ struct compat_statfs64 { __kernel_fsid_t f_fsid; __u32 f_namelen; __u32 f_frsize; - __u32 f_spare[5]; + __u32 f_flags; + __u32 f_spare[4]; } ARCH_PACK_COMPAT_STATFS64; #endif diff --git a/include/linux/statfs.h b/include/linux/statfs.h index b34cc829f98..0166d320a75 100644 --- a/include/linux/statfs.h +++ b/include/linux/statfs.h @@ -2,7 +2,6 @@ #define _LINUX_STATFS_H #include - #include struct kstatfs { @@ -16,7 +15,29 @@ struct kstatfs { __kernel_fsid_t f_fsid; long f_namelen; long f_frsize; - long f_spare[5]; + long f_flags; + long f_spare[4]; }; +/* + * Definitions for the flag in f_flag. + * + * Generally these flags are equivalent to the MS_ flags used in the mount + * ABI. The exception is ST_VALID which has the same value as MS_REMOUNT + * which doesn't make any sense for statfs. + */ +#define ST_RDONLY 0x0001 /* mount read-only */ +#define ST_NOSUID 0x0002 /* ignore suid and sgid bits */ +#define ST_NODEV 0x0004 /* disallow access to device special files */ +#define ST_NOEXEC 0x0008 /* disallow program execution */ +#define ST_SYNCHRONOUS 0x0010 /* writes are synced at once */ +#define ST_VALID 0x0020 /* f_flags support is implemented */ +#define ST_MANDLOCK 0x0040 /* allow mandatory locks on an FS */ +/* 0x0080 used for ST_WRITE in glibc */ +/* 0x0100 used for ST_APPEND in glibc */ +/* 0x0200 used for ST_IMMUTABLE in glibc */ +#define ST_NOATIME 0x0400 /* do not update access times */ +#define ST_NODIRATIME 0x0800 /* do not update directory access times */ +#define ST_RELATIME 0x1000 /* update atime relative to mtime/ctime */ + #endif -- cgit v1.2.3-70-g09d2 From 597781f3e51f48ef8e67be772196d9e9673752c4 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Mon, 9 Aug 2010 17:18:32 -0700 Subject: kmap_atomic: make kunmap_atomic() harder to misuse kunmap_atomic() is currently at level -4 on Rusty's "Hard To Misuse" list[1] ("Follow common convention and you'll get it wrong"), except in some architectures when CONFIG_DEBUG_HIGHMEM is set[2][3]. kunmap() takes a pointer to a struct page; kunmap_atomic(), however, takes takes a pointer to within the page itself. This seems to once in a while trip people up (the convention they are following is the one from kunmap()). Make it much harder to misuse, by moving it to level 9 on Rusty's list[4] ("The compiler/linker won't let you get it wrong"). This is done by refusing to build if the type of its first argument is a pointer to a struct page. The real kunmap_atomic() is renamed to kunmap_atomic_notypecheck() (which is what you would call in case for some strange reason calling it with a pointer to a struct page is not incorrect in your code). The previous version of this patch was compile tested on x86-64. [1] http://ozlabs.org/~rusty/index.cgi/tech/2008-04-01.html [2] In these cases, it is at level 5, "Do it right or it will always break at runtime." [3] At least mips and powerpc look very similar, and sparc also seems to share a common ancestor with both; there seems to be quite some degree of copy-and-paste coding here. The include/asm/highmem.h file for these three archs mention x86 CPUs at its top. [4] http://ozlabs.org/~rusty/index.cgi/tech/2008-03-30.html [5] As an aside, could someone tell me why mn10300 uses unsigned long as the first parameter of kunmap_atomic() instead of void *? Signed-off-by: Cesar Eduardo Barros Cc: Russell King (arch/arm) Cc: Ralf Baechle (arch/mips) Cc: David Howells (arch/frv, arch/mn10300) Cc: Koichi Yasutake (arch/mn10300) Cc: Kyle McMartin (arch/parisc) Cc: Helge Deller (arch/parisc) Cc: "James E.J. Bottomley" (arch/parisc) Cc: Benjamin Herrenschmidt (arch/powerpc) Cc: Paul Mackerras (arch/powerpc) Cc: "David S. Miller" (arch/sparc) Cc: Thomas Gleixner (arch/x86) Cc: Ingo Molnar (arch/x86) Cc: "H. Peter Anvin" (arch/x86) Cc: Arnd Bergmann (include/asm-generic) Cc: Rusty Russell ("Hard To Misuse" list) Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/include/asm/highmem.h | 2 +- arch/arm/mm/highmem.c | 4 ++-- arch/frv/include/asm/highmem.h | 2 +- arch/mips/include/asm/highmem.h | 4 ++-- arch/mips/mm/highmem.c | 4 ++-- arch/mn10300/include/asm/highmem.h | 2 +- arch/parisc/include/asm/cacheflush.h | 2 +- arch/powerpc/include/asm/highmem.h | 2 +- arch/powerpc/mm/highmem.c | 4 ++-- arch/sparc/include/asm/highmem.h | 2 +- arch/sparc/mm/highmem.c | 4 ++-- arch/x86/include/asm/highmem.h | 2 +- arch/x86/mm/highmem_32.c | 4 ++-- include/linux/highmem.h | 10 +++++++++- 14 files changed, 28 insertions(+), 20 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h index feb988a7ec3..5aff5812660 100644 --- a/arch/arm/include/asm/highmem.h +++ b/arch/arm/include/asm/highmem.h @@ -36,7 +36,7 @@ extern void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte); 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 kunmap_atomic_notypecheck(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/mm/highmem.c b/arch/arm/mm/highmem.c index 6ab244062b4..1fbdb55bfd1 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -82,7 +82,7 @@ void *kmap_atomic(struct page *page, enum km_type type) } EXPORT_SYMBOL(kmap_atomic); -void kunmap_atomic(void *kvaddr, enum km_type type) +void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; unsigned int idx = type + KM_TYPE_NR * smp_processor_id(); @@ -103,7 +103,7 @@ void kunmap_atomic(void *kvaddr, enum km_type type) } pagefault_enable(); } -EXPORT_SYMBOL(kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_notypecheck); void *kmap_atomic_pfn(unsigned long pfn, enum km_type type) { diff --git a/arch/frv/include/asm/highmem.h b/arch/frv/include/asm/highmem.h index 68e4677fb9e..cb4c317eaec 100644 --- a/arch/frv/include/asm/highmem.h +++ b/arch/frv/include/asm/highmem.h @@ -152,7 +152,7 @@ do { \ asm volatile("tlbpr %0,gr0,#4,#1" : : "r"(vaddr) : "memory"); \ } while(0) -static inline void kunmap_atomic(void *kvaddr, enum km_type type) +static inline void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type) { switch (type) { case 0: __kunmap_atomic_primary(0, 2); break; diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index 25adfb02923..75753ca73bf 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h @@ -48,14 +48,14 @@ 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 __kunmap_atomic_notypecheck(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(void *ptr); #define kmap __kmap #define kunmap __kunmap #define kmap_atomic __kmap_atomic -#define kunmap_atomic __kunmap_atomic +#define kunmap_atomic_notypecheck __kunmap_atomic_notypecheck #define kmap_atomic_to_page __kmap_atomic_to_page #define flush_cache_kmaps() flush_cache_all() diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index 127d732474b..6a2b1bf9ef1 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c @@ -64,7 +64,7 @@ void *__kmap_atomic(struct page *page, enum km_type type) } EXPORT_SYMBOL(__kmap_atomic); -void __kunmap_atomic(void *kvaddr, enum km_type type) +void __kunmap_atomic_notypecheck(void *kvaddr, enum km_type type) { #ifdef CONFIG_DEBUG_HIGHMEM unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; @@ -87,7 +87,7 @@ void __kunmap_atomic(void *kvaddr, enum km_type type) pagefault_enable(); } -EXPORT_SYMBOL(__kunmap_atomic); +EXPORT_SYMBOL(__kunmap_atomic_notypecheck); /* * This is the same as kmap_atomic() but can map memory that doesn't diff --git a/arch/mn10300/include/asm/highmem.h b/arch/mn10300/include/asm/highmem.h index 90f2abb04bf..b0b187a29b8 100644 --- a/arch/mn10300/include/asm/highmem.h +++ b/arch/mn10300/include/asm/highmem.h @@ -91,7 +91,7 @@ static inline unsigned long kmap_atomic(struct page *page, enum km_type type) return vaddr; } -static inline void kunmap_atomic(unsigned long vaddr, enum km_type type) +static inline void kunmap_atomic_notypecheck(unsigned long vaddr, enum km_type type) { #if HIGHMEM_DEBUG enum fixed_addresses idx = type + KM_TYPE_NR * smp_processor_id(); diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index 4556d820128..dba11aedce1 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -132,7 +132,7 @@ static inline void *kmap_atomic(struct page *page, enum km_type idx) return page_address(page); } -static inline void kunmap_atomic(void *addr, enum km_type idx) +static inline void kunmap_atomic_notypecheck(void *addr, enum km_type idx) { kunmap_parisc(addr); pagefault_enable(); diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h index a74c4ee6c02..d10d64a4be3 100644 --- a/arch/powerpc/include/asm/highmem.h +++ b/arch/powerpc/include/asm/highmem.h @@ -62,7 +62,7 @@ extern void *kmap_high(struct page *page); extern void kunmap_high(struct page *page); extern void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot); -extern void kunmap_atomic(void *kvaddr, enum km_type type); +extern void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type); static inline void *kmap(struct page *page) { diff --git a/arch/powerpc/mm/highmem.c b/arch/powerpc/mm/highmem.c index c2186c74c85..857d4173f9c 100644 --- a/arch/powerpc/mm/highmem.c +++ b/arch/powerpc/mm/highmem.c @@ -52,7 +52,7 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot) } EXPORT_SYMBOL(kmap_atomic_prot); -void kunmap_atomic(void *kvaddr, enum km_type type) +void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type) { #ifdef CONFIG_DEBUG_HIGHMEM unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; @@ -74,4 +74,4 @@ void kunmap_atomic(void *kvaddr, enum km_type type) #endif pagefault_enable(); } -EXPORT_SYMBOL(kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_notypecheck); diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h index 3de42e77627..ec23b0a87b9 100644 --- a/arch/sparc/include/asm/highmem.h +++ b/arch/sparc/include/asm/highmem.h @@ -71,7 +71,7 @@ static inline 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 kunmap_atomic_notypecheck(void *kvaddr, enum km_type type); extern struct page *kmap_atomic_to_page(void *vaddr); #define flush_cache_kmaps() flush_cache_all() diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c index 7916feba6e4..e139e9cbf5f 100644 --- a/arch/sparc/mm/highmem.c +++ b/arch/sparc/mm/highmem.c @@ -65,7 +65,7 @@ void *kmap_atomic(struct page *page, enum km_type type) } EXPORT_SYMBOL(kmap_atomic); -void kunmap_atomic(void *kvaddr, enum km_type type) +void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type) { #ifdef CONFIG_DEBUG_HIGHMEM unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; @@ -100,7 +100,7 @@ void kunmap_atomic(void *kvaddr, enum km_type type) pagefault_enable(); } -EXPORT_SYMBOL(kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_notypecheck); /* We may be fed a pagetable here by ptep_to_xxx and others. */ struct page *kmap_atomic_to_page(void *ptr) diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h index a726650fc80..8caac76ac32 100644 --- a/arch/x86/include/asm/highmem.h +++ b/arch/x86/include/asm/highmem.h @@ -61,7 +61,7 @@ void *kmap(struct page *page); void kunmap(struct page *page); void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot); void *kmap_atomic(struct page *page, enum km_type type); -void kunmap_atomic(void *kvaddr, enum km_type type); +void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type); void *kmap_atomic_pfn(unsigned long pfn, enum km_type type); void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot); struct page *kmap_atomic_to_page(void *ptr); diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index 63a6ba66cbe..5e8fa12ef86 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -53,7 +53,7 @@ void *kmap_atomic(struct page *page, enum km_type type) return kmap_atomic_prot(page, type, kmap_prot); } -void kunmap_atomic(void *kvaddr, enum km_type type) +void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); @@ -102,7 +102,7 @@ struct page *kmap_atomic_to_page(void *ptr) EXPORT_SYMBOL(kmap); EXPORT_SYMBOL(kunmap); EXPORT_SYMBOL(kmap_atomic); -EXPORT_SYMBOL(kunmap_atomic); +EXPORT_SYMBOL(kunmap_atomic_notypecheck); EXPORT_SYMBOL(kmap_atomic_prot); EXPORT_SYMBOL(kmap_atomic_to_page); diff --git a/include/linux/highmem.h b/include/linux/highmem.h index caafd0561aa..67460f01022 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -2,6 +2,7 @@ #define _LINUX_HIGHMEM_H #include +#include #include #include @@ -72,7 +73,7 @@ static inline void *kmap_atomic(struct page *page, enum km_type idx) } #define kmap_atomic_prot(page, idx, prot) kmap_atomic(page, idx) -#define kunmap_atomic(addr, idx) do { pagefault_enable(); } while (0) +#define kunmap_atomic_notypecheck(addr, idx) do { pagefault_enable(); } while (0) #define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx)) #define kmap_atomic_to_page(ptr) virt_to_page(ptr) @@ -81,6 +82,13 @@ static inline void *kmap_atomic(struct page *page, enum km_type idx) #endif /* CONFIG_HIGHMEM */ +/* Prevent people trying to call kunmap_atomic() as if it were kunmap() */ +/* kunmap_atomic() should get the return value of kmap_atomic, not the page. */ +#define kunmap_atomic(addr, idx) do { \ + BUILD_BUG_ON(__same_type((addr), struct page *)); \ + kunmap_atomic_notypecheck((addr), (idx)); \ + } while (0) + /* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */ #ifndef clear_user_highpage static inline void clear_user_highpage(struct page *page, unsigned long vaddr) -- cgit v1.2.3-70-g09d2 From a3c8ed693da9782f924223f65da9261da796e49b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 17 Jun 2010 13:16:08 -0700 Subject: tty: remove remaining Hayes ESP ioctls As Jeff Dike pointed out, the Hayes ESP driver was removed in commit f53a2ade0bb9f2a81f473e6469155172a96b7c38, so these ioctl definitions should also be removed. This cleans up the remaining arch-specific locations of this ioctl value. Thanks to Arnd for pointing these out. Cc: Jeff Dike Cc: Arnd Bergmann Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- arch/alpha/include/asm/ioctls.h | 2 -- arch/avr32/include/asm/ioctls.h | 2 -- arch/cris/include/asm/ioctls.h | 2 -- arch/ia64/include/asm/ioctls.h | 2 -- arch/m32r/include/asm/ioctls.h | 2 -- arch/mips/include/asm/ioctls.h | 2 -- arch/mn10300/include/asm/ioctls.h | 2 -- arch/parisc/include/asm/ioctls.h | 2 -- 8 files changed, 16 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/alpha/include/asm/ioctls.h b/arch/alpha/include/asm/ioctls.h index 67bb9f6fdbe..c7b0cc61ce5 100644 --- a/arch/alpha/include/asm/ioctls.h +++ b/arch/alpha/include/asm/ioctls.h @@ -106,7 +106,5 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ -#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ #endif /* _ASM_ALPHA_IOCTLS_H */ diff --git a/arch/avr32/include/asm/ioctls.h b/arch/avr32/include/asm/ioctls.h index e6ac0b66107..143dafb3997 100644 --- a/arch/avr32/include/asm/ioctls.h +++ b/arch/avr32/include/asm/ioctls.h @@ -72,8 +72,6 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ -#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ #define FIOQSIZE 0x5460 /* Used for packet mode */ diff --git a/arch/cris/include/asm/ioctls.h b/arch/cris/include/asm/ioctls.h index 076c07824eb..bb49142dc6a 100644 --- a/arch/cris/include/asm/ioctls.h +++ b/arch/cris/include/asm/ioctls.h @@ -70,8 +70,6 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ -#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ #define FIOQSIZE 0x5460 #define TIOCSERSETRS485 0x5461 /* enable rs-485 (deprecated) */ diff --git a/arch/ia64/include/asm/ioctls.h b/arch/ia64/include/asm/ioctls.h index f41b636a0bf..f0ee86c0b5f 100644 --- a/arch/ia64/include/asm/ioctls.h +++ b/arch/ia64/include/asm/ioctls.h @@ -75,8 +75,6 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ -#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ #define FIOQSIZE 0x5460 /* Used for packet mode */ diff --git a/arch/m32r/include/asm/ioctls.h b/arch/m32r/include/asm/ioctls.h index b9f54bb5d7c..f4c13a52fe4 100644 --- a/arch/m32r/include/asm/ioctls.h +++ b/arch/m32r/include/asm/ioctls.h @@ -69,8 +69,6 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ -#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ #define FIOQSIZE 0x5460 /* Used for packet mode */ diff --git a/arch/mips/include/asm/ioctls.h b/arch/mips/include/asm/ioctls.h index 3f04a995ec5..2fb9e1693bf 100644 --- a/arch/mips/include/asm/ioctls.h +++ b/arch/mips/include/asm/ioctls.h @@ -103,7 +103,5 @@ #define TIOCSERSETMULTI 0x5490 /* Set multiport config */ #define TIOCMIWAIT 0x5491 /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x5492 /* read serial port inline interrupt counts */ -#define TIOCGHAYESESP 0x5493 /* Get Hayes ESP configuration */ -#define TIOCSHAYESESP 0x5494 /* Set Hayes ESP configuration */ #endif /* __ASM_IOCTLS_H */ diff --git a/arch/mn10300/include/asm/ioctls.h b/arch/mn10300/include/asm/ioctls.h index dcbfb452974..638219a99b1 100644 --- a/arch/mn10300/include/asm/ioctls.h +++ b/arch/mn10300/include/asm/ioctls.h @@ -70,8 +70,6 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ -#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ #define FIOQSIZE 0x5460 /* Used for packet mode */ diff --git a/arch/parisc/include/asm/ioctls.h b/arch/parisc/include/asm/ioctls.h index 6747fad07a3..6cc497e5253 100644 --- a/arch/parisc/include/asm/ioctls.h +++ b/arch/parisc/include/asm/ioctls.h @@ -68,8 +68,6 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ -#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ #define FIOQSIZE 0x5460 /* Get exact space used by quota */ #define TIOCSTART 0x5461 -- cgit v1.2.3-70-g09d2 From 26df6d13406d1a53b0bda08bd712f1924affd7cd Mon Sep 17 00:00:00 2001 From: "hyc@symas.com" Date: Tue, 22 Jun 2010 10:14:49 -0700 Subject: tty: Add EXTPROC support for LINEMODE This patch is against the 2.6.34 source. Paraphrased from the 1989 BSD patch by David Borman @ cray.com: These are the changes needed for the kernel to support LINEMODE in the server. There is a new bit in the termios local flag word, EXTPROC. When this bit is set, several aspects of the terminal driver are disabled. Input line editing, character echo, and mapping of signals are all disabled. This allows the telnetd to turn off these functions when in linemode, but still keep track of what state the user wants the terminal to be in. New ioctl: TIOCSIG Generate a signal to processes in the current process group of the pty. There is a new mode for packet driver, the TIOCPKT_IOCTL bit. When packet mode is turned on in the pty, and the EXTPROC bit is set, then whenever the state of the pty is changed, the next read on the master side of the pty will have the TIOCPKT_IOCTL bit set. This allows the process on the server side of the pty to know when the state of the terminal has changed; it can then issue the appropriate ioctl to retrieve the new state. Since the original BSD patches accompanied the source code for telnet I've left that reference here, but obviously the feature is useful for any remote terminal protocol, including ssh. The corresponding feature has existed in the BSD tty driver since 1989. For historical reference, a good copy of the relevant files can be found here: http://anonsvn.mit.edu/viewvc/krb5/trunk/src/appl/telnet/?pathrev=17741 Signed-off-by: Howard Chu Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- arch/alpha/include/asm/ioctls.h | 2 ++ arch/alpha/include/asm/termbits.h | 1 + arch/arm/include/asm/ioctls.h | 2 ++ arch/arm/include/asm/termbits.h | 1 + arch/avr32/include/asm/ioctls.h | 2 ++ arch/avr32/include/asm/termbits.h | 1 + arch/cris/include/asm/ioctls.h | 2 ++ arch/cris/include/asm/termbits.h | 1 + arch/frv/include/asm/ioctls.h | 2 ++ arch/frv/include/asm/termbits.h | 1 + arch/h8300/include/asm/ioctls.h | 2 ++ arch/h8300/include/asm/termbits.h | 1 + arch/ia64/include/asm/ioctls.h | 2 ++ arch/ia64/include/asm/termbits.h | 1 + arch/m32r/include/asm/ioctls.h | 2 ++ arch/m32r/include/asm/termbits.h | 1 + arch/m68k/include/asm/ioctls.h | 2 ++ arch/m68k/include/asm/termbits.h | 1 + arch/mips/include/asm/ioctls.h | 3 ++- arch/mips/include/asm/termbits.h | 1 + arch/mn10300/include/asm/ioctls.h | 2 ++ arch/mn10300/include/asm/termbits.h | 1 + arch/parisc/include/asm/ioctls.h | 2 ++ arch/parisc/include/asm/termbits.h | 1 + arch/powerpc/include/asm/ioctls.h | 2 ++ arch/powerpc/include/asm/termbits.h | 1 + arch/s390/include/asm/ioctls.h | 2 ++ arch/sh/include/asm/ioctls.h | 2 ++ arch/sparc/include/asm/ioctls.h | 2 ++ arch/sparc/include/asm/termbits.h | 1 + arch/xtensa/include/asm/ioctls.h | 2 ++ arch/xtensa/include/asm/termbits.h | 1 + drivers/char/n_tty.c | 17 ++++++++++++++--- drivers/char/pty.c | 21 +++++++++++++++++++++ drivers/char/tty_ioctl.c | 18 ++++++++++++------ fs/compat_ioctl.c | 1 + include/asm-generic/ioctls.h | 2 ++ include/asm-generic/termbits.h | 1 + include/linux/tty.h | 1 + 39 files changed, 101 insertions(+), 10 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/alpha/include/asm/ioctls.h b/arch/alpha/include/asm/ioctls.h index c7b0cc61ce5..59617c3c2be 100644 --- a/arch/alpha/include/asm/ioctls.h +++ b/arch/alpha/include/asm/ioctls.h @@ -80,6 +80,7 @@ # define TIOCPKT_START 8 # define TIOCPKT_NOSTOP 16 # define TIOCPKT_DOSTOP 32 +# define TIOCPKT_IOCTL 64 #define TIOCNOTTY 0x5422 @@ -91,6 +92,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define TIOCSERCONFIG 0x5453 #define TIOCSERGWILD 0x5454 diff --git a/arch/alpha/include/asm/termbits.h b/arch/alpha/include/asm/termbits.h index ad854a4a3af..879dd358992 100644 --- a/arch/alpha/include/asm/termbits.h +++ b/arch/alpha/include/asm/termbits.h @@ -180,6 +180,7 @@ struct ktermios { #define FLUSHO 0x00800000 #define PENDIN 0x20000000 #define IEXTEN 0x00000400 +#define EXTPROC 0x10000000 /* Values for the ACTION argument to `tcflow'. */ #define TCOOFF 0 diff --git a/arch/arm/include/asm/ioctls.h b/arch/arm/include/asm/ioctls.h index 7f0b6d13296..0b30894b548 100644 --- a/arch/arm/include/asm/ioctls.h +++ b/arch/arm/include/asm/ioctls.h @@ -52,6 +52,7 @@ #define TCSETSF2 _IOW('T',0x2D, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define TIOCGRS485 0x542E #define TIOCSRS485 0x542F @@ -81,6 +82,7 @@ #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/arch/arm/include/asm/termbits.h b/arch/arm/include/asm/termbits.h index f784d11f40b..704135d28d1 100644 --- a/arch/arm/include/asm/termbits.h +++ b/arch/arm/include/asm/termbits.h @@ -177,6 +177,7 @@ struct ktermios { #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 +#define EXTPROC 0200000 /* tcflow() and TCXONC use these */ #define TCOOFF 0 diff --git a/arch/avr32/include/asm/ioctls.h b/arch/avr32/include/asm/ioctls.h index 143dafb3997..b7dd324b46a 100644 --- a/arch/avr32/include/asm/ioctls.h +++ b/arch/avr32/include/asm/ioctls.h @@ -53,6 +53,7 @@ #define TCSETSF2 _IOW('T',0x2D, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define TIOCGRS485 0x542E #define TIOCSRS485 0x542F @@ -82,6 +83,7 @@ #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/arch/avr32/include/asm/termbits.h b/arch/avr32/include/asm/termbits.h index db2daab31fd..366adc5ebb1 100644 --- a/arch/avr32/include/asm/termbits.h +++ b/arch/avr32/include/asm/termbits.h @@ -175,6 +175,7 @@ struct ktermios { #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 +#define EXTPROC 0200000 /* tcflow() and TCXONC use these */ #define TCOOFF 0 diff --git a/arch/cris/include/asm/ioctls.h b/arch/cris/include/asm/ioctls.h index bb49142dc6a..c9129ed3744 100644 --- a/arch/cris/include/asm/ioctls.h +++ b/arch/cris/include/asm/ioctls.h @@ -54,6 +54,7 @@ #define TCSETSF2 _IOW('T',0x2D, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 @@ -85,6 +86,7 @@ #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/arch/cris/include/asm/termbits.h b/arch/cris/include/asm/termbits.h index 66e1a7492a0..1c43bc874cc 100644 --- a/arch/cris/include/asm/termbits.h +++ b/arch/cris/include/asm/termbits.h @@ -214,6 +214,7 @@ struct ktermios { #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 +#define EXTPROC 0200000 /* tcflow() and TCXONC use these */ #define TCOOFF 0 diff --git a/arch/frv/include/asm/ioctls.h b/arch/frv/include/asm/ioctls.h index d0c30e31fbd..a993e3759cc 100644 --- a/arch/frv/include/asm/ioctls.h +++ b/arch/frv/include/asm/ioctls.h @@ -53,6 +53,7 @@ #define TCSETSF2 _IOW('T',0x2D, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 @@ -79,6 +80,7 @@ #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/arch/frv/include/asm/termbits.h b/arch/frv/include/asm/termbits.h index 5568492b508..7722e19cc34 100644 --- a/arch/frv/include/asm/termbits.h +++ b/arch/frv/include/asm/termbits.h @@ -180,6 +180,7 @@ struct ktermios { #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 +#define EXTPROC 0200000 /* tcflow() and TCXONC use these */ diff --git a/arch/h8300/include/asm/ioctls.h b/arch/h8300/include/asm/ioctls.h index 98a53d06726..b6b249f9f30 100644 --- a/arch/h8300/include/asm/ioctls.h +++ b/arch/h8300/include/asm/ioctls.h @@ -53,6 +53,7 @@ #define TCSETSF2 _IOW('T',0x2D, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 @@ -79,6 +80,7 @@ #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/arch/h8300/include/asm/termbits.h b/arch/h8300/include/asm/termbits.h index 31eca81db3f..3287a6244d7 100644 --- a/arch/h8300/include/asm/termbits.h +++ b/arch/h8300/include/asm/termbits.h @@ -179,6 +179,7 @@ struct ktermios { #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 +#define EXTPROC 0200000 /* tcflow() and TCXONC use these */ diff --git a/arch/ia64/include/asm/ioctls.h b/arch/ia64/include/asm/ioctls.h index f0ee86c0b5f..b79c385114e 100644 --- a/arch/ia64/include/asm/ioctls.h +++ b/arch/ia64/include/asm/ioctls.h @@ -59,6 +59,7 @@ #define TCSETSF2 _IOW('T',0x2D, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 @@ -85,6 +86,7 @@ #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/arch/ia64/include/asm/termbits.h b/arch/ia64/include/asm/termbits.h index 9f162e0089a..c009b94e58d 100644 --- a/arch/ia64/include/asm/termbits.h +++ b/arch/ia64/include/asm/termbits.h @@ -187,6 +187,7 @@ struct ktermios { #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 +#define EXTPROC 0200000 /* tcflow() and TCXONC use these */ #define TCOOFF 0 diff --git a/arch/m32r/include/asm/ioctls.h b/arch/m32r/include/asm/ioctls.h index f4c13a52fe4..66288063a4c 100644 --- a/arch/m32r/include/asm/ioctls.h +++ b/arch/m32r/include/asm/ioctls.h @@ -53,6 +53,7 @@ #define TCSETSF2 _IOW('T',0x2D, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define FIONCLEX 0x5450 #define FIOCLEX 0x5451 @@ -79,6 +80,7 @@ #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/arch/m32r/include/asm/termbits.h b/arch/m32r/include/asm/termbits.h index bc104008b55..957a3c68854 100644 --- a/arch/m32r/include/asm/termbits.h +++ b/arch/m32r/include/asm/termbits.h @@ -179,6 +179,7 @@ struct ktermios { #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 +#define EXTPROC 0200000 /* tcflow() and TCXONC use these */ #define TCOOFF 0 diff --git a/arch/m68k/include/asm/ioctls.h b/arch/m68k/include/asm/ioctls.h index b8d2f4be7fd..91a57d66546 100644 --- a/arch/m68k/include/asm/ioctls.h +++ b/arch/m68k/include/asm/ioctls.h @@ -52,6 +52,7 @@ #define TCSETSF2 _IOW('T',0x2D, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 @@ -78,6 +79,7 @@ #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/arch/m68k/include/asm/termbits.h b/arch/m68k/include/asm/termbits.h index 8c14170996b..aea1e37b765 100644 --- a/arch/m68k/include/asm/termbits.h +++ b/arch/m68k/include/asm/termbits.h @@ -179,6 +179,7 @@ struct ktermios { #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 +#define EXTPROC 0200000 /* tcflow() and TCXONC use these */ diff --git a/arch/mips/include/asm/ioctls.h b/arch/mips/include/asm/ioctls.h index 2fb9e1693bf..d87cb046569 100644 --- a/arch/mips/include/asm/ioctls.h +++ b/arch/mips/include/asm/ioctls.h @@ -41,7 +41,7 @@ #define TIOCPKT_START 0x08 /* start output */ #define TIOCPKT_NOSTOP 0x10 /* no more ^S, ^Q */ #define TIOCPKT_DOSTOP 0x20 /* now do ^S ^Q */ -/* #define TIOCPKT_IOCTL 0x40 state change of pty driver */ +#define TIOCPKT_IOCTL 0x40 /* state change of pty driver */ #define TIOCSWINSZ _IOW('t', 103, struct winsize) /* set window size */ #define TIOCGWINSZ _IOR('t', 104, struct winsize) /* get window size */ #define TIOCNOTTY 0x5471 /* void tty association */ @@ -83,6 +83,7 @@ #define TCSETSF2 _IOW('T', 0x2D, struct termios2) #define TIOCGPTN _IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T', 0x36, int) /* Generate signal on Pty slave */ /* I hope the range from 0x5480 on is free ... */ #define TIOCSCTTY 0x5480 /* become controlling tty */ diff --git a/arch/mips/include/asm/termbits.h b/arch/mips/include/asm/termbits.h index c83c68444e8..76630b396fa 100644 --- a/arch/mips/include/asm/termbits.h +++ b/arch/mips/include/asm/termbits.h @@ -203,6 +203,7 @@ struct ktermios { #define PENDIN 0040000 /* Retype pending input (state). */ #define TOSTOP 0100000 /* Send SIGTTOU for background output. */ #define ITOSTOP TOSTOP +#define EXTPROC 0200000 /* External processing on pty */ /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/arch/mn10300/include/asm/ioctls.h b/arch/mn10300/include/asm/ioctls.h index 638219a99b1..cb8cf190223 100644 --- a/arch/mn10300/include/asm/ioctls.h +++ b/arch/mn10300/include/asm/ioctls.h @@ -54,6 +54,7 @@ #define TIOCGPTN _IOR('T', 0x30, unsigned int) /* Get Pty Number * (of pty-mux device) */ #define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T', 0x36, int) /* Generate signal on Pty slave */ #define FIONCLEX 0x5450 #define FIOCLEX 0x5451 @@ -80,6 +81,7 @@ #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/arch/mn10300/include/asm/termbits.h b/arch/mn10300/include/asm/termbits.h index eb2b0dc1f69..130d4249597 100644 --- a/arch/mn10300/include/asm/termbits.h +++ b/arch/mn10300/include/asm/termbits.h @@ -180,6 +180,7 @@ struct ktermios { #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 +#define EXTPROC 0200000 /* tcflow() and TCXONC use these */ #define TCOOFF 0 diff --git a/arch/parisc/include/asm/ioctls.h b/arch/parisc/include/asm/ioctls.h index 6cc497e5253..4e0614456be 100644 --- a/arch/parisc/include/asm/ioctls.h +++ b/arch/parisc/include/asm/ioctls.h @@ -52,6 +52,7 @@ #define TCSETSF2 _IOW('T',0x2D, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 @@ -82,6 +83,7 @@ #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/arch/parisc/include/asm/termbits.h b/arch/parisc/include/asm/termbits.h index d8bbc73b16b..d1ab92177a5 100644 --- a/arch/parisc/include/asm/termbits.h +++ b/arch/parisc/include/asm/termbits.h @@ -180,6 +180,7 @@ struct ktermios { #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 +#define EXTPROC 0200000 /* tcflow() and TCXONC use these */ #define TCOOFF 0 diff --git a/arch/powerpc/include/asm/ioctls.h b/arch/powerpc/include/asm/ioctls.h index 1842186d872..851920052e0 100644 --- a/arch/powerpc/include/asm/ioctls.h +++ b/arch/powerpc/include/asm/ioctls.h @@ -80,6 +80,7 @@ # define TIOCPKT_START 8 # define TIOCPKT_NOSTOP 16 # define TIOCPKT_DOSTOP 32 +# define TIOCPKT_IOCTL 64 #define TIOCNOTTY 0x5422 @@ -93,6 +94,7 @@ #define TIOCSRS485 0x542f #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define TIOCSERCONFIG 0x5453 #define TIOCSERGWILD 0x5454 diff --git a/arch/powerpc/include/asm/termbits.h b/arch/powerpc/include/asm/termbits.h index 6698188ca55..549d700e18f 100644 --- a/arch/powerpc/include/asm/termbits.h +++ b/arch/powerpc/include/asm/termbits.h @@ -189,6 +189,7 @@ struct ktermios { #define FLUSHO 0x00800000 #define PENDIN 0x20000000 #define IEXTEN 0x00000400 +#define EXTPROC 0x10000000 /* Values for the ACTION argument to `tcflow'. */ #define TCOOFF 0 diff --git a/arch/s390/include/asm/ioctls.h b/arch/s390/include/asm/ioctls.h index 40e481b1b46..2f3d8736361 100644 --- a/arch/s390/include/asm/ioctls.h +++ b/arch/s390/include/asm/ioctls.h @@ -60,6 +60,7 @@ #define TCSETSF2 _IOW('T',0x2D, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 @@ -86,6 +87,7 @@ #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/arch/sh/include/asm/ioctls.h b/arch/sh/include/asm/ioctls.h index c212c371a4a..eb6c4c68797 100644 --- a/arch/sh/include/asm/ioctls.h +++ b/arch/sh/include/asm/ioctls.h @@ -69,6 +69,7 @@ # define TIOCPKT_START 8 # define TIOCPKT_NOSTOP 16 # define TIOCPKT_DOSTOP 32 +# define TIOCPKT_IOCTL 64 #define TIOCNOTTY _IO('T', 34) /* 0x5422 */ @@ -84,6 +85,7 @@ #define TCSETSF2 _IOW('T', 45, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */ #define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */ diff --git a/arch/sparc/include/asm/ioctls.h b/arch/sparc/include/asm/ioctls.h index 1fe6855c5c1..53f4ee009bd 100644 --- a/arch/sparc/include/asm/ioctls.h +++ b/arch/sparc/include/asm/ioctls.h @@ -80,6 +80,7 @@ /* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */ #define TIOCGPTN _IOR('t', 134, unsigned int) /* Get Pty Number */ #define TIOCSPTLCK _IOW('t', 135, int) /* Lock/unlock PTY */ +#define TIOCSIG _IOW('t', 136, int) /* Generate signal on Pty slave */ /* Little f */ #define FIOCLEX _IO('f', 1) @@ -132,5 +133,6 @@ #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 #endif /* !(_ASM_SPARC_IOCTLS_H) */ diff --git a/arch/sparc/include/asm/termbits.h b/arch/sparc/include/asm/termbits.h index d72dfed1f9d..23b10ff08df 100644 --- a/arch/sparc/include/asm/termbits.h +++ b/arch/sparc/include/asm/termbits.h @@ -225,6 +225,7 @@ struct ktermios { #define FLUSHO 0x00002000 #define PENDIN 0x00004000 #define IEXTEN 0x00008000 +#define EXTPROC 0x00010000 /* modem lines */ #define TIOCM_LE 0x001 diff --git a/arch/xtensa/include/asm/ioctls.h b/arch/xtensa/include/asm/ioctls.h index 0ffa942954b..ab1800012ed 100644 --- a/arch/xtensa/include/asm/ioctls.h +++ b/arch/xtensa/include/asm/ioctls.h @@ -81,6 +81,7 @@ # define TIOCPKT_START 8 # define TIOCPKT_NOSTOP 16 # define TIOCPKT_DOSTOP 32 +# define TIOCPKT_IOCTL 64 #define TIOCNOTTY _IO('T', 34) @@ -97,6 +98,7 @@ #define TCSETSF2 _IOW('T', 45, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ #define TIOCSERCONFIG _IO('T', 83) #define TIOCSERGWILD _IOR('T', 84, int) diff --git a/arch/xtensa/include/asm/termbits.h b/arch/xtensa/include/asm/termbits.h index 85aa6a3c0b6..0d6c8715b24 100644 --- a/arch/xtensa/include/asm/termbits.h +++ b/arch/xtensa/include/asm/termbits.h @@ -196,6 +196,7 @@ struct ktermios { #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 +#define EXTPROC 0200000 /* tcflow() and TCXONC use these */ diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index bdae8327143..428f4fe0b5f 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -1102,6 +1102,11 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) if (I_IUCLC(tty) && L_IEXTEN(tty)) c = tolower(c); + if (L_EXTPROC(tty)) { + put_tty_queue(c, tty); + return; + } + if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) && c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) { @@ -1409,7 +1414,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, n_tty_set_room(tty); - if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) { + if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) || + L_EXTPROC(tty)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); @@ -1585,7 +1591,7 @@ static int n_tty_open(struct tty_struct *tty) static inline int input_available_p(struct tty_struct *tty, int amt) { tty_flush_to_ldisc(tty); - if (tty->icanon) { + if (tty->icanon && !L_EXTPROC(tty)) { if (tty->canon_data) return 1; } else if (tty->read_cnt >= (amt ? amt : 1)) @@ -1632,6 +1638,11 @@ static int copy_from_read_buf(struct tty_struct *tty, spin_lock_irqsave(&tty->read_lock, flags); tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); tty->read_cnt -= n; + /* Turn single EOF into zero-length read */ + if (L_EXTPROC(tty) && tty->icanon && n == 1) { + if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty)) + n--; + } spin_unlock_irqrestore(&tty->read_lock, flags); *b += n; *nr -= n; @@ -1812,7 +1823,7 @@ do_it_again: nr--; } - if (tty->icanon) { + if (tty->icanon && !L_EXTPROC(tty)) { /* N.B. avoid overrun if nr == 0 */ while (nr && tty->read_cnt) { int eol; diff --git a/drivers/char/pty.c b/drivers/char/pty.c index d83a43130df..b640ef29be1 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -171,6 +171,23 @@ static int pty_set_lock(struct tty_struct *tty, int __user *arg) return 0; } +/* Send a signal to the slave */ +static int pty_signal(struct tty_struct *tty, int sig) +{ + unsigned long flags; + struct pid *pgrp; + + if (tty->link) { + spin_lock_irqsave(&tty->link->ctrl_lock, flags); + pgrp = get_pid(tty->link->pgrp); + spin_unlock_irqrestore(&tty->link->ctrl_lock, flags); + + kill_pgrp(pgrp, sig, 1); + put_pid(pgrp); + } + return 0; +} + static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; @@ -321,6 +338,8 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, switch (cmd) { case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ return pty_set_lock(tty, (int __user *) arg); + case TIOCSIG: /* Send signal to other side of pty */ + return pty_signal(tty, (int) arg); } return -ENOIOCTLCMD; } @@ -476,6 +495,8 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file, return pty_set_lock(tty, (int __user *)arg); case TIOCGPTN: /* Get PT Number */ return put_user(tty->index, (unsigned int __user *)arg); + case TIOCSIG: /* Send signal to other side of pty */ + return pty_signal(tty, (int) arg); } return -ENOIOCTLCMD; diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 6bd5f8866c7..0c188997145 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -517,19 +517,25 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) /* See if packet mode change of state. */ if (tty->link && tty->link->packet) { + int extproc = (old_termios.c_lflag & EXTPROC) | + (tty->termios->c_lflag & EXTPROC); int old_flow = ((old_termios.c_iflag & IXON) && (old_termios.c_cc[VSTOP] == '\023') && (old_termios.c_cc[VSTART] == '\021')); int new_flow = (I_IXON(tty) && STOP_CHAR(tty) == '\023' && START_CHAR(tty) == '\021'); - if (old_flow != new_flow) { + if ((old_flow != new_flow) || extproc) { spin_lock_irqsave(&tty->ctrl_lock, flags); - tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); - if (new_flow) - tty->ctrl_status |= TIOCPKT_DOSTOP; - else - tty->ctrl_status |= TIOCPKT_NOSTOP; + if (old_flow != new_flow) { + tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); + if (new_flow) + tty->ctrl_status |= TIOCPKT_DOSTOP; + else + tty->ctrl_status |= TIOCPKT_NOSTOP; + } + if (extproc) + tty->ctrl_status |= TIOCPKT_IOCTL; spin_unlock_irqrestore(&tty->ctrl_lock, flags); wake_up_interruptible(&tty->link->read_wait); } diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 63ae8583146..fa4bc48810f 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -969,6 +969,7 @@ COMPATIBLE_IOCTL(TIOCGPGRP) COMPATIBLE_IOCTL(TIOCGPTN) COMPATIBLE_IOCTL(TIOCSPTLCK) COMPATIBLE_IOCTL(TIOCSERGETLSR) +COMPATIBLE_IOCTL(TIOCSIG) #ifdef TCGETS2 COMPATIBLE_IOCTL(TCGETS2) COMPATIBLE_IOCTL(TCSETS2) diff --git a/include/asm-generic/ioctls.h b/include/asm-generic/ioctls.h index 1375fa1a7a4..8554cb6a81b 100644 --- a/include/asm-generic/ioctls.h +++ b/include/asm-generic/ioctls.h @@ -69,6 +69,7 @@ #define TCSETX 0x5433 #define TCSETXF 0x5434 #define TCSETXW 0x5435 +#define TIOCSIG _IOW('T', 0x36, int) /* pty: generate signal */ #define FIONCLEX 0x5450 #define FIOCLEX 0x5451 @@ -102,6 +103,7 @@ #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ diff --git a/include/asm-generic/termbits.h b/include/asm-generic/termbits.h index 1c9773d48cb..232b4781aef 100644 --- a/include/asm-generic/termbits.h +++ b/include/asm-generic/termbits.h @@ -178,6 +178,7 @@ struct ktermios { #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 +#define EXTPROC 0200000 /* tcflow() and TCXONC use these */ #define TCOOFF 0 diff --git a/include/linux/tty.h b/include/linux/tty.h index 7802a243ee1..2df60e4ff40 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -179,6 +179,7 @@ struct tty_bufhead { #define L_FLUSHO(tty) _L_FLAG((tty), FLUSHO) #define L_PENDIN(tty) _L_FLAG((tty), PENDIN) #define L_IEXTEN(tty) _L_FLAG((tty), IEXTEN) +#define L_EXTPROC(tty) _L_FLAG((tty), EXTPROC) struct device; struct signal_struct; -- cgit v1.2.3-70-g09d2 From a6eb9fe105d5de0053b261148cee56c94b4720ca Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Aug 2010 18:03:22 -0700 Subject: dma-mapping: rename ARCH_KMALLOC_MINALIGN to ARCH_DMA_MINALIGN Now each architecture has the own dma_get_cache_alignment implementation. dma_get_cache_alignment returns the minimum DMA alignment. Architectures define it as ARCH_KMALLOC_MINALIGN (it's used to make sure that malloc'ed buffer is DMA-safe; the buffer doesn't share a cache with the others). So we can unify dma_get_cache_alignment implementations. This patch: dma_get_cache_alignment() needs to know if an architecture defines ARCH_KMALLOC_MINALIGN or not (needs to know if architecture has DMA alignment restriction). However, slab.h define ARCH_KMALLOC_MINALIGN if architectures doesn't define it. Let's rename ARCH_KMALLOC_MINALIGN to ARCH_DMA_MINALIGN. ARCH_KMALLOC_MINALIGN is used only in the internals of slab/slob/slub (except for crypto). Signed-off-by: FUJITA Tomonori Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/include/asm/cache.h | 2 +- arch/avr32/include/asm/cache.h | 2 +- arch/blackfin/include/asm/cache.h | 2 +- arch/frv/include/asm/mem-layout.h | 2 +- arch/m68k/include/asm/cache.h | 2 +- arch/microblaze/include/asm/page.h | 2 +- arch/mips/include/asm/mach-generic/kmalloc.h | 2 +- arch/mips/include/asm/mach-ip27/kmalloc.h | 2 +- arch/mips/include/asm/mach-ip32/kmalloc.h | 4 ++-- arch/mn10300/include/asm/cache.h | 2 +- arch/powerpc/include/asm/page_32.h | 2 +- arch/sh/include/asm/page.h | 2 +- arch/xtensa/include/asm/cache.h | 2 +- include/linux/slab_def.h | 4 +++- include/linux/slob_def.h | 4 +++- include/linux/slub_def.h | 8 +++++--- 16 files changed, 25 insertions(+), 19 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h index 66c160b8547..9d6122096fb 100644 --- a/arch/arm/include/asm/cache.h +++ b/arch/arm/include/asm/cache.h @@ -14,7 +14,7 @@ * cache before the transfer is done, causing old data to be seen by * the CPU. */ -#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES /* * With EABI on ARMv5 and above we must have 64-bit aligned slab pointers. diff --git a/arch/avr32/include/asm/cache.h b/arch/avr32/include/asm/cache.h index d3cf35ab11a..c3a58a189a9 100644 --- a/arch/avr32/include/asm/cache.h +++ b/arch/avr32/include/asm/cache.h @@ -11,7 +11,7 @@ * cache before the transfer is done, causing old data to be seen by * the CPU. */ -#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES #ifndef __ASSEMBLER__ struct cache_info { diff --git a/arch/blackfin/include/asm/cache.h b/arch/blackfin/include/asm/cache.h index 93f6c634fdf..bd0641a267f 100644 --- a/arch/blackfin/include/asm/cache.h +++ b/arch/blackfin/include/asm/cache.h @@ -15,7 +15,7 @@ #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) #define SMP_CACHE_BYTES L1_CACHE_BYTES -#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES #ifdef CONFIG_SMP #define __cacheline_aligned diff --git a/arch/frv/include/asm/mem-layout.h b/arch/frv/include/asm/mem-layout.h index ccae981876f..e9a0ec85a40 100644 --- a/arch/frv/include/asm/mem-layout.h +++ b/arch/frv/include/asm/mem-layout.h @@ -35,7 +35,7 @@ * the slab must be aligned such that load- and store-double instructions don't * fault if used */ -#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES #define ARCH_SLAB_MINALIGN L1_CACHE_BYTES /*****************************************************************************/ diff --git a/arch/m68k/include/asm/cache.h b/arch/m68k/include/asm/cache.h index ecafbe1718c..0395c51e46a 100644 --- a/arch/m68k/include/asm/cache.h +++ b/arch/m68k/include/asm/cache.h @@ -8,6 +8,6 @@ #define L1_CACHE_SHIFT 4 #define L1_CACHE_BYTES (1<< L1_CACHE_SHIFT) -#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES #endif diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h index 4f268faa012..cf377d91da7 100644 --- a/arch/microblaze/include/asm/page.h +++ b/arch/microblaze/include/asm/page.h @@ -40,7 +40,7 @@ #ifndef __ASSEMBLY__ /* MS be sure that SLAB allocates aligned objects */ -#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES #define ARCH_SLAB_MINALIGN L1_CACHE_BYTES diff --git a/arch/mips/include/asm/mach-generic/kmalloc.h b/arch/mips/include/asm/mach-generic/kmalloc.h index b8e6deba352..a5d669086ed 100644 --- a/arch/mips/include/asm/mach-generic/kmalloc.h +++ b/arch/mips/include/asm/mach-generic/kmalloc.h @@ -7,7 +7,7 @@ * Total overkill for most systems but need as a safe default. * Set this one if any device in the system might do non-coherent DMA. */ -#define ARCH_KMALLOC_MINALIGN 128 +#define ARCH_DMA_MINALIGN 128 #endif #endif /* __ASM_MACH_GENERIC_KMALLOC_H */ diff --git a/arch/mips/include/asm/mach-ip27/kmalloc.h b/arch/mips/include/asm/mach-ip27/kmalloc.h index 426bd049b2d..82c23ce2afa 100644 --- a/arch/mips/include/asm/mach-ip27/kmalloc.h +++ b/arch/mips/include/asm/mach-ip27/kmalloc.h @@ -2,7 +2,7 @@ #define __ASM_MACH_IP27_KMALLOC_H /* - * All happy, no need to define ARCH_KMALLOC_MINALIGN + * All happy, no need to define ARCH_DMA_MINALIGN */ #endif /* __ASM_MACH_IP27_KMALLOC_H */ diff --git a/arch/mips/include/asm/mach-ip32/kmalloc.h b/arch/mips/include/asm/mach-ip32/kmalloc.h index b1e0be60f72..042ca926c48 100644 --- a/arch/mips/include/asm/mach-ip32/kmalloc.h +++ b/arch/mips/include/asm/mach-ip32/kmalloc.h @@ -3,9 +3,9 @@ #if defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_RM7000) -#define ARCH_KMALLOC_MINALIGN 32 +#define ARCH_DMA_MINALIGN 32 #else -#define ARCH_KMALLOC_MINALIGN 128 +#define ARCH_DMA_MINALIGN 128 #endif #endif /* __ASM_MACH_IP32_KMALLOC_H */ diff --git a/arch/mn10300/include/asm/cache.h b/arch/mn10300/include/asm/cache.h index 6e2fe28dde4..781bf613366 100644 --- a/arch/mn10300/include/asm/cache.h +++ b/arch/mn10300/include/asm/cache.h @@ -21,7 +21,7 @@ #define L1_CACHE_DISPARITY L1_CACHE_NENTRIES * L1_CACHE_BYTES #endif -#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES /* data cache purge registers * - read from the register to unconditionally purge that cache line diff --git a/arch/powerpc/include/asm/page_32.h b/arch/powerpc/include/asm/page_32.h index bd0849dbcaa..68d73b2a7bf 100644 --- a/arch/powerpc/include/asm/page_32.h +++ b/arch/powerpc/include/asm/page_32.h @@ -10,7 +10,7 @@ #define VM_DATA_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS32 #ifdef CONFIG_NOT_COHERENT_CACHE -#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES #endif #ifdef CONFIG_PTE_64BIT diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h index fb703d120d0..c4e0b3d472b 100644 --- a/arch/sh/include/asm/page.h +++ b/arch/sh/include/asm/page.h @@ -180,7 +180,7 @@ typedef struct page *pgtable_t; * Some drivers need to perform DMA into kmalloc'ed buffers * and so we have to increase the kmalloc minalign for this. */ -#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES #ifdef CONFIG_SUPERH64 /* diff --git a/arch/xtensa/include/asm/cache.h b/arch/xtensa/include/asm/cache.h index ed8cd3cbd49..d2fd932fdb4 100644 --- a/arch/xtensa/include/asm/cache.h +++ b/arch/xtensa/include/asm/cache.h @@ -29,6 +29,6 @@ # define CACHE_WAY_SIZE ICACHE_WAY_SIZE #endif -#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES #endif /* _XTENSA_CACHE_H */ diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h index 1acfa73ce2a..791a502f690 100644 --- a/include/linux/slab_def.h +++ b/include/linux/slab_def.h @@ -17,7 +17,6 @@ #include -#ifndef ARCH_KMALLOC_MINALIGN /* * Enforce a minimum alignment for the kmalloc caches. * Usually, the kmalloc caches are cache_line_size() aligned, except when @@ -27,6 +26,9 @@ * ARCH_KMALLOC_MINALIGN allows that. * Note that increasing this value may disable some debug features. */ +#ifdef ARCH_DMA_MINALIGN +#define ARCH_KMALLOC_MINALIGN ARCH_DMA_MINALIGN +#else #define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long) #endif diff --git a/include/linux/slob_def.h b/include/linux/slob_def.h index 62667f72c2e..4382db09df4 100644 --- a/include/linux/slob_def.h +++ b/include/linux/slob_def.h @@ -1,7 +1,9 @@ #ifndef __LINUX_SLOB_DEF_H #define __LINUX_SLOB_DEF_H -#ifndef ARCH_KMALLOC_MINALIGN +#ifdef ARCH_DMA_MINALIGN +#define ARCH_KMALLOC_MINALIGN ARCH_DMA_MINALIGN +#else #define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long) #endif diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h index 6447a723ecb..6d14409c4d9 100644 --- a/include/linux/slub_def.h +++ b/include/linux/slub_def.h @@ -106,15 +106,17 @@ struct kmem_cache { /* * Kmalloc subsystem. */ -#if defined(ARCH_KMALLOC_MINALIGN) && ARCH_KMALLOC_MINALIGN > 8 -#define KMALLOC_MIN_SIZE ARCH_KMALLOC_MINALIGN +#if defined(ARCH_DMA_MINALIGN) && ARCH_DMA_MINALIGN > 8 +#define KMALLOC_MIN_SIZE ARCH_DMA_MINALIGN #else #define KMALLOC_MIN_SIZE 8 #endif #define KMALLOC_SHIFT_LOW ilog2(KMALLOC_MIN_SIZE) -#ifndef ARCH_KMALLOC_MINALIGN +#ifdef ARCH_DMA_MINALIGN +#define ARCH_KMALLOC_MINALIGN ARCH_DMA_MINALIGN +#else #define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long) #endif -- cgit v1.2.3-70-g09d2 From 4565f0170dfc849b3629c27d769db800467baa62 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Aug 2010 18:03:22 -0700 Subject: dma-mapping: unify dma_get_cache_alignment implementations dma_get_cache_alignment returns the minimum DMA alignment. Architectures defines it as ARCH_DMA_MINALIGN (formally ARCH_KMALLOC_MINALIGN). So we can unify dma_get_cache_alignment implementations. Note that some architectures implement dma_get_cache_alignment wrongly. dma_get_cache_alignment() should return the minimum DMA alignment. So fully-coherent architectures should return 1. This patch also fixes this issue. Signed-off-by: FUJITA Tomonori Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/include/asm/dma-mapping.h | 1 - arch/arm/include/asm/dma-mapping.h | 5 ----- arch/avr32/include/asm/dma-mapping.h | 5 ----- arch/blackfin/include/asm/dma-mapping.h | 1 - arch/cris/include/asm/dma-mapping.h | 6 ------ arch/frv/include/asm/dma-mapping.h | 6 ------ arch/ia64/include/asm/dma-mapping.h | 2 -- arch/ia64/kernel/setup.c | 6 ------ arch/m68k/include/asm/dma-mapping.h | 5 ----- arch/microblaze/include/asm/dma-mapping.h | 5 ----- arch/mips/include/asm/dma-mapping.h | 7 ------- arch/mn10300/include/asm/dma-mapping.h | 6 ------ arch/parisc/include/asm/dma-mapping.h | 6 ------ arch/powerpc/include/asm/dma-mapping.h | 15 --------------- arch/sh/include/asm/dma-mapping.h | 9 --------- arch/sparc/include/asm/dma-mapping.h | 9 --------- arch/tile/include/asm/dma-mapping.h | 7 ------- arch/x86/include/asm/dma-mapping.h | 7 ------- arch/xtensa/include/asm/dma-mapping.h | 6 ------ include/linux/dma-mapping.h | 8 ++++++++ 20 files changed, 8 insertions(+), 114 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/arch/alpha/include/asm/dma-mapping.h b/arch/alpha/include/asm/dma-mapping.h index 1bce8169733..b3423d96acc 100644 --- a/arch/alpha/include/asm/dma-mapping.h +++ b/arch/alpha/include/asm/dma-mapping.h @@ -44,6 +44,5 @@ static inline int dma_set_mask(struct device *dev, u64 mask) #define dma_is_consistent(d, h) (1) #define dma_cache_sync(dev, va, size, dir) ((void)0) -#define dma_get_cache_alignment() L1_CACHE_BYTES #endif /* _ALPHA_DMA_MAPPING_H */ diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 69ce0727edb..f4a996d5ae9 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -144,11 +144,6 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask) return 0; } -static inline int dma_get_cache_alignment(void) -{ - return 32; -} - static inline int dma_is_consistent(struct device *dev, dma_addr_t handle) { return !!arch_is_coherent(); diff --git a/arch/avr32/include/asm/dma-mapping.h b/arch/avr32/include/asm/dma-mapping.h index 0399359ab5d..af6b8165507 100644 --- a/arch/avr32/include/asm/dma-mapping.h +++ b/arch/avr32/include/asm/dma-mapping.h @@ -341,9 +341,4 @@ static inline int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) return 1; } -static inline int dma_get_cache_alignment(void) -{ - return boot_cpu_data.dcache.linesz; -} - #endif /* __ASM_AVR32_DMA_MAPPING_H */ diff --git a/arch/blackfin/include/asm/dma-mapping.h b/arch/blackfin/include/asm/dma-mapping.h index 212cb80fd74..6694a0f55de 100644 --- a/arch/blackfin/include/asm/dma-mapping.h +++ b/arch/blackfin/include/asm/dma-mapping.h @@ -21,7 +21,6 @@ void dma_free_coherent(struct device *dev, size_t size, void *vaddr, #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) #define dma_supported(d, m) (1) -#define dma_get_cache_alignment() (32) #define dma_is_consistent(d, h) (1) static inline int diff --git a/arch/cris/include/asm/dma-mapping.h b/arch/cris/include/asm/dma-mapping.h index da8ef8e8f84..fc30fd0b2a0 100644 --- a/arch/cris/include/asm/dma-mapping.h +++ b/arch/cris/include/asm/dma-mapping.h @@ -152,12 +152,6 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } -static inline int -dma_get_cache_alignment(void) -{ - return (1 << INTERNODE_CACHE_SHIFT); -} - #define dma_is_consistent(d, h) (1) static inline void diff --git a/arch/frv/include/asm/dma-mapping.h b/arch/frv/include/asm/dma-mapping.h index 6af5d83e2fb..7b05ce14177 100644 --- a/arch/frv/include/asm/dma-mapping.h +++ b/arch/frv/include/asm/dma-mapping.h @@ -125,12 +125,6 @@ int dma_set_mask(struct device *dev, u64 mask) return 0; } -static inline -int dma_get_cache_alignment(void) -{ - return 1 << L1_CACHE_SHIFT; -} - #define dma_is_consistent(d, h) (1) static inline diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index 7d09a09cdaa..8d52deed375 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h @@ -86,8 +86,6 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) return daddr; } -extern int dma_get_cache_alignment(void); - static inline void dma_cache_sync (struct device *dev, void *vaddr, size_t size, enum dma_data_direction dir) diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 41ae6a596b5..8fb958abf8d 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -98,12 +98,6 @@ static struct resource bss_resource = { unsigned long ia64_max_cacheline_size; -int dma_get_cache_alignment(void) -{ - return ia64_max_cacheline_size; -} -EXPORT_SYMBOL(dma_get_cache_alignment); - unsigned long ia64_iobase; /* virtual address for I/O accesses */ EXPORT_SYMBOL(ia64_iobase); struct io_space io_space[MAX_IO_SPACES]; diff --git a/arch/m68k/include/asm/dma-mapping.h b/arch/m68k/include/asm/dma-mapping.h index 26f505488c1..a1ae732c724 100644 --- a/arch/m68k/include/asm/dma-mapping.h +++ b/arch/m68k/include/asm/dma-mapping.h @@ -16,11 +16,6 @@ static inline int dma_set_mask(struct device *dev, u64 mask) return 0; } -static inline int dma_get_cache_alignment(void) -{ - return 1 << L1_CACHE_SHIFT; -} - static inline int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) { return 0; diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h index 50738958070..21df7cbae65 100644 --- a/arch/microblaze/include/asm/dma-mapping.h +++ b/arch/microblaze/include/asm/dma-mapping.h @@ -132,11 +132,6 @@ static inline void dma_free_coherent(struct device *dev, size_t size, ops->free_coherent(dev, size, cpu_addr, dma_handle); } -static inline int dma_get_cache_alignment(void) -{ - return L1_CACHE_BYTES; -} - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h index 664ba53dc32..d724a15f043 100644 --- a/arch/mips/include/asm/dma-mapping.h +++ b/arch/mips/include/asm/dma-mapping.h @@ -62,13 +62,6 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } -static inline int -dma_get_cache_alignment(void) -{ - /* XXX Largest on any MIPS */ - return 128; -} - extern int dma_is_consistent(struct device *dev, dma_addr_t dma_addr); extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size, diff --git a/arch/mn10300/include/asm/dma-mapping.h b/arch/mn10300/include/asm/dma-mapping.h index 4ed1522b38d..8d452a65779 100644 --- a/arch/mn10300/include/asm/dma-mapping.h +++ b/arch/mn10300/include/asm/dma-mapping.h @@ -161,12 +161,6 @@ int dma_set_mask(struct device *dev, u64 mask) return 0; } -static inline -int dma_get_cache_alignment(void) -{ - return 1 << L1_CACHE_SHIFT; -} - #define dma_is_consistent(d) (1) static inline diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h index da694338090..44d3f62ccf9 100644 --- a/arch/parisc/include/asm/dma-mapping.h +++ b/arch/parisc/include/asm/dma-mapping.h @@ -184,12 +184,6 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } -static inline int -dma_get_cache_alignment(void) -{ - return dcache_stride; -} - static inline int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) { diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index c85ef230135..a77ba280af0 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -215,21 +215,6 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) #define dma_is_consistent(d, h) (1) #endif -static inline int dma_get_cache_alignment(void) -{ -#ifdef CONFIG_PPC64 - /* no easy way to get cache size on all processors, so return - * the maximum possible, to be safe */ - return (1 << INTERNODE_CACHE_SHIFT); -#else - /* - * Each processor family will define its own L1_CACHE_SHIFT, - * L1_CACHE_BYTES wraps to this, so this is always safe. - */ - return L1_CACHE_BYTES; -#endif -} - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h index bea3337a426..6bb5cc9decf 100644 --- a/arch/sh/include/asm/dma-mapping.h +++ b/arch/sh/include/asm/dma-mapping.h @@ -48,15 +48,6 @@ void dma_cache_sync(struct device *dev, void *vaddr, size_t size, #define dma_is_consistent(d, h) (0) #endif -static inline int dma_get_cache_alignment(void) -{ - /* - * Each processor family will define its own L1_CACHE_SHIFT, - * L1_CACHE_BYTES wraps to this, so this is always safe. - */ - return L1_CACHE_BYTES; -} - static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { struct dma_map_ops *ops = get_dma_ops(dev); diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 4b4a0c0b0cc..74db853ec2c 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -52,15 +52,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) return (dma_addr == DMA_ERROR_CODE); } -static inline int dma_get_cache_alignment(void) -{ - /* - * no easy way to get cache size on all processors, so return - * the maximum possible, to be safe - */ - return (1 << INTERNODE_CACHE_SHIFT); -} - static inline int dma_set_mask(struct device *dev, u64 mask) { #ifdef CONFIG_PCI diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h index cf466b39aa1..1326b910fec 100644 --- a/arch/tile/include/asm/dma-mapping.h +++ b/arch/tile/include/asm/dma-mapping.h @@ -90,13 +90,6 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } -static inline int -dma_get_cache_alignment(void) -{ - return L2_CACHE_BYTES; -} - #define dma_is_consistent(d, h) (1) - #endif /* _ASM_TILE_DMA_MAPPING_H */ diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index ac91eed2106..f9c67e83f64 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -87,13 +87,6 @@ dma_cache_sync(struct device *dev, void *vaddr, size_t size, flush_write_buffers(); } -static inline int dma_get_cache_alignment(void) -{ - /* no easy way to get cache size on all x86, so return the - * maximum possible, to be safe */ - return boot_cpu_data.x86_clflush_size; -} - static inline unsigned long dma_alloc_coherent_mask(struct device *dev, gfp_t gfp) { diff --git a/arch/xtensa/include/asm/dma-mapping.h b/arch/xtensa/include/asm/dma-mapping.h index 51882ae3db4..7104f2f9823 100644 --- a/arch/xtensa/include/asm/dma-mapping.h +++ b/arch/xtensa/include/asm/dma-mapping.h @@ -161,12 +161,6 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } -static inline int -dma_get_cache_alignment(void) -{ - return L1_CACHE_BYTES; -} - #define dma_is_consistent(d, h) (1) static inline void diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 89b7e1a605b..e0670a51205 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -142,6 +142,14 @@ static inline int dma_set_seg_boundary(struct device *dev, unsigned long mask) return -EIO; } +static inline int dma_get_cache_alignment(void) +{ +#ifdef ARCH_DMA_MINALIGN + return ARCH_DMA_MINALIGN; +#endif + return 1; +} + /* flags for the coherent memory api */ #define DMA_MEMORY_MAP 0x01 #define DMA_MEMORY_IO 0x02 -- cgit v1.2.3-70-g09d2 From 3b9c6c11f519718d618f5d7c9508daf78b207f6f Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Aug 2010 18:03:25 -0700 Subject: dma-mapping: remove dma_is_consistent API Architectures implement dma_is_consistent() in different ways (some misinterpret the definition of API in DMA-API.txt). So it hasn't been so useful for drivers. We have only one user of the API in tree. Unlikely out-of-tree drivers use the API. Even if we fix dma_is_consistent() in some architectures, it doesn't look useful at all. It was invented long ago for some old systems that can't allocate coherent memory at all. It's better to export only APIs that are definitely necessary for drivers. Let's remove this API. Signed-off-by: FUJITA Tomonori Cc: James Bottomley Reviewed-by: Konrad Rzeszutek Wilk Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/DMA-API.txt | 6 ------ arch/alpha/include/asm/dma-mapping.h | 1 - arch/arm/include/asm/dma-mapping.h | 5 ----- arch/avr32/include/asm/dma-mapping.h | 5 ----- arch/blackfin/include/asm/dma-mapping.h | 1 - arch/cris/include/asm/dma-mapping.h | 2 -- arch/frv/include/asm/dma-mapping.h | 2 -- arch/ia64/include/asm/dma-mapping.h | 2 -- arch/m68k/include/asm/dma-mapping.h | 5 ----- arch/microblaze/include/asm/dma-mapping.h | 1 - arch/mips/include/asm/dma-mapping.h | 2 -- arch/mips/mm/dma-default.c | 7 ------- arch/mn10300/include/asm/dma-mapping.h | 2 -- arch/parisc/include/asm/dma-mapping.h | 6 ------ arch/powerpc/include/asm/dma-mapping.h | 5 ----- arch/sh/include/asm/dma-mapping.h | 6 ------ arch/sparc/include/asm/dma-mapping.h | 1 - arch/tile/include/asm/dma-mapping.h | 2 -- arch/um/include/asm/dma-mapping.h | 1 - arch/x86/include/asm/dma-mapping.h | 1 - arch/xtensa/include/asm/dma-mapping.h | 2 -- include/asm-generic/dma-mapping-broken.h | 3 --- 22 files changed, 68 deletions(-) (limited to 'arch/mips/include/asm') diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt index 05e2ae23686..fe232690661 100644 --- a/Documentation/DMA-API.txt +++ b/Documentation/DMA-API.txt @@ -455,12 +455,6 @@ Free memory allocated by the nonconsistent API. All parameters must be identical to those passed in (and returned by dma_alloc_noncoherent()). -int -dma_is_consistent(struct device *dev, dma_addr_t dma_handle) - -Returns true if the device dev is performing consistent DMA on the memory -area pointed to by the dma_handle. - int dma_get_cache_alignment(void) diff --git a/arch/alpha/include/asm/dma-mapping.h b/arch/alpha/include/asm/dma-mapping.h index b3423d96acc..4567aca6fdd 100644 --- a/arch/alpha/include/asm/dma-mapping.h +++ b/arch/alpha/include/asm/dma-mapping.h @@ -41,7 +41,6 @@ static inline int dma_set_mask(struct device *dev, u64 mask) #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -#define dma_is_consistent(d, h) (1) #define dma_cache_sync(dev, va, size, dir) ((void)0) diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index f4a996d5ae9..c568da7dcae 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -144,11 +144,6 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask) return 0; } -static inline int dma_is_consistent(struct device *dev, dma_addr_t handle) -{ - return !!arch_is_coherent(); -} - /* * DMA errors are defined by all-bits-set in the DMA address. */ diff --git a/arch/avr32/include/asm/dma-mapping.h b/arch/avr32/include/asm/dma-mapping.h index af6b8165507..aaf5199d8fc 100644 --- a/arch/avr32/include/asm/dma-mapping.h +++ b/arch/avr32/include/asm/dma-mapping.h @@ -336,9 +336,4 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -static inline int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) -{ - return 1; -} - #endif /* __ASM_AVR32_DMA_MAPPING_H */ diff --git a/arch/blackfin/include/asm/dma-mapping.h b/arch/blackfin/include/asm/dma-mapping.h index 6694a0f55de..bbf461076a0 100644 --- a/arch/blackfin/include/asm/dma-mapping.h +++ b/arch/blackfin/include/asm/dma-mapping.h @@ -21,7 +21,6 @@ void dma_free_coherent(struct device *dev, size_t size, void *vaddr, #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) #define dma_supported(d, m) (1) -#define dma_is_consistent(d, h) (1) static inline int dma_set_mask(struct device *dev, u64 dma_mask) diff --git a/arch/cris/include/asm/dma-mapping.h b/arch/cris/include/asm/dma-mapping.h index fc30fd0b2a0..8588b2ccf85 100644 --- a/arch/cris/include/asm/dma-mapping.h +++ b/arch/cris/include/asm/dma-mapping.h @@ -152,8 +152,6 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } -#define dma_is_consistent(d, h) (1) - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) diff --git a/arch/frv/include/asm/dma-mapping.h b/arch/frv/include/asm/dma-mapping.h index 7b05ce14177..dfb811002c6 100644 --- a/arch/frv/include/asm/dma-mapping.h +++ b/arch/frv/include/asm/dma-mapping.h @@ -125,8 +125,6 @@ int dma_set_mask(struct device *dev, u64 mask) return 0; } -#define dma_is_consistent(d, h) (1) - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index 8d52deed375..a2e7368a015 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h @@ -97,6 +97,4 @@ dma_cache_sync (struct device *dev, void *vaddr, size_t size, mb(); } -#define dma_is_consistent(d, h) (1) /* all we do is coherent memory... */ - #endif /* _ASM_IA64_DMA_MAPPING_H */ diff --git a/arch/m68k/include/asm/dma-mapping.h b/arch/m68k/include/asm/dma-mapping.h index a1ae732c724..17f7a45948e 100644 --- a/arch/m68k/include/asm/dma-mapping.h +++ b/arch/m68k/include/asm/dma-mapping.h @@ -16,11 +16,6 @@ static inline int dma_set_mask(struct device *dev, u64 mask) return 0; } -static inline int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) -{ - return 0; -} - extern void *dma_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t); extern void dma_free_coherent(struct device *, size_t, diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h index 21df7cbae65..8fbb0ec1023 100644 --- a/arch/microblaze/include/asm/dma-mapping.h +++ b/arch/microblaze/include/asm/dma-mapping.h @@ -106,7 +106,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -#define dma_is_consistent(d, h) (1) static inline void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h index d724a15f043..18fbf7af8e9 100644 --- a/arch/mips/include/asm/dma-mapping.h +++ b/arch/mips/include/asm/dma-mapping.h @@ -62,8 +62,6 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } -extern int dma_is_consistent(struct device *dev, dma_addr_t dma_addr); - extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction); diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 9547bc0cf18..7ba890860d9 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -357,13 +357,6 @@ int dma_supported(struct device *dev, u64 mask) EXPORT_SYMBOL(dma_supported); -int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) -{ - return plat_device_is_coherent(dev); -} - -EXPORT_SYMBOL(dma_is_consistent); - void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { diff --git a/arch/mn10300/include/asm/dma-mapping.h b/arch/mn10300/include/asm/dma-mapping.h index 8d452a65779..c1be4397b1e 100644 --- a/arch/mn10300/include/asm/dma-mapping.h +++ b/arch/mn10300/include/asm/dma-mapping.h @@ -161,8 +161,6 @@ int dma_set_mask(struct device *dev, u64 mask) return 0; } -#define dma_is_consistent(d) (1) - static inline void dma_cache_sync(void *vaddr, size_t size, enum dma_data_direction direction) diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h index 44d3f62ccf9..4ef73b09b16 100644 --- a/arch/parisc/include/asm/dma-mapping.h +++ b/arch/parisc/include/asm/dma-mapping.h @@ -184,12 +184,6 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } -static inline int -dma_is_consistent(struct device *dev, dma_addr_t dma_addr) -{ - return (hppa_dma_ops->dma_sync_single_for_cpu == NULL); -} - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index a77ba280af0..8c9c6ad2004 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -209,11 +209,6 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -#ifdef CONFIG_NOT_COHERENT_CACHE -#define dma_is_consistent(d, h) (0) -#else -#define dma_is_consistent(d, h) (1) -#endif static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h index 6bb5cc9decf..1a73c3e759a 100644 --- a/arch/sh/include/asm/dma-mapping.h +++ b/arch/sh/include/asm/dma-mapping.h @@ -42,12 +42,6 @@ void dma_cache_sync(struct device *dev, void *vaddr, size_t size, #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -#ifdef CONFIG_DMA_COHERENT -#define dma_is_consistent(d, h) (1) -#else -#define dma_is_consistent(d, h) (0) -#endif - static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { struct dma_map_ops *ops = get_dma_ops(dev); diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 74db853ec2c..8c0e4f7bb20 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -11,7 +11,6 @@ extern int dma_supported(struct device *dev, u64 mask); #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -#define dma_is_consistent(d, h) (1) extern struct dma_map_ops *dma_ops, pci32_dma_ops; extern struct bus_type pci_bus_type; diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h index 1326b910fec..15e1dceecc6 100644 --- a/arch/tile/include/asm/dma-mapping.h +++ b/arch/tile/include/asm/dma-mapping.h @@ -90,6 +90,4 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } -#define dma_is_consistent(d, h) (1) - #endif /* _ASM_TILE_DMA_MAPPING_H */ diff --git a/arch/um/include/asm/dma-mapping.h b/arch/um/include/asm/dma-mapping.h index b948c14a786..17a2cb5a417 100644 --- a/arch/um/include/asm/dma-mapping.h +++ b/arch/um/include/asm/dma-mapping.h @@ -94,7 +94,6 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -#define dma_is_consistent(d, h) (1) static inline int dma_get_cache_alignment(void) diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index f9c67e83f64..d4c419f883a 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -54,7 +54,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -#define dma_is_consistent(d, h) (1) extern int dma_supported(struct device *hwdev, u64 mask); extern int dma_set_mask(struct device *dev, u64 mask); diff --git a/arch/xtensa/include/asm/dma-mapping.h b/arch/xtensa/include/asm/dma-mapping.h index 7104f2f9823..492c95790ad 100644 --- a/arch/xtensa/include/asm/dma-mapping.h +++ b/arch/xtensa/include/asm/dma-mapping.h @@ -161,8 +161,6 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } -#define dma_is_consistent(d, h) (1) - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) diff --git a/include/asm-generic/dma-mapping-broken.h b/include/asm-generic/dma-mapping-broken.h index 82cd0cb1c3f..ccf7b4f34a3 100644 --- a/include/asm-generic/dma-mapping-broken.h +++ b/include/asm-generic/dma-mapping-broken.h @@ -72,9 +72,6 @@ dma_set_mask(struct device *dev, u64 mask); extern int dma_get_cache_alignment(void); -extern int -dma_is_consistent(struct device *dev, dma_addr_t dma_handle); - extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction); -- cgit v1.2.3-70-g09d2